Merge "Make it possible to opt out of nested transactions"

This commit is contained in:
Zuul 2019-03-20 15:14:15 +00:00 committed by Gerrit Code Review
commit 684c1e7c5b
4 changed files with 37 additions and 7 deletions

View File

@ -71,8 +71,9 @@ class Transaction(object):
@six.add_metaclass(abc.ABCMeta)
class API(object):
def __init__(self):
def __init__(self, nested_transactions=True):
# Mapping between a (green)thread and its transaction.
self._nested_txns = nested_transactions
self._nested_txns_map = {}
@abc.abstractmethod
@ -88,17 +89,23 @@ class API(object):
"""
@contextlib.contextmanager
def transaction(self, check_error=False, log_errors=True, **kwargs):
def transaction(self, check_error=False, log_errors=True, nested=True,
**kwargs):
"""Create a transaction context.
:param check_error: Allow the transaction to raise an exception?
:type check_error: bool
:param log_errors: Log an error if the transaction fails?
:type log_errors: bool
:param nested: Allow nested transactions be merged into one txn
:type nested: bool
:returns: Either a new transaction or an existing one.
:rtype: :class:`Transaction`
"""
cur_thread_id = thread.get_ident()
# ojbect() is unique, so if we are not nested, this will always result
# in a KeyError on lookup and so a unique Transaction
nested = nested and self._nested_txns
cur_thread_id = thread.get_ident() if nested else object()
try:
yield self._nested_txns_map[cur_thread_id]

View File

@ -26,8 +26,8 @@ class Backend(object):
lookup_table = {}
ovsdb_connection = None
def __init__(self, connection):
super(Backend, self).__init__()
def __init__(self, connection, **kwargs):
super(Backend, self).__init__(**kwargs)
self.start_connection(connection)
@classmethod

View File

@ -33,3 +33,10 @@ class TransactionTestCase(base.TestCase):
transaction = impl_idl.OvsVsctlTransaction(mock.sentinel,
mock.Mock(), 0)
transaction.post_commit(mock.Mock())
class TestOvsdbIdl(base.TestCase):
def test_nested_txns(self):
conn = mock.MagicMock()
api = impl_idl.OvsdbIdl(conn, nested_transactions=False)
self.assertFalse(api._nested_txns)

View File

@ -65,7 +65,9 @@ class FakeTransaction(object):
class TestingAPI(api.API):
def create_transaction(self, check_error=False, log_errors=True, **kwargs):
return FakeTransaction()
txn = FakeTransaction()
mock.patch.object(txn, 'commit').start()
return txn
TestingAPI.__abstractmethods__ = set()
@ -75,7 +77,6 @@ class TransactionTestCase(base.TestCase):
def setUp(self):
super(TransactionTestCase, self).setUp()
self.api = TestingAPI()
mock.patch.object(FakeTransaction, 'commit').start()
self.useFixture(GreenThreadingFixture())
def test_transaction_nested(self):
@ -84,6 +85,21 @@ class TransactionTestCase(base.TestCase):
self.assertIs(txn1, txn2)
txn1.commit.assert_called_once_with()
def test_transaction_nested_false(self):
with self.api.transaction(nested=False) as txn1:
with self.api.transaction() as txn2:
self.assertIsNot(txn1, txn2)
txn1.commit.assert_called_once_with()
txn2.commit.assert_called_once_with()
def test_api_level_transaction_nested_fales(self):
api = TestingAPI(nested_transactions=False)
with api.transaction() as txn1:
with api.transaction() as txn2:
self.assertIsNot(txn1, txn2)
txn1.commit.assert_called_once_with()
txn2.commit.assert_called_once_with()
def test_transaction_no_nested_transaction_after_error(self):
class TestException(Exception):
pass