[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):