[Zope-Checkins]
SVN: Zope/branches/Zope-2_8-branch/lib/python/tempstorage/
Allow tempstorage to participate in MVCC. Also fix minor bug
where conflict cache could be poisoned by a transaction that
failed after store was called.
Chris McDonough
chrism at plope.com
Thu Jun 16 17:49:51 EDT 2005
Log message for revision 30823:
Allow tempstorage to participate in MVCC. Also fix minor bug where conflict cache could be poisoned by a transaction that failed after store was called.
Changed:
U Zope/branches/Zope-2_8-branch/lib/python/tempstorage/TemporaryStorage.py
U Zope/branches/Zope-2_8-branch/lib/python/tempstorage/tests/testTemporaryStorage.py
-=-
Modified: Zope/branches/Zope-2_8-branch/lib/python/tempstorage/TemporaryStorage.py
===================================================================
--- Zope/branches/Zope-2_8-branch/lib/python/tempstorage/TemporaryStorage.py 2005-06-16 21:42:33 UTC (rev 30822)
+++ Zope/branches/Zope-2_8-branch/lib/python/tempstorage/TemporaryStorage.py 2005-06-16 21:49:50 UTC (rev 30823)
@@ -28,6 +28,7 @@
from ZODB.BaseStorage import BaseStorage
from ZODB.ConflictResolution import ConflictResolvingStorage, ResolvedSerial
import time
+import bisect
# keep old object revisions for CONFLICT_CACHE_MAXAGE seconds
CONFLICT_CACHE_MAXAGE = 60
@@ -135,6 +136,31 @@
finally:
self._lock_release()
+ def loadBefore(self, oid, tid):
+ """Return most recent revision of oid before tid committed
+ (for MVCC)
+ ."""
+ # implementation stolen from ZODB.test_storage.MinimalMemoryStorage
+ self._lock_acquire()
+ try:
+ tids = [stid for soid, stid in self._conflict_cache if soid == oid]
+ if not tids:
+ raise KeyError, oid
+ tids.sort()
+ i = bisect.bisect_left(tids, tid) -1
+ if i == -1:
+ return None
+ start_tid = tids[i]
+ j = i + 1
+ if j == len(tids):
+ end_tid = None
+ else:
+ end_tid = tids[j]
+ data = self.loadSerial(oid, start_tid)
+ return data, start_tid, end_tid
+ finally:
+ self._lock_release()
+
def store(self, oid, serial, data, version, transaction):
if transaction is not self._transaction:
raise POSException.StorageTransactionError(self, transaction)
@@ -163,8 +189,6 @@
oserial = serial
newserial=self._tid
self._tmp.append((oid, data))
- now = time.time()
- self._conflict_cache[(oid, newserial)] = data, now
return serial == oserial and newserial or ResolvedSerial
finally:
self._lock_release()
@@ -238,6 +262,8 @@
index[oid] = serial
opickle[oid] = data
+ now = time.time()
+ self._conflict_cache[(oid, serial)] = data, now
if zeros:
for oid in zeros.keys():
Modified: Zope/branches/Zope-2_8-branch/lib/python/tempstorage/tests/testTemporaryStorage.py
===================================================================
--- Zope/branches/Zope-2_8-branch/lib/python/tempstorage/tests/testTemporaryStorage.py 2005-06-16 21:42:33 UTC (rev 30822)
+++ Zope/branches/Zope-2_8-branch/lib/python/tempstorage/tests/testTemporaryStorage.py 2005-06-16 21:49:50 UTC (rev 30823)
@@ -7,6 +7,11 @@
Synchronization, ConflictResolution, \
Corruption, RevisionStorage, MTStorage
+from persistent import Persistent
+import transaction
+from ZODB.DB import DB
+from ZODB.POSException import ReadConflictError
+
class TemporaryStorageTests(
StorageTestBase.StorageTestBase,
## RevisionStorage.RevisionStorage, # not a revision storage, but passes
@@ -49,6 +54,48 @@
TemporaryStorage.CONFLICT_CACHE_GCEVERY = old_gcevery
TemporaryStorage.CONFLICT_CACHE_MAXAGE = old_maxage
+ def doreadconflict(self, db, mvcc):
+ tm1 = transaction.TransactionManager()
+ conn = db.open(mvcc=mvcc, transaction_manager=tm1)
+ r1 = conn.root()
+ obj = MinPO('root')
+ r1["p"] = obj
+ obj = r1["p"]
+ obj.child1 = MinPO('child1')
+ tm1.get().commit()
+
+ # start a new transaction with a new connection
+ tm2 = transaction.TransactionManager()
+ cn2 = db.open(mvcc=mvcc, transaction_manager=tm2)
+ r2 = cn2.root()
+
+ self.assertEqual(r1._p_serial, r2._p_serial)
+
+ obj.child2 = MinPO('child2')
+ tm1.get().commit()
+
+ # resume the transaction using cn2
+ obj = r2["p"]
+
+ # An attempt to access obj.child1 should fail with an RCE
+ # below if conn isn't using mvcc, because r2 was read earlier
+ # in the transaction and obj was modified by the other
+ # transaction.
+
+ obj.child1
+ return obj
+
+ def checkWithoutMVCCRaisesReadConflict(self):
+ db = DB(self._storage)
+ self.assertRaises(ReadConflictError, self.doreadconflict, db, False)
+
+ def checkWithMVCCDoesntRaiseReadConflict(self):
+ db = DB(self._storage)
+ ob = self.doreadconflict(db, True)
+ self.assertEquals(ob.__class__, MinPO)
+ self.assertEquals(getattr(ob, 'child1', MinPO()).value, 'child1')
+ self.failIf(getattr(ob, 'child2', None))
+
def test_suite():
suite = unittest.makeSuite(TemporaryStorageTests, 'check')
suite2 = unittest.makeSuite(Corruption.FileStorageCorruptTests, 'check')
More information about the Zope-Checkins
mailing list