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

Reply via email to