[Zodb-checkins] CVS: Zope/lib/python/ZODB - Connection.py:1.83 DB.py:1.47 ExportImport.py:1.16 ZApplication.py:1.12

Shane Hathaway shane@zope.com
Fri, 17 Jan 2003 12:23:49 -0500


Update of /cvs-repository/Zope/lib/python/ZODB
In directory cvs.zope.org:/tmp/cvs-serv22844

Modified Files:
	Connection.py DB.py ExportImport.py ZApplication.py 
Log Message:
Merged shane-local-transactions-branch.

This change adds a new method, setLocalTransaction(), to the
Connection class.  ZODB applications can call this method to bind
transactions to connections rather than threads.  This is especially
useful for GUI applications, which often have only one thread but
multiple independent activities within that thread (generally one per
window).  Thanks to Christian Reis for championing this feature.

Applications that take advantage of this feature should not use the
get_transaction() function.  Until now, ZODB itself sometimes assumed
get_transaction() was the only way to get the transaction.  Minor
corrections have been added.  The ZODB test suite, on the other hand,
can continue to use get_transaction(), since it is free to assume that
transactions are bound to threads.



=== Zope/lib/python/ZODB/Connection.py 1.82 => 1.83 ===
--- Zope/lib/python/ZODB/Connection.py:1.82	Wed Jan 15 16:29:26 2003
+++ Zope/lib/python/ZODB/Connection.py	Fri Jan 17 12:23:14 2003
@@ -22,6 +22,7 @@
 from zLOG import LOG, ERROR, BLATHER, WARNING
 from coptimizations import new_persistent_id
 from ConflictResolution import ResolvedSerial
+from Transaction import Transaction, get_transaction
 
 from cPickle import Unpickler, Pickler
 from cStringIO import StringIO
@@ -55,6 +56,7 @@
     _debug_info=()
     _opened=None
     _code_timestamp = 0
+    _transaction = None
 
     # Experimental. Other connections can register to be closed
     # when we close by putting something here.
@@ -80,6 +82,19 @@
         self._load_count = 0   # Number of objects unghosted
         self._store_count = 0  # Number of objects stored
 
+    def getTransaction(self):
+        t = self._transaction
+        if t is None:
+            # Fall back to thread-bound transactions
+            t = get_transaction()
+        return t
+
+    def setLocalTransaction(self):
+        """Use a transaction bound to the connection rather than the thread"""
+        if self._transaction is None:
+            self._transaction = Transaction()
+        return self._transaction
+
     def _cache_items(self):
         # find all items on the lru list
         items = self._cache.lru_items()
@@ -269,7 +284,7 @@
         if self.__onCommitActions is None:
             self.__onCommitActions = []
         self.__onCommitActions.append((method_name, args, kw))
-        get_transaction().register(self)
+        self.getTransaction().register(self)
 
     def commit(self, object, transaction):
         if object is self:
@@ -484,7 +499,7 @@
         assert object._p_jar is self
         # XXX Figure out why this assert causes test failures
         # assert object._p_oid is not None
-        get_transaction().register(object)
+        self.getTransaction().register(object)
 
     def root(self):
         return self['\0\0\0\0\0\0\0\0']
@@ -516,7 +531,7 @@
             # XXX Need unit tests for _p_independent.
             if self._invalid(oid):
                 if not hasattr(object.__class__, '_p_independent'):
-                    get_transaction().register(self)
+                    self.getTransaction().register(self)
                     raise ReadConflictError(object=object)
                 invalid = 1
             else:
@@ -544,7 +559,7 @@
                     except KeyError:
                         pass
                 else:
-                    get_transaction().register(self)
+                    self.getTransaction().register(self)
                     raise ConflictError(object=object)
 
         except ConflictError:
@@ -695,7 +710,7 @@
         self._db.finish_invalidation()
 
     def sync(self):
-        get_transaction().abort()
+        self.getTransaction().abort()
         sync=getattr(self._storage, 'sync', 0)
         if sync != 0: sync()
         self._cache.invalidate(self._invalidated)
@@ -726,7 +741,7 @@
         new._p_oid=oid
         new._p_jar=self
         new._p_changed=1
