[Zodb-checkins] CVS: ZODB3/ZODB - fsdump.py:1.3.72.1 FileStorage.py:1.105.2.4 BaseStorage.py:1.24.2.1

Jeremy Hylton jeremy@zope.com
Mon, 21 Oct 2002 11:15:56 -0400


Update of /cvs-repository/ZODB3/ZODB
In directory cvs.zope.org:/tmp/cvs-serv7174/ZODB

Modified Files:
      Tag: ZODB3-3_1-branch
	fsdump.py FileStorage.py BaseStorage.py 
Log Message:
Backport from trunk: restore() / backpointer fixes

FileStorage.py: A version of restore() that writes backpointers...
BaseStorage.py: sync up with new restore() signature.
fsdump.py: Print backpointer if it exists.


=== ZODB3/ZODB/fsdump.py 1.3 => 1.3.72.1 ===
--- ZODB3/ZODB/fsdump.py:1.3	Mon Feb 11 14:38:09 2002
+++ ZODB3/ZODB/fsdump.py	Mon Oct 21 11:15:55 2002
@@ -64,8 +64,14 @@
                 version = "version=%s " % rec.version
             else:
                 version = ''
-            print >> file, "  data #%05d oid=%016x %sclass=%s" % \
-                  (j, U64(rec.oid), version, fullclass)
+            if rec.data_txn:
+                # XXX It would be nice to print the transaction number
+                # (i) but it would be too expensive to keep track of.
+                bp = "bp=%016x" % U64(rec.data_txn)
+            else:
+                bp = ""
+            print >> file, "  data #%05d oid=%016x %sclass=%s %s" % \
+                  (j, U64(rec.oid), version, fullclass, bp)
             j += 1
         print >> file
         i += 1


=== ZODB3/ZODB/FileStorage.py 1.105.2.3 => 1.105.2.4 ===
--- ZODB3/ZODB/FileStorage.py:1.105.2.3	Fri Oct 18 15:39:58 2002
+++ ZODB3/ZODB/FileStorage.py	Mon Oct 21 11:15:55 2002
@@ -742,7 +742,40 @@
         finally:
             self._lock_release()
 
-    def restore(self, oid, serial, data, version, transaction):
+    def _data_find(self, tpos, oid, data):
+        # Return backpointer to oid in data record for in transaction at tpos.
+        # It should contain a pickle identical to data. Returns 0 on failure.
+        # Must call with lock held.
+        self._file.seek(tpos)
+        h = self._file.read(TRANS_HDR_LEN)
+        tid, stl, status, ul, dl, el = struct.unpack(TRANS_HDR, h)
+        self._file.read(ul + dl + el)
+        tend = tpos + U64(stl) + 8
+        pos = self._file.tell()
+        while pos < tend:
+            h = self._file.read(DATA_HDR_LEN)
+            _oid, serial, sprev, stpos, vl, sdl = struct.unpack(DATA_HDR, h)
+            dl = U64(sdl)
+            reclen = DATA_HDR_LEN + vl + dl
+            if vl:
+                reclen += 16
+            if _oid == oid:
+                if vl:
+                    self._file.read(vl + 16)
+                # Make sure this looks like the right data record
+                if dl != len(data):
+                    # XXX what if this data record also has a backpointer?
+                    # I don't think that's possible, but I'm not sure.
+                    return 0
+                _data = self._file.read(dl)
+                if data != _data:
+                    return 0
+                return pos
+            pos += reclen
+            self._file.seek(pos)
+        return 0
+
+    def restore(self, oid, serial, data, version, prev_txn, transaction):
         # A lot like store() but without all the consistency checks.  This
         # should only be used when we /know/ the data is good, hence the
         # method name.  While the signature looks like store() there are some
@@ -756,6 +789,9 @@
         #
         # - data can be None, which indicates a George Bailey object
         #   (i.e. one who's creation has been transactionally undone).
+        #
+        # If prev_txn is not None, it should contain the same data as
+        # the argument data.  If it does, write a backpointer to it.
         if self._is_read_only:
             raise POSException.ReadOnlyError()
         if transaction is not self._transaction:
@@ -763,17 +799,25 @@
 
         self._lock_acquire()
         try:
+            prev_pos = 0
+            if prev_txn is not None:
+                prev_txn_pos = self._txn_find(prev_txn)
+                if prev_txn_pos:
+                    prev_pos = self._data_find(prev_txn_pos, oid, data)
             old = self._index_get(oid, 0)
             # Calculate the file position in the temporary file
             here = self._pos + self._tfile.tell() + self._thl
             # And update the temp file index
             self._tindex[oid] = here
-            # Write the recovery data record
+            if prev_pos:
+                # If there is a valid prev_pos, don't write data.
+                data = None
             if data is None:
                 dlen = 0
             else:
                 dlen = len(data)
-            self._tfile.write(pack('>8s8s8s8sH8s',
+            # Write the recovery data record
+            self._tfile.write(pack(DATA_HDR,
                                    oid, serial, p64(old), p64(self._pos),
                                    len(version), p64(dlen)))
             # We need to write some version information if this revision is
@@ -806,9 +850,13 @@
                 self._tfile.write(version)
             # And finally, write the data
             if data is None:
-                # Write a zero backpointer, which indicates an
-                # un-creation transaction.
-                self._tfile.write(z64)
+                if prev_pos:
+                    self._tfile.write(p64(prev_pos))
+                else:
+                    # Write a zero backpointer, which indicates an
+                    # un-creation transaction.
+                    # write a backpointer instead of data
+                    self._tfile.write(z64)
             else:
                 self._tfile.write(data)
         finally:


=== ZODB3/ZODB/BaseStorage.py 1.24 => 1.24.2.1 ===
--- ZODB3/ZODB/BaseStorage.py:1.24	Sat Sep 28 05:16:46 2002
+++ ZODB3/ZODB/BaseStorage.py	Mon Oct 21 11:15:55 2002
@@ -281,7 +281,8 @@
                 oid=r.oid
                 if verbose: print `oid`, r.version, len(r.data)
                 if restoring:
-                    self.restore(oid, r.serial, r.data, r.version, transaction)
+                    self.restore(oid, r.serial, r.data, r.version,
+                                 r.data_txn, transaction)
                 else:
                     pre=preget(oid, None)
                     s=self.store(oid, pre, r.data, r.version, transaction)