[Zodb-checkins] SVN: ZODB/trunk/src/ZODB/ Fixed bug:
Jim Fulton
jim at zope.com
Mon Aug 24 14:17:57 EDT 2009
Log message for revision 103176:
Fixed bug:
Savepoint blob data wasn't cleaned up after a transaction abort.
https://bugs.launchpad.net/zodb/+bug/323067
Changed:
U ZODB/trunk/src/ZODB/Connection.py
U ZODB/trunk/src/ZODB/tests/blob_transaction.txt
U ZODB/trunk/src/ZODB/tests/testblob.py
-=-
Modified: ZODB/trunk/src/ZODB/Connection.py
===================================================================
--- ZODB/trunk/src/ZODB/Connection.py 2009-08-24 18:17:54 UTC (rev 103175)
+++ ZODB/trunk/src/ZODB/Connection.py 2009-08-24 18:17:56 UTC (rev 103176)
@@ -31,7 +31,7 @@
from ZODB.interfaces import IConnection
from ZODB.interfaces import IBlobStorage
from ZODB.interfaces import IMVCCStorage
-from ZODB.blob import Blob, rename_or_copy_blob
+from ZODB.blob import Blob, rename_or_copy_blob, remove_committed_dir
from transaction.interfaces import ISavepointDataManager
from transaction.interfaces import IDataManagerSavepoint
from transaction.interfaces import ISynchronizer
@@ -1239,11 +1239,16 @@
self.index = {}
self.creating = {}
+ self._blob_dir = None
+
def __len__(self):
return len(self.index)
def close(self):
self._file.close()
+ if self._blob_dir is not None:
+ remove_committed_dir(self._blob_dir)
+ self._blob_dir = None
def load(self, oid, version):
pos = self.index.get(oid)
@@ -1307,12 +1312,19 @@
return ZODB.blob.BlobFile(blob_filename, 'r', blob)
def _getBlobPath(self):
- return os.path.join(self.temporaryDirectory(), 'savepoints')
+ blob_dir = self._blob_dir
+ if blob_dir is None:
+ blob_dir = tempfile.mkdtemp(dir=self.temporaryDirectory(),
+ prefix='savepoints')
+ self._blob_dir = blob_dir
+ return blob_dir
def _getCleanFilename(self, oid, tid):
- return os.path.join(self._getBlobPath(),
- "%s-%s%s" % (utils.oid_repr(oid), utils.tid_repr(tid), SAVEPOINT_SUFFIX,)
- )
+ return os.path.join(
+ self._getBlobPath(),
+ "%s-%s%s" % (utils.oid_repr(oid), utils.tid_repr(tid),
+ SAVEPOINT_SUFFIX,)
+ )
def temporaryDirectory(self):
return self._storage.temporaryDirectory()
Modified: ZODB/trunk/src/ZODB/tests/blob_transaction.txt
===================================================================
--- ZODB/trunk/src/ZODB/tests/blob_transaction.txt 2009-08-24 18:17:54 UTC (rev 103175)
+++ ZODB/trunk/src/ZODB/tests/blob_transaction.txt 2009-08-24 18:17:56 UTC (rev 103176)
@@ -231,18 +231,22 @@
>>> root5['blob'].open("r").read()
"I'm a happy blob. And I'm singing."
-Savepoints store the blobs in the `savepoints` directory in the temporary
+Savepoints store the blobs in temporary directories in the temporary
directory of the blob storage:
- >>> os.listdir(os.path.join(blob_dir, 'tmp', 'savepoints'))
- ['0x...-0x....spb']
- >>> transaction.commit()
+ >>> len([name for name in os.listdir(os.path.join(blob_dir, 'tmp'))
+ ... if name.startswith('savepoint')])
+ 1
+ >>> os.listdir(os.path.join(blob_dir, 'tmp'))[0].startswith('savepoint')
+ True
After committing the transaction, the temporary savepoint files are moved to
the committed location again:
- >>> os.listdir(os.path.join(blob_dir, 'tmp', 'savepoints'))
- []
+ >>> transaction.commit()
+ >>> len([name for name in os.listdir(os.path.join(blob_dir, 'tmp'))
+ ... if name.startswith('savepoint')])
+ 0
We support non-optimistic savepoints too:
@@ -251,28 +255,24 @@
"I'm a happy blob. And I'm singing. And I'm dancing."
>>> savepoint = transaction.savepoint()
-Again, the savepoint creates a new file for the blob state in the savepoints
-directory:
+Again, the savepoint creates a new savepoints directory:
- >>> os.listdir(os.path.join(blob_dir, 'tmp', 'savepoints'))
- ['0x...-0x....spb']
+ >>> len([name for name in os.listdir(os.path.join(blob_dir, 'tmp'))
+ ... if name.startswith('savepoint')])
+ 1
>>> root5['blob'].open("w").write(" And the weather is beautiful.")
>>> savepoint.rollback()
-XXX Currently, savepoint state of blobs remains after a rollback:
-
- >>> os.listdir(os.path.join(blob_dir, 'tmp', 'savepoints'))
- ['0x...-0x....spb']
-
>>> root5['blob'].open("r").read()
"I'm a happy blob. And I'm singing. And I'm dancing."
>>> transaction.abort()
-XXX Currently, savepoint state of blobs remains even after an abort:
+The savepoint blob directory gets cleaned up on an abort:
- >>> os.listdir(os.path.join(blob_dir, 'tmp', 'savepoints'))
- ['0x...-0x....spb']
+ >>> len([name for name in os.listdir(os.path.join(blob_dir, 'tmp'))
+ ... if name.startswith('savepoint')])
+ 0
Reading Blobs outside of a transaction
--------------------------------------
Modified: ZODB/trunk/src/ZODB/tests/testblob.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testblob.py 2009-08-24 18:17:54 UTC (rev 103175)
+++ ZODB/trunk/src/ZODB/tests/testblob.py 2009-08-24 18:17:56 UTC (rev 103176)
@@ -15,23 +15,17 @@
from pickle import Pickler
from pickle import Unpickler
from StringIO import StringIO
-from ZConfig import ConfigurationSyntaxError
-from ZODB.blob import Blob, BlobStorage
+from ZODB.blob import Blob
from ZODB.DB import DB
from ZODB.FileStorage import FileStorage
-from ZODB import utils
from ZODB.tests.testConfig import ConfigTestBase
from zope.testing import doctest
-import base64
import os
import random
import re
-import shutil
-import stat
import struct
import sys
-import sys
import time
import transaction
import unittest
@@ -538,6 +532,59 @@
>>> bs.close()
"""
+def savepoint_isolation():
+ """Make sure savepoint data is distinct accross transactions
+
+ >>> bs = create_storage()
+ >>> db = DB(bs)
+ >>> conn = db.open()
+ >>> conn.root.b = ZODB.blob.Blob('initial')
+ >>> transaction.commit()
+ >>> conn.root.b.open('w').write('1')
+ >>> _ = transaction.savepoint()
+ >>> tm = transaction.TransactionManager()
+ >>> conn2 = db.open(transaction_manager=tm)
+ >>> conn2.root.b.open('w').write('2')
+ >>> _ = tm.savepoint()
+ >>> conn.root.b.open().read()
+ '1'
+ >>> conn2.root.b.open().read()
+ '2'
+ >>> transaction.abort()
+ >>> tm.commit()
+ >>> conn.sync()
+ >>> conn.root.b.open().read()
+ '2'
+ >>> db.close()
+ """
+
+def savepoint_cleanup():
+ """Make sure savepoint data gets cleaned up.
+
+ >>> bs = create_storage()
+ >>> tdir = bs.temporaryDirectory()
+ >>> os.listdir(tdir)
+ []
+
+ >>> db = DB(bs)
+ >>> conn = db.open()
+ >>> conn.root.b = ZODB.blob.Blob('initial')
+ >>> _ = transaction.savepoint()
+ >>> len(os.listdir(tdir))
+ 1
+ >>> transaction.abort()
+ >>> os.listdir(tdir)
+ []
+ >>> conn.root.b = ZODB.blob.Blob('initial')
+ >>> transaction.commit()
+ >>> conn.root.b.open('w').write('1')
+ >>> _ = transaction.savepoint()
+ >>> transaction.abort()
+ >>> os.listdir(tdir)
+ []
+ """
+
+
def setUp(test):
ZODB.tests.util.setUp(test)
test.globs['rmtree'] = zope.testing.setupstack.rmtree
More information about the Zodb-checkins
mailing list