Commit 94b2c942 authored by Tim Peters's avatar Tim Peters

Tentative fix.

parent 5a09264e
...@@ -70,7 +70,9 @@ merge_error(int p1, int p2, int p3, int reason) ...@@ -70,7 +70,9 @@ merge_error(int p1, int p2, int p3, int reason)
* However, it's not OK for s2 and s3 to, between them, end up deleting all * However, it's not OK for s2 and s3 to, between them, end up deleting all
* the keys. This is a higher-level constraint, due to that the caller of * the keys. This is a higher-level constraint, due to that the caller of
* bucket_merge() doesn't have enough info to unlink the resulting empty * bucket_merge() doesn't have enough info to unlink the resulting empty
* bucket from its BTree correctly. * bucket from its BTree correctly. It's also not OK if s2 or s3 are empty,
* because the transaction that emptied the bucket unlinked the bucket from
* the tree, and nothing we do here can get it linked back in again.
* *
* Key insertion: s2 or s3 can add a new key, provided the other transaction * Key insertion: s2 or s3 can add a new key, provided the other transaction
* doesn't insert the same key. It's not OK even if they insert the same * doesn't insert the same key. It's not OK even if they insert the same
...@@ -115,6 +117,13 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3) ...@@ -115,6 +117,13 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
if (i3.next(&i3) < 0) if (i3.next(&i3) < 0)
goto err; goto err;
/* If either "after" bucket was empty, punt. */
if (i2.position < 0 || i3.position < 0)
{
merge_error(i1.position, i2.position, i3.position, 12);
goto err;
}
/* Consult zodb/btrees/interfaces.py for the meaning of the last /* Consult zodb/btrees/interfaces.py for the meaning of the last
* argument passed to merge_error(). * argument passed to merge_error().
*/ */
......
...@@ -178,7 +178,7 @@ class MappingBase(Base): ...@@ -178,7 +178,7 @@ class MappingBase(Base):
test_merge(base, b1, b2, bm, 'merge insert from empty') test_merge(base, b1, b2, bm, 'merge insert from empty')
def testMergeEmptyAndFill(self): def testFailMergeEmptyAndFill(self):
base, b1, b2, bm, e1, e2, items = self._setupConflict() base, b1, b2, bm, e1, e2, items = self._setupConflict()
b1.clear() b1.clear()
...@@ -186,7 +186,7 @@ class MappingBase(Base): ...@@ -186,7 +186,7 @@ class MappingBase(Base):
b2.update(e2) b2.update(e2)
bm.update(e2) bm.update(e2)
test_merge(base, b1, b2, bm, 'merge insert from empty') test_merge(base, b1, b2, bm, 'merge insert from empty', should_fail=1)
def testMergeEmpty(self): def testMergeEmpty(self):
base, b1, b2, bm, e1, e2, items = self._setupConflict() base, b1, b2, bm, e1, e2, items = self._setupConflict()
...@@ -275,7 +275,7 @@ class SetTests(Base): ...@@ -275,7 +275,7 @@ class SetTests(Base):
test_merge(base, b1, b2, bm, 'merge insert from empty') test_merge(base, b1, b2, bm, 'merge insert from empty')
def testMergeEmptyAndFill(self): def testFailMergeEmptyAndFill(self):
base, b1, b2, bm, e1, e2, items = self._setupConflict() base, b1, b2, bm, e1, e2, items = self._setupConflict()
b1.clear() b1.clear()
...@@ -283,7 +283,7 @@ class SetTests(Base): ...@@ -283,7 +283,7 @@ class SetTests(Base):
b2.update(e2) b2.update(e2)
bm.update(e2) bm.update(e2)
test_merge(base, b1, b2, bm, 'merge insert from empty') test_merge(base, b1, b2, bm, 'merge insert from empty', should_fail=1)
def testMergeEmpty(self): def testMergeEmpty(self):
base, b1, b2, bm, e1, e2, items = self._setupConflict() base, b1, b2, bm, e1, e2, items = self._setupConflict()
...@@ -810,7 +810,6 @@ class NastyConfict(Base, TestCase): ...@@ -810,7 +810,6 @@ class NastyConfict(Base, TestCase):
self.assert_(str(detail).startswith('database conflict error')) self.assert_(str(detail).startswith('database conflict error'))
transaction.abort() transaction.abort()
else: else:
print list(copy.items())
self.fail("expected ConflictError") self.fail("expected ConflictError")
......
...@@ -187,6 +187,9 @@ class BTreesConflictError(ConflictError): ...@@ -187,6 +187,9 @@ class BTreesConflictError(ConflictError):
# 11; conflicting changes in an internal BTree node # 11; conflicting changes in an internal BTree node
'Conflicting changes in an internal BTree node', 'Conflicting changes in an internal BTree node',
# 12; i2 or i3 was empty
'Empty bucket in a transaction',
] ]
def __init__(self, p1, p2, p3, reason): def __init__(self, p1, p2, p3, reason):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment