[Zope3-checkins] CVS: Zope3/src/zodb/storage/file - pack.py:1.1.2.2

Jeremy Hylton jeremy@zope.com
Thu, 17 Apr 2003 15:55:50 -0400


Update of /cvs-repository/Zope3/src/zodb/storage/file
In directory cvs.zope.org:/tmp/cvs-serv12991/file

Modified Files:
      Tag: jeremy-new-pack-branch
	pack.py 
Log Message:
Make pack work for objects created in versions that are unreachable at
the pack time.


=== Zope3/src/zodb/storage/file/pack.py 1.1.2.1 => 1.1.2.2 ===
--- Zope3/src/zodb/storage/file/pack.py:1.1.2.1	Wed Apr 16 14:12:32 2003
+++ Zope3/src/zodb/storage/file/pack.py	Thu Apr 17 15:55:50 2003
@@ -29,18 +29,12 @@
         self.packtime = packtime
         # packpos: position of first txn header after pack time
         self.packpos = None
-        # XXX pos2oid may be unnecessary
-        self.pos2oid = {} # maps data record position to oid
         self.oid2curpos = {} # maps oid to current data record position
+        self.oid2verpos = {} # maps oid to current version data
         self.reachable = {} # maps oid to list of reachable data record pos
 
-    # XXX what about versions?
-    # need PackAfterUndoDeleteVersion
-
     def findReachable(self):
         self.buildPackIndex()
-        if ZERO not in self.oid2curpos:
-            return
         self.findReachableAtPacktime([ZERO])
         self.findReachableFromFuture()
 
@@ -56,8 +50,10 @@
 
             while pos < end:
                 dh = self._read_data_header(pos)
-                self.pos2oid[pos] = dh.oid
-                self.oid2curpos[dh.oid] = pos
+                if dh.version:
+                    self.oid2verpos[dh.oid] = pos
+                else:
+                    self.oid2curpos[dh.oid] = pos
                 pos += dh.recordlen()
 
             tlen = self._read_num(pos)
@@ -74,9 +70,19 @@
             if oid in self.reachable:
                 continue
 
-            pos = self.oid2curpos[oid]
-            self.reachable[oid] = [pos]
-            todo.extend(self.findrefs(pos))
+            L = []
+
+            pos = self.oid2curpos.get(oid)
+            if pos is not None:
+                L.append(pos)
+                todo.extend(self.findrefs(pos))
+
+            pos = self.oid2verpos.get(oid)
+            if pos is not None:
+                L.append(pos)
+                todo.extend(self.findrefs(pos))
+
+            self.reachable[oid] = L
 
     def findReachableFromFuture(self):
         # In this pass, the roots are positions of object revisions.
@@ -100,6 +106,12 @@
                     if dh.back not in L:
                         L.append(dh.back)
                         extra_roots.append(dh.back)
+
+                if dh.pnv and dh.pnv < self.packpos:
+                    L = self.reachable.setdefault(dh.oid, [])
+                    if dh.pnv not in L:
+                        L.append(dh.pnv)
+                        extra_roots.append(dh.pnv)
                         
                 pos += dh.recordlen()
 
@@ -340,69 +352,17 @@
             if h.plen:
                 refs = self._file.read(8 * h.nrefs)
                 data = self._file.read(h.plen)
-            else:
+            elif h.back:
                 # If a current record has a backpointer, fetch
                 # refs and data from the backpointer.  We need
                 # to write the data in the new record.
                 data, refs, serial, tid = self._loadBackTxn(h.oid, h.back)
                 refs = "".join(refs)
-
-            self.writePackedDataRecord(h, data, refs, new_tpos)
-            new_pos = self._tfile.tell()
-
-        return new_tpos, pos
-
-    def VERSIONcopyDataRecords(self, pos, th):
-        """Copy any current data records between pos and tend.
-
-        Returns position of txn header in output file and position
-        of next record in the input file.
-        
-        If any data records are copied, also write txn header (th).
-        """
-        copy = False
-        new_tpos = 0
-        tend = pos + th.tlen
-        pos += th.headerlen()
-        while pos < tend:
-            h = self._read_data_header(pos)
-            cur_nonversion = False
-
-            # If this data record isn't current, don't copy it.
-            # If the current record is in a version, this may be
-            # the current non-version data.
-            curpos = self.pindex.get(h.oid, 0)
-            if curpos != pos:
-                if self.isCurNonversion(h, pos, curpos):
-                    cur_nonversion = True
-                else:
-                    pos += h.recordlen()
-                    continue
-            pos += h.recordlen()
-
-            # If we are going to copy any data, we need to copy
-            # the transaction header.  Note that we will need to
-            # patch up the transaction length when we are done.
-            if not copy:
-                th.status = "p"
-                s = th.asString()
-                new_tpos = self._tfile.tell()
-                self._tfile.write(s)
-                new_pos = new_tpos + len(s)
-                copy = True
-
-            if cur_nonversion:
-                self.nvindex[h.oid] = new_pos
-
-            if h.plen:
-                refs = self._file.read(8 * h.nrefs)
-                data = self._file.read(h.plen)
             else:
-                # If a current record has a backpointer, fetch
-                # refs and data from the backpointer.  We need
-                # to write the data in the new record.
-                data, refs, serial, tid = self._loadBackTxn(h.oid, h.back)
-                refs = "".join(refs)
+                assert h.plen == 0 and h.back == 0
+                data = ""
+                refs = ""
+                print "george", h.__dict__
 
             self.writePackedDataRecord(h, data, refs, new_tpos)
             new_pos = self._tfile.tell()
@@ -417,16 +377,26 @@
         h.plen = len(data)
         h.nrefs = len(refs) / 8
         h.tloc = new_tpos
+        pos = self._tfile.tell()
         if h.version:
-            h.pnv = self.nvindex.get(h.oid, 0)
+            h.pnv = self.index.get(h.oid, 0)
             h.vprev = self.vindex.get(h.version, 0)
-        pos = self._tfile.tell()
+            self.vindex[h.version] = pos
         self.index[h.oid] = pos
         if h.version:
             self.vindex[h.version] = pos
+        if not (data or refs):
+            print h.__dict__
+            print repr(h.asString())
+        print "writing at %d" % self._tfile.tell()
         self._tfile.write(h.asString())
         self._tfile.write(refs)
         self._tfile.write(data)
+        if not data:
+            # Packed records never have backpointers (?).
+            # If there is no data, write a ZERO backpointer.
+            # This is a George Bailey event.
+            self._tfile.write(ZERO)
 
     def copyRest(self, ipos):
         # After the pack time, all data records are copied.