Commit e0f1a9d5 authored by Tres Seaver's avatar Tres Seaver

Clean imports, docstrings; add an instance-level hook for GC parms.

parent d49d49a3
...@@ -10,45 +10,50 @@ ...@@ -10,45 +10,50 @@
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE
# #
############################################################################## ##############################################################################
""" A storage implementation which uses RAM to persist objects
""" Although this storage is much like MappingStorage, it does not need to be
A storage implementation which uses RAM to persist objects, much like packed to get rid of non-cyclic garbage and it does rudimentary conflict
MappingStorage. Unlike MappingStorage, it needs not be packed to get rid of resolution.
non-cyclic garbage and it does rudimentary conflict resolution. This is a
ripoff of Jim's Packless bsddb3 storage.
$Id$ This is a ripoff of Jim's Packless bsddb3 storage.
""" """
import bisect
__version__ ='$Revision: 1.1.2.2 $'[11:-2]
from logging import getLogger from logging import getLogger
from ZODB.serialize import referencesf import time
from ZODB.utils import z64
from ZODB import POSException from ZODB import POSException
from ZODB.BaseStorage import BaseStorage from ZODB.BaseStorage import BaseStorage
from ZODB.ConflictResolution import ConflictResolvingStorage, ResolvedSerial from ZODB.ConflictResolution import ConflictResolvingStorage
import time from ZODB.ConflictResolution import ResolvedSerial
import bisect from ZODB.serialize import referencesf
from ZODB.utils import z64
# keep old object revisions for CONFLICT_CACHE_MAXAGE seconds # keep old object revisions for CONFLICT_CACHE_MAXAGE seconds
CONFLICT_CACHE_MAXAGE = 60 CONFLICT_CACHE_MAXAGE = 60
# garbage collect conflict cache every CONFLICT_CACHE_GCEVERY seconds # garbage collect conflict cache every CONFLICT_CACHE_GCEVERY seconds
CONFLICT_CACHE_GCEVERY = 60 CONFLICT_CACHE_GCEVERY = 60
# keep history of recently gc'ed oids of length RECENTLY_GC_OIDS_LEN # keep history of recently gc'ed oids of length RECENTLY_GC_OIDS_LEN
RECENTLY_GC_OIDS_LEN = 200 RECENTLY_GC_OIDS_LEN = 200
LOG = getLogger('TemporaryStorage') LOG = getLogger('TemporaryStorage')
class ReferenceCountError(POSException.POSError): class ReferenceCountError(POSException.POSError):
""" An error occured while decrementing a reference to an object in """ Error while decrementing a reference to an object in the commit phase.
the commit phase. The object's reference count was below zero."""
The object's reference count was below zero.
"""
class TemporaryStorageError(POSException.POSError): class TemporaryStorageError(POSException.POSError):
""" A Temporary Storage exception occurred. This probably indicates that """ A Temporary Storage exception occurred.
there is a low memory condition or a tempfile space shortage. Check
available tempfile space and RAM consumption and restart the server This probably indicates that there is a low memory condition or a
process.""" tempfile space shortage. Check available tempfile space and RAM
consumption and restart the server process.
"""
class TemporaryStorage(BaseStorage, ConflictResolvingStorage): class TemporaryStorage(BaseStorage, ConflictResolvingStorage):
...@@ -76,8 +81,13 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage): ...@@ -76,8 +81,13 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage):
self._oid = z64 self._oid = z64
self._ltid = z64 self._ltid = z64
# Alow overrides for testing.
self._conflict_cache_gcevery = CONFLICT_CACHE_GCEVERY
self._conflict_cache_maxage = CONFLICT_CACHE_MAXAGE
def lastTransaction(self): def lastTransaction(self):
""" Return tid for last committed transaction (for ZEO) """ """ Return tid for last committed transaction (for ZEO)
"""
return self._ltid return self._ltid
def __len__(self): def __len__(self):
...@@ -88,17 +98,16 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage): ...@@ -88,17 +98,16 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage):
def _clear_temp(self): def _clear_temp(self):
now = time.time() now = time.time()
if now > (self._last_cache_gc + CONFLICT_CACHE_GCEVERY): if now > (self._last_cache_gc + self._conflict_cache_gcevery):
for k, v in self._conflict_cache.items(): for k, v in self._conflict_cache.items():
data, t = v data, t = v
if now > (t + CONFLICT_CACHE_MAXAGE): if now > (t + self._conflict_cache_maxage):
del self._conflict_cache[k] del self._conflict_cache[k]
self._last_cache_gc = now self._last_cache_gc = now
self._tmp = [] self._tmp = []
def close(self): def close(self):
""" """ Close the storage
Close the storage
""" """
def load(self, oid, version): def load(self, oid, version):
...@@ -140,9 +149,11 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage): ...@@ -140,9 +149,11 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage):
return (data[0], data[1], "") return (data[0], data[1], "")
def loadSerial(self, oid, serial, marker=[]): def loadSerial(self, oid, serial, marker=[]):
""" this is only useful to make conflict resolution work. It """ This is only useful to make conflict resolution work.
does not actually implement all the semantics that a revisioning
storage needs! """ It does not actually implement all the semantics that a revisioning
storage needs!
"""
self._lock_acquire() self._lock_acquire()
try: try:
data = self._conflict_cache.get((oid, serial), marker) data = self._conflict_cache.get((oid, serial), marker)
...@@ -156,9 +167,10 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage): ...@@ -156,9 +167,10 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage):
self._lock_release() self._lock_release()
def loadBefore(self, oid, tid): def loadBefore(self, oid, tid):
"""Return most recent revision of oid before tid committed """ Return most recent revision of oid before tid committed.
(for MVCC)
.""" Needed for MVCC.
"""
# implementation stolen from ZODB.test_storage.MinimalMemoryStorage # implementation stolen from ZODB.test_storage.MinimalMemoryStorage
self._lock_acquire() self._lock_acquire()
try: try:
...@@ -186,8 +198,8 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage): ...@@ -186,8 +198,8 @@ class TemporaryStorage(BaseStorage, ConflictResolvingStorage):
if version: if version:
# we allow a version to be in use although we don't # we allow a version to be in use although we don't
# support versions in the storage. # support versions in the storage.
LOG.debug('versions in use with TemporaryStorage although Temporary ' LOG.debug('versions in use with TemporaryStorage although'
'Storage doesnt support versions') 'Temporary Storage doesnt support versions')
self._lock_acquire() self._lock_acquire()
try: try:
......
...@@ -17,8 +17,6 @@ class TemporaryStorageTests(StorageTestBase.StorageTestBase, ...@@ -17,8 +17,6 @@ class TemporaryStorageTests(StorageTestBase.StorageTestBase,
MTStorage.MTStorage, MTStorage.MTStorage,
): ):
_old_conflict_cache = None
def open(self, **kwargs): def open(self, **kwargs):
from tempstorage.TemporaryStorage import TemporaryStorage from tempstorage.TemporaryStorage import TemporaryStorage
self._storage = TemporaryStorage('foo') self._storage = TemporaryStorage('foo')
...@@ -29,17 +27,6 @@ class TemporaryStorageTests(StorageTestBase.StorageTestBase, ...@@ -29,17 +27,6 @@ class TemporaryStorageTests(StorageTestBase.StorageTestBase,
def tearDown(self): def tearDown(self):
StorageTestBase.StorageTestBase.tearDown(self) StorageTestBase.StorageTestBase.tearDown(self)
if self._old_conflict_cache is not None:
from tempstorage import TemporaryStorage as TS
(TS.CONFLICT_CACHE_GCEVERY,
TS.CONFLICT_CACHE_MAXAGE) = self._old_conflict_cache
def _set_conflict_cache(self, gcevery, maxage):
from tempstorage import TemporaryStorage as TS
self._old_conflict_cache = (TS.CONFLICT_CACHE_GCEVERY,
TS.CONFLICT_CACHE_MAXAGE)
TS.CONFLICT_CACHE_GCEVERY = gcevery
TS.CONFLICT_CACHE_MAXAGE = maxage
def _do_read_conflict(self, db, mvcc): def _do_read_conflict(self, db, mvcc):
import transaction import transaction
...@@ -78,7 +65,8 @@ class TemporaryStorageTests(StorageTestBase.StorageTestBase, ...@@ -78,7 +65,8 @@ class TemporaryStorageTests(StorageTestBase.StorageTestBase,
def checkConflictCacheIsCleared(self): def checkConflictCacheIsCleared(self):
import time import time
from ZODB.tests.MinPO import MinPO from ZODB.tests.MinPO import MinPO
self._set_conflict_cache(1, 1) self._storage._conflict_cache_gcevery = 1 # second
self._storage._conflict_cache_maxage = 1 # second
oid = self._storage.new_oid() oid = self._storage.new_oid()
self._dostore(oid, data=MinPO(5)) self._dostore(oid, data=MinPO(5))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment