Pass the source file information to the Move API of the driver
Signed-off-by: Tejaswini Duggaraju <naduggar@microsoft.com> Format the file using go fmt
This commit is contained in:
parent
ae2e973db9
commit
fa4a8b0a7e
13 changed files with 64 additions and 20 deletions
|
@ -321,7 +321,8 @@ func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor
|
||||||
// the size here and write a zero-length file to blobPath if this is the
|
// the size here and write a zero-length file to blobPath if this is the
|
||||||
// case. For the most part, this should only ever happen with zero-length
|
// case. For the most part, this should only ever happen with zero-length
|
||||||
// blobs.
|
// blobs.
|
||||||
if _, err := bw.blobStore.driver.Stat(ctx, bw.path); err != nil {
|
sourceFileInfo, err := bw.blobStore.driver.Stat(ctx, bw.path)
|
||||||
|
if err != nil {
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
case storagedriver.PathNotFoundError:
|
case storagedriver.PathNotFoundError:
|
||||||
// HACK(stevvooe): This is slightly dangerous: if we verify above,
|
// HACK(stevvooe): This is slightly dangerous: if we verify above,
|
||||||
|
@ -340,11 +341,16 @@ func (bw *blobWriter) moveBlob(ctx context.Context, desc distribution.Descriptor
|
||||||
default:
|
default:
|
||||||
return err // unrelated error
|
return err // unrelated error
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// We will make sure that the size on the blob store matches with the local commited file.
|
||||||
|
if sourceFileInfo.Size() != desc.Size {
|
||||||
|
return distribution.ErrBlobInvalidLength
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(stevvooe): We should also write the mediatype when executing this move.
|
// TODO(stevvooe): We should also write the mediatype when executing this move.
|
||||||
|
|
||||||
return bw.blobStore.driver.Move(ctx, bw.path, blobPath)
|
return bw.blobStore.driver.Move(ctx, bw.path, blobPath, sourceFileInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeResources should clean up all resources associated with the upload
|
// removeResources should clean up all resources associated with the upload
|
||||||
|
|
|
@ -291,11 +291,18 @@ func (d *driver) List(ctx context.Context, path string) ([]string, error) {
|
||||||
|
|
||||||
// Move moves an object stored at sourcePath to destPath, removing the original
|
// Move moves an object stored at sourcePath to destPath, removing the original
|
||||||
// object.
|
// object.
|
||||||
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
srcBlobRef := d.client.GetContainerReference(d.container).GetBlobReference(sourcePath)
|
srcBlobRef := d.client.GetContainerReference(d.container).GetBlobReference(sourcePath)
|
||||||
sourceBlobURL := srcBlobRef.GetURL()
|
sourceBlobURL := srcBlobRef.GetURL()
|
||||||
destBlobRef := d.client.GetContainerReference(d.container).GetBlobReference(destPath)
|
destBlobRef := d.client.GetContainerReference(d.container).GetBlobReference(destPath)
|
||||||
err := destBlobRef.Copy(sourceBlobURL, nil)
|
options := &azure.CopyOptions{}
|
||||||
|
// sourceFileInfo can be nil if the source path is not found. If the file info is available
|
||||||
|
// we will ensure it is unmodified during the move operation.
|
||||||
|
if sourceFileInfo != nil {
|
||||||
|
lastModTime := sourceFileInfo.ModTime()
|
||||||
|
options.Source.IfUnmodifiedSince = &lastModTime
|
||||||
|
}
|
||||||
|
err := destBlobRef.Copy(sourceBlobURL, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if is404(err) {
|
if is404(err) {
|
||||||
return storagedriver.PathNotFoundError{Path: sourcePath}
|
return storagedriver.PathNotFoundError{Path: sourcePath}
|
||||||
|
|
|
@ -181,7 +181,7 @@ func (base *Base) List(ctx context.Context, path string) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move wraps Move of underlying storage driver.
|
// Move wraps Move of underlying storage driver.
|
||||||
func (base *Base) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (base *Base) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
ctx, done := dcontext.WithTrace(ctx)
|
ctx, done := dcontext.WithTrace(ctx)
|
||||||
defer done("%s.Move(%q, %q", base.Name(), sourcePath, destPath)
|
defer done("%s.Move(%q, %q", base.Name(), sourcePath, destPath)
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ func (base *Base) Move(ctx context.Context, sourcePath string, destPath string)
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
err := base.setDriverName(base.StorageDriver.Move(ctx, sourcePath, destPath))
|
err := base.setDriverName(base.StorageDriver.Move(ctx, sourcePath, destPath, sourceFileInfo))
|
||||||
storageAction.WithValues(base.Name(), "Move").UpdateSince(start)
|
storageAction.WithValues(base.Name(), "Move").UpdateSince(start)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,11 +157,11 @@ func (r *regulator) List(ctx context.Context, path string) ([]string, error) {
|
||||||
// original object.
|
// original object.
|
||||||
// Note: This may be no more efficient than a copy followed by a delete for
|
// Note: This may be no more efficient than a copy followed by a delete for
|
||||||
// many implementations.
|
// many implementations.
|
||||||
func (r *regulator) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (r *regulator) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
r.enter()
|
r.enter()
|
||||||
defer r.exit()
|
defer r.exit()
|
||||||
|
|
||||||
return r.StorageDriver.Move(ctx, sourcePath, destPath)
|
return r.StorageDriver.Move(ctx, sourcePath, destPath, sourceFileInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete recursively deletes all objects stored at "path" and its subpaths.
|
// Delete recursively deletes all objects stored at "path" and its subpaths.
|
||||||
|
|
|
@ -252,7 +252,7 @@ func (d *driver) List(ctx context.Context, subPath string) ([]string, error) {
|
||||||
|
|
||||||
// Move moves an object stored at sourcePath to destPath, removing the original
|
// Move moves an object stored at sourcePath to destPath, removing the original
|
||||||
// object.
|
// object.
|
||||||
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
source := d.fullPath(sourcePath)
|
source := d.fullPath(sourcePath)
|
||||||
dest := d.fullPath(destPath)
|
dest := d.fullPath(destPath)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
dcontext "github.com/docker/distribution/context"
|
dcontext "github.com/docker/distribution/context"
|
||||||
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
||||||
|
@ -292,6 +293,13 @@ func TestMoveDirectory(t *testing.T) {
|
||||||
|
|
||||||
ctx := dcontext.Background()
|
ctx := dcontext.Background()
|
||||||
contents := []byte("contents")
|
contents := []byte("contents")
|
||||||
|
sourcePath := "/parent/dir"
|
||||||
|
sourceFileInfo := storagedriver.FileInfoInternal{FileInfoFields: storagedriver.FileInfoFields{
|
||||||
|
Path: sourcePath,
|
||||||
|
Size: int64(len(contents)),
|
||||||
|
ModTime: time.Now(),
|
||||||
|
IsDir: false,
|
||||||
|
}}
|
||||||
// Create a regular file.
|
// Create a regular file.
|
||||||
err = driver.PutContent(ctx, "/parent/dir/foo", contents)
|
err = driver.PutContent(ctx, "/parent/dir/foo", contents)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -304,7 +312,7 @@ func TestMoveDirectory(t *testing.T) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = driver.Move(ctx, "/parent/dir", "/parent/other")
|
err = driver.Move(ctx, sourcePath, "/parent/other", sourceFileInfo)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("Moving directory /parent/dir /parent/other should have return a non-nil error\n")
|
t.Fatalf("Moving directory /parent/dir /parent/other should have return a non-nil error\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ func (d *driver) List(ctx context.Context, path string) ([]string, error) {
|
||||||
|
|
||||||
// Move moves an object stored at sourcePath to destPath, removing the original
|
// Move moves an object stored at sourcePath to destPath, removing the original
|
||||||
// object.
|
// object.
|
||||||
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
d.mutex.Lock()
|
d.mutex.Lock()
|
||||||
defer d.mutex.Unlock()
|
defer d.mutex.Unlock()
|
||||||
|
|
||||||
|
|
|
@ -407,7 +407,7 @@ const maxConcurrency = 10
|
||||||
|
|
||||||
// Move moves an object stored at sourcePath to destPath, removing the original
|
// Move moves an object stored at sourcePath to destPath, removing the original
|
||||||
// object.
|
// object.
|
||||||
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
logrus.Infof("Move from %s to %s", d.ossPath(sourcePath), d.ossPath(destPath))
|
logrus.Infof("Move from %s to %s", d.ossPath(sourcePath), d.ossPath(destPath))
|
||||||
err := d.Bucket.CopyLargeFileInParallel(d.ossPath(sourcePath), d.ossPath(destPath),
|
err := d.Bucket.CopyLargeFileInParallel(d.ossPath(sourcePath), d.ossPath(destPath),
|
||||||
d.getContentType(),
|
d.getContentType(),
|
||||||
|
|
|
@ -696,7 +696,7 @@ func (d *driver) List(ctx context.Context, opath string) ([]string, error) {
|
||||||
|
|
||||||
// Move moves an object stored at sourcePath to destPath, removing the original
|
// Move moves an object stored at sourcePath to destPath, removing the original
|
||||||
// object.
|
// object.
|
||||||
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
/* This is terrible, but aws doesn't have an actual move. */
|
/* This is terrible, but aws doesn't have an actual move. */
|
||||||
if err := d.copy(ctx, sourcePath, destPath); err != nil {
|
if err := d.copy(ctx, sourcePath, destPath); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"gopkg.in/check.v1"
|
"gopkg.in/check.v1"
|
||||||
|
|
||||||
|
@ -303,7 +304,14 @@ func TestMoveWithMultipartCopy(t *testing.T) {
|
||||||
t.Fatalf("unexpected error creating content: %v", err)
|
t.Fatalf("unexpected error creating content: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.Move(ctx, sourcePath, destPath)
|
sourceFileInfo := storagedriver.FileInfoInternal{FileInfoFields: storagedriver.FileInfoFields{
|
||||||
|
Path: sourcePath,
|
||||||
|
Size: int64(len(contents)),
|
||||||
|
ModTime: time.Now(),
|
||||||
|
IsDir: false,
|
||||||
|
}}
|
||||||
|
|
||||||
|
err = d.Move(ctx, sourcePath, destPath, sourceFileInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error moving file: %v", err)
|
t.Fatalf("unexpected error moving file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,10 @@ type StorageDriver interface {
|
||||||
// original object.
|
// original object.
|
||||||
// Note: This may be no more efficient than a copy followed by a delete for
|
// Note: This may be no more efficient than a copy followed by a delete for
|
||||||
// many implementations.
|
// many implementations.
|
||||||
Move(ctx context.Context, sourcePath string, destPath string) error
|
// We will pass along the source file info so the driver can verify the
|
||||||
|
// parity of the moved object.
|
||||||
|
// Note: the source file info can be nil in the case the source path is not found.
|
||||||
|
Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo FileInfo) error
|
||||||
|
|
||||||
// Delete recursively deletes all objects stored at "path" and its subpaths.
|
// Delete recursively deletes all objects stored at "path" and its subpaths.
|
||||||
Delete(ctx context.Context, path string) error
|
Delete(ctx context.Context, path string) error
|
||||||
|
|
|
@ -498,7 +498,7 @@ func (d *driver) List(ctx context.Context, path string) ([]string, error) {
|
||||||
|
|
||||||
// Move moves an object stored at sourcePath to destPath, removing the original
|
// Move moves an object stored at sourcePath to destPath, removing the original
|
||||||
// object.
|
// object.
|
||||||
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) error {
|
func (d *driver) Move(ctx context.Context, sourcePath string, destPath string, sourceFileInfo storagedriver.FileInfo) error {
|
||||||
_, headers, err := d.Conn.Object(d.Container, d.swiftPath(sourcePath))
|
_, headers, err := d.Conn.Object(d.Container, d.swiftPath(sourcePath))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if manifest, ok := headers["X-Object-Manifest"]; ok {
|
if manifest, ok := headers["X-Object-Manifest"]; ok {
|
||||||
|
|
|
@ -514,6 +514,12 @@ func (suite *DriverSuite) TestMove(c *check.C) {
|
||||||
contents := randomContents(32)
|
contents := randomContents(32)
|
||||||
sourcePath := randomPath(32)
|
sourcePath := randomPath(32)
|
||||||
destPath := randomPath(32)
|
destPath := randomPath(32)
|
||||||
|
sourceFileInfo := storagedriver.FileInfoInternal{FileInfoFields: storagedriver.FileInfoFields{
|
||||||
|
Path: sourcePath,
|
||||||
|
Size: int64(len(contents)),
|
||||||
|
ModTime: time.Now(),
|
||||||
|
IsDir: false,
|
||||||
|
}}
|
||||||
|
|
||||||
defer suite.deletePath(c, firstPart(sourcePath))
|
defer suite.deletePath(c, firstPart(sourcePath))
|
||||||
defer suite.deletePath(c, firstPart(destPath))
|
defer suite.deletePath(c, firstPart(destPath))
|
||||||
|
@ -521,7 +527,7 @@ func (suite *DriverSuite) TestMove(c *check.C) {
|
||||||
err := suite.StorageDriver.PutContent(suite.ctx, sourcePath, contents)
|
err := suite.StorageDriver.PutContent(suite.ctx, sourcePath, contents)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath)
|
err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath, sourceFileInfo)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
received, err := suite.StorageDriver.GetContent(suite.ctx, destPath)
|
received, err := suite.StorageDriver.GetContent(suite.ctx, destPath)
|
||||||
|
@ -541,6 +547,12 @@ func (suite *DriverSuite) TestMoveOverwrite(c *check.C) {
|
||||||
destPath := randomPath(32)
|
destPath := randomPath(32)
|
||||||
sourceContents := randomContents(32)
|
sourceContents := randomContents(32)
|
||||||
destContents := randomContents(64)
|
destContents := randomContents(64)
|
||||||
|
sourceFileInfo := storagedriver.FileInfoInternal{FileInfoFields: storagedriver.FileInfoFields{
|
||||||
|
Path: sourcePath,
|
||||||
|
Size: int64(len(sourceContents)),
|
||||||
|
ModTime: time.Now(),
|
||||||
|
IsDir: false,
|
||||||
|
}}
|
||||||
|
|
||||||
defer suite.deletePath(c, firstPart(sourcePath))
|
defer suite.deletePath(c, firstPart(sourcePath))
|
||||||
defer suite.deletePath(c, firstPart(destPath))
|
defer suite.deletePath(c, firstPart(destPath))
|
||||||
|
@ -551,7 +563,7 @@ func (suite *DriverSuite) TestMoveOverwrite(c *check.C) {
|
||||||
err = suite.StorageDriver.PutContent(suite.ctx, destPath, destContents)
|
err = suite.StorageDriver.PutContent(suite.ctx, destPath, destContents)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath)
|
err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath, sourceFileInfo)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
received, err := suite.StorageDriver.GetContent(suite.ctx, destPath)
|
received, err := suite.StorageDriver.GetContent(suite.ctx, destPath)
|
||||||
|
@ -576,7 +588,7 @@ func (suite *DriverSuite) TestMoveNonexistent(c *check.C) {
|
||||||
err := suite.StorageDriver.PutContent(suite.ctx, destPath, contents)
|
err := suite.StorageDriver.PutContent(suite.ctx, destPath, contents)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath)
|
err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath, nil)
|
||||||
c.Assert(err, check.NotNil)
|
c.Assert(err, check.NotNil)
|
||||||
c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
|
c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
|
||||||
c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
|
c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
|
||||||
|
@ -596,7 +608,7 @@ func (suite *DriverSuite) TestMoveInvalid(c *check.C) {
|
||||||
defer suite.deletePath(c, "/notadir")
|
defer suite.deletePath(c, "/notadir")
|
||||||
|
|
||||||
// Now try to move a non-existent file under it.
|
// Now try to move a non-existent file under it.
|
||||||
err = suite.StorageDriver.Move(suite.ctx, "/notadir/foo", "/notadir/bar")
|
err = suite.StorageDriver.Move(suite.ctx, "/notadir/foo", "/notadir/bar", nil)
|
||||||
c.Assert(err, check.NotNil) // non-nil error
|
c.Assert(err, check.NotNil) // non-nil error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue