Change transaction isolation so retry logic could work properly

Lower isolation level from REPEATABLE READ to READ COMMITTED for
transaction that is used to create a network.
This allows retry logic to see changes done in other connections
while doing the same query.
Perform that only for mysql db backend.

Change-Id: I6b9d9212c37fe028566e0df4a3dfa51f284ce6e9
Closes-Bug: #1382064
This commit is contained in:
Eugene Nikanorov 2014-11-17 11:00:49 +04:00 committed by enikanorov
parent 5638a7c4e8
commit 6617f8fccc
3 changed files with 88 additions and 1 deletions

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import contextlib
from six import moves
import sqlalchemy
from sqlalchemy.orm import properties
@ -105,3 +107,27 @@ def paginate_query(query, model, limit, sorts, marker_obj=None):
query = query.limit(limit)
return query
default_tx_isolation_level = None
def get_default_tx_level(engine):
global default_tx_isolation_level
if not default_tx_isolation_level:
default_tx_isolation_level = engine.dialect.get_isolation_level(
engine.raw_connection())
return default_tx_isolation_level
@contextlib.contextmanager
def set_mysql_tx_isolation_level(session, level):
engine = session.connection().engine
if (engine.name == "mysql" and level != get_default_tx_level(engine)):
session.connection().execution_options(
isolation_level=level)
yield
engine = session.connection().engine
if engine.name == "mysql":
session.connection().execution_options(
isolation_level=get_default_tx_level(engine))

View File

@ -48,6 +48,7 @@ from neutron.db import extradhcpopt_db
from neutron.db import models_v2
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_rpc_base as sg_db_rpc
from neutron.db import sqlalchemyutils as sqla
from neutron.extensions import allowedaddresspairs as addr_pair
from neutron.extensions import extra_dhcp_opt as edo_ext
from neutron.extensions import l3agentscheduler
@ -538,7 +539,10 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
net_data = network[attributes.NETWORK]
tenant_id = self._get_tenant_id_for_create(context, net_data)
session = context.session
with session.begin(subtransactions=True):
with contextlib.nested(
session.begin(subtransactions=True),
sqla.set_mysql_tx_isolation_level(session, "READ COMMITTED")
):
self._ensure_default_security_group(context, tenant_id)
result = super(Ml2Plugin, self).create_network(context, network)
self.extension_manager.process_create_network(session, net_data,

View File

@ -0,0 +1,57 @@
# Copyright (c) 2014 OpenStack Foundation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import contextlib
from oslo.config import cfg
from oslo.db.sqlalchemy import test_base
from neutron import context
from neutron.db import sqlalchemyutils
from neutron.tests import base
class TestSettingTXIsolationLevel(base.BaseTestCase,
test_base.MySQLOpportunisticTestCase):
"""Check that transaction isolation level indeed changes."""
def setUp(self):
super(TestSettingTXIsolationLevel, self).setUp()
cfg.CONF.set_override('connection',
self.engine.url,
group='database')
def _get_session_tx_isolation(self, session):
sql = "SELECT @@tx_isolation;"
res = session.connection().execute(sql)
res = [r for r in res]
res = [r for r in res[0]]
return res[0]
def test_set_tx_iso_level_changes_back_and_forth_mysql(self):
ctx = context.get_admin_context()
default_level = sqlalchemyutils.get_default_tx_level(self.engine)
other_level = ("READ COMMITTED" if default_level == "REPEATABLE READ"
else "REPEATABLE READ")
with contextlib.nested(
ctx.session.begin(subtransactions=True),
sqlalchemyutils.set_mysql_tx_isolation_level(
ctx.session, other_level)
):
res = self._get_session_tx_isolation(ctx.session)
self.assertEqual(other_level.replace(' ', '-'), res)
#check that context manager changes tx isolation level back
res = self._get_session_tx_isolation(ctx.session)
self.assertEqual(default_level.replace(' ', '-'), res)