From ac9cc15164f0afcac4b3320bcd58d36c00f3232c Mon Sep 17 00:00:00 2001 From: Boris Pavlovic Date: Wed, 8 May 2013 16:25:46 +0400 Subject: Optimize db.instance_floating_address_get_all method Optimize db.instance_floating_address_get_all Was: Get FixedIps with corresponding instance_uuid For each FixedIp get associated FloatIp (N request) Now: Get only list of FixedIps ids Get all corresponding FloatingIp with one query (select in) Get only addresses from FloatingIps (because we are using only it) Add temporary test for db.instance_floating_address_get_all to ensure that it works as expected. Change-Id: Id3c515de0ca35707bbfe46b991c2d7cf591e431b --- nova/db/sqlalchemy/api.py | 21 +++++++++++++++------ nova/network/api.py | 2 +- nova/tests/test_db_api.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index d5f4c8e6f..bb5978f82 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -1911,14 +1911,23 @@ def instance_get_floating_address(context, instance_id): @require_context def instance_floating_address_get_all(context, instance_uuid): - fixed_ips = fixed_ip_get_by_instance(context, instance_uuid) + if not uuidutils.is_uuid_like(instance_uuid): + raise exception.InvalidUUID(uuid=instance_uuid) + + fixed_ip_ids = model_query(context, models.FixedIp.id, + base_model=models.FixedIp).\ + filter_by(instance_uuid=instance_uuid).\ + all() + if not fixed_ip_ids: + raise exception.FixedIpNotFoundForInstance(instance_uuid=instance_uuid) - floating_ips = [] - for fixed_ip in fixed_ips: - _floating_ips = floating_ip_get_by_fixed_ip_id(context, fixed_ip['id']) - floating_ips += _floating_ips + fixed_ip_ids = [fixed_ip_id.id for fixed_ip_id in fixed_ip_ids] - return floating_ips + floating_ips = model_query(context, models.FloatingIp.address, + base_model=models.FloatingIp).\ + filter(models.FloatingIp.fixed_ip_id.in_(fixed_ip_ids)).\ + all() + return [floating_ip.address for floating_ip in floating_ips] @require_admin_context diff --git a/nova/network/api.py b/nova/network/api.py index b8baf9810..26ca7584a 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -486,7 +486,7 @@ class API(base.Base): def _get_floating_ip_addresses(self, context, instance): floating_ips = self.db.instance_floating_address_get_all(context, instance['uuid']) - return [floating_ip['address'] for floating_ip in floating_ips] + return floating_ips @wrap_check_policy def migrate_instance_start(self, context, instance, migration): diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py index cfed3ab3b..626cad630 100644 --- a/nova/tests/test_db_api.py +++ b/nova/tests/test_db_api.py @@ -1023,6 +1023,34 @@ class DbApiTestCase(DbTestCase): self.assertEqual(db.network_in_use_on_host(ctxt, 1, 'foo'), True) self.assertEqual(db.network_in_use_on_host(ctxt, 1, 'bar'), False) + def test_instance_floating_address_get_all(self): + ctxt = context.get_admin_context() + + instance1 = db.instance_create(ctxt, {'host': 'h1', 'hostname': 'n1'}) + instance2 = db.instance_create(ctxt, {'host': 'h2', 'hostname': 'n2'}) + + fixed_addresses = ['1.1.1.1', '1.1.1.2', '1.1.1.3'] + float_addresses = ['2.1.1.1', '2.1.1.2', '2.1.1.3'] + instance_uuids = [instance1['uuid'], instance1['uuid'], + instance2['uuid']] + + for fixed_addr, float_addr, instance_uuid in zip(fixed_addresses, + float_addresses, + instance_uuids): + db.fixed_ip_create(ctxt, {'address': fixed_addr, + 'instance_uuid': instance_uuid}) + fixed_id = db.fixed_ip_get_by_address(ctxt, fixed_addr)['id'] + db.floating_ip_create(ctxt, + {'address': float_addr, + 'fixed_ip_id': fixed_id}) + + real_float_addresses = \ + db.instance_floating_address_get_all(ctxt, instance_uuids[0]) + self.assertEqual(set(float_addresses[:2]), set(real_float_addresses)) + real_float_addresses = \ + db.instance_floating_address_get_all(ctxt, instance_uuids[2]) + self.assertEqual(set([float_addresses[2]]), set(real_float_addresses)) + def test_get_vol_mapping_non_admin(self): ref = db.ec2_volume_create(self.context, 'fake-uuid') ec2_id = db.get_ec2_volume_id_by_uuid(self.context, 'fake-uuid') -- cgit