From e9a7ed8c63ec5bb0fdca3406c8b21071729dd09d Mon Sep 17 00:00:00 2001 From: "ymadhavi@in.ibm.com" Date: Tue, 31 Jul 2018 06:16:09 -0400 Subject: [PATCH] Update network revision only when it needs Basically, in case of concurrent requests creating ports on *one* network, only one request succeeds, other requests mostly getting 'standardattribute' update error as network revision_number changed about 8 times for all port updates. This patch increases network revision_number in database, only when a port is created in a network, instead of each update on port. Change-Id: Idffb4edda616677b9b071644d3835c85052091a5 Closes-Bug: #1782421 --- neutron/db/models_v2.py | 7 ++++++- neutron/services/revisions/revision_plugin.py | 3 ++- .../revisions/test_revision_plugin.py | 20 +++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/neutron/db/models_v2.py b/neutron/db/models_v2.py index 6863cc3b267..d37e2f9ad62 100644 --- a/neutron/db/models_v2.py +++ b/neutron/db/models_v2.py @@ -56,7 +56,12 @@ class IPAllocation(model_base.BASEV2): network_id = sa.Column(sa.String(36), sa.ForeignKey("networks.id", ondelete="CASCADE"), nullable=False, primary_key=True) - revises_on_change = ('port', ) + network_standard_attr = orm.relationship( + 'StandardAttribute', lazy='subquery', viewonly=True, + secondary='networks', uselist=False, + load_on_pending=True) + + revises_on_change = ('port', 'network_standard_attr',) class Route(object): diff --git a/neutron/services/revisions/revision_plugin.py b/neutron/services/revisions/revision_plugin.py index 4a63e9fc36c..619d83ade1b 100644 --- a/neutron/services/revisions/revision_plugin.py +++ b/neutron/services/revisions/revision_plugin.py @@ -47,7 +47,8 @@ class RevisionPlugin(service_base.ServicePluginBase): self._enforce_if_match_constraints(session) # bump revision number for any updated objects in the session for obj in session.dirty: - if isinstance(obj, standard_attr.HasStandardAttributes): + if (session.is_modified(obj) and + isinstance(obj, standard_attr.HasStandardAttributes)): self._bump_obj_revision(session, obj) # see if any created/updated/deleted objects bump the revision diff --git a/neutron/tests/unit/services/revisions/test_revision_plugin.py b/neutron/tests/unit/services/revisions/test_revision_plugin.py index 8ae6315785c..9048d184a2e 100644 --- a/neutron/tests/unit/services/revisions/test_revision_plugin.py +++ b/neutron/tests/unit/services/revisions/test_revision_plugin.py @@ -86,10 +86,17 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase): def test_port_name_update_revises(self): with self.port() as port: rev = port['port']['revision_number'] + network = directory.get_plugin().get_network( + self.ctx, port['port']['network_id']) + net_rev = network['revision_number'] new = {'port': {'name': 'seaweed'}} response = self._update('ports', port['port']['id'], new) new_rev = response['port']['revision_number'] self.assertGreater(new_rev, rev) + network = directory.get_plugin().get_network( + self.ctx, port['port']['network_id']) + net_ew_rev = network['revision_number'] + self.assertEqual(net_ew_rev, net_rev) def test_constrained_port_update(self): with self.port() as port: @@ -145,6 +152,9 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase): def test_port_ip_update_revises(self): with self.port() as port: rev = port['port']['revision_number'] + network = directory.get_plugin().get_network( + self.ctx, port['port']['network_id']) + net_rev = network['revision_number'] new = {'port': {'fixed_ips': port['port']['fixed_ips']}} # ensure adding an IP allocation updates the port next_ip = str(netaddr.IPAddress( @@ -154,13 +164,23 @@ class TestRevisionPlugin(test_plugin.Ml2PluginV2TestCase): self.assertEqual(2, len(response['port']['fixed_ips'])) new_rev = response['port']['revision_number'] self.assertGreater(new_rev, rev) + network = directory.get_plugin().get_network( + self.ctx, port['port']['network_id']) + new_net_rev = network['revision_number'] + self.assertGreater(new_net_rev, net_rev) + # ensure deleting an IP allocation updates the port rev = new_rev + net_rev = new_net_rev new['port']['fixed_ips'].pop() response = self._update('ports', port['port']['id'], new) self.assertEqual(1, len(response['port']['fixed_ips'])) new_rev = response['port']['revision_number'] self.assertGreater(new_rev, rev) + network = directory.get_plugin().get_network( + self.ctx, port['port']['network_id']) + new_net_rev = network['revision_number'] + self.assertGreater(new_net_rev, net_rev) def test_security_group_rule_ops_bump_security_group(self): s = {'security_group': {'tenant_id': 'some_tenant', 'name': '',