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
This commit is contained in:
Nick Craig-Wood 2022-08-01 17:51:46 +01:00
parent 639624184d
commit a875320e37
2 changed files with 20 additions and 8 deletions

View File

@ -1952,11 +1952,17 @@ func moveOrCopyFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName str
return err return err
} }
} }
NoNeedTransfer, err := CompareOrCopyDest(ctx, fdst, dstObj, srcObj, copyDestDir, backupDir) needTransfer := NeedTransfer(ctx, dstObj, srcObj)
if err != nil { if needTransfer {
return err 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 destination already exists, then we must move it into --backup-dir if required
if dstObj != nil && backupDir != nil { if dstObj != nil && backupDir != nil {
err = MoveBackupDir(ctx, backupDir, dstObj) err = MoveBackupDir(ctx, backupDir, dstObj)

View File

@ -331,11 +331,17 @@ func (s *syncCopyMove) pairChecker(in *pipe, out *pipe, fraction int, wg *sync.W
tr := accounting.Stats(s.ctx).NewCheckingTransfer(src) tr := accounting.Stats(s.ctx).NewCheckingTransfer(src)
// Check to see if can store this // Check to see if can store this
if src.Storable() { if src.Storable() {
NoNeedTransfer, err := operations.CompareOrCopyDest(s.ctx, s.fdst, pair.Dst, pair.Src, s.compareCopyDest, s.backupDir) needTransfer := operations.NeedTransfer(s.ctx, pair.Dst, pair.Src)
if err != nil { if needTransfer {
s.processError(err) 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 files are treated as immutable, fail if destination exists and does not match
if s.ci.Immutable && pair.Dst != nil { if s.ci.Immutable && pair.Dst != nil {
err := fs.CountError(fserrors.NoRetryError(fs.ErrorImmutableModified)) err := fs.CountError(fserrors.NoRetryError(fs.ErrorImmutableModified))