Optimize pid property in AsyncProcess class
The pid property in the the AsyncProcess process class executes command 'ps --ppid <pid> -o pid=' every time the associated asynchronous process's pid is needed. This can be very heavy in high load network and compute nodes. Please see related bug. This change optimizes the pid property to execute 'ps --ppid <pid> -o pid=' only the first time it is called, memoizing the retrieved pid for future calls. Change-Id: Idd347b0b22320cbfdb5d6a738e218e5788dd7d6b Closes-Bug:1663465
This commit is contained in:
parent
44a51b8c09
commit
ee5677bd61
neutron
@ -78,6 +78,7 @@ class AsyncProcess(object):
|
||||
raise ValueError(_('respawn_interval must be >= 0 if provided.'))
|
||||
self.respawn_interval = respawn_interval
|
||||
self._process = None
|
||||
self._pid = None
|
||||
self._is_running = False
|
||||
self._kill_event = None
|
||||
self._reset_queues()
|
||||
@ -95,8 +96,8 @@ class AsyncProcess(object):
|
||||
|
||||
def is_active(self):
|
||||
# If using sudo rootwrap as a root_helper, we have to wait until sudo
|
||||
# spawns rootwrap and rootwrap spawns the process.
|
||||
|
||||
# spawns rootwrap and rootwrap spawns the process. self.pid will make
|
||||
# sure to get the correct pid.
|
||||
return utils.pid_invoked_with_cmdline(
|
||||
self.pid, self.cmd_without_namespace)
|
||||
|
||||
@ -137,6 +138,7 @@ class AsyncProcess(object):
|
||||
def _spawn(self):
|
||||
"""Spawn a process and its watchers."""
|
||||
self._is_running = True
|
||||
self._pid = None
|
||||
self._kill_event = eventlet.event.Event()
|
||||
self._process, cmd = utils.create_process(self._cmd,
|
||||
run_as_root=self.run_as_root)
|
||||
@ -154,16 +156,19 @@ class AsyncProcess(object):
|
||||
@property
|
||||
def pid(self):
|
||||
if self._process:
|
||||
return utils.get_root_helper_child_pid(
|
||||
self._process.pid,
|
||||
self.cmd_without_namespace,
|
||||
run_as_root=self.run_as_root)
|
||||
if not self._pid:
|
||||
self._pid = utils.get_root_helper_child_pid(
|
||||
self._process.pid,
|
||||
self.cmd_without_namespace,
|
||||
run_as_root=self.run_as_root)
|
||||
return self._pid
|
||||
|
||||
def _kill(self, kill_signal):
|
||||
"""Kill the process and the associated watcher greenthreads."""
|
||||
pid = self.pid
|
||||
if pid:
|
||||
self._is_running = False
|
||||
self._pid = None
|
||||
self._kill_process(pid, kill_signal)
|
||||
|
||||
# Halt the greenthreads if they weren't already.
|
||||
|
@ -56,6 +56,25 @@ class TestAsyncProcess(base.BaseTestCase):
|
||||
])
|
||||
self.assertEqual(len(proc._watchers), 2)
|
||||
|
||||
def test__pid_none(self):
|
||||
pid = 1
|
||||
self.proc._pid = None
|
||||
with mock.patch.object(self.proc, '_process') as _process:
|
||||
with mock.patch.object(utils,
|
||||
'get_root_helper_child_pid') as func:
|
||||
func.return_value = pid
|
||||
self.assertEqual(self.proc.pid, pid)
|
||||
func.assert_called_once_with(_process.pid, ['fake'],
|
||||
run_as_root=False)
|
||||
self.assertEqual(self.proc._pid, pid)
|
||||
|
||||
def test__pid_not_none(self):
|
||||
self.proc._pid = 1
|
||||
with mock.patch.object(self.proc, '_process'),\
|
||||
mock.patch.object(utils, 'get_root_helper_child_pid') as func:
|
||||
self.assertEqual(self.proc.pid, 1)
|
||||
func.assert_not_called()
|
||||
|
||||
def test__handle_process_error_kills_with_respawn(self):
|
||||
with mock.patch.object(self.proc, '_kill') as kill:
|
||||
self.proc._handle_process_error()
|
||||
@ -185,6 +204,7 @@ class TestAsyncProcess(base.BaseTestCase):
|
||||
|
||||
self.assertIsNone(self.proc._kill_event)
|
||||
self.assertFalse(self.proc._is_running)
|
||||
self.assertIsNone(self.proc._pid)
|
||||
|
||||
mock_kill_event.send.assert_called_once_with()
|
||||
if pid:
|
||||
|
Loading…
x
Reference in New Issue
Block a user