[Zodb-checkins] CVS: ZODB3/bsddb3Storage/bsddb3Storage - Full.py:1.44.2.5

Barry Warsaw barry@wooz.org
Thu, 24 Oct 2002 09:54:52 -0400


Update of /cvs-repository/ZODB3/bsddb3Storage/bsddb3Storage
In directory cvs.zope.org:/tmp/cvs-serv17651

Modified Files:
      Tag: bdb-nolocks
	Full.py 
Log Message:
restore(), _dorestore(): A (mostly) working restore.  One test still
fails, but I wanted to checkpoint this code anyway.

_doAbortVersion(): Small fix so that this passes
checkCreateObjectInVersionWithAbort().

Add a note that we still need to implemented the extended iterator
interface.

Added next() methods to all the iterator helper classes, since the
RecoveryStorage tests use this interface instead of __getitem__().
__getitem__() is retained for backward compatibility.


=== ZODB3/bsddb3Storage/bsddb3Storage/Full.py 1.44.2.4 => 1.44.2.5 ===
--- ZODB3/bsddb3Storage/bsddb3Storage/Full.py:1.44.2.4	Tue Oct 22 19:17:49 2002
+++ ZODB3/bsddb3Storage/bsddb3Storage/Full.py	Thu Oct 24 09:54:52 2002
@@ -549,6 +549,90 @@
         finally:
             self._lock_release()
 
+    def _dorestore(self, txn, oid, serial, data, version, prev_txn):
+        tid = self._serial
+        vid = nvrevid = ZERO
+        prevrevid = prev_txn
+        # self._serial contains the transaction id as set by
+        # BaseStorage.tpc_begin().
+        revid = oid + tid
+        # Calculate and write the entries for version ids
+        if version:
+            vid = self._findcreatevid(version, txn)
+        # Calculate the previous revision id for this object, but only if we
+        # weren't told what to believe, via prev_txn
+        if prevrevid is None:
+            # Get the metadata for the current revision of the object
+            cserial, crevid = self._getSerialAndTidMissingOk(oid)
+            if crevid is None:
+                # There's never been a previous revision of this object
+                prevrevid = ZERO
+            else:
+                prevrevid = crevid
+        # Get the metadata for the previous revision, so that we can dig out
+        # the non-version revid, but only if there /is/ a previous revision
+        if prevrevid <> ZERO:
+            ovid, onvrevid = unpack(
+                '>8s8s', self._metadata[oid+prevrevid][:16])
+            if ovid == ZERO:
+                # The last revision of this object was made on the
+                # non-version, we don't care where the current change is
+                # made.  But if we're storing this change on a version then
+                # the non-version revid will be the previous revid
+                if version:
+                    nvrevid = prevrevid
+            else:
+                # We're making another change to this object on this version.
+                # The non-version revid is the same as for the previous
+                # revision of the object.
+                nvrevid = onvrevid
+        # Check for George Bailey Events
+        if data is None:
+            lrevid = DNE
+        else:
+            # Store the pickle record.  Remember that the reference counts are
+            # updated in _docommit().
+            self._pickles.put(revid, data, txn=txn)
+            lrevid = tid
+        # Update the serials table, but if the transaction id is different
+        # than the serial number, we need to write our special long record
+        if serial <> self._serial:
+            self._serials.put(oid, serial+tid, txn=txn)
+        else:
+            self._serials.put(oid, serial, txn=txn)
+        # Update the rest of the tables
+        self._metadata.put(revid, vid+nvrevid+lrevid+prevrevid, txn=txn)
+        self._txnoids.put(tid, oid, txn=txn)
+        self._oids.put(oid, PRESENT, txn=txn)
+        if vid <> ZERO:
+            self._currentVersions.put(vid, revid, txn=txn)
+
+    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
+        # differences:
+        #
+        # - serial is the serial number of /this/ revision, not of the
+        #   previous revision.  It is used instead of self._serial, which is
+        #   ignored.
+        #
+        # - Nothing is returned
+        #
+        # - 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 transaction is not self._transaction:
+            raise POSException.StorageTransactionError(self, transaction)
+        self._lock_acquire()
+        try:
+            self._withtxn(
+                self._dorestore, oid, serial, data, version, prev_txn)
+        finally:
+            self._lock_release()
+
     #
     # Things we can do in and to a version
     #
@@ -594,6 +678,8 @@
                     c.delete()
                     rec = c.next()
                     continue
+                # This object was modified
+                rtnoids[oid] = 1
                 # Calculate the values for the new transaction metadata
                 serial, tid = self._getSerialAndTid(oid)
                 meta = self._metadata[oid+tid]
@@ -606,8 +692,6 @@
                     c.delete()
                     rec = c.next()
                     continue
-                # This object was modified
-                rtnoids[oid] = 1
                 # Get the non-version data for the object
                 nvmeta = self._metadata[oid+nvrevid]
                 xcurvid, xnvrevid, lrevid = unpack('>8s8s8s', nvmeta[:24])
@@ -1509,6 +1593,7 @@
     # Iterator protocol
     #
 
+    # XXX extended iterator
     def iterator(self):
         """Get a transactions iterator for the storage."""
         return _TransactionsIterator(self)
@@ -1577,7 +1662,16 @@
 
 
 
-class _TransactionsIterator:
+class _GetItemBase:
+    def __getitem__(self, i):
+        # Ignore the index, since we expect .next() will raise the appropriate
+        # IndexError when the iterator is exhausted.
+        return self.next()
+        
+
+
+
+class _TransactionsIterator(_GetItemBase):
     """Provide forward iteration through the transactions in a storage.
 
     Transactions *must* be accessed sequentially (e.g. with a for loop).
@@ -1587,7 +1681,7 @@
         self._tid = None
         self._closed = 0
 
-    def __getitem__(self, i):
+    def next(self):
         """Return the ith item in the sequence of transaction data.
 
         Items must be accessed sequentially, and are instances of
@@ -1606,7 +1700,7 @@
 
 
 
-class _RecordsIterator:
+class _RecordsIterator(_GetItemBase):
     """Provide transaction meta-data and forward iteration through the
     transactions in a storage.
 
@@ -1645,7 +1739,7 @@
         # To make .pop() more efficient
         self._oids.reverse()
 
-    def __getitem__(self, i):
+    def next(self):
         """Return the ith item in the sequence of record data.
 
         Items must be accessed sequentially, and are instances of Record.  An