[Zodb-checkins] SVN: ZODB/trunk/ Merge rev 37239 from 3.4 branch.

Tim Peters tim.one at comcast.net
Mon Jul 18 11:46:58 EDT 2005


Log message for revision 37241:
  Merge rev 37239 from 3.4 branch.
  
  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.
  

Changed:
  U   ZODB/trunk/NEWS.txt
  U   ZODB/trunk/src/ZODB/fsrecover.py
  U   ZODB/trunk/src/ZODB/tests/testRecover.py

-=-
Modified: ZODB/trunk/NEWS.txt
===================================================================
--- ZODB/trunk/NEWS.txt	2005-07-18 15:44:18 UTC (rev 37240)
+++ ZODB/trunk/NEWS.txt	2005-07-18 15:46:58 UTC (rev 37241)
@@ -74,6 +74,12 @@
   been added.  See ``ZODB/cross-database-references.txt`` for an
   introduction.
 
+Tools
+-----
+
+- (3.5a5) Collector #1846:  If an uncommitted transaction was found,
+  fsrecover.py fell into an infinite loop.
+
 ThreadedAsync.LoopCallback
 --------------------------
 
@@ -130,6 +136,7 @@
 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
@@ -222,6 +229,13 @@
   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
 -----------
 

Modified: ZODB/trunk/src/ZODB/fsrecover.py
===================================================================
--- ZODB/trunk/src/ZODB/fsrecover.py	2005-07-18 15:44:18 UTC (rev 37240)
+++ ZODB/trunk/src/ZODB/fsrecover.py	2005-07-18 15:46:58 UTC (rev 37241)
@@ -162,12 +162,18 @@
 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()

Modified: ZODB/trunk/src/ZODB/tests/testRecover.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testRecover.py	2005-07-18 15:44:18 UTC (rev 37240)
+++ ZODB/trunk/src/ZODB/tests/testRecover.py	2005-07-18 15:46:58 UTC (rev 37241)
@@ -23,7 +23,7 @@
 
 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 @@
         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 @@
         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)



More information about the Zodb-checkins mailing list