[Zodb-checkins] CVS: Zope3/src/zodb/btrees/tests - test_conflict.py:1.11
Tim Peters
tim.one@comcast.net
Fri, 17 Jan 2003 11:44:40 -0500
Update of /cvs-repository/Zope3/src/zodb/btrees/tests
In directory cvs.zope.org:/tmp/cvs-serv17396/src/zodb/btrees/tests
Modified Files:
test_conflict.py
Log Message:
Fixing a rare BTree conflict resolution error.
+ Transaction T1 deletes some of the keys in bucket B,
but not all of the keys.
+ Transaction T2 deletes (exactly) the keys in B that
aren't deleted by T1.
The version of B each transaction sees is then non-empty,
but conflict resolution creates an empty bucket. However,
conflict resolution doesn't have enough info to unlink an
empty bucket from its containing BTree correctly.
The result is that an empty bucket is left in the BTree,
which violates a BTree invariant. The most probable
symptom is a segfault, when later & unrelated code tries
to access this bucket: an empty bucket has NULL
pointers where the vectors of keys and values should be,
and accessing code tries to dereference the NULL pointers.
I don't know that this error has been seen in real life.
It was provoked by a randomized multithreaded simulation
program that was trying to provoke errors. This error was
provoked frequently by that program; no other kinds of
errors have come out of it.
=== Zope3/src/zodb/btrees/tests/test_conflict.py 1.10 => 1.11 ===
--- Zope3/src/zodb/btrees/tests/test_conflict.py:1.10 Wed Jan 15 14:15:30 2003
+++ Zope3/src/zodb/btrees/tests/test_conflict.py Fri Jan 17 11:44:36 2003
@@ -192,7 +192,7 @@
b1.clear()
bm.clear()
- test_merge(base, b1, b2, bm, 'empty one and not other')
+ test_merge(base, b1, b2, bm, 'empty one and not other', should_fail=1)
def testFailMergeInsert(self):
base, b1, b2, bm, e1, e2, items = self._setupConflict()
@@ -289,7 +289,7 @@
b1.clear()
bm.clear()
- test_merge(base, b1, b2, bm, 'empty one and not other')
+ test_merge(base, b1, b2, bm, 'empty one and not other', should_fail=1)
def testFailMergeInsert(self):
base, b1, b2, bm, e1, e2, items = self._setupConflict()
@@ -585,21 +585,12 @@
self.assertEqual(state[0][1], 60)
self.assertEqual(state[0][3], 120)
- # Conflict resolution empties bucket1 entirely.
-
- # XXX This is broken: it doesn't raise ConflictError now.
- ### XXX The ConflictError imported at the top of this module isn't
- ### XXX the ConflictError that gets raised here.
- ##from zodb.interfaces import ConflictError
- ##self.assertRaises(ConflictError, get_transaction().commit)
- ##get_transaction().abort() # horrible things happen w/o this
-
- # XXX Instead it creates an insane BTree (with an empty bucket
- # XXX still linked in. Remove the remaining lines and uncomment
- # XXX the lines above when this is fixed.
- # XXX AssertionError: Bucket length < 1
- get_transaction().commit()
- self.assertRaises(AssertionError, b._check)
+ # Conflict resolution empties bucket1 entirely. This used to
+ # create an "insane" BTree (a legit BTree cannot contain an empty
+ # bucket -- it contains NULL pointers the BTree code doesn't
+ # expect, and segfaults result).
+ self.assertRaises(ConflictError, get_transaction().commit)
+ get_transaction().abort() # horrible things happen w/o this
def testEmptyBucketNoConflict(self):