[Zodb-checkins] SVN: ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/ - fixed bug in consumeFile() because it forgot to set _p_changed correctly

Christian Theune ct at gocept.com
Thu Mar 8 14:38:42 EST 2007


Log message for revision 73071:
   - fixed bug in consumeFile() because it forgot to set _p_changed correctly
  

Changed:
  U   ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/Blob.py
  U   ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/tests/test_undo.py

-=-
Modified: ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/Blob.py
===================================================================
--- ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/Blob.py	2007-03-08 18:46:17 UTC (rev 73070)
+++ ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/Blob.py	2007-03-08 19:38:41 UTC (rev 73071)
@@ -101,35 +101,7 @@
             raise IOError('invalid mode: %s ' % mode)
 
         if result is not None:
-            # We join the transaction with our own data manager in order to be
-            # notified of commit/vote/abort events.  We do this because at
-            # transaction boundaries, we need to fix up _p_ reference counts
-            # that keep track of open readers and writers and close any
-            # writable filehandles we've opened.
-            if self._p_blob_manager is None:
-                # Blobs need to always participate in transactions.
-                if self._p_jar is not None:
-                    # If we are connected to a database, then we use the
-                    # transaction manager that belongs to this connection
-                    tm = self._p_jar.transaction_manager
-                else:
-                    # If we are not connected to a database, we check whether
-                    # we have been given an explicit transaction manager
-                    if self._p_blob_transaction:
-                        tm = self._p_blob_transaction
-                    else:
-                        # Otherwise we use the default
-                        # transaction manager as an educated guess.
-                        tm = transaction.manager
-                # Create our datamanager and join he current transaction.
-                dm = BlobDataManager(self, result, tm)
-                tm.get().join(dm)
-            else:
-                # Each blob data manager should manage only the one blob
-                # assigned to it.  Assert that this is the case and it is the
-                # correct blob
-                assert self._p_blob_manager.blob is self
-                self._p_blob_manager.register_fh(result)
+            self._setup_transaction_manager(result)
         return result
 
     def openDetached(self, class_=file):
@@ -189,6 +161,10 @@
                 # set aside.
                 os.unlink(target_aside)
 
+            # We changed the blob state and have to make sure we join the
+            # transaction.
+            self._change()
+
     # utility methods
 
     def _current_filename(self):
@@ -205,6 +181,37 @@
     def _change(self):
         self._p_changed = 1
 
+    def _setup_transaction_manager(self, result):
+        # We join the transaction with our own data manager in order to be
+        # notified of commit/vote/abort events.  We do this because at
+        # transaction boundaries, we need to fix up _p_ reference counts
+        # that keep track of open readers and writers and close any
+        # writable filehandles we've opened.
+        if self._p_blob_manager is None:
+            # Blobs need to always participate in transactions.
+            if self._p_jar is not None:
+                # If we are connected to a database, then we use the
+                # transaction manager that belongs to this connection
+                tm = self._p_jar.transaction_manager
+            else:
+                # If we are not connected to a database, we check whether
+                # we have been given an explicit transaction manager
+                if self._p_blob_transaction:
+                    tm = self._p_blob_transaction
+                else:
+                    # Otherwise we use the default
+                    # transaction manager as an educated guess.
+                    tm = transaction.manager
+            # Create our datamanager and join he current transaction.
+            dm = BlobDataManager(self, result, tm)
+            tm.get().join(dm)
+        elif result:
+            # Each blob data manager should manage only the one blob
+            # assigned to it.  Assert that this is the case and it is the
+            # correct blob
+            assert self._p_blob_manager.blob is self
+            self._p_blob_manager.register_fh(result)
+
     # utility methods which should not cause the object's state to be
     # loaded if they are called while the object is a ghost.  Thus,
     # they are named with the _p_ convention and only operate against

Modified: ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/tests/test_undo.py
===================================================================
--- ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/tests/test_undo.py	2007-03-08 18:46:17 UTC (rev 73070)
+++ ZODB/branches/ctheune-blobszerocopy/src/ZODB/Blobs/tests/test_undo.py	2007-03-08 19:38:41 UTC (rev 73071)
@@ -94,6 +94,47 @@
         self.assertEqual(blob.open('r').read(), 'this is state 1')
         transaction.abort()
 
+    def testUndoAfterConsumption(self):
+        base_storage = FileStorage(self.storagefile)
+        blob_storage = BlobStorage(self.blob_dir, base_storage)
+        database = DB(blob_storage)
+        connection = database.open()
+        root = connection.root()
+        transaction.begin()
+        to_consume = tempfile.NamedTemporaryFile()
+        to_consume.write('this is state 1')
+        to_consume.flush()
+
+        blob = Blob()
+        blob.consumeFile(to_consume.name)
+
+        root['blob'] = blob
+        transaction.commit()
+
+        transaction.begin()
+        blob = root['blob']
+        to_consume = tempfile.NamedTemporaryFile()
+        to_consume.write('this is state 2')
+        to_consume.flush()
+        blob.consumeFile(to_consume.name)
+        transaction.commit()
+
+        transaction.begin()
+        blob = root['blob']
+        self.assertEqual(blob.open('r').read(), 'this is state 2')
+        transaction.abort()
+
+        serial = base64.encodestring(blob_storage._tid)
+
+        transaction.begin()
+        blob_storage.undo(serial, blob_storage._transaction)
+        transaction.commit()
+
+        transaction.begin()
+        blob = root['blob']
+        self.assertEqual(blob.open('r').read(), 'this is state 1')
+        transaction.abort()
+
     def testRedo(self):
         base_storage = FileStorage(self.storagefile)
         blob_storage = BlobStorage(self.blob_dir, base_storage)



More information about the Zodb-checkins mailing list