From ae9c0e56c893869cacf739a12a68453d89046d6d Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Sat, 10 Aug 2019 10:28:26 +0100 Subject: [PATCH] operations: run hashing operations in parallel #3419 Before this change for a post copy Hash check we would run the hashes sequentially. Now we run the hashes in parallel for a useful speedup. Note that this refactors the hash check in Copy to use the standard hash checking routine. --- fs/operations/operations.go | 68 ++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/fs/operations/operations.go b/fs/operations/operations.go index 81c723174..28d7c0499 100644 --- a/fs/operations/operations.go +++ b/fs/operations/operations.go @@ -51,30 +51,46 @@ func CheckHashes(ctx context.Context, src fs.ObjectInfo, dst fs.Object) (equal b if common.Count() == 0 { return true, hash.None, nil } - ht = common.GetOne() - srcHash, err := src.Hash(ctx, ht) + equal, ht, _, _, err = checkHashes(ctx, src, dst, common.GetOne()) + return equal, ht, err +} + +// checkHashes does the work of CheckHashes but takes a hash.Type and +// returns the effective hash type used. +func checkHashes(ctx context.Context, src fs.ObjectInfo, dst fs.Object, ht hash.Type) (equal bool, htOut hash.Type, srcHash, dstHash string, err error) { + // Calculate hashes in parallel + g, ctx := errgroup.WithContext(ctx) + g.Go(func() (err error) { + srcHash, err = src.Hash(ctx, ht) + if err != nil { + fs.CountError(err) + fs.Errorf(src, "Failed to calculate src hash: %v", err) + } + return err + }) + g.Go(func() (err error) { + dstHash, err = dst.Hash(ctx, ht) + if err != nil { + fs.CountError(err) + fs.Errorf(dst, "Failed to calculate dst hash: %v", err) + } + return err + }) + err = g.Wait() if err != nil { - fs.CountError(err) - fs.Errorf(src, "Failed to calculate src hash: %v", err) - return false, ht, err + return false, ht, srcHash, dstHash, err } if srcHash == "" { - return true, hash.None, nil - } - dstHash, err := dst.Hash(ctx, ht) - if err != nil { - fs.CountError(err) - fs.Errorf(dst, "Failed to calculate dst hash: %v", err) - return false, ht, err + return true, hash.None, srcHash, dstHash, nil } if dstHash == "" { - return true, hash.None, nil + return true, hash.None, srcHash, dstHash, nil } if srcHash != dstHash { fs.Debugf(src, "%v = %s (%v)", ht, srcHash, src.Fs()) fs.Debugf(dst, "%v = %s (%v)", ht, dstHash, dst.Fs()) } - return srcHash == dstHash, ht, nil + return srcHash == dstHash, ht, srcHash, dstHash, nil } // Equal checks to see if the src and dst objects are equal by looking at @@ -377,24 +393,14 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj // Verify hashes are the same after transfer - ignoring blank hashes if !fs.Config.IgnoreChecksum && hashType != hash.None { - var srcSum string - srcSum, err = src.Hash(ctx, hashType) - if err != nil { + // checkHashes has logged and counted errors + equal, _, srcSum, dstSum, _ := checkHashes(ctx, src, dst, hashType) + if !equal { + err = errors.Errorf("corrupted on transfer: %v hash differ %q vs %q", hashType, srcSum, dstSum) + fs.Errorf(dst, "%v", err) fs.CountError(err) - fs.Errorf(src, "Failed to read src hash: %v", err) - } else if srcSum != "" { - var dstSum string - dstSum, err = dst.Hash(ctx, hashType) - if err != nil { - fs.CountError(err) - fs.Errorf(dst, "Failed to read hash: %v", err) - } else if !hash.Equals(srcSum, dstSum) { - err = errors.Errorf("corrupted on transfer: %v hash differ %q vs %q", hashType, srcSum, dstSum) - fs.Errorf(dst, "%v", err) - fs.CountError(err) - removeFailedCopy(ctx, dst) - return newDst, err - } + removeFailedCopy(ctx, dst) + return newDst, err } }