Merge "Make revision bump robust to concurrent removals"
This commit is contained in:
commit
23db089f36
|
@ -13,6 +13,7 @@
|
|||
|
||||
from oslo_log import log as logging
|
||||
from sqlalchemy import event
|
||||
from sqlalchemy.orm import exc
|
||||
from sqlalchemy.orm import session as se
|
||||
|
||||
from neutron._i18n import _, _LW
|
||||
|
@ -53,17 +54,21 @@ class RevisionPlugin(service_base.ServicePluginBase):
|
|||
|
||||
def _bump_related_revisions(self, session, obj):
|
||||
for revises_col in getattr(obj, 'revises_on_change', ()):
|
||||
related_obj = self._find_related_obj(session, obj, revises_col)
|
||||
if not related_obj:
|
||||
LOG.warning(_LW("Could not find related %(col)s for resource "
|
||||
"%(obj)s to bump revision."),
|
||||
{'obj': obj, 'col': revises_col})
|
||||
continue
|
||||
# if related object revises others, bump those as well
|
||||
self._bump_related_revisions(session, related_obj)
|
||||
# no need to bump revisions on related objects being deleted
|
||||
if related_obj not in session.deleted:
|
||||
related_obj.bump_revision()
|
||||
try:
|
||||
related_obj = self._find_related_obj(session, obj, revises_col)
|
||||
if not related_obj:
|
||||
LOG.warning(_LW("Could not find related %(col)s for "
|
||||
"resource %(obj)s to bump revision."),
|
||||
{'obj': obj, 'col': revises_col})
|
||||
continue
|
||||
# if related object revises others, bump those as well
|
||||
self._bump_related_revisions(session, related_obj)
|
||||
# no need to bump revisions on related objects being deleted
|
||||
if related_obj not in session.deleted:
|
||||
related_obj.bump_revision()
|
||||
except exc.ObjectDeletedError:
|
||||
# object was in session but another writer deleted it
|
||||
pass
|
||||
|
||||
def get_plugin_type(self):
|
||||
return "revision_plugin"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import netaddr
|
||||
|
||||
from neutron import context as nctx
|
||||
from neutron.db import models_v2
|
||||
from neutron import manager
|
||||
from neutron.tests.unit.plugins.ml2 import test_plugin
|
||||
|
||||
|
@ -34,6 +35,20 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase):
|
|||
get_service_plugins()['L3_ROUTER_NAT'])
|
||||
self.ctx = nctx.get_admin_context()
|
||||
|
||||
def test_handle_expired_object(self):
|
||||
rp = manager.NeutronManager.get_service_plugins()['revision_plugin']
|
||||
with self.port():
|
||||
with self.ctx.session.begin():
|
||||
ipal_obj = self.ctx.session.query(models_v2.IPAllocation).one()
|
||||
# load port into our session
|
||||
port_obj = self.ctx.session.query(models_v2.Port).one()
|
||||
# simulate concurrent delete in another session
|
||||
nctx.get_admin_context().session.query(models_v2.Port).delete()
|
||||
# expire the port so the revision bumping code will trigger a
|
||||
# lookup on its attributes and encounter an ObjectDeletedError
|
||||
self.ctx.session.expire(port_obj)
|
||||
rp._bump_related_revisions(self.ctx.session, ipal_obj)
|
||||
|
||||
def test_port_name_update_revises(self):
|
||||
with self.port() as port:
|
||||
rev = port['port']['revision']
|
||||
|
|
Loading…
Reference in New Issue