Dont query image metadata for empty volume list

This query creates a table scan in sqlalchemy when there are no entries
in the IN() clause.

With a large image metadata table, this makes a volume list on a project
with no volumes take an incredible amount of time.

Change-Id: I51733e1e3c526f4ca46e2826c242924407fabbe4
Closes-Bug: #1561174
This commit is contained in:
Cory Stone 2016-03-24 10:28:37 -05:00
parent 0a9943b52a
commit 4c810374e3
2 changed files with 19 additions and 13 deletions

View File

@ -13,7 +13,6 @@
# under the License. # under the License.
"""The Volume Image Metadata API extension.""" """The Volume Image Metadata API extension."""
import six
import webob import webob
from oslo_log import log as logging from oslo_log import log as logging
@ -47,16 +46,6 @@ class VolumeImageMetadataController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=msg) raise webob.exc.HTTPNotFound(explanation=msg)
return (volume, meta) return (volume, meta)
def _get_all_images_metadata(self, context):
"""Returns the image metadata for all volumes."""
try:
all_metadata = self.volume_api.get_volumes_image_metadata(context)
except Exception as e:
LOG.debug('Problem retrieving volume image metadata. '
'It will be skipped. Error: %s', six.text_type(e))
all_metadata = {}
return all_metadata
def _add_image_metadata(self, context, resp_volume_list, image_metas=None): def _add_image_metadata(self, context, resp_volume_list, image_metas=None):
"""Appends the image metadata to each of the given volume. """Appends the image metadata to each of the given volume.
@ -95,8 +84,9 @@ class VolumeImageMetadataController(wsgi.Controller):
if authorize(context): if authorize(context):
resp_obj.attach(xml=VolumesImageMetadataTemplate()) resp_obj.attach(xml=VolumesImageMetadataTemplate())
# Just get the image metadata of those volumes in response. # Just get the image metadata of those volumes in response.
self._add_image_metadata(context, volumes = list(resp_obj.obj.get('volumes', []))
list(resp_obj.obj.get('volumes', []))) if volumes:
self._add_image_metadata(context, volumes)
@wsgi.action("os-set_image_metadata") @wsgi.action("os-set_image_metadata")
@wsgi.serializers(xml=common.MetadataTemplate) @wsgi.serializers(xml=common.MetadataTemplate)

View File

@ -61,6 +61,10 @@ def fake_volume_get_all(*args, **kwargs):
return objects.VolumeList(objects=[fake_volume_api_get()]) return objects.VolumeList(objects=[fake_volume_api_get()])
def fake_volume_get_all_empty(*args, **kwargs):
return objects.VolumeList(objects=[])
fake_image_metadata = { fake_image_metadata = {
'image_id': 'someid', 'image_id': 'someid',
'image_name': 'fake', 'image_name': 'fake',
@ -150,6 +154,18 @@ class VolumeImageMetadataTest(test.TestCase):
self.assertEqual(fake_image_metadata, self.assertEqual(fake_image_metadata,
self._get_image_metadata_list(res.body)[0]) self._get_image_metadata_list(res.body)[0])
def test_list_detail_empty_volumes(self):
def fake_dont_call_this(*args, **kwargs):
fake_dont_call_this.called = True
fake_dont_call_this.called = False
self.stubs.Set(volume.api.API, 'get_list_volumes_image_metadata',
fake_dont_call_this)
self.stubs.Set(volume.api.API, 'get_all', fake_volume_get_all_empty)
res = self._make_request('/v2/fake/volumes/detail')
self.assertEqual(200, res.status_int)
self.assertFalse(fake_dont_call_this.called)
def test_list_detail_volumes_with_limit(self): def test_list_detail_volumes_with_limit(self):
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
db.volume_create(ctxt, {'id': 'fake', 'status': 'available', db.volume_create(ctxt, {'id': 'fake', 'status': 'available',