From aada19391a4cd3f1663067407d8d977ff2a0f25c Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Fri, 21 Feb 2014 17:42:46 +0900 Subject: [PATCH] nec plugin: Avoid long transaction in delete_ports db_plugin.delete_ports() can lead to long transaction if plugin.deleete_port talks with external system. This commit removes a transaction in delete_ports and allows NEC plugin to use more granular db transactions in delete_port. It greatly helps db race conditions and timeouts in delete_port operations. To avoid to impact other plugins/drivers by changing db_plugin.delete_ports directly and to land this patch soon, this commit overrides delete_ports() in NEC plugin. Further disssion on transaction in delete_ports will be discussed under bug 1282925. Closes-Bug: #1282922 Related-Bug: #1282925 Change-Id: I2c00694ad34eb2058bf7a0ff1c920ceded327d43 --- neutron/plugins/nec/nec_plugin.py | 13 +++++++++++++ neutron/tests/unit/nec/test_nec_plugin.py | 23 ++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/neutron/plugins/nec/nec_plugin.py b/neutron/plugins/nec/nec_plugin.py index fd69b20e70..a4614bd60e 100644 --- a/neutron/plugins/nec/nec_plugin.py +++ b/neutron/plugins/nec/nec_plugin.py @@ -31,6 +31,7 @@ from neutron.db import db_base_plugin_v2 from neutron.db import dhcp_rpc_base from neutron.db import external_net_db from neutron.db import l3_rpc_base +from neutron.db import models_v2 from neutron.db import portbindings_base from neutron.db import portbindings_db from neutron.db import quota_db # noqa @@ -646,6 +647,18 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2, super(NECPluginV2, self).delete_port(context, id) self.notify_security_groups_member_updated(context, port) + def delete_ports(self, context, filters): + # Note(amotoki): Override the superclass method to avoid + # a long transaction over external API calls. + # TODO(amotoki): Need to revisit after bug 1282925 is addressed. + query = context.session.query( + models_v2.Port).enable_eagerloads(False) + query = self._apply_filters_to_query( + query, models_v2.Port, filters) + port_ids = [p['id'] for p in query] + for port_id in port_ids: + self.delete_port(context, port_id) + class NECPluginV2AgentNotifierApi(proxy.RpcProxy, sg_rpc.SecurityGroupAgentRpcApiMixin): diff --git a/neutron/tests/unit/nec/test_nec_plugin.py b/neutron/tests/unit/nec/test_nec_plugin.py index fa061cfad3..a0e27da394 100644 --- a/neutron/tests/unit/nec/test_nec_plugin.py +++ b/neutron/tests/unit/nec/test_nec_plugin.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import contextlib import os import fixtures @@ -127,7 +128,27 @@ class TestNecV2HTTPResponse(test_plugin.TestV2HTTPResponse, class TestNecPortsV2(test_plugin.TestPortsV2, NecPluginV2TestCase): - pass + + def test_delete_ports(self): + with self.subnet() as subnet: + with contextlib.nested( + self.port(subnet=subnet, device_owner='test-owner', + no_delete=True), + self.port(subnet=subnet, device_owner='test-owner', + no_delete=True), + self.port(subnet=subnet, device_owner='other-owner'), + ) as (p1, p2, p3): + network_id = subnet['subnet']['network_id'] + filters = {'network_id': [network_id], + 'device_owner': ['test-owner']} + self.plugin.delete_ports(self.context, filters) + + self._show('ports', p1['port']['id'], + expected_code=webob.exc.HTTPNotFound.code) + self._show('ports', p2['port']['id'], + expected_code=webob.exc.HTTPNotFound.code) + self._show('ports', p3['port']['id'], + expected_code=webob.exc.HTTPOk.code) class TestNecNetworksV2(test_plugin.TestNetworksV2, NecPluginV2TestCase):