[Checkins] SVN: relstorage/trunk/ In rare circumstances, ZODB can legitimately commit an object twice in a

Shane Hathaway shane at hathawaymix.org
Wed Jan 28 20:58:44 EST 2009


Log message for revision 95361:
  In rare circumstances, ZODB can legitimately commit an object twice in a
  single transaction.  Fixed RelStorage to accept that.
  

Changed:
  U   relstorage/trunk/CHANGES.txt
  U   relstorage/trunk/relstorage/adapters/mysql.py
  U   relstorage/trunk/relstorage/adapters/oracle.py
  U   relstorage/trunk/relstorage/adapters/postgresql.py
  U   relstorage/trunk/relstorage/tests/reltestbase.py

-=-
Modified: relstorage/trunk/CHANGES.txt
===================================================================
--- relstorage/trunk/CHANGES.txt	2009-01-28 23:09:52 UTC (rev 95360)
+++ relstorage/trunk/CHANGES.txt	2009-01-29 01:58:44 UTC (rev 95361)
@@ -2,6 +2,8 @@
 Next Release
 ------------
 
+- In rare circumstances, ZODB can legitimately commit an object twice in a
+  single transaction.  Fixed RelStorage to accept that.
 
 
 Version 1.1.2 (2009-01-27)

Modified: relstorage/trunk/relstorage/adapters/mysql.py
===================================================================
--- relstorage/trunk/relstorage/adapters/mysql.py	2009-01-28 23:09:52 UTC (rev 95360)
+++ relstorage/trunk/relstorage/adapters/mysql.py	2009-01-29 01:58:44 UTC (rev 95361)
@@ -464,7 +464,7 @@
     def store_temp(self, cursor, oid, prev_tid, md5sum, data):
         """Store an object in the temporary table."""
         stmt = """
-        INSERT INTO temp_store (zoid, prev_tid, md5, state)
+        REPLACE INTO temp_store (zoid, prev_tid, md5, state)
         VALUES (%s, %s, %s, %s)
         """
         cursor.execute(stmt, (oid, prev_tid, md5sum, MySQLdb.Binary(data)))

Modified: relstorage/trunk/relstorage/adapters/oracle.py
===================================================================
--- relstorage/trunk/relstorage/adapters/oracle.py	2009-01-28 23:09:52 UTC (rev 95360)
+++ relstorage/trunk/relstorage/adapters/oracle.py	2009-01-29 01:58:44 UTC (rev 95361)
@@ -536,6 +536,7 @@
 
     def store_temp(self, cursor, oid, prev_tid, md5sum, data):
         """Store an object in the temporary table."""
+        cursor.execute("DELETE FROM temp_store WHERE zoid = :oid", oid=oid)
         if len(data) <= 2000:
             # Send data inline for speed.  Oracle docs say maximum size
             # of a RAW is 2000 bytes.  cx_Oracle.BINARY corresponds with RAW.

Modified: relstorage/trunk/relstorage/adapters/postgresql.py
===================================================================
--- relstorage/trunk/relstorage/adapters/postgresql.py	2009-01-28 23:09:52 UTC (rev 95360)
+++ relstorage/trunk/relstorage/adapters/postgresql.py	2009-01-29 01:58:44 UTC (rev 95361)
@@ -415,10 +415,11 @@
     def store_temp(self, cursor, oid, prev_tid, md5sum, data):
         """Store an object in the temporary table."""
         stmt = """
+        DELETE FROM temp_store WHERE zoid = %s;
         INSERT INTO temp_store (zoid, prev_tid, md5, state)
         VALUES (%s, %s, %s, decode(%s, 'base64'))
         """
-        cursor.execute(stmt, (oid, prev_tid, md5sum, encodestring(data)))
+        cursor.execute(stmt, (oid, oid, prev_tid, md5sum, encodestring(data)))
 
     def replace_temp(self, cursor, oid, prev_tid, md5sum, data):
         """Replace an object in the temporary table."""

Modified: relstorage/trunk/relstorage/tests/reltestbase.py
===================================================================
--- relstorage/trunk/relstorage/tests/reltestbase.py	2009-01-28 23:09:52 UTC (rev 95360)
+++ relstorage/trunk/relstorage/tests/reltestbase.py	2009-01-29 01:58:44 UTC (rev 95361)
@@ -21,6 +21,7 @@
 from ZODB.DB import DB
 from ZODB.utils import p64
 from ZODB.FileStorage import FileStorage
+from persistent import Persistent
 from persistent.mapping import PersistentMapping
 import transaction
 
@@ -565,9 +566,34 @@
             self.assertEquals(len(slept), 1)
         finally:
             db.close()
+
+    def checkDoubleCommitter(self):
+        # Verify we can store an object that gets committed twice in
+        # a single transaction.
+        db = DB(self._storage)
+        try:
+            conn = db.open()
+            try:
+                conn.root()['dc'] = DoubleCommitter()
+                transaction.commit()
+                conn2 = db.open()
+                self.assertEquals(conn2.root()['dc'].new_attribute, 1)
+                conn2.close()
+            finally:
+                transaction.abort()
+                conn.close()
+        finally:
+            db.close()
         
 
+class DoubleCommitter(Persistent):
+    """A crazy persistent class that changes self in __getstate__"""
+    def __getstate__(self):
+        if not hasattr(self, 'new_attribute'):
+            self.new_attribute = 1
+        return Persistent.__getstate__(self)
 
+
 class IteratorDeepCompareUnordered:
     # Like IteratorDeepCompare, but compensates for OID order
     # differences in transactions.



More information about the Checkins mailing list