[Zodb-checkins] CVS: ZODB3/ZODB - Connection.py:1.75

Jeremy Hylton jeremy@zope.com
Sat, 7 Sep 2002 13:22:10 -0400


Update of /cvs-repository/ZODB3/ZODB
In directory cvs.zope.org:/tmp/cvs-serv28166

Modified Files:
	Connection.py 
Log Message:
Handle empty transactions without touching the storage.

# NB: commit() is responsible for calling tpc_begin() on the storage.
# It uses self._begun to track whether it has been called.  When
# self._begun is None, it has not been called.
 
# This arrangement allows us to handle the special case of a
# transaction with no modified objects.  It is possible for
# registration to be occur unintentionally and for a persistent
# object to compensate by making itself as unchanged.  When this
# happens, it's possible to commit a transaction with no modified
# objects.
 
# Since tpc_begin() may raise a ReadOnlyError, don't call it if there
# are no objects.  This avoids spurious (?) errors when working with
# a read-only storage.

Add code to handle this in Connection's tpc_begin() and commit()
methods.

Add two tests in testZODB.


=== ZODB3/ZODB/Connection.py 1.74 => 1.75 ===
--- ZODB3/ZODB/Connection.py:1.74	Sat Sep  7 12:40:59 2002
+++ ZODB3/ZODB/Connection.py	Sat Sep  7 13:22:09 2002
@@ -268,13 +268,33 @@
         self.__onCommitActions.append((method_name, args, kw))
         get_transaction().register(self)
 
+    # NB: commit() is responsible for calling tpc_begin() on the storage.
+    # It uses self._begun to track whether it has been called.  When
+    # self._begun is None, it has not been called.
+
+    # This arrangement allows us to handle the special case of a
+    # transaction with no modified objects.  It is possible for
+    # registration to be occur unintentionally and for a persistent
+    # object to compensate by making itself as unchanged.  When this
+    # happens, it's possible to commit a transaction with no modified
+    # objects.
+
+    # Since tpc_begin() may raise a ReadOnlyError, don't call it if there
+    # are no objects.  This avoids spurious (?) errors when working with
+    # a read-only storage.
+
     def commit(self, object, transaction):
         if object is self:
+            if self._begun is None:
+                self._storage.tpc_begin(transaction)
+                self._begun = 1
+
             # We registered ourself.  Execute a commit action, if any.
             if self.__onCommitActions is not None:
                 method_name, args, kw = self.__onCommitActions.pop(0)
                 apply(getattr(self, method_name), (transaction,) + args, kw)
             return
+        
         oid = object._p_oid
         invalid = self._invalid
         if oid is None or object._p_jar is not self:
@@ -293,6 +313,10 @@
             # Nothing to do
             return
 
+        if self._begun is None:
+            self._storage.tpc_begin(transaction)
+            self._begun = 1
+
         stack = [object]
 
         # Create a special persistent_id that passes T and the subobject
@@ -592,31 +616,33 @@
         if self.__onCommitActions is not None:
             del self.__onCommitActions
         self._storage.tpc_abort(transaction)
-        cache=self._cache
-        cache.invalidate(self._invalidated)
-        cache.invalidate(self._invalidating)
+        self._cache.invalidate(self._invalidated)
+        self._cache.invalidate(self._invalidating)
         self._invalidate_creating()
 
     def tpc_begin(self, transaction, sub=None):
         self._invalidating = []
         self._creating = []
+        self._begun = None
 
         if sub:
             # Sub-transaction!
-            _tmp=self._tmp
-            if _tmp is None:
-                _tmp=TmpStore.TmpStore(self._version)
-                self._tmp=self._storage
-                self._storage=_tmp
+            if self._tmp is None:
+                _tmp = TmpStore.TmpStore(self._version)
+                self._tmp = self._storage
+                self._storage = _tmp
                 _tmp.registerDB(self._db, 0)
 
-        self._storage.tpc_begin(transaction)
+            # It's okay to always call tpc_begin() for a sub-transaction
+            # because this isn't the real storage.
+            self._storage.tpc_begin(transaction)
+            self._begun = 1
 
     def tpc_vote(self, transaction):
         if self.__onCommitActions is not None:
             del self.__onCommitActions
         try:
-            vote=self._storage.tpc_vote
+            vote = self._storage.tpc_vote
         except AttributeError:
             return
         s = vote(transaction)