From 840e04b6f122f022f67b600ed2f96ae5e92eabe0 Mon Sep 17 00:00:00 2001 From: Kevin Benton Date: Wed, 15 Feb 2017 20:49:45 -0800 Subject: [PATCH] Skip native DHCP notifications on status change On profiling the get_devices_details communications between the agent and the server, a significant amount of time (60% in my dev env) is being spent in the AFTER_UPDATE events for the port updates resulting from the port status changes. One of the major offenders is the native DHCP agent notifier. On each port update it ends up retrieving the network for the port, the DHCP agents for the network, and the segments. This patch addresses this particular issue by adding logic to skip a DHCP notification if the only thing that changed on the port was the status. The DHCP agent doesn't do anything based on the status field so there is no need to update it when this is the only change. Change-Id: I948132924ec5021a9db78cf17efbba96b2500e8e Partial-Bug: #1665215 --- .../rpc/agentnotifiers/dhcp_rpc_agent_api.py | 20 +++++++++++++++++++ .../agentnotifiers/test_dhcp_rpc_agent_api.py | 15 ++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py b/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py index 7fed042dfa2..5c0a84cbb1d 100644 --- a/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py +++ b/neutron/api/rpc/agentnotifiers/dhcp_rpc_agent_api.py @@ -241,8 +241,28 @@ class DhcpAgentNotifyAPI(object): method_name = '.'.join((resource, action, 'end')) payload = kwargs[resource] data = {resource: payload} + if resource == resources.PORT: + if self._only_status_changed(kwargs.get('original_port'), + kwargs.get('port')): + # don't waste time updating the DHCP agent for status updates + return self.notify(context, data, method_name) + def _only_status_changed(self, orig, new): + # a status change will manifest as a bumped revision number, a new + # updated_at timestamp, and a new status. If that's all that changed, + # return True, else False + if not orig or not new: + return False + if set(orig.keys()) != set(new.keys()): + return False + for k in orig.keys(): + if k in ('status', 'updated_at', 'revision_number'): + continue + if orig[k] != new[k]: + return False + return True + def _send_dhcp_notification(self, resource, event, trigger, context=None, data=None, method_name=None, collection=None, action='', **kwargs): diff --git a/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py b/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py index ed3feb2aeaf..e20381bbdfd 100644 --- a/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py +++ b/neutron/tests/unit/api/rpc/agentnotifiers/test_dhcp_rpc_agent_api.py @@ -238,3 +238,18 @@ class TestDhcpAgentNotifyAPI(base.BaseTestCase): registry.notify(res, events.AFTER_CREATE, self, context=mock.Mock(), **kwargs) self.assertEqual([res], self.notifier._unsubscribed_resources) + + def test__only_status_changed(self): + p1 = {'id': 1, 'status': 'DOWN', 'updated_at': '10:00:00', + 'revision_number': 1} + p2 = dict(p1) + p2['status'] = 'ACTIVE' + p2['revision_number'] = 2 + p2['updated_at'] = '10:00:01' + self.assertTrue(self.notifier._only_status_changed(p1, p2)) + p2['name'] = 'test' + self.assertFalse(self.notifier._only_status_changed(p1, p2)) + p1['name'] = 'test' + self.assertTrue(self.notifier._only_status_changed(p1, p2)) + p1['name'] = 'test1' + self.assertFalse(self.notifier._only_status_changed(p1, p2))