Merge "Make it possible to opt out of nested transactions"
This commit is contained in:
commit
684c1e7c5b
|
@ -71,8 +71,9 @@ class Transaction(object):
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class API(object):
|
class API(object):
|
||||||
def __init__(self):
|
def __init__(self, nested_transactions=True):
|
||||||
# Mapping between a (green)thread and its transaction.
|
# Mapping between a (green)thread and its transaction.
|
||||||
|
self._nested_txns = nested_transactions
|
||||||
self._nested_txns_map = {}
|
self._nested_txns_map = {}
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
|
@ -88,17 +89,23 @@ class API(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@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.
|
"""Create a transaction context.
|
||||||
|
|
||||||
:param check_error: Allow the transaction to raise an exception?
|
:param check_error: Allow the transaction to raise an exception?
|
||||||
:type check_error: bool
|
:type check_error: bool
|
||||||
:param log_errors: Log an error if the transaction fails?
|
:param log_errors: Log an error if the transaction fails?
|
||||||
:type log_errors: bool
|
: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.
|
:returns: Either a new transaction or an existing one.
|
||||||
:rtype: :class:`Transaction`
|
: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:
|
try:
|
||||||
yield self._nested_txns_map[cur_thread_id]
|
yield self._nested_txns_map[cur_thread_id]
|
||||||
|
|
|
@ -26,8 +26,8 @@ class Backend(object):
|
||||||
lookup_table = {}
|
lookup_table = {}
|
||||||
ovsdb_connection = None
|
ovsdb_connection = None
|
||||||
|
|
||||||
def __init__(self, connection):
|
def __init__(self, connection, **kwargs):
|
||||||
super(Backend, self).__init__()
|
super(Backend, self).__init__(**kwargs)
|
||||||
self.start_connection(connection)
|
self.start_connection(connection)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -33,3 +33,10 @@ class TransactionTestCase(base.TestCase):
|
||||||
transaction = impl_idl.OvsVsctlTransaction(mock.sentinel,
|
transaction = impl_idl.OvsVsctlTransaction(mock.sentinel,
|
||||||
mock.Mock(), 0)
|
mock.Mock(), 0)
|
||||||
transaction.post_commit(mock.Mock())
|
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)
|
||||||
|
|
|
@ -65,7 +65,9 @@ class FakeTransaction(object):
|
||||||
|
|
||||||
class TestingAPI(api.API):
|
class TestingAPI(api.API):
|
||||||
def create_transaction(self, check_error=False, log_errors=True, **kwargs):
|
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()
|
TestingAPI.__abstractmethods__ = set()
|
||||||
|
@ -75,7 +77,6 @@ class TransactionTestCase(base.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TransactionTestCase, self).setUp()
|
super(TransactionTestCase, self).setUp()
|
||||||
self.api = TestingAPI()
|
self.api = TestingAPI()
|
||||||
mock.patch.object(FakeTransaction, 'commit').start()
|
|
||||||
self.useFixture(GreenThreadingFixture())
|
self.useFixture(GreenThreadingFixture())
|
||||||
|
|
||||||
def test_transaction_nested(self):
|
def test_transaction_nested(self):
|
||||||
|
@ -84,6 +85,21 @@ class TransactionTestCase(base.TestCase):
|
||||||
self.assertIs(txn1, txn2)
|
self.assertIs(txn1, txn2)
|
||||||
txn1.commit.assert_called_once_with()
|
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):
|
def test_transaction_no_nested_transaction_after_error(self):
|
||||||
class TestException(Exception):
|
class TestException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue