Skip to content

Commit

Permalink
Add caching of service_min_versions in the conductor
Browse files Browse the repository at this point in the history
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
  • Loading branch information
djipko committed Jan 11, 2016
1 parent f1da349 commit 5b13f1d
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 1 deletion.
1 change: 1 addition & 0 deletions nova/cmd/conductor.py
Expand Up @@ -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)

Expand Down
3 changes: 3 additions & 0 deletions nova/conductor/manager.py
Expand Up @@ -131,6 +131,9 @@ def object_backport_versions(self, context, objinst, object_versions):
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.
Expand Down
22 changes: 21 additions & 1 deletion nova/objects/service.py
Expand Up @@ -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
Expand Down Expand Up @@ -279,20 +282,37 @@ def save(self):
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-'):
LOG.warning(_LW('get_minimum_version called with likely-incorrect '
'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
Expand Down
6 changes: 6 additions & 0 deletions nova/tests/unit/conductor/test_conductor.py
Expand Up @@ -189,6 +189,12 @@ def foo(cls, context):
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."""
Expand Down
17 changes: 17 additions & 0 deletions nova/tests/unit/objects/test_service.py
Expand Up @@ -296,6 +296,23 @@ def test_get_minimum_version_checks_binary(self, mock_log, mock_get):
'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',
Expand Down

0 comments on commit 5b13f1d

Please sign in to comment.