From 0065bb6cd4b5a72dec8f6a2b96b3d279352f2b0c Mon Sep 17 00:00:00 2001 From: Balazs Gibizer Date: Wed, 28 May 2025 16:47:29 +0200 Subject: [PATCH] Cache [pci]alias parsing For each lifecycle operation nova re-load, parses, and validates the [pci]alias config option. This is wasteful. So this patch adds functools.cache decorator on the function used to do this work. Change-Id: If2ffb25430749a22c923c0938221833e7b883873 --- nova/pci/request.py | 3 ++- nova/test.py | 9 +++++++++ nova/tests/unit/pci/test_request.py | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/nova/pci/request.py b/nova/pci/request.py index 7c7c418f01..0e61be9a1e 100644 --- a/nova/pci/request.py +++ b/nova/pci/request.py @@ -37,7 +37,7 @@ These two aliases define a device request meaning: vendor_id is "8086" and product_id is "0442" or "0443". """ - +import functools import typing as ty import jsonschema @@ -173,6 +173,7 @@ def _validate_aliases(aliases): _validate_required_ids(aliases) +@functools.cache def get_alias_from_config() -> Alias: """Parse and validate PCI aliases from the nova config. diff --git a/nova/test.py b/nova/test.py index dd9d7098f5..b5815966d5 100644 --- a/nova/test.py +++ b/nova/test.py @@ -62,6 +62,7 @@ from nova.db.main import api as db_api from nova import exception from nova import objects from nova.objects import base as objects_base +from nova.pci import request from nova import quota from nova.scheduler.client import report from nova.scheduler import utils as scheduler_utils @@ -190,6 +191,10 @@ class TestCase(base.BaseTestCase): self.useFixture( nova_fixtures.PropagateTestCaseIdToChildEventlets(self.id())) + # Ensure that the pci alias is reset between test cases running in + # the same process + request.get_alias_from_config.cache_clear() + # How many of which service we've started. {$service-name: $count} self._service_fixture_count = collections.defaultdict(int) @@ -426,6 +431,10 @@ class TestCase(base.BaseTestCase): group = kw.pop('group', None) for k, v in kw.items(): CONF.set_override(k, v, group) + # loading and validating alias is cached so if it is reconfigured + # we need to reset the cache + if k == 'alias' and group == 'pci': + request.get_alias_from_config.cache_clear() def reset_flags(self, *k, **kw): """Reset flag variables for a test.""" diff --git a/nova/tests/unit/pci/test_request.py b/nova/tests/unit/pci/test_request.py index 4a736193e8..f1cfc477f6 100644 --- a/nova/tests/unit/pci/test_request.py +++ b/nova/tests/unit/pci/test_request.py @@ -342,6 +342,23 @@ class PciRequestTestCase(test.NoDBTestCase): "product_id fields set or resource_class field set.", str(ex)) + def test_get_alias_from_config_cached(self): + alias = jsonutils.dumps({ + "name": "a5", + "vendor_id": "4444", + "product_id": "4444", + }) + self.flags(alias=[alias], group='pci') + + origi_loads = jsonutils.loads + + with mock.patch('oslo_serialization.jsonutils.loads') as mock_loads: + mock_loads.side_effect = origi_loads + request.get_alias_from_config() + request.get_alias_from_config() + + mock_loads.assert_called_once() + def _verify_result(self, expected, real): exp_real = zip(expected, real) for exp, real in exp_real: