# UNDF: UNDF-2026-000001024 --- a/cmd/bisync/listing.go +++ b/cmd/bisync/listing.go @@ -727,8 +727,14 @@ func (b *bisyncRun) recheck(ctxRecheck context.Context, src, dst fs.Fs, srcList, var srcObjs []fs.Object var dstObjs []fs.Object - var resolved []string var toRollback []string + resolvedSet := make(map[string]struct{}) + + // Build a map from dstObj.Remote() to dstObj for O(1) lookup + // instead of O(S*D) nested loop + dstByRemote := make(map[string]fs.Object) + dstByAlias := make(map[string]fs.Object) if err := operations.ListFn(ctxRecheck, src, func(obj fs.Object) { srcObjs = append(srcObjs, obj) @@ -740,29 +746,33 @@ func (b *bisyncRun) recheck(ctxRecheck context.Context, src, dst fs.Fs, srcList, fs.Debugf(dst, "error recchecking dst obj: %v", err) } + for _, dstObj := range dstObjs { + dstByRemote[dstObj.Remote()] = dstObj + alias := b.aliases.Alias(dstObj.Remote()) + if alias != dstObj.Remote() { + dstByAlias[alias] = dstObj + } + } + putObj := func(obj fs.Object, list *fileList) { hashVal := "" if !b.opt.IgnoreListingChecksum { @@ -760,18 +770,20 @@ func (b *bisyncRun) recheck(ctxRecheck context.Context, src, dst fs.Fs, srcList, for _, srcObj := range srcObjs { fs.Debugf(srcObj, "rechecking") - for _, dstObj := range dstObjs { - if srcObj.Remote() == dstObj.Remote() || srcObj.Remote() == b.aliases.Alias(dstObj.Remote()) { - // note: unlike Equal(), WhichEqual() does not update the modtime in dest if sums match but modtimes don't. - if b.opt.DryRun || b.WhichEqual(ctxRecheck, srcObj, dstObj, src, dst) { - putObj(srcObj, srcList) - putObj(dstObj, dstList) - resolved = append(resolved, srcObj.Remote()) - } else { - fs.Infof(srcObj, "files not equal on recheck: %v %v", srcObj, dstObj) - } + remote := srcObj.Remote() + dstObj, found := dstByRemote[remote] + if !found { + dstObj, found = dstByAlias[remote] + } + if found { + // note: unlike Equal(), WhichEqual() does not update the modtime in dest if sums match but modtimes don't. + if b.opt.DryRun || b.WhichEqual(ctxRecheck, srcObj, dstObj, src, dst) { + putObj(srcObj, srcList) + putObj(dstObj, dstList) + resolvedSet[remote] = struct{}{} + } else { + fs.Infof(srcObj, "files not equal on recheck: %v %v", srcObj, dstObj) } } - // if srcObj not resolved by now (either because no dstObj match or files not equal), - // roll it back to old version, so it gets retried next time. - // skip and error during --resync, as rollback is not possible - if !slices.Contains(resolved, srcObj.Remote()) && !b.opt.DryRun { + if _, ok := resolvedSet[remote]; !ok && !b.opt.DryRun { if b.opt.Resync { err := errors.New("no dstObj match or files not equal") b.handleErr(srcObj, "Unable to rollback during --resync", err, true, false)