From 7bbe9752bd0676947b43718a47583c0524e9a8af Mon Sep 17 00:00:00 2001 From: Andrew Laski Date: Fri, 26 Jul 2013 09:53:31 -0400 Subject: [PATCH] Bypass queries which cause a contradiction This addresses the cause of the log lines like: SAWarning: The IN-predicate on "instance_system_metadata.instance_uuid" was invoked with an empty sequence. This results in a contradiction, which nonetheless can be expensive to evaluate. Consider alternative strategies for improved performance. for instance_metadata, instance_system_metadata, and instance_faults. It especially helps the case of a call to /servers/detail when there are no servers to list because each of those tables is scanned despite a guarantee that there will be now rows. Bug 1204916 Change-Id: I62e65c4409d3e3ab8373eb66450414565c222547 --- nova/db/sqlalchemy/api.py | 7 +++++++ nova/tests/db/test_db_api.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 75b693a96f..e2d5537080 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -4186,6 +4186,8 @@ def cell_get_all(context): # User-provided metadata def _instance_metadata_get_multi(context, instance_uuids, session=None): + if not instance_uuids: + return [] return model_query(context, models.InstanceMetadata, session=session).\ filter( @@ -4257,6 +4259,8 @@ def instance_metadata_update(context, instance_uuid, metadata, delete, def _instance_system_metadata_get_multi(context, instance_uuids, session=None): + if not instance_uuids: + return [] return model_query(context, models.InstanceSystemMetadata, session=session).\ filter( @@ -4885,6 +4889,9 @@ def instance_fault_create(context, values): def instance_fault_get_by_instance_uuids(context, instance_uuids): """Get all instance faults for the provided instance_uuids.""" + if not instance_uuids: + return {} + rows = model_query(context, models.InstanceFault, read_deleted='no').\ filter(models.InstanceFault.instance_uuid.in_( instance_uuids)).\ diff --git a/nova/tests/db/test_db_api.py b/nova/tests/db/test_db_api.py index 89c8622a99..dbb3f59ea3 100644 --- a/nova/tests/db/test_db_api.py +++ b/nova/tests/db/test_db_api.py @@ -1349,6 +1349,29 @@ class InstanceTestCase(test.TestCase, ModelsObjectComparatorMixin): filtered_instances = db.instance_get_all_by_filters(self.ctxt, {}) self._assertEqualListsOfInstances(instances, filtered_instances) + def test_instance_metadata_get_multi(self): + uuids = [self.create_instance_with_args()['uuid'] for i in range(3)] + meta = sqlalchemy_api._instance_metadata_get_multi(self.ctxt, uuids) + for row in meta: + self.assertTrue(row['instance_uuid'] in uuids) + + def test_instance_metadata_get_multi_no_uuids(self): + self.mox.StubOutWithMock(query.Query, 'filter') + self.mox.ReplayAll() + sqlalchemy_api._instance_metadata_get_multi(self.ctxt, []) + + def test_instance_system_system_metadata_get_multi(self): + uuids = [self.create_instance_with_args()['uuid'] for i in range(3)] + sys_meta = sqlalchemy_api._instance_system_metadata_get_multi( + self.ctxt, uuids) + for row in sys_meta: + self.assertTrue(row['instance_uuid'] in uuids) + + def test_instance_system_metadata_get_multi_no_uuids(self): + self.mox.StubOutWithMock(query.Query, 'filter') + self.mox.ReplayAll() + sqlalchemy_api._instance_system_metadata_get_multi(self.ctxt, []) + def test_instance_get_all_by_filters_regex(self): i1 = self.create_instance_with_args(display_name='test1') i2 = self.create_instance_with_args(display_name='teeeest2') @@ -2268,6 +2291,12 @@ class InstanceFaultTestCase(test.TestCase, ModelsObjectComparatorMixin): expected = {uuid: []} self.assertEqual(expected, faults) + def test_instance_faults_get_by_instance_uuids_no_uuids(self): + self.mox.StubOutWithMock(query.Query, 'filter') + self.mox.ReplayAll() + faults = db.instance_fault_get_by_instance_uuids(self.ctxt, []) + self.assertEqual({}, faults) + class InstanceTypeTestCase(BaseInstanceTypeTestCase):