Get list of disks to copy early to avoid multiple DB hits

To support selective block migration we need to read block devices
from nova block device mappings instead of libvirt block info.
It means that in current implementation we would call
_live_migration_copy_disk_paths two times - from
live_migration_operations and from live_migration_monitor.
To avoid that this change gets disk paths early and pass them as
and additional paremeter to live migration monitor.

Change-Id: Ic894cfc7374ba06b436b2a76a5984012d1dba3a5
Related-bug: #1398999
This commit is contained in:
Pawel Koniszewski 2015-12-11 03:28:50 +01:00
parent a237fc84d3
commit f0d5fc6191
2 changed files with 30 additions and 31 deletions

View File

@ -6870,20 +6870,14 @@ class LibvirtConnTestCase(test.NoDBTestCase):
"_live_migration_copy_disk_paths")
def test_live_migration_data_gb_plain(self, mock_paths):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
dom = fakelibvirt.Domain(drvr._get_connection(), "<domain/>", False)
guest = libvirt_guest.Guest(dom)
instance = objects.Instance(**self.test_instance)
data_gb = drvr._live_migration_data_gb(instance, guest, False)
data_gb = drvr._live_migration_data_gb(instance, [])
self.assertEqual(2, data_gb)
self.assertEqual(0, mock_paths.call_count)
@mock.patch.object(libvirt_driver.LibvirtDriver,
"_live_migration_copy_disk_paths")
def test_live_migration_data_gb_block(self, mock_paths):
def test_live_migration_data_gb_block(self):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
dom = fakelibvirt.Domain(drvr._get_connection(), "<domain/>", False)
guest = libvirt_guest.Guest(dom)
instance = objects.Instance(**self.test_instance)
def fake_stat(path):
@ -6902,15 +6896,14 @@ class LibvirtConnTestCase(test.NoDBTestCase):
else:
raise Exception("Should not be reached")
mock_paths.return_value = ["/var/lib/nova/instance/123/disk.root",
"/dev/mapper/somevol"]
disk_paths = ["/var/lib/nova/instance/123/disk.root",
"/dev/mapper/somevol"]
with mock.patch.object(os, "stat") as mock_stat:
mock_stat.side_effect = fake_stat
data_gb = drvr._live_migration_data_gb(instance, guest, True)
data_gb = drvr._live_migration_data_gb(instance, disk_paths)
# Expecting 2 GB for RAM, plus 10 GB for disk.root
# and 1.5 GB rounded to 2 GB for somevol, so 14 GB
self.assertEqual(14, data_gb)
self.assertEqual(1, mock_paths.call_count)
EXPECT_SUCCESS = 1
EXPECT_FAILURE = 2
@ -6978,7 +6971,8 @@ class LibvirtConnTestCase(test.NoDBTestCase):
False,
migrate_data,
dom,
finish_event)
finish_event,
[])
if expect_result == self.EXPECT_SUCCESS:
self.assertFalse(fake_recover_method.called,
@ -7239,14 +7233,18 @@ class LibvirtConnTestCase(test.NoDBTestCase):
@mock.patch.object(libvirt_driver.LibvirtDriver, "_live_migration_monitor")
@mock.patch.object(host.Host, "get_guest")
@mock.patch.object(fakelibvirt.Connection, "_mark_running")
def test_live_migration_main(self, mock_running, mock_guest,
mock_monitor, mock_thread):
@mock.patch.object(libvirt_driver.LibvirtDriver,
"_live_migration_copy_disk_paths")
def test_live_migration_main(self, mock_copy_disk_path, mock_running,
mock_guest, mock_monitor, mock_thread):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
instance = objects.Instance(**self.test_instance)
dom = fakelibvirt.Domain(drvr._get_connection(),
"<domain><name>demo</name></domain>", True)
guest = libvirt_guest.Guest(dom)
migrate_data = {}
disk_paths = ['/dev/vda', '/dev/vdb']
mock_copy_disk_path.return_value = disk_paths
mock_guest.return_value = guest
@ -7257,7 +7255,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
pass
drvr._live_migration(self.context, instance, "fakehost",
fake_post, fake_recover, False,
fake_post, fake_recover, True,
migrate_data)
class AnyEventletEvent(object):
@ -7266,12 +7264,12 @@ class LibvirtConnTestCase(test.NoDBTestCase):
mock_thread.assert_called_once_with(
drvr._live_migration_operation,
self.context, instance, "fakehost", False,
self.context, instance, "fakehost", True,
migrate_data, dom)
mock_monitor.assert_called_once_with(
self.context, instance, guest, "fakehost",
fake_post, fake_recover, False,
migrate_data, dom, AnyEventletEvent())
fake_post, fake_recover, True,
migrate_data, dom, AnyEventletEvent(), disk_paths)
def _do_test_create_images_and_backing(self, disk_type):
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)

View File

@ -5828,12 +5828,12 @@ class LibvirtDriver(driver.ComputeDriver):
disks.append(dev.source_path)
return disks
def _live_migration_data_gb(self, instance, guest, block_migration):
def _live_migration_data_gb(self, instance, disk_paths):
'''Calculate total amount of data to be transferred
:param instance: the nova.objects.Instance being migrated
:param guest: the Guest being migrated
:param block_migration: true if block migration is requested
:param disk_paths: list of disk paths that are being migrated
with instance
Calculates the total amount of data that needs to be
transferred during the live migration. The actual
@ -5849,12 +5849,8 @@ class LibvirtDriver(driver.ComputeDriver):
if ram_gb < 2:
ram_gb = 2
if not block_migration:
return ram_gb
paths = self._live_migration_copy_disk_paths(guest)
disk_gb = 0
for path in paths:
for path in disk_paths:
try:
size = os.stat(path).st_size
size_gb = (size / units.Gi)
@ -5872,9 +5868,9 @@ class LibvirtDriver(driver.ComputeDriver):
def _live_migration_monitor(self, context, instance, guest,
dest, post_method,
recover_method, block_migration,
migrate_data, dom, finish_event):
data_gb = self._live_migration_data_gb(instance, guest,
block_migration)
migrate_data, dom, finish_event,
disk_paths):
data_gb = self._live_migration_data_gb(instance, disk_paths)
downtime_steps = list(self._migration_downtime_steps(data_gb))
completion_timeout = int(
CONF.libvirt.live_migration_completion_timeout * data_gb)
@ -6087,6 +6083,11 @@ class LibvirtDriver(driver.ComputeDriver):
guest = self._host.get_guest(instance)
disk_paths = []
if block_migration:
disk_paths = self._live_migration_copy_disk_paths(
context, instance, guest)
# TODO(sahid): We are converting all calls from a
# virDomain object to use nova.virt.libvirt.Guest.
# We should be able to remove dom at the end.
@ -6114,7 +6115,7 @@ class LibvirtDriver(driver.ComputeDriver):
self._live_migration_monitor(context, instance, guest, dest,
post_method, recover_method,
block_migration, migrate_data,
dom, finish_event)
dom, finish_event, disk_paths)
except Exception as ex:
LOG.warn(_LW("Error monitoring migration: %(ex)s"),
{"ex": ex}, instance=instance, exc_info=True)