Add caching of service_min_versions in the conductor

Since we may need this information in the conductor a lot, as it has to
be used to determine whether data migration can be done, we cache the
results.

The cache gets cleared on SIGHUP, so any update of a service would
require a SIGHUP to the conductors Now (similar to how it's done for the
compute task service).

We enable this caching only for the conductor nodes as it is not needed
elsewhere.

Change-Id: I79e2f0e79e17141052e7a8128e0d64975e0b4b5f
This commit is contained in:
Nikola Dipanov 2016-01-08 15:00:18 +00:00
parent f1da349a4f
commit 5b13f1d0c5
5 changed files with 48 additions and 1 deletions

View File

@ -36,6 +36,7 @@ def main():
logging.setup(CONF, "nova")
utils.monkey_patch()
objects.register_all()
objects.Service.enable_min_version_cache()
gmr.TextGuruMeditation.setup_autorun(version)

View File

@ -131,6 +131,9 @@ class ConductorManager(manager.Manager):
return objinst.obj_to_primitive(target_version=target,
version_manifest=object_versions)
def reset(self):
objects.Service.clear_min_version_cache()
class ComputeTaskManager(base.Base):
"""Namespace for compute methods.

View File

@ -102,6 +102,9 @@ class Service(base.NovaPersistentObject, base.NovaObject,
'version': fields.IntegerField(),
}
_MIN_VERSION_CACHE = {}
_SERVICE_VERSION_CACHING = False
def __init__(self, *args, **kwargs):
# NOTE(danms): We're going against the rules here and overriding
# init. The reason is that we want to *ensure* that we're always
@ -279,6 +282,15 @@ class Service(base.NovaPersistentObject, base.NovaObject,
def destroy(self):
db.service_destroy(self._context, self.id)
@classmethod
def enable_min_version_cache(cls):
cls.clear_min_version_cache()
cls._SERVICE_VERSION_CACHING = True
@classmethod
def clear_min_version_cache(cls):
cls._MIN_VERSION_CACHE = {}
@base.remotable_classmethod
def get_minimum_version(cls, context, binary, use_slave=False):
if not binary.startswith('nova-'):
@ -286,13 +298,21 @@ class Service(base.NovaPersistentObject, base.NovaObject,
'binary `%s\''), binary)
raise exception.ObjectActionError(action='get_minimum_version',
reason='Invalid binary prefix')
if cls._SERVICE_VERSION_CACHING:
cached_version = cls._MIN_VERSION_CACHE.get(binary)
if cached_version:
return cached_version
version = db.service_get_minimum_version(context, binary,
use_slave=use_slave)
if version is None:
return 0
# NOTE(danms): Since our return value is not controlled by object
# schema, be explicit here.
return int(version)
version = int(version)
cls._MIN_VERSION_CACHE[binary] = version
return version
@base.NovaObjectRegistry.register

View File

@ -189,6 +189,12 @@ class ConductorTestCase(_BaseTestCase, test.TestCase):
m.return_value.obj_to_primitive.assert_called_once_with(
target_version='1.2', version_manifest=versions)
def test_reset(self):
with mock.patch.object(objects.Service, 'clear_min_version_cache'
) as mock_clear_cache:
self.conductor.reset()
mock_clear_cache.assert_called_once_with()
class ConductorRPCAPITestCase(_BaseTestCase, test.TestCase):
"""Conductor RPC API Tests."""

View File

@ -296,6 +296,23 @@ class _TestServiceObject(object):
'compute')
self.assertTrue(mock_log.warning.called)
@mock.patch('nova.db.service_get_minimum_version')
def test_get_minimum_version_with_caching(self, mock_get):
objects.Service.enable_min_version_cache()
mock_get.return_value = 123
self.assertEqual(123,
objects.Service.get_minimum_version(self.context,
'nova-compute'))
self.assertEqual({"nova-compute": 123},
objects.Service._MIN_VERSION_CACHE)
self.assertEqual(123,
objects.Service.get_minimum_version(self.context,
'nova-compute'))
mock_get.assert_called_once_with(self.context, 'nova-compute',
use_slave=False)
objects.Service._SERVICE_VERSION_CACHING = False
objects.Service.clear_min_version_cache()
@mock.patch('nova.db.service_get_minimum_version', return_value=2)
def test_create_above_minimum(self, mock_get):
with mock.patch('nova.objects.service.SERVICE_VERSION',