[lxc-devel] [lxd/master] Storage migration volume pre-filler

tomponline on Github lxc-bot at linuxcontainers.org
Thu Dec 5 09:24:02 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1022 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191205/3897b814/attachment-0001.bin>
-------------- next part --------------
From 2bce8df7fe9c0b583536dd1a4847e031997b5092 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Dec 2019 09:16:29 +0000
Subject: [PATCH 1/7] lxd/storage/drivers/driver/types: Moves Info definition
 and adds VolumeFiller type

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_types.go | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 lxd/storage/drivers/driver_types.go

diff --git a/lxd/storage/drivers/driver_types.go b/lxd/storage/drivers/driver_types.go
new file mode 100644
index 0000000000..61c5dd6084
--- /dev/null
+++ b/lxd/storage/drivers/driver_types.go
@@ -0,0 +1,21 @@
+package drivers
+
+// Info represents information about a storage driver.
+type Info struct {
+	Name                  string
+	Version               string
+	VolumeTypes           []VolumeType // Supported volume types.
+	Remote                bool         // Whether the driver uses a remote backing store.
+	OptimizedImages       bool         // Whether driver stores images as separate volume.
+	PreservesInodes       bool         // Whether driver preserves inodes when volumes are moved hosts.
+	BlockBacking          bool         // Whether driver uses block devices as backing store.
+	RunningQuotaResize    bool         // Whether quota resize is supported whilst instance running.
+	RunningSnapshotFreeze bool         // Whether instance should be frozen during snapshot if running.
+}
+
+// VolumeFiller provides a struct for filling a volume.
+type VolumeFiller struct {
+	Fill func(mountPath, rootBlockPath string) error // Function to fill the volume.
+
+	Fingerprint string // If the Filler will unpack an image, it should be this fingerprint.
+}

From adcdceb9d1532e20817bc8d23f8fbc51b25f8048 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Dec 2019 09:17:19 +0000
Subject: [PATCH 2/7] lxd/storage/drivers/load: Removes non-load related types
 from this file

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/load.go | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/lxd/storage/drivers/load.go b/lxd/storage/drivers/load.go
index 3f851a90bc..84e8dc2cc7 100644
--- a/lxd/storage/drivers/load.go
+++ b/lxd/storage/drivers/load.go
@@ -27,19 +27,6 @@ func Load(state *state.State, driverName string, name string, config map[string]
 	return d, nil
 }
 
-// Info represents information about a storage driver.
-type Info struct {
-	Name                  string
-	Version               string
-	VolumeTypes           []VolumeType // Supported volume types.
-	Remote                bool         // Whether the driver uses a remote backing store.
-	OptimizedImages       bool         // Whether driver stores images as separate volume.
-	PreservesInodes       bool         // Whether driver preserves inodes when volumes are moved hosts.
-	BlockBacking          bool         // Whether driver uses block devices as backing store.
-	RunningQuotaResize    bool         // Whether quota resize is supported whilst instance running.
-	RunningSnapshotFreeze bool         // Whether instance should be frozen during snapshot if running.
-}
-
 // SupportedDrivers returns a list of supported storage drivers.
 func SupportedDrivers() []Info {
 	supportedDrivers := []Info{}

From ca0dac25b7a46bdd98a5d1b4a5c29e56c6c3860e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Dec 2019 09:17:45 +0000
Subject: [PATCH 3/7] lxd/storage/drivers/interface: Updates
 CreateVolumeFromMigration and CreateVolume to use VolumeFiller

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/interface.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lxd/storage/drivers/interface.go b/lxd/storage/drivers/interface.go
index 8297b2d7b9..bc2c4cca36 100644
--- a/lxd/storage/drivers/interface.go
+++ b/lxd/storage/drivers/interface.go
@@ -34,7 +34,7 @@ type Driver interface {
 
 	// Volumes.
 	ValidateVolume(vol Volume, removeUnknownKeys bool) error
-	CreateVolume(vol Volume, filler func(mountPath, rootBlockPath string) error, op *operations.Operation) error
+	CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Operation) error
 	CreateVolumeFromCopy(vol Volume, srcVol Volume, copySnapshots bool, op *operations.Operation) error
 	RefreshVolume(vol Volume, srcVol Volume, srcSnapshots []Volume, op *operations.Operation) error
 	DeleteVolume(volType VolumeType, volName string, op *operations.Operation) error
@@ -69,7 +69,7 @@ type Driver interface {
 	// Migration.
 	MigrationTypes(contentType ContentType) []migration.Type
 	MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migration.VolumeSourceArgs, op *operations.Operation) error
-	CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, op *operations.Operation) error
+	CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error
 
 	// Backup.
 	BackupVolume(vol Volume, targetPath string, optimized bool, snapshots bool, op *operations.Operation) error

