Commit ad2fef94 authored by Tim Peters's avatar Tim Peters

Port from ZODB 3.2.

Collector #1846:  If an uncommitted transaction was found, fsrecover.py
fell into an infinite loop.  Fixed that, and added a new test
(testUncommittedAtEnd) to ensure this stays fixed.
parent 60d1c768
......@@ -5,6 +5,7 @@ Release date: DD-MMM-2005
Following are dates of internal releases (to support ongoing Zope 2
development) since ZODB 3.4's last public release:
- 3.4.1a6 DD-MMM-2005
- 3.4.1a5 12-Jul-2005
- 3.4.1a4 08-Jul-2005
- 3.4.1a3 02-Jul-2005
......@@ -97,6 +98,13 @@ ThreadedAsync.LoopCallback
example, debugging prints added to Python's ``asyncore.loop`` won't be lost
anymore).
Tools
-----
- (3.4.1a6) Collector #1846: If an uncommitted transaction was found,
fsrecover.py fell into an infinite loop.
DemoStorage
-----------
......
......@@ -162,12 +162,18 @@ def read_txn_header(f, pos, file_size, outp, ltid):
def truncate(f, pos, file_size, outp):
"""Copy data from pos to end of f to a .trNNN file."""
# _trname is global so that the test suite can know the path too (in
# order to delete the file when the test ends).
global _trname
i = 0
while 1:
trname = outp + ".tr%d" % i
if os.path.exists(trname):
_trname = outp + ".tr%d" % i
if os.path.exists(_trname):
i += 1
tr = open(trname, "wb")
else:
break
tr = open(_trname, "wb")
copy(f, tr, file_size - pos)
f.seek(pos)
tr.close()
......
......@@ -23,7 +23,7 @@ import StringIO
import ZODB
from ZODB.FileStorage import FileStorage
from ZODB.fsrecover import recover
import ZODB.fsrecover
from persistent.mapping import PersistentMapping
import transaction
......@@ -83,7 +83,7 @@ class RecoverTest(unittest.TestCase):
try:
sys.stdout = faux_stdout
try:
recover(self.path, self.dest,
ZODB.fsrecover.recover(self.path, self.dest,
verbose=0, partial=True, force=False, pack=1)
except SystemExit:
raise RuntimeError, "recover tried to exit"
......@@ -180,6 +180,36 @@ class RecoverTest(unittest.TestCase):
self.recovered = FileStorage(self.dest)
self.recovered.close()
# Issue 1846: When a transaction had 'c' status (not yet committed),
# the attempt to open a temp file to write the trailing bytes fell
# into an infinite loop.
def testUncommittedAtEnd(self):
# Find a transaction near the end.
L = self.storage.undoLog()
r = L[1]
tid = base64.decodestring(r["id"] + "\n")
pos = self.storage._txn_find(tid, 0)
# Overwrite its status with 'c'.
f = open(self.path, "r+b")
f.seek(pos + 16)
current_status = f.read(1)
self.assertEqual(current_status, ' ')
f.seek(pos + 16)
f.write('c')
f.close()
# Try to recover. The original bug was that this never completed --
# infinite loop in fsrecover.py. Also, in the ZODB 3.2 line,
# reference to an undefined global masked the infinite loop.
self.recover()
# Verify the destination got truncated.
self.assertEqual(os.path.getsize(self.dest), pos)
# Get rid of the temp file holding the truncated bytes.
os.remove(ZODB.fsrecover._trname)
def test_suite():
return unittest.makeSuite(RecoverTest)
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