[Zodb-checkins] SVN: ZODB/trunk/src/ZODB/DemoStorage. Refactored stacking support:
Jim Fulton
jim at zope.com
Wed Oct 29 19:08:33 EDT 2008
Log message for revision 92687:
Refactored stacking support:
- explicit push and pop methods
- backward compatible with old behavior.
Changed:
U ZODB/trunk/src/ZODB/DemoStorage.py
U ZODB/trunk/src/ZODB/DemoStorage.test
-=-
Modified: ZODB/trunk/src/ZODB/DemoStorage.py
===================================================================
--- ZODB/trunk/src/ZODB/DemoStorage.py 2008-10-29 20:53:30 UTC (rev 92686)
+++ ZODB/trunk/src/ZODB/DemoStorage.py 2008-10-29 23:08:31 UTC (rev 92687)
@@ -19,7 +19,9 @@
The base storage must not change.
"""
+import os
import random
+import weakref
import tempfile
import threading
import ZODB.blob
@@ -36,35 +38,41 @@
ZODB.interfaces.IStorageIteration,
)
- def __init__(self, name=None, base=None, changes=None,
- keep_base_open=False):
- self._keep_base_open = keep_base_open
+ def __init__(self, name=None, base=None, changes=None):
if base is None:
base = ZODB.MappingStorage.MappingStorage()
+ self._temporary_base = True
+ else:
+ self._temporary_base = False
self.base = base
if changes is None:
changes = ZODB.MappingStorage.MappingStorage()
zope.interface.alsoProvides(self, ZODB.interfaces.IBlobStorage)
self._temporary_changes = True
- self._blob_dir = None
else:
if ZODB.interfaces.IBlobStorage.providedBy(changes):
zope.interface.alsoProvides(self, ZODB.interfaces.IBlobStorage)
self._temporary_changes = False
self.changes = changes
-
+
if name is None:
name = 'DemoStorage(%r, %r)' % (base.getName(), changes.getName())
self.__name__ = name
self._copy_methods_from_changes(changes)
+
def _blobify(self):
- if self._temporary_changes and self._blob_dir is None:
- self._blob_dir = tempfile.mkdtemp('blobs')
- self.changes = ZODB.blob.BlobStorage(self._blob_dir, self.changes)
+ if (self._temporary_changes and
+ isinstance(self.changes, ZODB.MappingStorage.MappingStorage)
+ ):
+ blob_dir = tempfile.mkdtemp('.demoblobs')
+ _temporary_blobdirs[
+ weakref.ref(self, cleanup_temporary_blobdir)
+ ] = blob_dir
+ self.changes = ZODB.blob.BlobStorage(blob_dir, self.changes)
self._copy_methods_from_changes(self.changes)
return True
@@ -73,11 +81,10 @@
self.changes.cleanup()
def close(self):
- if not self._keep_base_open:
+ if not self._temporary_base:
self.base.close()
- self.changes.close()
- if getattr(self, '_blob_dir', ''):
- ZODB.blob.remove_committed_dir(self._blob_dir)
+ if not self._temporary_changes:
+ self.changes.close()
def _copy_methods_from_changes(self, changes):
for meth in (
@@ -195,6 +202,13 @@
pass # The gc arg isn't supported. Don't pack
raise
+ def pop(self):
+ self.changes.close()
+ return self.base
+
+ def push(self, changes=None):
+ return self.__class__(base=self, changes=changes)
+
def store(self, oid, serial, data, version, transaction):
assert version=='', "versions aren't supported"
@@ -231,3 +245,12 @@
if self._blobify():
return self.changes.temporaryDirectory()
raise
+
+_temporary_blobdirs = {}
+def cleanup_temporary_blobdir(
+ ref,
+ _temporary_blobdirs=_temporary_blobdirs, # Make sure it stays around
+ ):
+ blob_dir = _temporary_blobdirs.pop(ref, None)
+ if blob_dir and os.path.exists(blob_dir):
+ ZODB.blob.remove_committed_dir(blob_dir)
Modified: ZODB/trunk/src/ZODB/DemoStorage.test
===================================================================
--- ZODB/trunk/src/ZODB/DemoStorage.test 2008-10-29 20:53:30 UTC (rev 92686)
+++ ZODB/trunk/src/ZODB/DemoStorage.test 2008-10-29 23:08:31 UTC (rev 92687)
@@ -120,38 +120,67 @@
... ]
[True, True, True, True]
+ >>> db.close()
-Normally, when we close a demo storage, the changes and base storages
-are closed:
+Storage Stacking
+================
- >>> db.close()
- >>> base._file.closed
+A common use case is to stack demo storages. DemoStorage provides
+some helper functions to help with this. The push method, just
+creates a new demo storage who's base is the original demo storage:
+
+ >>> demo = DemoStorage()
+ >>> demo2 = demo.push()
+ >>> demo2.base is demo
True
- >>> changes._file.closed
+
+We can also supply an explicit changes storage, if we wish:
+
+ >>> from ZODB.MappingStorage import MappingStorage
+ >>> changes = MappingStorage()
+ >>> demo3 = demo2.push(changes)
+ >>> demo3.changes is changes, demo3.base is demo2
+ (True, True)
+
+The pop method closes the changes storage and returns the base
+*without* closing it:
+
+ >>> demo3.pop() is demo2
True
-A common use case is to stack multiple DemoStorages, returning to a
-previous state by popping a DemoStorage off the stack. In this case,
-we want to leave the base storage open:
+ >>> changes.opened()
+ False
- >>> base = FileStorage('base.fs', read_only=True)
- >>> storage = DemoStorage(base=base, keep_base_open=True)
+Special backward compatibility support
+--------------------------------------
-Here, we didn't specify a changes storage. A MappingStorage was
-automatically created:
+Normally, when a demo storage is closed, it's base and changes
+storage are closed:
- >>> type(storage.changes).__name__
- 'MappingStorage'
+ >>> demo = DemoStorage(base=MappingStorage(), changes=MappingStorage())
+ >>> demo.close()
+ >>> demo.base.opened(), demo.changes.opened()
+ (False, False)
-Because we specified the keep_base_open option, the base storage is
-left open when we close the DemoStorage:
+Older versions of DemoStorage didn't have a separate changes storage
+and didn't close or discard their changes when they were closed. When
+a stack was built solely of demo storages, the close method
+effectively did nothing. To maintain backward compatibility, when no
+base or changes storage is supplied in the constructor, the underlying
+storage created by the demo storage isn't closed by the demo storage.
+This backward-compatibility is deprecated.
- >>> storage.close()
- >>> base._file.closed
- False
- >>> storage.changes.opened()
- False
+ >>> demo = DemoStorage()
+ >>> demo.close()
+ >>> demo.changes.opened(), demo.base.opened()
+ (True, True)
+ >>> demo = DemoStorage(base=MappingStorage())
+ >>> demo2 = demo.push()
+ >>> demo2.close()
+ >>> demo2.changes.opened(), demo2.base.base.opened()
+ (True, False)
+
Blob Support
============
@@ -236,6 +265,16 @@
.. Check that the temporary directory is gone
+ For now, it won't go until the storage does.
+
+ >>> transaction.abort()
+ >>> conn.close()
+ >>> blobdir = storage.temporaryDirectory()
+ >>> del db, conn, storage, _
+
+ >>> import gc
+ >>> _ = gc.collect()
+
>>> import os
- >>> os.path.exists(storage.temporaryDirectory())
+ >>> os.path.exists(blobdir)
False
More information about the Zodb-checkins
mailing list