From 7f84989bf39455a10402d127463aa572531fdaf0 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Dec 2019 09:18:38 +0000
Subject: [PATCH 4/7] lxd/storage/drivers/driver/cephfs: Updates
 CreateVolumeFromMigration and CreateVolume to use VolumeFiller

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_cephfs.go | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/lxd/storage/drivers/driver_cephfs.go b/lxd/storage/drivers/driver_cephfs.go
index 75e589ea68..3568d00d42 100644
--- a/lxd/storage/drivers/driver_cephfs.go
+++ b/lxd/storage/drivers/driver_cephfs.go
@@ -313,7 +313,7 @@ func (d *cephfs) GetVolumeDiskPath(volType VolumeType, volName string) (string,
 	return "", ErrNotImplemented
 }
 
-func (d *cephfs) CreateVolume(vol Volume, filler func(mountPath, rootBlockPath string) error, op *operations.Operation) error {
+func (d *cephfs) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Operation) error {
 	if vol.volType != VolumeTypeCustom {
 		return fmt.Errorf("Volume type not supported")
 	}
@@ -336,8 +336,9 @@ func (d *cephfs) CreateVolume(vol Volume, filler func(mountPath, rootBlockPath s
 		}
 	}()
 
-	if filler != nil {
-		err = filler(volPath, "")
+	if filler != nil && filler.Fill != nil {
+		d.logger.Debug("Running filler function")
+		err = filler.Fill(volPath, "")
 		if err != nil {
 			return err
 		}
@@ -824,7 +825,7 @@ func (d *cephfs) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs m
 	}, op)
 }
 
