[ZODB-Dev] Inconsistent use of ConflictError

Greg Ward gward@mems-exchange.org
Thu, 16 Aug 2001 15:42:00 -0400


--SLDf9lqlvOQaIe6s
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On 16 August 2001, I said:
> Preliminary patch forthcoming...

OK, I'm attaching three patches to this message:

  POSException.patch    bulks out the ConflictError class and adds
                        ReadConflictError
  ZODB.patch            fixes Connection.py and ZODB/*Storage.py
                        to raise ConflictError "correctly"
  bsddb3Storage.patch   fixes bsddb3Storage/bsddb3Storage/*Storage.py
                        similarly

This is *COMPLETELY UNTESTED*.  I need to get back to work, but I wanted
to post this while it's fresh.  Plus some feedback would be nice.

Oops, I forgot to try to figure out which conflicts are read conflicts
-- so ReadConflictError is currently unused.  That needs fixing.

        Greg
-- 
Greg Ward - software developer                gward@mems-exchange.org
MEMS Exchange                            http://www.mems-exchange.org

--SLDf9lqlvOQaIe6s
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="POSException.patch"

Index: POSException.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/ZODB/POSException.py,v
retrieving revision 1.7
diff -u -1 -r1.7 POSException.py
--- POSException.py	12 Apr 2001 20:47:00 -0000	1.7
+++ POSException.py	16 Aug 2001 19:36:43 -0000
@@ -102,6 +102,77 @@
 class ConflictError(TransactionError):
-    """Two transactions tried to modify the same object at once
+    """Two transactions tried to modify the same object at once.  This
+    transaction should be resubmitted.
 
-    This transaction should be resubmitted.
+    Instance attributes:
+      oid : string
+        the OID (8-byte packed string) of the object in conflict
+      class_name : string
+        the fully-qualified name of that object's class
+      message : string
+        a human-readable explanation of the error
+      serials : (string, string)
+        a pair of 8-byte packed strings; these are the serial numbers
+        (old and new) of the object in conflict.  (Serial numbers are
+        closely related [equal?] to transaction IDs; a ConflictError may
+        be triggered by a serial number mismatch.)
     """
+
+    def __init__(self, message=None, object=None, serials=None):
+        if message is None:
+            self.message = "database conflict error"
+        else:
+            self.message = message
+
+        if object is not None:
+            self.oid = object._p_oid
+            klass = object.__class__
+            self.class_name = klass.__module__ + "." + klass.__name__
+        else:
+            self.oid = self.class_name = None
+
+        self.oid = oid
+        self.class_name = class_name
+        self.serials = serials
+
+    def __str__(self):
+        extras = []
+        if self.oid:
+            extras.append("oid %016x" % utils.U64(self.oid))
+        if self.class_name:
+            extras.append("class %s" % self.class_name)
+        if self.serials:
+            extras.append("serial was %016x, now %016x" %
+                          map(utils.U64, self.serials))
+        if extras:
+            return "%s (%s)" % (self.message, ", ".join(extras))
+        else:
+            return self.message
+
+    def get_oid(self):
+        return self.oid
+
+    def get_class_name(self):
+        return self.class_name
+
+    def get_old_serial(self):
+        return self.serials[0]
+
+    def get_new_serial(self):
+        return self.serials[1]
+
+    def get_serials(self):
+        return self.serials
+
+
+class ReadConflictError(ConflictError):
+    """A conflict detected at read time -- attempt to read an object
+    that has changed in another transaction (eg. another thread
+    or process).
+    """
+    def __init__(self, message=None, object=None, serials=None):
+        if message is None:
+            message = "database read conflict error"
+        ConflictError.__init__(self, message=message, object=object,
+                               serials=serials)
+
 

--SLDf9lqlvOQaIe6s
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ZODB.patch"

Index: Connection.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/ZODB/Connection.py,v
retrieving revision 1.58
diff -u -1 -r1.58 Connection.py
--- Connection.py	4 Jun 2001 12:34:57 -0000	1.58
+++ Connection.py	16 Aug 2001 19:37:32 -0000
@@ -323,3 +323,3 @@
                 ):
-                raise ConflictError, `oid`
+                raise ConflictError(object=object)
             self._invalidating.append(oid)
@@ -390,3 +390,3 @@
                     ):
-                    raise ConflictError, `oid`
+                    raise ConflictError(object=object)
                 self._invalidating.append(oid)
@@ -534,3 +534,3 @@
                     get_transaction().register(self)
-                    raise ConflictError(`oid`, `object.__class__`)
+                    raise ConflictError(object=object)
                 invalid=1
@@ -559,3 +559,3 @@
                     get_transaction().register(self)
-                    raise ConflictError(`oid`, `object.__class__`)
+                    raise ConflictError(object=object)
 
@@ -619,3 +619,3 @@
         if self._invalid(None): # Some nitwit invalidated everything!
-            raise ConflictError, "transaction already invalidated"
+            raise ConflictError("transaction already invalidated")
         self._invalidating=[]
Index: DemoStorage.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/ZODB/DemoStorage.py,v
retrieving revision 1.6
diff -u -1 -r1.6 DemoStorage.py
--- DemoStorage.py	20 Feb 2001 15:00:07 -0000	1.6
+++ DemoStorage.py	16 Aug 2001 19:37:32 -0000
@@ -297,3 +297,4 @@
 
-                if serial != oserial: raise POSException.ConflictError
+                if serial != oserial:
+                    raise POSException.ConflictError(serials=(oserial, serial))
                 
Index: FileStorage.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/ZODB/FileStorage.py,v
retrieving revision 1.62
diff -u -1 -r1.62 FileStorage.py
--- FileStorage.py	19 Jul 2001 12:03:43 -0000	1.62
+++ FileStorage.py	16 Aug 2001 19:37:33 -0000
@@ -662,4 +662,4 @@
                     if not data:
-                        raise POSException.ConflictError, (
-                            serial, oserial)
+                        raise POSException.ConflictError(
+                            serials=(oserial, serial))
             else:
Index: MappingStorage.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/ZODB/MappingStorage.py,v
retrieving revision 1.3
diff -u -1 -r1.3 MappingStorage.py
--- MappingStorage.py	11 Jul 1999 21:51:42 -0000	1.3
+++ MappingStorage.py	16 Aug 2001 19:37:33 -0000
@@ -210,3 +210,4 @@
                 oserial=old[:8]
-                if serial != oserial: raise POSException.ConflictError
+                if serial != oserial:
+                    raise POSException.ConflictError(serials=(oserial, serial))
                 

--SLDf9lqlvOQaIe6s
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="bsddb3Storage.patch"

Index: Full.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/bsddb3Storage/bsddb3Storage/Full.py,v
retrieving revision 1.29
diff -u -1 -r1.29 Full.py
--- Full.py	9 Jul 2001 18:38:42 -0000	1.29
+++ Full.py	16 Aug 2001 19:37:54 -0000
@@ -573,4 +573,3 @@
                     raise POSException.ConflictError(
-                        'serial number mismatch (was: %s, has: %s)' %
-                        (utils.U64(oserial), utils.U64(serial)))
+                        serials=(oserial, serial))
             # Do we already know about this version?  If not, we need to
Index: Minimal.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/bsddb3Storage/bsddb3Storage/Minimal.py,v
retrieving revision 1.9
diff -u -1 -r1.9 Minimal.py
--- Minimal.py	27 Apr 2001 23:28:59 -0000	1.9
+++ Minimal.py	16 Aug 2001 19:37:54 -0000
@@ -178,4 +178,3 @@
                 raise POSException.ConflictError(
-                    'serial number mismatch (was: %s, has: %s)' %
-                    (utils.U64(oserial), utils.U64(serial)))
+                    serials=(oserial, serial))
             # Our serial number is updated in BaseStorage's tpc_begin() call,
Index: MinimalReplicated.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/bsddb3Storage/bsddb3Storage/MinimalReplicated.py,v
retrieving revision 1.1
diff -u -1 -r1.1 MinimalReplicated.py
--- MinimalReplicated.py	9 Nov 2000 16:47:31 -0000	1.1
+++ MinimalReplicated.py	16 Aug 2001 19:37:54 -0000
@@ -30,3 +30,4 @@
                 oserial=self._index[oid]
-                if serial != oserial: raise POSException.ConflictError
+                if serial != oserial:
+                    raise POSException.ConflictError(serials=(oserial, serial))
                 
Index: Packless.py
===================================================================
RCS file: /cvs-repository/StandaloneZODB/bsddb3Storage/bsddb3Storage/Packless.py,v
retrieving revision 1.5
diff -u -1 -r1.5 Packless.py
--- Packless.py	27 Mar 2001 21:26:16 -0000	1.5
+++ Packless.py	16 Aug 2001 19:37:54 -0000
@@ -157,3 +157,4 @@
                 oserial=self._index[oid]
-                if serial != oserial: raise POSException.ConflictError
+                if serial != oserial:
+                    raise POSException.ConflictError(serials=(oserial, serial))
                 

--SLDf9lqlvOQaIe6s--