diff --git a/buildout.cfg b/buildout.cfg index 9d9d56f..a6cc148 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -2,12 +2,12 @@ develop = . base-parts = test py python omelette coverage-test coverage-report parts = ${buildout:base-parts} -eggs = relstorage +eggs = relstorage [${buildout:db}] db = [test] recipe = zc.recipe.testrunner -eggs = relstorage [test, ${buildout:db}] +eggs = relstorage [test, ${buildout:db}] [py] recipe = zc.recipe.egg diff --git a/relstorage/storage.py b/relstorage/storage.py index 24f9ecc..ba8264a 100644 --- a/relstorage/storage.py +++ b/relstorage/storage.py @@ -97,6 +97,13 @@ class _DummyLock(object): def release(self): return +def optional_interfaces(): + try: + from ZODB.interfaces import IMVCCAfterCompletionStorage + return (IMVCCAfterCompletionStorage,) + except ImportError: + return () + @implementer(ZODB.interfaces.IStorage, ZODB.interfaces.IMVCCStorage, ZODB.interfaces.IMultiCommitStorage, @@ -104,7 +111,8 @@ class _DummyLock(object): ZODB.interfaces.IStorageIteration, ZODB.interfaces.IStorageUndoable, ZODB.interfaces.IBlobStorage, - ZODB.interfaces.IBlobStorageRestoreable) + ZODB.interfaces.IBlobStorageRestoreable, + *optional_interfaces()) class RelStorage(UndoLogCompatible, ConflictResolution.ConflictResolvingStorage): """Storage to a relational database, based on invalidation polling""" @@ -1074,6 +1082,12 @@ class RelStorage(UndoLogCompatible, self.blobhelper.abort() def afterCompletion(self): + # Note that this method exists mainly to deal with read-only + # transactions that don't go through 2-phase commit (although + # it's called for all transactions). For this reason, we only + # have to roll back the load connection. The store connection + # is completed during normal write-transaction commit or + # abort. self._rollback_load_connection() def lastTransaction(self): diff --git a/relstorage/tests/reltestbase.py b/relstorage/tests/reltestbase.py index 5348d21..f013951 100644 --- a/relstorage/tests/reltestbase.py +++ b/relstorage/tests/reltestbase.py @@ -852,12 +852,20 @@ class GenericRelStorageTests( # outside of 2-phase commit is otherise equivalent to calling # tpc_abort. self._storage = self.make_storage(revert_when_stale=False) + import mock with mock.patch.object( self._storage, '_rollback_load_connection') as rb: self._storage.afterCompletion() rb.assert_called_with() + try: + from ZODB.interfaces import IMVCCAfterCompletionStorage + except ImportError: + pass + else: + self.assertTrue( + IMVCCAfterCompletionStorage.providedBy(self._storage)) from .test_zodbconvert import FSZODBConvertTests