Commit 77d1593a authored by Jim Fulton's avatar Jim Fulton

Fixed a pack bug (or possibly a missfeature). POSKeyErrors were

ignored when doing GC.  That is, when traversing from the root, if a
reference object wasn't found, it was simply ignored, covering up a
potential problem.  Now raise a key error, which stops packing.
parent ce7385d7
...@@ -248,26 +248,27 @@ class GC(FileStorageFormatter): ...@@ -248,26 +248,27 @@ class GC(FileStorageFormatter):
def findReachableAtPacktime(self, roots): def findReachableAtPacktime(self, roots):
"""Mark all objects reachable from the oids in roots as reachable.""" """Mark all objects reachable from the oids in roots as reachable."""
reachable = self.reachable
oid2curpos = self.oid2curpos
todo = list(roots) todo = list(roots)
while todo: while todo:
oid = todo.pop() oid = todo.pop()
if self.reachable.has_key(oid): if oid in reachable:
continue continue
L = [] try:
pos = oid2curpos[oid]
pos = self.oid2curpos.get(oid) except KeyError:
if pos is not None: if oid == z64 and len(oid2curpos) == 0:
L.append(pos) # special case, pack to before creation time
todo.extend(self.findrefs(pos)) continue
raise
if not L:
continue reachable[oid] = pos
for oid in self.findrefs(pos):
pos = L.pop() if oid not in reachable:
self.reachable[oid] = pos todo.append(oid)
if L:
self.reach_ex[oid] = L
def findReachableFromFuture(self): def findReachableFromFuture(self):
# In this pass, the roots are positions of object revisions. # In this pass, the roots are positions of object revisions.
......
...@@ -427,10 +427,23 @@ class TransactionalUndoStorage: ...@@ -427,10 +427,23 @@ class TransactionalUndoStorage:
self._iterate() self._iterate()
def checkTransactionalUndoAfterPack(self): def checkTransactionalUndoAfterPack(self):
eq = self.assertEqual # bwarsaw Date: Thu Mar 28 21:04:43 2002 UTC
# This is a test which should provoke the underlying bug in
# transactionalUndo() on a standby storage. If our hypothesis
# is correct, the bug is in FileStorage, and is caused by
# encoding the file position in the `id' field of the undoLog
# information. Note that Full just encodes the tid, but this
# is a problem for FileStorage (we have a strategy for fixing
# this).
# So, basically, this makes sure that undo info doesn't depend
# on file positions. We change the file positions in an undo
# record by packing.
# Add a few object revisions # Add a few object revisions
oid = self._storage.new_oid() oid = '\0'*8
revid1 = self._dostore(oid, data=MinPO(51)) revid0 = self._dostore(oid, data=MinPO(50))
revid1 = self._dostore(oid, revid=revid0, data=MinPO(51))
snooze() snooze()
packtime = time.time() packtime = time.time()
snooze() # time.time() now distinct from packtime snooze() # time.time() now distinct from packtime
...@@ -438,7 +451,7 @@ class TransactionalUndoStorage: ...@@ -438,7 +451,7 @@ class TransactionalUndoStorage:
self._dostore(oid, revid=revid2, data=MinPO(53)) self._dostore(oid, revid=revid2, data=MinPO(53))
# Now get the undo log # Now get the undo log
info = self._storage.undoInfo() info = self._storage.undoInfo()
eq(len(info), 3) self.assertEqual(len(info), 4)
tid = info[0]['id'] tid = info[0]['id']
# Now pack just the initial revision of the object. We need the # Now pack just the initial revision of the object. We need the
# second revision otherwise we won't be able to undo the third # second revision otherwise we won't be able to undo the third
...@@ -446,18 +459,18 @@ class TransactionalUndoStorage: ...@@ -446,18 +459,18 @@ class TransactionalUndoStorage:
self._storage.pack(packtime, referencesf) self._storage.pack(packtime, referencesf)
# Make some basic assertions about the undo information now # Make some basic assertions about the undo information now
info2 = self._storage.undoInfo() info2 = self._storage.undoInfo()
eq(len(info2), 2) self.assertEqual(len(info2), 2)
# And now attempt to undo the last transaction # And now attempt to undo the last transaction
t = Transaction() t = Transaction()
self._storage.tpc_begin(t) self._storage.tpc_begin(t)
tid, oids = self._storage.undo(tid, t) tid, oids = self._storage.undo(tid, t)
self._storage.tpc_vote(t) self._storage.tpc_vote(t)
self._storage.tpc_finish(t) self._storage.tpc_finish(t)
eq(len(oids), 1) self.assertEqual(len(oids), 1)
eq(oids[0], oid) self.assertEqual(oids[0], oid)
data, revid = self._storage.load(oid, '') data, revid = self._storage.load(oid, '')
# The object must now be at the second state # The object must now be at the second state
eq(zodb_unpickle(data), MinPO(52)) self.assertEqual(zodb_unpickle(data), MinPO(52))
self._iterate() self._iterate()
def checkTransactionalUndoAfterPackWithObjectUnlinkFromRoot(self): def checkTransactionalUndoAfterPackWithObjectUnlinkFromRoot(self):
......
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