Merge "objects: automatically detect whether engine facade is used"

This commit is contained in:
Zuul 2018-05-02 13:06:53 +00:00 committed by Gerrit Code Review
commit aef0b3c6da
4 changed files with 43 additions and 10 deletions

View File

@ -360,6 +360,10 @@ following database session decorators:
``db_context_reader`` and ``db_context_writer`` decorators abstract the choice
of engine facade used for particular object from action implementation.
Alternatively, you can call all OVO actions under an active ``reader.using`` /
``writer.using`` context manager (or ``session.begin``). In this case, OVO will
pick the appropriate method to open a subtransaction.
Synthetic fields
----------------
:code:`synthetic_fields` is a list of fields, that are not directly backed by

View File

@ -19,6 +19,7 @@ import itertools
from neutron_lib import exceptions as n_exc
from neutron_lib.objects import exceptions as o_exc
from oslo_db import exception as obj_exc
from oslo_db.sqlalchemy import enginefacade
from oslo_db.sqlalchemy import utils as db_utils
from oslo_log import log as logging
from oslo_serialization import jsonutils
@ -505,17 +506,26 @@ class NeutronDbObject(NeutronObject):
if is_attr_nullable:
self[attrname] = None
# TODO(ihrachys) remove once we switch plugin code to enginefacade
@staticmethod
def _use_db_facade(context):
try:
enginefacade._transaction_ctx_for_context(context)
except obj_exc.NoEngineContextEstablished:
return False
return True
@classmethod
def db_context_writer(cls, context):
"""Return read-write session activation decorator."""
if cls.new_facade:
if cls.new_facade or cls._use_db_facade(context):
return db_api.context_manager.writer.using(context)
return db_api.autonested_transaction(context.session)
@classmethod
def db_context_reader(cls, context):
"""Return read-only session activation decorator."""
if cls.new_facade:
if cls.new_facade or cls._use_db_facade(context):
return db_api.context_manager.reader.using(context)
return db_api.autonested_transaction(context.session)

View File

@ -32,6 +32,7 @@ from oslo_versionedobjects import fields as obj_fields
import testtools
from neutron.db import _model_query as model_query
from neutron.db import api as db_api
from neutron import objects
from neutron.objects import agent
from neutron.objects import base
@ -1694,16 +1695,23 @@ class BaseDbObjectTestCase(_BaseObjectTestCase,
self.assertEqual(1, mock_commit.call_count)
def _get_ro_txn_exit_func_name(self):
# for old engine facade, we didn't have distinction between r/o and r/w
# transactions and so we always call commit even for getters when the
# old facade is used
# with no engine facade, we didn't have distinction between r/o and
# r/w transactions and so we always call commit even for getters when
# no facade is used
return (
SQLALCHEMY_CLOSE
if self._test_class.new_facade else SQLALCHEMY_COMMIT)
if self._test_class._use_db_facade else SQLALCHEMY_COMMIT)
def test_get_objects_single_transaction(self):
with mock.patch(self._get_ro_txn_exit_func_name()) as mock_exit:
self._test_class.get_objects(self.context)
with db_api.autonested_transaction(self.context.session):
self._test_class.get_objects(self.context)
self.assertEqual(1, mock_exit.call_count)
def test_get_objects_single_transaction_enginefacade(self):
with mock.patch(self._get_ro_txn_exit_func_name()) as mock_exit:
with db_api.context_manager.reader.using(self.context):
self._test_class.get_objects(self.context)
self.assertEqual(1, mock_exit.call_count)
def test_get_object_single_transaction(self):
@ -1711,8 +1719,19 @@ class BaseDbObjectTestCase(_BaseObjectTestCase,
obj.create()
with mock.patch(self._get_ro_txn_exit_func_name()) as mock_exit:
obj = self._test_class.get_object(self.context,
**obj._get_composite_keys())
with db_api.autonested_transaction(self.context.session):
obj = self._test_class.get_object(self.context,
**obj._get_composite_keys())
self.assertEqual(1, mock_exit.call_count)
def test_get_object_single_transaction_enginefacade(self):
obj = self._make_object(self.obj_fields[0])
obj.create()
with mock.patch(self._get_ro_txn_exit_func_name()) as mock_exit:
with db_api.context_manager.reader.using(self.context):
obj = self._test_class.get_object(self.context,
**obj._get_composite_keys())
self.assertEqual(1, mock_exit.call_count)
def test_get_objects_supports_extra_filtername(self):

View File

@ -1685,7 +1685,7 @@ class TestMl2DvrPortsV2(TestMl2PortsV2):
{'subnet_id': s['subnet']['id']})
# lie to turn the port into an SNAT interface
with db_api.context_manager.reader.using(self.context):
with db_api.context_manager.writer.using(self.context):
pager = base_obj.Pager(limit=1)
rp = l3_obj.RouterPort.get_objects(
self.context, _pager=pager, port_id=p['port_id'])