The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6555
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Adds a new type called `VolumeFiller` which contains a filler function and an optional image fingerprint string. This is then used by `CreateVolume` for volume filling, but also specifically `CreateVolumeFromMigration` to support a pre-filler optimisation when using Rsync and `dir` driver for migration. If the base image exists on the target, the new volume will be pre-filled from the image before performing the rsync in an attempt to reduce the amount of data needing to be transferred over the network. By supplying the image fingerprint in the VolumeFiller as well, other storage drivers that use optimised volumes can check if the volume exists first and then just create a volume from that existing volume.
From 2bce8df7fe9c0b583536dd1a4847e031997b5092 Mon Sep 17 00:00:00 2001 From: Thomas Parrott <thomas.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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.parr...@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
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel