Optimize floating ip list to make one db query

Currently the floating ip code will make 2 db queries for every
single associated floating ip when list is called. This adds
a couple of joins in the db layer to avoid having to make so many
calls. This dramatically improves floating-ip-list. On a simple one
node test the time dropped from 2.35 seconds down to 0.5 seconds
for a list with 10 associated floating ips.

Part of blueprint optimize-nova-network

Change-Id: I0571013393b2dbad42c15e690c7783d5ceecaeb2
This commit is contained in:
Vishvananda Ishaya 2013-01-30 16:23:04 -08:00
parent 922f81c18b
commit 655ae2e939
4 changed files with 37 additions and 46 deletions

View File

@ -109,33 +109,14 @@ class FloatingIPController(object):
self.network_api = network.API()
super(FloatingIPController, self).__init__()
def _get_fixed_ip(self, context, fixed_ip_id):
if fixed_ip_id is None:
return None
try:
return self.network_api.get_fixed_ip(context, fixed_ip_id)
except exception.FixedIpNotFound:
return None
def _get_instance(self, context, instance_id):
return self.compute_api.get(context, instance_id)
def _set_metadata(self, context, floating_ip):
# When Quantum v2 API is used, 'fixed_ip' and 'instance' are
# already set. In this case we don't need to update the fields.
if 'fixed_ip' not in floating_ip:
fixed_ip_id = floating_ip['fixed_ip_id']
floating_ip['fixed_ip'] = self._get_fixed_ip(context,
fixed_ip_id)
def _normalize_ip(self, floating_ip):
# NOTE(vish): translate expects instance to be in the floating_ip
# dict but it is returned in the fixed_ip dict by
# nova-network
fixed_ip = floating_ip.get('fixed_ip')
if 'instance' not in floating_ip:
instance_uuid = None
if floating_ip['fixed_ip']:
instance_uuid = floating_ip['fixed_ip']['instance_uuid']
if instance_uuid:
floating_ip['instance'] = self._get_instance(context,
instance_uuid)
if fixed_ip:
floating_ip['instance'] = fixed_ip['instance']
else:
floating_ip['instance'] = None
@ -151,7 +132,7 @@ class FloatingIPController(object):
msg = _("Floating ip not found for id %s") % id
raise webob.exc.HTTPNotFound(explanation=msg)
self._set_metadata(context, floating_ip)
self._normalize_ip(floating_ip)
return _translate_floating_ip_view(floating_ip)
@ -164,7 +145,7 @@ class FloatingIPController(object):
floating_ips = self.network_api.get_floating_ips_by_project(context)
for floating_ip in floating_ips:
self._set_metadata(context, floating_ip)
self._normalize_ip(floating_ip)
return _translate_floating_ips_view(floating_ips)

View File

@ -627,6 +627,7 @@ def certificate_get_all_by_user_and_project(context, user_id, project_id):
def floating_ip_get(context, id):
result = model_query(context, models.FloatingIp, project_only=True).\
filter_by(id=id).\
options(joinedload_all('fixed_ip.instance')).\
first()
if not result:
@ -841,6 +842,7 @@ def floating_ip_get_all_by_project(context, project_id):
return _floating_ip_get_all(context).\
filter_by(project_id=project_id).\
filter_by(auto_assigned=False).\
options(joinedload_all('fixed_ip.instance')).\
all()
@ -858,6 +860,7 @@ def _floating_ip_get_by_address(context, address, session=None):
result = model_query(context, models.FloatingIp, session=session).\
filter_by(address=address).\
options(joinedload_all('fixed_ip.instance')).\
first()
if not result:

View File

@ -724,7 +724,14 @@ class FixedIp(BASE, NovaBase):
foreign_keys=network_id,
primaryjoin='and_('
'FixedIp.network_id == Network.id,'
'FixedIp.deleted == 0)')
'FixedIp.deleted == 0,'
'Network.deleted == 0)')
instance = relationship(Instance,
foreign_keys=instance_uuid,
primaryjoin='and_('
'FixedIp.instance_uuid == Instance.uuid,'
'FixedIp.deleted == 0,'
'Instance.deleted == 0)')
class FloatingIp(BASE, NovaBase):
@ -738,6 +745,13 @@ class FloatingIp(BASE, NovaBase):
auto_assigned = Column(Boolean, default=False, nullable=False)
pool = Column(String(255))
interface = Column(String(255))
fixed_ip = relationship(FixedIp,
backref=backref('floating_ips'),
foreign_keys=fixed_ip_id,
primaryjoin='and_('
'FloatingIp.fixed_ip_id == FixedIp.id,'
'FloatingIp.deleted == 0,'
'FixedIp.deleted == 0)')
class DNSDomain(BASE, NovaBase):

View File

@ -36,12 +36,6 @@ from nova.tests import fake_network
FAKE_UUID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
def network_api_get_fixed_ip(self, context, id):
if id is None:
return None
return {'address': '10.0.0.1', 'id': id, 'instance_uuid': 1}
def network_api_get_floating_ip(self, context, id):
return {'id': 1, 'address': '10.10.10.10', 'pool': 'nova',
'fixed_ip_id': None}
@ -56,11 +50,12 @@ def network_api_get_floating_ips_by_project(self, context):
return [{'id': 1,
'address': '10.10.10.10',
'pool': 'nova',
'fixed_ip_id': 20},
'fixed_ip': {'address': '10.0.0.1',
'instance': {'uuid': FAKE_UUID}}},
{'id': 2,
'pool': 'nova', 'interface': 'eth0',
'address': '10.10.10.11',
'fixed_ip_id': None}]
'fixed_ip': None}]
def compute_api_get(self, context, instance_id):
@ -131,8 +126,6 @@ class FloatingIpTest(test.TestCase):
def setUp(self):
super(FloatingIpTest, self).setUp()
self.stubs.Set(network.api.API, "get_fixed_ip",
network_api_get_fixed_ip)
self.stubs.Set(compute.api.API, "get",
compute_api_get)
self.stubs.Set(network.api.API, "get_floating_ip",
@ -173,8 +166,9 @@ class FloatingIpTest(test.TestCase):
floating_ip_address = self.floating_ip
floating_ip = db.floating_ip_get_by_address(self.context,
floating_ip_address)
floating_ip['fixed_ip'] = None
floating_ip['instance'] = None
# NOTE(vish): network_get uses the id not the address
floating_ip = db.floating_ip_get(self.context, floating_ip['id'])
self.controller._normalize_ip(floating_ip)
view = floating_ips._translate_floating_ip_view(floating_ip)
self.assertTrue('floating_ip' in view)
self.assertTrue(view['floating_ip']['id'])
@ -185,6 +179,7 @@ class FloatingIpTest(test.TestCase):
def test_translate_floating_ip_view_dict(self):
floating_ip = {'id': 0, 'address': '10.0.0.10', 'pool': 'nova',
'fixed_ip': None}
self.controller._normalize_ip(floating_ip)
view = floating_ips._translate_floating_ip_view(floating_ip)
self.assertTrue('floating_ip' in view)
@ -245,19 +240,17 @@ class FloatingIpTest(test.TestCase):
def test_show_associated_floating_ip(self):
def get_floating_ip(self, context, id):
return {'id': 1, 'address': '10.10.10.10', 'pool': 'nova',
'fixed_ip_id': 11}
def get_fixed_ip(self, context, id):
return {'address': '10.0.0.1', 'instance_uuid': 1}
'fixed_ip': {'address': '10.0.0.1',
'instance': {'uuid': FAKE_UUID}}}
self.stubs.Set(network.api.API, "get_floating_ip", get_floating_ip)
self.stubs.Set(network.api.API, "get_fixed_ip", get_fixed_ip)
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips/1')
res_dict = self.controller.show(req, 1)
self.assertEqual(res_dict['floating_ip']['id'], 1)
self.assertEqual(res_dict['floating_ip']['ip'], '10.10.10.10')
self.assertEqual(res_dict['floating_ip']['fixed_ip'], '10.0.0.1')
self.assertEqual(res_dict['floating_ip']['instance_id'], FAKE_UUID)
def test_recreation_of_floating_ip(self):