[Zope3-checkins] CVS: Zope3/src/zodb/storage - bdbfull.py:1.22

Barry Warsaw barry@wooz.org
Wed, 9 Apr 2003 13:57:59 -0400


Update of /cvs-repository/Zope3/src/zodb/storage
In directory cvs.zope.org:/tmp/cvs-serv13369

Modified Files:
	bdbfull.py 
Log Message:
_begin(), _dobegin(), _finish(): Fix signatures since user,
description, ext is never passed here.  Get the information from
self._ude where needed.

_unpack_txnmeta(): Refactor the decoding of the transaction metadata
string, including utf-8 decoding the stored user and description 8-bit
strings back to Unicode.  Also factors out the unpickling of the
extension object.

_doundolog(), _nexttxn(): Use _unpack_txnmeta()

_RecordIterator.__init__(): The ext object passed in here is already
unpickled.


=== Zope3/src/zodb/storage/bdbfull.py 1.21 => 1.22 ===
--- Zope3/src/zodb/storage/bdbfull.py:1.21	Thu Apr  3 17:16:48 2003
+++ Zope3/src/zodb/storage/bdbfull.py	Wed Apr  9 13:57:58 2003
@@ -164,10 +164,14 @@
         #         8-byte unsigned long integer
         #     desclen is the length in characters of the `desc' field as an
         #         8-byte unsigned long integer
-        #     user is the user information passed to tpc_finish()
-        #     desc is the description info passed to tpc_finish()
-        #     ext is the extra info passed to tpc_finish().  It is a
-        #         dictionary that we get already pickled by BaseStorage.
+        #     user is the user information passed in the transaction object
+        #     desc is the description info passed in the transaction object
+        #     ext is the extra info passed in the transaction object.  It is a
+        #         mapping that we get already pickled by BaseStorage.
+        #
+        #     Note: txnBegin() can get user and desc as Unicode strings, so
+        #     they are stored in this table as utf-8 encoded byte strings, and
+        #     decoded back to Unicode when requested.
         #
         # txnoids -- {tid -> [oid]}
         #     Maps transaction ids to the oids of the objects modified by the
@@ -451,25 +455,27 @@
                 self._packmark.put(oid, PRESENT, txn=txn)
         self._oids.truncate(txn)
 
-    def _dobegin(self, txn, tid, u, d, e):
-        # When a transaction begins, we set the pending flag to ABORT,
-        # meaning, if we crash between now and the time we vote, all changes
-        # will be aborted.
-        #
+    def _dobegin(self, txn, tid):
         # It's more convenient to store the transaction metadata now, rather
         # than in the _finish() call.  Doesn't matter because if the ZODB
-        # transaction were to abort, we'd clean this up anyway.
-        userlen = len(u)
-        desclen = len(d)
+        # transaction were to abort, we'd clean this up anyway.  Watch out for
+        # Unicode user or description data.  XXX Assume the extended data is
+        # /not/ Unicode -- it's usually a pickle.
+        user, desc, ext = self._ude
+        userlen = len(user)
+        desclen = len(desc)
         lengths = pack('>2I', userlen, desclen)
-        data = lengths + u + d + e
+        data = lengths + user + desc + ext
+        # When a transaction begins, we set the pending flag to ABORT,
+        # meaning, if we crash between now and the time we vote, all changes
+        # will be aborted.
         self._pending.put(tid, ABORT, txn=txn)
         self._txnMetadata.put(tid, data, txn=txn)
 
-    def _begin(self, tid, u, d, e):
-        self._withtxn(self._dobegin, self._serial, u, d, e)
+    def _begin(self, tid):
+        self._withtxn(self._dobegin, self._serial)
 
-    def _finish(self, tid, u, d, e):
+    def _finish(self, tid):
         self._withtxn(self._docommit, self._serial)
         self._ltid = tid
 
@@ -1231,6 +1237,24 @@
         finally:
             self._lock_release()
 
+    def _unpack_txnmeta(self, txnmeta):
+        userlen, desclen = unpack('>2I', txnmeta[:8])
+        usafe = txnmeta[8:8+userlen]
+        dsafe = txnmeta[8+userlen:8+userlen+desclen]
+        # user and desc are utf-8 encoded
+        user = usafe.decode('utf-8')
+        desc = dsafe.decode('utf-8')
+        extdata = txnmeta[8+userlen+desclen:]
+        # ext is a pickled mapping.  Any exceptions are ignored, but XXX can
+        # we (and FileStorage :) do better?
+        ext = {}
+        if extdata:
+            try:
+                ext = pickle.loads(extdata)
+            except Exception, e:
+                self.log('Error unpickling extension data: %s', e)
+        return user, desc, ext
+
     def _doundolog(self, first, last, filter):
         # Get the last packtime
         packtime = self._last_packtime()
@@ -1248,26 +1272,16 @@
                 rec = c.prev()
                 if tid <= packtime:
                     break
-                userlen, desclen = unpack('>2I', txnmeta[:8])
-                user = txnmeta[8:8+userlen]
-                desc = txnmeta[8+userlen:8+userlen+desclen]
-                ext = txnmeta[8+userlen+desclen:]
+                user, desc, ext = self._unpack_txnmeta(txnmeta)
                 # Create a dictionary for the TransactionDescription
                 txndesc = {'id'         : tid,
                            'time'       : TimeStamp(tid).timeTime(),
                            'user_name'  : user,
                            'description': desc,
                            }
-                # The extension stuff is a picklable mapping, so if we can
-                # unpickle it, we update the TransactionDescription dictionary
-                # with that data.  BAW: The bare except is disgusting, but I'm
-                # too lazy to figure out what exceptions could actually be
-                # raised here...
-                if ext:
-                    try:
-                        txndesc.update(pickle.loads(ext))
-                    except:
-                        pass
+                # Update the transaction description dictionary with the
+                # extension mapping.
+                txndesc.update(ext)
                 # Now call the filter to see if this transaction should be
                 # added to the return list...
                 if filter is None or filter(txndesc):
@@ -1652,7 +1666,7 @@
                 rec = c.next()
             if rec is None:
                 raise IndexError
-            tid, data = rec
+            tid, txnmeta = rec
             # Now unpack the necessary information.  Don't impedence match the
             # status flag (that's done by the caller).
             packtime = self._last_packtime()
@@ -1660,10 +1674,7 @@
                 packedp = True
             else:
                 packedp = False
-            userlen, desclen = unpack('>2I', data[:8])
-            user = data[8:8+userlen]
-            desc = data[8+userlen:8+userlen+desclen]
-            ext = data[8+userlen+desclen:]
+            user, desc, ext = self._unpack_txnmeta(txnmeta)
             return tid, packedp, user, desc, ext
         finally:
             if c:
@@ -1759,10 +1770,7 @@
             self.status = ' '
         self.user = user
         self.description = desc
-        try:
-            self._extension = pickle.loads(ext)
-        except EOFError:
-            self._extension = {}
+        self._extension = ext
         # BAW: touching the storage's private parts!
         self._table = self._storage._txnoids
         self._cursor = None