-func (d *cephfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, op *operations.Operation) error {
+func (d *cephfs) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error {
 	if vol.volType != VolumeTypeCustom {
 		return fmt.Errorf("Volume type not supported")
 	}

From 76289e3afa79cd1ef224ab5d40d62f432753d17b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Dec 2019 09:19:15 +0000
Subject: [PATCH 5/7] lxd/storage/drivers/driver/dir: Updates CreateVolume to
 use VolumeFiller

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_dir.go | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go
index 7d8a0563bd..4a08a3871d 100644
--- a/lxd/storage/drivers/driver_dir.go
+++ b/lxd/storage/drivers/driver_dir.go
@@ -220,7 +220,7 @@ func (d *dir) setupInitialQuota(vol Volume) (func(), error) {
 
 // CreateVolume creates an empty volume and can optionally fill it by executing the supplied
 // filler function.
-func (d *dir) CreateVolume(vol Volume, filler func(mountPath, rootBlockPath string) error, op *operations.Operation) error {
+func (d *dir) CreateVolume(vol Volume, filler *VolumeFiller, op *operations.Operation) error {
 	volPath := vol.MountPath()
 	err := vol.CreateMountPath()
 	if err != nil {
@@ -258,8 +258,9 @@ func (d *dir) CreateVolume(vol Volume, filler func(mountPath, rootBlockPath stri
 	}
 
 	// Run the volume filler function if supplied.
-	if filler != nil {
-		err = filler(volPath, rootBlockPath)
+	if filler != nil && filler.Fill != nil {
+		d.logger.Debug("Running filler function")
+		err = filler.Fill(volPath, rootBlockPath)
 		if err != nil {
 			return err
 		}

From 35f8fa5dc31325589e108c9eff4021907eabb997 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Dec 2019 09:19:45 +0000
Subject: [PATCH 6/7] lxd/storage/drivers/driver/dir: Updates
 CreateVolumeFromMigration to accept a pre-VolumeFiller argument

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/drivers/driver_dir.go | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/lxd/storage/drivers/driver_dir.go b/lxd/storage/drivers/driver_dir.go
index 4a08a3871d..194dc96665 100644
--- a/lxd/storage/drivers/driver_dir.go
+++ b/lxd/storage/drivers/driver_dir.go
@@ -350,7 +350,7 @@ func (d *dir) MigrateVolume(vol Volume, conn io.ReadWriteCloser, volSrcArgs migr
 }
 
 // CreateVolumeFromMigration creates a volume being sent via a migration.
-func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, op *operations.Operation) error {
+func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, volTargetArgs migration.VolumeTargetArgs, preFiller *VolumeFiller, op *operations.Operation) error {
 	if vol.contentType != ContentTypeFS {
 		return fmt.Errorf("Content type not supported")
 	}
@@ -391,6 +391,16 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 	err = vol.MountTask(func(mountPath string, op *operations.Operation) error {
 		path := shared.AddSlash(mountPath)
 
+		// Run the volume pre-filler function if supplied.
+		if preFiller != nil && preFiller.Fill != nil {
+			d.logger.Debug("Running pre-filler function", log.Ctx{"volume": vol.name, "path": path})
+			err = preFiller.Fill(path, "")
+			if err != nil {
+				return err
+			}
+			d.logger.Debug("Finished pre-filler function", log.Ctx{"volume": vol.name})
+		}
+
 		// Snapshots are sent first by the sender, so create these first.
 		for _, snapName := range volTargetArgs.Snapshots {
 			// Receive the snapshot
@@ -399,6 +409,7 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 				wrapper = migration.ProgressTracker(op, "fs_progress", snapName)
 			}
 
+			d.logger.Debug("Receiving volume", log.Ctx{"volume": vol.name, "snapshot": snapName, "path": path})
 			err = rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features)
 			if err != nil {
 				return err
@@ -432,6 +443,7 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 			wrapper = migration.ProgressTracker(op, "fs_progress", vol.name)
 		}
 
+		d.logger.Debug("Receiving volume", log.Ctx{"volume": vol.name, "path": path})
 		err = rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features)
 		if err != nil {
 			return err
@@ -443,6 +455,7 @@ func (d *dir) CreateVolumeFromMigration(vol Volume, conn io.ReadWriteCloser, vol
 				wrapper = migration.ProgressTracker(op, "fs_progress", vol.name)
 			}
 
+			d.logger.Debug("Receiving volume (final stage)", log.Ctx{"vol": vol.name, "path": path})
 			err = rsync.Recv(path, conn, wrapper, volTargetArgs.MigrationType.Features)
 			if err != nil {
 				return err

From 99872c5a27437f2bbc8a7eb1cbc5e0f013b5e065 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 5 Dec 2019 09:20:21 +0000
Subject: [PATCH 7/7] lxd/storage/backend/lxd: Updates to use VolumeFillers

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/backend_lxd.go | 37 +++++++++++++++++++++++++++++++------
 1 file changed, 31 insertions(+), 6 deletions(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index 8173a7a450..c6f40d6345 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -761,7 +761,12 @@ func (b *lxdBackend) CreateInstanceFromImage(inst instance.Instance, fingerprint
 	// If the driver doesn't support optimized image volumes then create a new empty volume and
 	// populate it with the contents of the image archive.
 	if !b.driver.Info().OptimizedImages {
-		err = b.driver.CreateVolume(vol, b.imageFiller(fingerprint, op), op)
+		volFiller := drivers.VolumeFiller{
+			Fingerprint: fingerprint,
+			Fill:        b.imageFiller(fingerprint, op),
+		}
+
+		err = b.driver.CreateVolume(vol, &volFiller, op)
 		if err != nil {
 			return err
 		}
@@ -832,7 +837,10 @@ func (b *lxdBackend) CreateInstanceFromMigration(inst instance.Instance, conn io
 
 	vol := b.newVolume(volType, contentType, volStorageName, args.Config)
 
+	var preFiller drivers.VolumeFiller
+
 	revert := true
+
 	if !args.Refresh {
 		defer func() {
 			if !revert {
@@ -842,7 +850,7 @@ func (b *lxdBackend) CreateInstanceFromMigration(inst instance.Instance, conn io
 		}()
 
 		// If the negotiated migration method is rsync and the instance's base image is
-		// already on the host then pre-create the instance's volume using the local image
+		// already on the host then setup a pre-filler that will unpack the local image
 		// to try and speed up the rsync of the incoming volume by avoiding the need to
 		// transfer the base image files too.
 		if args.MigrationType.FSType == migration.MigrationFSType_RSYNC {
@@ -854,7 +862,18 @@ func (b *lxdBackend) CreateInstanceFromMigration(inst instance.Instance, conn io
 
 			if err == nil {
 				logger.Debug("Using optimised migration from existing image", log.Ctx{"fingerprint": fingerprint})
-				err = b.driver.CreateVolume(vol, b.imageFiller(fingerprint, op), op)
+
+				// Populate the volume filler with the fingerprint and image filler
+				// function that can be used by the driver to pre-populate the
+				// volume with the contents of the image.
+				preFiller = drivers.VolumeFiller{
+					Fingerprint: fingerprint,
+					Fill:        b.imageFiller(fingerprint, op),
+				}
+
+				// Ensure if the image doesn't yet exist on a driver which supports
+				// optimized storage, then it gets created first.
+				err = b.EnsureImage(preFiller.Fingerprint, op)
 				if err != nil {
 					return err
 				}
@@ -862,7 +881,7 @@ func (b *lxdBackend) CreateInstanceFromMigration(inst instance.Instance, conn io
 		}
 	}
 
-	err = b.driver.CreateVolumeFromMigration(vol, conn, args, op)
+	err = b.driver.CreateVolumeFromMigration(vol, conn, args, &preFiller, op)
 	if err != nil {
 		conn.Close()
 		return err
@@ -1507,7 +1526,13 @@ func (b *lxdBackend) EnsureImage(fingerprint string, op *operations.Operation) e
 
 	// Create the new image volume. No config for an image volume so set to nil.
 	imgVol := b.newVolume(drivers.VolumeTypeImage, contentType, fingerprint, nil)
-	err = b.driver.CreateVolume(imgVol, b.imageFiller(fingerprint, op), op)
+
+	volFiller := drivers.VolumeFiller{
+		Fingerprint: fingerprint,
+		Fill:        b.imageFiller(fingerprint, op),
+	}
+
+	err = b.driver.CreateVolume(imgVol, &volFiller, op)
 	if err != nil {
 		return err
 	}
@@ -1816,7 +1841,7 @@ func (b *lxdBackend) CreateCustomVolumeFromMigration(conn io.ReadWriteCloser, ar
 	}
 
 	vol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentTypeFS, args.Name, args.Config)
-	err = b.driver.CreateVolumeFromMigration(vol, conn, args, op)
+	err = b.driver.CreateVolumeFromMigration(vol, conn, args, nil, op)
 	if err != nil {
 		conn.Close()
 		return err


More information about the lxc-devel mailing list