-        get_transaction().register(new)
+        self.getTransaction().register(new)
         self._cache[oid]=new
 
 class tConnection(Connection):


=== Zope/lib/python/ZODB/DB.py 1.46 => 1.47 ===
--- Zope/lib/python/ZODB/DB.py:1.46	Tue Dec  3 12:40:56 2002
+++ Zope/lib/python/ZODB/DB.py	Fri Jan 17 12:23:14 2003
@@ -19,7 +19,7 @@
 import cPickle, cStringIO, sys, POSException, UndoLogCompatible
 from Connection import Connection
 from bpthread import allocate_lock
-from Transaction import Transaction
+from Transaction import Transaction, get_transaction
 from referencesf import referencesf
 from time import time, ctime
 from zLOG import LOG, ERROR
@@ -153,8 +153,10 @@
                 self._temps=t
         finally: self._r()
 
-    def abortVersion(self, version):
-        AbortVersion(self, version)
+    def abortVersion(self, version, transaction=None):
+        if transaction is None:
+            transaction = get_transaction()
+        transaction.register(AbortVersion(self, version))
 
     def cacheDetail(self):
         """Return information on objects in the various caches
@@ -248,8 +250,10 @@
     def close(self):
         self._storage.close()
 
-    def commitVersion(self, source, destination=''):
-        CommitVersion(self, source, destination)
+    def commitVersion(self, source, destination='', transaction=None):
+        if transaction is None:
+            transaction = get_transaction()
+        transaction.register(CommitVersion(self, source, destination))
 
     def exportFile(self, oid, file=None):
         raise 'Not yet implemented'
@@ -542,7 +546,7 @@
 
     def cacheStatistics(self): return () # :(
 
-    def undo(self, id):
+    def undo(self, id, transaction=None):
         storage=self._storage
         try: supportsTransactionalUndo = storage.supportsTransactionalUndo
         except AttributeError:
@@ -552,7 +556,9 @@
 
         if supportsTransactionalUndo:
             # new style undo
-            TransactionalUndo(self, id)
+            if transaction is None:
+                transaction = get_transaction()
+            transaction.register(TransactionalUndo(self, id))
         else:
             # fall back to old undo
             for oid in storage.undo(id):
@@ -576,7 +582,6 @@
         self.tpc_vote=s.tpc_vote
         self.tpc_finish=s.tpc_finish
         self._sortKey=s.sortKey
-        get_transaction().register(self)
 
     def sortKey(self):
         return "%s:%s" % (self._sortKey(), id(self))
@@ -613,9 +618,9 @@
     in cooperation with a transaction manager.
     """
 
-    # I'm lazy. I'm reusing __init__ and abort and reusing the
-    # version attr for the transavtion id. There's such a strong
-    # similarity of rythm, that I think it's justified.
+    # I (Jim) am lazy.  I'm reusing __init__ and abort and reusing the
+    # version attr for the transaction id.  There's such a strong
+    # similarity of rhythm that I think it's justified.
 
     def commit(self, reallyme, t):
         db=self._db


=== Zope/lib/python/ZODB/ExportImport.py 1.15 => 1.16 ===
--- Zope/lib/python/ZODB/ExportImport.py:1.15	Mon Dec  2 17:04:37 2002
+++ Zope/lib/python/ZODB/ExportImport.py	Fri Jan 17 12:23:14 2003
@@ -76,7 +76,7 @@
                 return customImporters[magic](self, file, clue)
             raise POSException.ExportError, 'Invalid export header'
 
-        t = get_transaction()
+        t = self.getTransaction()
         if clue: t.note(clue)
 
         return_oid_list = []


=== Zope/lib/python/ZODB/ZApplication.py 1.11 => 1.12 ===
--- Zope/lib/python/ZODB/ZApplication.py:1.11	Wed Aug 14 18:07:09 2002
+++ Zope/lib/python/ZODB/ZApplication.py	Fri Jan 17 12:23:14 2003
@@ -31,7 +31,7 @@
             root=conn.root()
             if not root.has_key(name):
                 root[name]=klass()
-                get_transaction().commit()
+                conn.getTransaction().commit()
             conn.close()
             self._klass=klass