From a875320e37a6eb349899f4f6058ed0c692d92a60 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 1 Aug 2022 17:51:46 +0100 Subject: [PATCH] sync,operations: optimise --copy-dest and --compare-dest Before this change --compare-dest and --copy-dest would check to see if the compare/copy object existed first, before seeing if the destination object was present. This is inefficient, because in most --copy-dest syncs the destination will be present and the compare/copy object need never be tested. --compare-dest syncs may also be speeded up if they are done to the same directory repeatedly. This fixes the problem by re-arranging the logic so if the transfer is not needed then the compare/copy object is never tested. See: https://forum.rclone.org/t/union-with-copy-dest-enabled-is-slower-than-expected/32172 --- fs/operations/operations.go | 14 ++++++++++---- fs/sync/sync.go | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/fs/operations/operations.go b/fs/operations/operations.go index a02aead24..081ceb7a7 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -1952,11 +1952,17 @@ func moveOrCopyFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName str return err } } - NoNeedTransfer, err := CompareOrCopyDest(ctx, fdst, dstObj, srcObj, copyDestDir, backupDir) - if err != nil { - return err + needTransfer := NeedTransfer(ctx, dstObj, srcObj) + if needTransfer { + NoNeedTransfer, err := CompareOrCopyDest(ctx, fdst, dstObj, srcObj, copyDestDir, backupDir) + if err != nil { + return err + } + if NoNeedTransfer { + needTransfer = false + } } - if !NoNeedTransfer && NeedTransfer(ctx, dstObj, srcObj) { + if needTransfer { // If destination already exists, then we must move it into --backup-dir if required if dstObj != nil && backupDir != nil { err = MoveBackupDir(ctx, backupDir, dstObj) diff --git a/fs/sync/sync.go b/fs/sync/sync.go index 052b867e8..2c671cf72 100644 --- a/fs/sync/sync.go +++ b/fs/sync/sync.go @@ -331,11 +331,17 @@ func (s *syncCopyMove) pairChecker(in *pipe, out *pipe, fraction int, wg *sync.W tr := accounting.Stats(s.ctx).NewCheckingTransfer(src) // Check to see if can store this if src.Storable() { - NoNeedTransfer, err := operations.CompareOrCopyDest(s.ctx, s.fdst, pair.Dst, pair.Src, s.compareCopyDest, s.backupDir) - if err != nil { - s.processError(err) + needTransfer := operations.NeedTransfer(s.ctx, pair.Dst, pair.Src) + if needTransfer { + NoNeedTransfer, err := operations.CompareOrCopyDest(s.ctx, s.fdst, pair.Dst, pair.Src, s.compareCopyDest, s.backupDir) + if err != nil { + s.processError(err) + } + if NoNeedTransfer { + needTransfer = false + } } - if !NoNeedTransfer && operations.NeedTransfer(s.ctx, pair.Dst, pair.Src) { + if needTransfer { // If files are treated as immutable, fail if destination exists and does not match if s.ci.Immutable && pair.Dst != nil { err := fs.CountError(fserrors.NoRetryError(fs.ErrorImmutableModified))