[Zodb-checkins] CVS: ZODB3/BDBStorage - BDBFullStorage.py:1.75.2.4

Jeremy Hylton cvs-admin at zope.org
Mon Nov 24 17:41:00 EST 2003


Update of /cvs-repository/ZODB3/BDBStorage
In directory cvs.zope.org:/tmp/cvs-serv32409/BDBStorage

Modified Files:
      Tag: ZODB3-mvcc-2-branch
	BDBFullStorage.py 
Log Message:
Add loadNonCurrent() implementation after help from Barry.

This passes everything except checkAbortVersionNonCurrent.  I'm not
sure how to figure out the serial number of a non-current revision
that was created by abortVersion.


=== ZODB3/BDBStorage/BDBFullStorage.py 1.75.2.3 => 1.75.2.4 ===
--- ZODB3/BDBStorage/BDBFullStorage.py:1.75.2.3	Sun Nov 23 16:39:23 2003
+++ ZODB3/BDBStorage/BDBFullStorage.py	Mon Nov 24 17:40:54 2003
@@ -914,34 +914,90 @@
     # Accessor interface
     #
 
+    def _load(self, oid, serial, tid, version):
+        # Get the metadata associated with this revision of the object.
+        # All we really need is the vid, the non-version revid and the
+        # pickle pointer revid.
+        rec = self._metadata[oid+tid]
+        vid, nvrevid, lrevid = unpack('>8s8s8s', rec[:24])
+        if lrevid == DNE:
+            raise KeyError, 'Object does not exist: %r' % oid
+        # If the object isn't living in a version, or if the version the
+        # object is living in is the one that was requested, we simply
+        # return the current revision's pickle.
+        if vid == ZERO:
+            return self._pickles[oid+lrevid], serial, tid, ""
+        if self._versions.get(vid) == version:
+            return self._pickles[oid+lrevid], serial, tid, version
+        # The object was living in a version, but not the one requested.
+        # Semantics here are to return the non-version revision.  Allow
+        # KeyErrors to percolate up (meaning there's no non-version rev).
+        lrevid = self._metadata[oid+nvrevid][16:24]
+        return self._pickles[oid+lrevid], lrevid, tid, ""
+
     def loadEx(self, oid, version):
         self._lock_acquire()
         try:
             # Get the current revision information for the object.  As per the
             # protocol, let Key errors percolate up.
             serial, tid = self._getSerialAndTid(oid)
-            # Get the metadata associated with this revision of the object.
-            # All we really need is the vid, the non-version revid and the
-            # pickle pointer revid.
-            rec = self._metadata[oid+tid]
-            vid, nvrevid, lrevid = unpack('>8s8s8s', rec[:24])
-            if lrevid == DNE:
-                raise KeyError, 'Object does not exist: %r' % oid
-            # If the object isn't living in a version, or if the version the
-            # object is living in is the one that was requested, we simply
-            # return the current revision's pickle.
-            if vid == ZERO or self._versions.get(vid) == version:
-                return self._pickles[oid+lrevid], serial, tid, version
-            # The object was living in a version, but not the one requested.
-            # Semantics here are to return the non-version revision.  Allow
-            # KeyErrors to percolate up (meaning there's no non-version rev).
-            lrevid = self._metadata[oid+nvrevid][16:24]
-            return self._pickles[oid+lrevid], serial, tid, ""
+            return self._load(oid, serial, tid, version)
         finally:
             self._lock_release()
 
     def load(self, oid, version):
         return self.loadEx(oid, version)[:2]
+
+    def loadNonCurrent(self, oid, tid):
+        self._lock_acquire()
+        try:
+            c = self._metadata.cursor()
+            try:
+                # The range search will return the smallest key greater
+                # than oid + tid.  We need to look at the previous record.
+                try:
+                    p = c.set_range(oid + tid)
+                except db.DBNotFoundError:
+                    # If tid > cur tid for oid, then we'll get a not-found
+                    # error.  Perhaps the current tid is sufficient?
+                    cur_serial, cur_tid = self._getSerialAndTid(oid)
+                    # if cur_tid >= tid, set_range() would have worked
+                    assert cur_tid < tid
+                    data, serial, tid, version = self._load(oid, cur_serial,
+                                                            cur_tid, "")
+                    return data, serial, cur_tid, None
+                        
+                next_tid = p[0][8:]
+                return self._noncurrent_search(c, oid, tid, next_tid)
+            finally:
+                c.close()
+        finally:
+            self._lock_release()
+
+    def _noncurrent_search(self, c, oid, tid, end_tid):
+        # Operates on the cursor created by loadNonCurrent().
+        p = c.prev()
+        if p is None:
+            return None
+        key, rec = p
+        # If the previous record is for a different oid, then
+        # there is no matching record.
+        if key[:8] != oid:
+            return None
+        # It's possible that the range search hits oid, tid + 1 exactly,
+        # but only the first time.
+        if key == oid + tid:
+            return self._noncurrent_search(c, oid, tid, tid)
+        vid, nvrevid, lrevid = unpack(">8s8s8s", rec[:24])
+        if vid == ZERO:
+            revid = lrevid
+        else:
+            revid = nvrevid
+        data = self._pickles[oid+revid]
+        tid = key[8:]
+        # XXX What about abortVersion?  Does that give a different
+        # serial no than tid?
+        return data, tid, tid, end_tid
 
     def _getSerialAndTidMissingOk(self, oid):
         # For the object, return the curent serial number and transaction id




More information about the Zodb-checkins mailing list