diff --git a/src/ZODB/BaseStorage.py b/src/ZODB/BaseStorage.py index 8711ed58f..b51bc69de 100644 --- a/src/ZODB/BaseStorage.py +++ b/src/ZODB/BaseStorage.py @@ -269,7 +269,7 @@ def tpc_vote(self, transaction): if transaction is not self._transaction: raise POSException.StorageTransactionError( "tpc_vote called with wrong transaction") - self._vote() + return self._vote() finally: self._lock_release() @@ -398,8 +398,8 @@ def copy(source, dest, verbose=0): r.data_txn, transaction) else: pre = preget(oid, None) - s = dest.store(oid, pre, r.data, r.version, transaction) - preindex[oid] = s + dest.store(oid, pre, r.data, r.version, transaction) + preindex[oid] = tid dest.tpc_vote(transaction) dest.tpc_finish(transaction) diff --git a/src/ZODB/Connection.py b/src/ZODB/Connection.py index 8442198f2..30d2541bf 100644 --- a/src/ZODB/Connection.py +++ b/src/ZODB/Connection.py @@ -613,16 +613,17 @@ def _commit(self, transaction): raise InvalidObjectReference(obj, obj._p_jar) elif oid in self._added: assert obj._p_serial == z64 - elif obj._p_changed: + elif obj._p_changed and oid not in self._creating: if oid in self._invalidated: resolve = getattr(obj, "_p_resolveConflict", None) if resolve is None: raise ConflictError(object=obj) - self._modified.append(oid) else: # Nothing to do. It's been said that it's legal, e.g., for # an object to set _p_changed to false after it's been # changed and registered. + # And new objects that are registered after any referrer are + # already processed. continue self._store_objects(ObjectWriter(obj), transaction) diff --git a/src/ZODB/blob.py b/src/ZODB/blob.py index 20fb4aa5f..66df7ed10 100644 --- a/src/ZODB/blob.py +++ b/src/ZODB/blob.py @@ -713,9 +713,8 @@ def storeBlob(self, oid, oldserial, data, blobfilename, version, """Stores data that has a BLOB attached.""" assert not version, "Versions aren't supported." serial = self.store(oid, oldserial, data, '', transaction) - self._blob_storeblob(oid, serial, blobfilename) - - return self._tid + self._blob_storeblob(oid, self._tid, blobfilename) + return serial def temporaryDirectory(self): return self.fshelper.temp_dir @@ -764,8 +763,9 @@ def tpc_finish(self, *arg, **kw): # We need to override the base storage's tpc_finish instead of # providing a _finish method because methods found on the proxied # object aren't rebound to the proxy - self.__storage.tpc_finish(*arg, **kw) + tid = self.__storage.tpc_finish(*arg, **kw) self._blob_tpc_finish() + return tid def tpc_abort(self, *arg, **kw): # We need to override the base storage's abort instead of diff --git a/src/ZODB/tests/MVCCMappingStorage.py b/src/ZODB/tests/MVCCMappingStorage.py index ceb37271b..4755b0f1b 100644 --- a/src/ZODB/tests/MVCCMappingStorage.py +++ b/src/ZODB/tests/MVCCMappingStorage.py @@ -117,7 +117,7 @@ def poll_invalidations(self): def tpc_finish(self, transaction, func = lambda tid: None): self._data_snapshot = None - MappingStorage.tpc_finish(self, transaction, func) + return MappingStorage.tpc_finish(self, transaction, func) def tpc_abort(self, transaction): self._data_snapshot = None diff --git a/src/ZODB/tests/blob_packing.txt b/src/ZODB/tests/blob_packing.txt index 9f7c3c4b7..1e9637d8e 100644 --- a/src/ZODB/tests/blob_packing.txt +++ b/src/ZODB/tests/blob_packing.txt @@ -38,34 +38,35 @@ Put some revisions of a blob object in our database and on the filesystem: ... _ = file.write(b'this is blob data 0') >>> root['blob'] = blob >>> transaction.commit() - >>> tids.append(blob._p_serial) >>> nothing = transaction.begin() >>> times.append(new_time()) >>> with root['blob'].open('w') as file: ... _ = file.write(b'this is blob data 1') - >>> transaction.commit() >>> tids.append(blob._p_serial) + >>> transaction.commit() >>> nothing = transaction.begin() >>> times.append(new_time()) >>> with root['blob'].open('w') as file: ... _ = file.write(b'this is blob data 2') - >>> transaction.commit() >>> tids.append(blob._p_serial) + >>> transaction.commit() >>> nothing = transaction.begin() >>> times.append(new_time()) >>> with root['blob'].open('w') as file: ... _ = file.write(b'this is blob data 3') - >>> transaction.commit() >>> tids.append(blob._p_serial) + >>> transaction.commit() >>> nothing = transaction.begin() >>> times.append(new_time()) >>> with root['blob'].open('w') as file: ... _ = file.write(b'this is blob data 4') + >>> tids.append(blob._p_serial) >>> transaction.commit() + >>> blob._p_activate() >>> tids.append(blob._p_serial) >>> oid = root['blob']._p_oid diff --git a/src/ZODB/tests/testConnection.py b/src/ZODB/tests/testConnection.py index bb685ebd7..ebcdd830f 100644 --- a/src/ZODB/tests/testConnection.py +++ b/src/ZODB/tests/testConnection.py @@ -1025,9 +1025,14 @@ def doctest_lp485456_setattr_in_setstate_doesnt_cause_multiple_stores(): storing '\x00\x00\x00\x00\x00\x00\x00\x00' storing '\x00\x00\x00\x00\x00\x00\x00\x01' - >>> conn.add(C()) + Retry with the new object registered before its referrer. + + >>> z = C() + >>> conn.add(z) + >>> conn.root.z = z >>> transaction.commit() storing '\x00\x00\x00\x00\x00\x00\x00\x02' + storing '\x00\x00\x00\x00\x00\x00\x00\x00' We still see updates: diff --git a/src/ZODB/tests/testblob.py b/src/ZODB/tests/testblob.py index fff201eb3..1f6bbf0d0 100644 --- a/src/ZODB/tests/testblob.py +++ b/src/ZODB/tests/testblob.py @@ -706,8 +706,8 @@ def lp440234_Setting__p_changed_of_a_Blob_w_no_uncomitted_changes_is_noop(): >>> blob = ZODB.blob.Blob(b'blah') >>> conn.add(blob) >>> transaction.commit() - >>> old_serial = blob._p_serial >>> blob._p_changed = True + >>> old_serial = blob._p_serial >>> transaction.commit() >>> with blob.open() as fp: fp.read() 'blah'