[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