[Zodb-checkins] SVN: ZODB/branches/ctheune-blobsupport/src/ - Fixed
deprecation warning for connection.txt
Christian Theune
ct at gocept.com
Thu Mar 24 03:00:23 EST 2005
Log message for revision 29659:
- Fixed deprecation warning for connection.txt
- added clean(er?) handling on cleaning up blobs on transaction boundaries and
beeing more careful not to cause harmful states when leaking BlobFiles out
of threads/transactions (e.g. to Medusa)
Changed:
U ZODB/branches/ctheune-blobsupport/src/ZEO/runzeo.py
U ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/Blob.py
U ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/tests/connection.txt
U ZODB/branches/ctheune-blobsupport/src/ZODB/component.xml
U ZODB/branches/ctheune-blobsupport/src/ZODB/config.py
U ZODB/branches/ctheune-blobsupport/src/transaction/interfaces.py
-=-
Modified: ZODB/branches/ctheune-blobsupport/src/ZEO/runzeo.py
===================================================================
--- ZODB/branches/ctheune-blobsupport/src/ZEO/runzeo.py 2005-03-24 06:16:33 UTC (rev 29658)
+++ ZODB/branches/ctheune-blobsupport/src/ZEO/runzeo.py 2005-03-24 08:00:22 UTC (rev 29659)
@@ -235,7 +235,7 @@
storage.close()
except: # Keep going
log("failed to close storage %r" % name,
- level=logging.EXCEPTION, exc_info=True)
+ level=logging.exception, exc_info=True)
# Signal names
Modified: ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/Blob.py
===================================================================
--- ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/Blob.py 2005-03-24 06:16:33 UTC (rev 29658)
+++ ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/Blob.py 2005-03-24 08:00:22 UTC (rev 29659)
@@ -1,5 +1,6 @@
import os
+import time
import tempfile
from zope.interface import implements
@@ -7,6 +8,8 @@
from ZODB.Blobs.interfaces import IBlob
from ZODB.Blobs.exceptions import BlobError
from ZODB import utils
+import transaction
+from transaction.interfaces import IDataManager
from persistent import Persistent
try:
@@ -25,6 +28,8 @@
def open(self, mode):
"""Returns a file(-like) object for handling the blob data."""
+ result = None
+
if mode == "r":
if self._current_filename() is None:
raise BlobError, "Blob does not exist."
@@ -33,7 +38,7 @@
raise BlobError, "Already opened for writing."
self._p_blob_readers += 1
- return BlobFile(self._current_filename(), "rb", self)
+ result = BlobFile(self._current_filename(), "rb", self)
if mode == "w":
if self._p_blob_readers != 0:
@@ -43,7 +48,7 @@
self._p_blob_uncommitted = utils.mktemp()
self._p_blob_writers += 1
- return BlobFile(self._p_blob_uncommitted, "wb", self)
+ result = BlobFile(self._p_blob_uncommitted, "wb", self)
if mode =="a":
if self._current_filename() is None:
@@ -63,13 +68,75 @@
uncommitted = BlobFile(self._p_blob_uncommitted, "ab", self)
self._p_blob_writers +=1
- return uncommitted
+ result = uncommitted
+ if result is not None:
+ dm = BlobDataManager(self, result)
+ transaction.get().register(dm)
+ return result
+
# utility methods
def _current_filename(self):
return self._p_blob_uncommitted or self._p_blob_data
+class BlobDataManager:
+ """Special data manager to handle transaction boundaries for blobs.
+
+ Blobs need some special care taking on transaction boundaries. As
+ a) the ghost objects might get reused, the _p_ attributes must be
+ set to a consistent state
+ b) the file objects might get passed out of the thread/transaction
+ and must deny any relationship to the original blob.
+ """
+
+ implements(IDataManager)
+
+ def __init__(self, blob, filehandle):
+ self.blob = blob
+ self.filehandle = filehandle
+ self.isSub = False
+ self._sortkey = time.time()
+
+ def _cleanUpBlob(self):
+ self.blob._p_blob_readers = 0
+ self.blob._p_blob_writers = 0
+ self.filehandle.cleanTransaction()
+
+ def abort_sub(self, transaction):
+ pass
+
+ def commit_sub(self, transaction):
+ pass
+
+ def tpc_begin(self, transaction, subtransaction=False):
+ self.isSub = subtransaction
+
+ def tpc_abort(self, transaction):
+ self._cleanUpBlob()
+
+ def tpc_finish(self, transaction):
+ self.isSub = False
+
+ def tpc_vote(self, transaction):
+ if not self.isSub:
+ self._cleanUpBlob()
+
+ def commit(self, object, transaction):
+ pass
+
+ def abort(self, object, transaction):
+ self._cleanUpBlob()
+
+ def sortKey(self):
+ return self._sortkey
+
+ def beforeCompletion(self, transaction):
+ pass
+
+ def afterCompletion(self, transaction):
+ pass
+
class BlobFile(file):
# XXX those files should be created in the same partition as
@@ -83,30 +150,39 @@
self.blob = blob
self.streamsize = 1<<16
+ def _p_changed(self):
+ if self.blob is not None:
+ self.blob._p_changed = 1
+
def write(self, data):
super(BlobFile, self).write(data)
- self.blob._p_changed = 1
+ self._p_changed()
def writelines(self, lines):
super(BlobFile, self).writelines(lines)
- self.blob._p_changed = 1
+ self._p_changed()
def truncate(self, size):
super(BlobFile, self).truncate(size)
- self.blob._p_changed = 1
+ self._p_changed()
def close(self):
- if (self.mode.startswith("w") or
- self.mode.startswith("a")):
- self.blob._p_blob_writers -= 1
- else:
- self.blob._p_blob_readers -= 1
+ if self.blob is not None:
+ if (self.mode.startswith("w") or
+ self.mode.startswith("a")):
+ self.blob._p_blob_writers -= 1
+ else:
+ self.blob._p_blob_readers -= 1
super(BlobFile, self).close()
+ def cleanTransaction(self):
+ self.blob = None
+
def next(self):
data = self.read(self.streamsize)
if not data:
- self.blob._p_blob_readers -= 1
+ if self.blob is not None:
+ self.blob._p_blob_readers -= 1
raise StopIteration
return data
Modified: ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/tests/connection.txt
===================================================================
--- ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/tests/connection.txt 2005-03-24 06:16:33 UTC (rev 29658)
+++ ZODB/branches/ctheune-blobsupport/src/ZODB/Blobs/tests/connection.txt 2005-03-24 08:00:22 UTC (rev 29659)
@@ -49,7 +49,7 @@
>>> connection2 = database.open()
>>> root = connection2.root()
>>> blob2 = root['myblob']
- >>> IBlob.isImplementedBy(blob2)
+ >>> IBlob.providedBy(blob2)
True
>>> blob2.open("r").read()
"I'm a happy Blob."
Modified: ZODB/branches/ctheune-blobsupport/src/ZODB/component.xml
===================================================================
--- ZODB/branches/ctheune-blobsupport/src/ZODB/component.xml 2005-03-24 06:16:33 UTC (rev 29658)
+++ ZODB/branches/ctheune-blobsupport/src/ZODB/component.xml 2005-03-24 08:00:22 UTC (rev 29659)
@@ -164,14 +164,17 @@
<key name="version-cache-size" datatype="integer" default="100"/>
</sectiontype>
- <sectiontype name="blobfilestorage" datatype=".BlobFileStorage"
- implements="ZODB.storage" extends="filestorage">
+ <sectiontype name="blobstorage" datatype=".BlobStorage"
+ implements="ZODB.storage">
<key name="blob-dir" required="yes">
<description>
Path name to the blob storage directory.
</description>
</key>
+ <section type="ZODB.storage" name="*" attribute="base"/>
</sectiontype>
+
+
Modified: ZODB/branches/ctheune-blobsupport/src/ZODB/config.py
===================================================================
--- ZODB/branches/ctheune-blobsupport/src/ZODB/config.py 2005-03-24 06:16:33 UTC (rev 29658)
+++ ZODB/branches/ctheune-blobsupport/src/ZODB/config.py 2005-03-24 08:00:22 UTC (rev 29659)
@@ -132,14 +132,13 @@
read_only=self.config.read_only,
quota=self.config.quota)
-class BlobFileStorage(FileStorage):
+class BlobStorage(BaseConfig):
def open(self):
from ZODB.Blobs.BlobStorage import BlobStorage
- base_storage = FileStorage.open(self)
- return BlobStorage(self.config.blob_dir, base_storage)
+ base = self.config.base.open()
+ return BlobStorage(self.config.blob_dir, base)
-
class ZEOClient(BaseConfig):
Modified: ZODB/branches/ctheune-blobsupport/src/transaction/interfaces.py
===================================================================
--- ZODB/branches/ctheune-blobsupport/src/transaction/interfaces.py 2005-03-24 06:16:33 UTC (rev 29658)
+++ ZODB/branches/ctheune-blobsupport/src/transaction/interfaces.py 2005-03-24 08:00:22 UTC (rev 29659)
@@ -124,7 +124,7 @@
transaction being committed.
"""
- def commit(transaction):
+ def commit(object, transaction):
"""Commit modifications to registered objects.
Save the object as part of the data to be made persistent if
@@ -134,7 +134,7 @@
errors occur it saves the objects in the storage.
"""
- def abort(transaction):
+ def abort(object, transaction):
"""Abort a transaction and forget all changes.
Abort must be called outside of a two-phase commit.
More information about the Zodb-checkins
mailing list