[Zodb-checkins] CVS: Packages/ZODB - Connection.py:1.98.4.7 POSException.py:1.20.4.3

Tim Peters tim.one at comcast.net
Fri Aug 27 15:04:15 EDT 2004


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

Modified Files:
      Tag: Zope-2_7-branch
	Connection.py POSException.py 
Log Message:
New ConnectionStateError raised if an attempt to close a Connection occurs
while a transaction involving that Connection has pending changes.
Collector #789 is a starting point for rationale (short course:
POSKeyErrors, both temporary and permanent, can result otherwise).
The ZODB3 NEWS file will contain more info.


=== Packages/ZODB/Connection.py 1.98.4.6 => 1.98.4.7 ===
--- Packages/ZODB/Connection.py:1.98.4.6	Fri May 21 12:14:04 2004
+++ Packages/ZODB/Connection.py	Fri Aug 27 15:03:42 2004
@@ -15,8 +15,16 @@
 
 $Id$"""
 
+from cPickle import Unpickler, Pickler
+from cStringIO import StringIO
+import sys
+import threading
+from time import time
+from types import StringType, ClassType
+
 from cPickleCache import PickleCache
 from POSException import ConflictError, ReadConflictError, TransactionError
+from POSException import ConnectionStateError
 from ExtensionClass import Base
 import ExportImport, TmpStore
 from zLOG import LOG, ERROR, BLATHER, WARNING
@@ -25,13 +33,6 @@
 from Transaction import Transaction, get_transaction
 from ZODB.utils import oid_repr
 
-from cPickle import Unpickler, Pickler
-from cStringIO import StringIO
-import sys
-import threading
-from time import time
-from types import StringType, ClassType
-
 global_code_timestamp = 0
 
 def updateCodeTimestamp():
@@ -53,9 +54,9 @@
 
     The Connection manages movement of objects in and out of object storage.
     """
-    _tmp=None
-    _debug_info=()
-    _opened=None
+    _tmp = None
+    _debug_info = ()
+    _opened = None
     _code_timestamp = 0
     _transaction = None
 
@@ -98,6 +99,18 @@
         self._invalid = d.has_key
         self._conflicts = {}
 
+        # We want to raise ConnectionStateError if an attempt to close is
+        # made while modifications are pending.  This is easier in ZODB
+        # 3.3.  While it's not obvious, self._tmp is non-None iff a
+        # committed subtransaction is pending.  For "top level" pending
+        # changes, we set _object_registered to True in register(), and
+        # back to False in abort() and _flush_invalidations().  The latter
+        # is an odd choice, but is common to most ways of clearing pending 
+        # top-level change (tpc_finish, tpc_abort, sync, _setDB).  abort()
+        # is also a bit peculiar, but it's the only Connection method
+        # Transaction.abort() calls, so there's not much choice.
+        self._object_registered = False
+
     def getTransaction(self):
         t = self._transaction
         if t is None:
@@ -258,6 +271,7 @@
         else:
             assert object._p_oid is not None
             self._cache.invalidate(object._p_oid)
+            self._object_registered = False
 
     def cacheFullSweep(self, dt=0):
         self._cache.full_sweep(dt)
@@ -274,6 +288,19 @@
         self.__onCloseCallbacks.append(f)
 
     def close(self):
+        if self._object_registered:
+            # We're currently joined to a transaction.  This spelling
+            # doesn't make much sense here, but I want to keep this
+            # exception the same as in ZODB 3.3 (where this spelling
+            # does make sense).
+            raise ConnectionStateError("Cannot close a connection joined to "
+                                       "a transaction")
+
+        if self._tmp is not None:
+            # There are no direct modifications pending, but a subtransaction
+            # is pending.
+            raise ConnectionStateError("Cannot close a connection with a "
+                                       "pending subtransaction")
         if self._incrgc is not None:
             self._incrgc() # This is a good time to do some GC
 
@@ -519,6 +546,7 @@
             self._inv_lock.release()
         # Now is a good time to collect some garbage
         self._cache.incrgc()
+        self._object_registered = False
 
     def modifiedInVersion(self, oid):
         try: return self._db.modifiedInVersion(oid)
@@ -535,6 +563,7 @@
         # XXX Figure out why this assert causes test failures
         # assert object._p_oid is not None
         self.getTransaction().register(object)
+        self._object_registered = True
 
     def root(self):
         return self['\0\0\0\0\0\0\0\0']


=== Packages/ZODB/POSException.py 1.20.4.2 => 1.20.4.3 ===
--- Packages/ZODB/POSException.py:1.20.4.2	Thu Oct 23 20:45:55 2003
+++ Packages/ZODB/POSException.py	Fri Aug 27 15:03:42 2004
@@ -219,3 +219,14 @@
 
     XXX The exception ought to have a member that is the invalid object.
     """
+
+class ConnectionStateError(POSError):
+    """A Connection isn't in the required state for an operation.
+
+    o An operation such as a load is attempted on a closed connection.
+
+    o An attempt to close a connection is made while the connection is
+      still joined to a transaction (for example, a transaction is in
+      progress, with uncommitted modifications in the connection).
+    """
+ 
\ No newline at end of file



More information about the Zodb-checkins mailing list