xenapi: stop using get_all_vdis_in_sr in spawn

Currently when trying to find a cached image, the very expensive call to
get_all_vdis_in_sr is used, where we could instead fetch the VDI
directly using a more targeted query.

Now we are fetching the VDI by name_label we must ensure to clear the
name_label on newly created VDIs to ensure they do not get picked up by
later calls to _find_cached_image().

Fixes bug 1221292

The above code that checks for _find_cached_images has race conditions
where its possible to end up with two VDIs returned. To stop this
happening the code to create the cached images is now synchronized on
the image being fetched.

Fixes bug 1226073

Change-Id: I534fb8f42b00b5d39dc17dd5fee297144b5f379a
This commit is contained in:
John Garbutt 2013-09-13 17:04:06 +01:00 committed by Gerrit Code Review
parent 29d037a3d3
commit ce8e95c7a3

@ -791,8 +791,15 @@ def _find_cached_images(session, sr_ref):
def _find_cached_image(session, image_id, sr_ref):
"""Returns the vdi-ref of the cached image."""
cached_images = _find_cached_images(session, sr_ref)
return cached_images.get(image_id)
name_label = _get_image_vdi_label(image_id)
recs = session.call_xenapi("VDI.get_all_records_where",
'field "name__label"="%s"'
% name_label)
number_found = len(recs)
if number_found > 0:
if number_found > 1:
LOG.warn(_("Multiple base images for image: %s") % image_id)
return recs.keys()[0]
def resize_disk(session, instance, vdi_ref, instance_type):
@ -1087,43 +1094,60 @@ def destroy_kernel_ramdisk(session, instance, kernel, ramdisk):
session.call_plugin('kernel', 'remove_kernel_ramdisk', args)
def _get_image_vdi_label(image_id):
return 'Glance Image %s' % image_id
def _create_cached_image(context, session, instance, name_label,
image_id, image_type):
sr_ref = safe_find_sr(session)
sr_type = session.call_xenapi('SR.get_record', sr_ref)["type"]
vdis = {}
if CONF.use_cow_images and sr_type != "ext":
LOG.warning(_("Fast cloning is only supported on default local SR "
"of type ext. SR on this system was found to be of "
"type %s. Ignoring the cow flag."), sr_type)
cache_vdi_ref = _find_cached_image(session, image_id, sr_ref)
if cache_vdi_ref is None:
vdis = _fetch_image(context, session, instance, name_label,
image_id, image_type)
@utils.synchronized('xenapi-image-cache' + image_id)
def _create_cached_image_impl(context, session, instance, name_label,
image_id, image_type, sr_ref):
cache_vdi_ref = _find_cached_image(session, image_id, sr_ref)
if cache_vdi_ref is None:
vdis = _fetch_image(context, session, instance, name_label,
image_id, image_type)
cache_vdi_ref = session.call_xenapi(
'VDI.get_by_uuid', vdis['root']['uuid'])
cache_vdi_ref = session.call_xenapi(
'VDI.get_by_uuid', vdis['root']['uuid'])
session.call_xenapi('VDI.set_name_label', cache_vdi_ref,
'Glance Image %s' % image_id)
session.call_xenapi('VDI.set_name_description', cache_vdi_ref, 'root')
session.call_xenapi('VDI.add_to_other_config',
cache_vdi_ref, 'image-id', str(image_id))
session.call_xenapi('VDI.set_name_label', cache_vdi_ref,
_get_image_vdi_label(image_id))
session.call_xenapi('VDI.set_name_description', cache_vdi_ref,
'root')
session.call_xenapi('VDI.add_to_other_config',
cache_vdi_ref, 'image-id', str(image_id))
if CONF.use_cow_images and sr_type == 'ext':
new_vdi_ref = _clone_vdi(session, cache_vdi_ref)
elif sr_type == 'ext':
new_vdi_ref = _safe_copy_vdi(session, sr_ref, instance, cache_vdi_ref)
else:
new_vdi_ref = session.call_xenapi("VDI.copy", cache_vdi_ref, sr_ref)
if CONF.use_cow_images and sr_type == 'ext':
new_vdi_ref = _clone_vdi(session, cache_vdi_ref)
elif sr_type == 'ext':
new_vdi_ref = _safe_copy_vdi(session, sr_ref, instance,
cache_vdi_ref)
else:
new_vdi_ref = session.call_xenapi("VDI.copy", cache_vdi_ref,
sr_ref)
session.call_xenapi('VDI.remove_from_other_config',
new_vdi_ref, 'image-id')
session.call_xenapi('VDI.set_name_label', cache_vdi_ref, '')
session.call_xenapi('VDI.set_name_description', cache_vdi_ref, '')
session.call_xenapi('VDI.remove_from_other_config',
new_vdi_ref, 'image-id')
vdi_uuid = session.call_xenapi('VDI.get_uuid', new_vdi_ref)
return vdi_uuid
vdi_uuid = _create_cached_image_impl(context, session, instance,
name_label, image_id, image_type, sr_ref)
vdis = {}
vdi_type = ImageType.get_role(image_type)
vdi_uuid = session.call_xenapi('VDI.get_uuid', new_vdi_ref)
vdis[vdi_type] = dict(uuid=vdi_uuid, file=None)
return vdis