• Kirill Smelkov's avatar
    bigfile/zodb: ZBlk._p_invalidate() can be called more than once, in particular in case of conflicts · 800c14a9
    Kirill Smelkov authored
    When there is a conflict (on any object, but on ZBlk in particular) ZODB
    machinery calls its ._p_invalidate() twice:
    
      File ".../wendelin.core/bigfile/tests/test_filezodb.py", line 661, in test_bigfile_filezodb_vs_conflicts
        tm2.commit()    # this should raise ConflictError and stay at 11 state
      File ".../transaction/_manager.py", line 111, in commit
        return self.get().commit()
      File ".../transaction/_transaction.py", line 271, in commit
        self._commitResources()
      File ".../transaction/_transaction.py", line 414, in _commitResources
        self._cleanup(L)
      File ".../transaction/_transaction.py", line 426, in _cleanup
        rm.abort(self)
      File ".../ZODB/Connection.py", line 436, in abort
        self._abort()
      File ".../ZODB/Connection.py", line 479, in _abort
        self._cache.invalidate(oid)
      File ".../wendelin.core/bigfile/file_zodb.py", line 148, in _p_invalidate
        traceback.print_stack()
    
    and
    
      File ".../wendelin.core/bigfile/tests/test_filezodb.py", line 661, in test_bigfile_filezodb_vs_conflicts
        tm2.commit()    # this should raise ConflictError and stay at 11 state
      File ".../transaction/_manager.py", line 111, in commit
        return self.get().commit()
      File ".../transaction/_transaction.py", line 271, in commit
        self._commitResources()
      File ".../transaction/_transaction.py", line 416, in _commitResources
        self._synchronizers.map(lambda s: s.afterCompletion(self))
      File ".../transaction/weakset.py", line 59, in map
        f(elt)
      File ".../transaction/_transaction.py", line 416, in <lambda>
        self._synchronizers.map(lambda s: s.afterCompletion(self))
      File ".../ZODB/Connection.py", line 831, in _storage_sync
        self._flush_invalidations()
      File ".../ZODB/Connection.py", line 539, in _flush_invalidations
        self._cache.invalidate(invalidated)
      File ".../wendelin.core/bigfile/file_zodb.py", line 148, in _p_invalidate
        traceback.print_stack()
    
    i.e. first invalidation is done by commit cleanup:
    
        https://github.com/zopefoundation/transaction/blob/1.4.4/transaction/_transaction.py#L414
        https://github.com/zopefoundation/ZODB/blob/3.10/src/ZODB/Connection.py#L479
    
    and then Connection.afterCompletion() flushes invalidation again:
    
        https://github.com/zopefoundation/transaction/blob/1.4.4/transaction/_transaction.py#L416
        https://github.com/zopefoundation/ZODB/blob/3.10/src/ZODB/Connection.py#L833
        https://github.com/zopefoundation/ZODB/blob/3.10/src/ZODB/Connection.py#L539
    
    If there was no conflict - there will be no ConflictError raised and
    thus no Transaction._cleanup() done in its ._commitResources() ->
    invalidation called only once. But with ConflictError - it is twice.
    
    Adjust ZBlk._p_invalidate() not to delve into real invalidation more
    than once - else we will fail, as ZBlk._v_zfile becomes unbound after
    invalidation done the first time.
    800c14a9
Name
Last commit
Last update
3rdparty Loading commit data...
bigarray Loading commit data...
bigfile Loading commit data...
demo Loading commit data...
include/wendelin Loading commit data...
lib Loading commit data...
t Loading commit data...
.gitignore Loading commit data...
.gitmodules Loading commit data...
CHANGES Loading commit data...
COPYING Loading commit data...
Makefile Loading commit data...
setup.py Loading commit data...
tox.ini Loading commit data...
wendelin.py Loading commit data...