[Zope3-checkins] CVS: Zope3/src/zodb/storage - demo.py:1.4
Jeremy Hylton
jeremy@zope.com
Fri, 14 Mar 2003 11:24:28 -0500
Update of /cvs-repository/Zope3/src/zodb/storage
In directory cvs.zope.org:/tmp/cvs-serv23447
Modified Files:
demo.py
Log Message:
Add incomplete implementation of undo.
=== Zope3/src/zodb/storage/demo.py 1.3 => 1.4 ===
--- Zope3/src/zodb/storage/demo.py:1.3 Fri Mar 14 03:12:42 2003
+++ Zope3/src/zodb/storage/demo.py Fri Mar 14 11:24:27 2003
@@ -26,9 +26,12 @@
from __future__ import generators
+import base64
+
from zodb.interfaces import *
from zodb.storage.base import BaseStorage
from zodb.storage.interfaces import *
+from zodb.timestamp import TimeStamp
class TxnRecord(object):
@@ -37,8 +40,12 @@
self.user = user
self.desc = desc
self.ext = ext
+ self.packed = False
self.data = []
+ def setPack(self):
+ self.packed = True
+
def append(self, rec):
self.data.append(rec)
@@ -46,8 +53,17 @@
for rec in self.data:
yield rec
+ def undoInfo(self):
+ return {"id": base64.encodestring(self.tid).rstrip(),
+ "time": TimeStamp(self.tid).timeTime(),
+ "user_name": self.user,
+ "description": self.desc}
+
class DataRecord(object):
+ # XXX Need to add a prev_txn field for transactions created
+ # by undo or commit/abort version.
+
def __init__(self, oid, serial, data, refs, version, prev):
self.oid = oid
self.serial = serial
@@ -207,11 +223,57 @@
def _abort(self):
self._cur_txn = None
- def undo(self, tid):
- pass
+ # XXX Should it be possible to undo a transaction in the base storage?
+
+ def undo(self, base64_tid, txn):
+ tid = base64.decodestring(base64_tid + "\n")
+ txn = self._data.get(tid)
+ if txn is None:
+ raise UndoError("Invalid transaction id")
+ if txn.packed:
+ raise UndoError("Can't undo packed transaction")
+ oids = []
+ for rec in txn:
+ # In order to be able to undo this transaction, we must be
+ # undoing either the current revision of the object, or we
+ # must be restoring the exact same pickle (identity compared)
+ # that would be restored if we were undoing the current
+ # revision. Otherwise, we attempt application level conflict
+ # resolution. If that fails, we raise an exception.
+ if rec != self._loadCurrent(rec.oid):
+ raise UndoError(rec.oid, "Can't undo transaction, "
+ "because data is not current")
+ if rec.prev:
+ prev = rec.prev
+ new = DataRecord(prev.oid, prev.serial, prev.data, prev.refs,
+ prev.version, prev.prev)
+ else:
+ new = DataRecord(rec.oid, None, None, None, None, rec)
+ self._cur_txn.append(new)
+ oids.append(new.oid)
+ return oids
def undoLog(self, first, last, filter=None):
- pass
+ if last < 0:
+ last = first - last + 1
+ L = self._data.keys()
+ L.sort()
+ L.reverse()
+ i = 0
+ results = []
+ print "undoLog", first, last, filter, len(L)
+ for tid in L:
+ rec = self._data[tid]
+ if rec.packed:
+ break
+ info = rec.undoInfo()
+ if not filter or filter(info):
+ if i > first:
+ results.append(info)
+ i += 1
+ if i > last:
+ break
+ return results
def versionEmpty(self, version):
if self._vindex.get(version):