From a0d60ee00f2b88dfb984583c4ceb67b9bbeff05a Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 6 Nov 2026 01:28:09 -0800 Subject: [PATCH] filer.remote.sync: say that any saved offset wins over the creation time The creation time in seconds was compared with the offset in milliseconds, which made any saved offset win. That is the behaviour to keep: remote.unmount recreates the directory and then saves the offset, usually in the same second, so a seconds comparison would start at the creation second and replay the purge. The comparison now states it. Co-Authored-By: Claude Opus 5.5 --- weed/command/filer_remote_sync_dir.go | 4 +++- weed/command/filer_remote_sync_dir_test.go | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/weed/command/filer_remote_sync_dir.go b/weed/command/filer_remote_sync_dir.go index 99986e94e5..5e3cd8cd5c 100644 --- a/weed/command/filer_remote_sync_dir.go +++ b/weed/command/filer_remote_sync_dir.go @@ -1145,7 +1145,9 @@ func resolveLastSyncOffset(mountedDir string, timeAgo time.Duration, lookupMount return time.Time{}, fmt.Errorf("read the sync offset of %s: %w", mountedDir, err) } if mountedDirEntry != nil { - if mountedDirEntry.Attributes.Crtime < lastOffsetTsNs/1000000 { + // a saved offset wins even over a newer creation time: remote.unmount + // saves one after recreating the directory, often in the same second + if lastOffsetTsNs > 0 { lastOffsetTs = time.Unix(0, lastOffsetTsNs) glog.V(0).Infof("resume from %v", lastOffsetTs) } else { diff --git a/weed/command/filer_remote_sync_dir_test.go b/weed/command/filer_remote_sync_dir_test.go index 1275f44c78..0c2d65c90e 100644 --- a/weed/command/filer_remote_sync_dir_test.go +++ b/weed/command/filer_remote_sync_dir_test.go @@ -658,6 +658,17 @@ func TestResolveLastSyncOffsetKeepsTheSavedOffsetWhenTheLookupFails(t *testing.T if !got.Equal(saved) { t.Fatalf("resolved %v, want %v", got, saved) } + + // remote.unmount recreates the directory, then saves the offset in the same + // second: starting at the creation second would replay the unmount's purge + unmounted := &filer_pb.Entry{Name: "x", Attributes: &filer_pb.FuseAttributes{Crtime: saved.Unix()}} + got, err = resolveLastSyncOffset("/buckets/x", 0, func() (*filer_pb.Entry, error) { return unmounted, nil }, savedOffset) + if err != nil { + t.Fatal(err) + } + if !got.Equal(saved) { + t.Fatalf("resolved %v, want the saved offset %v", got, saved) + } } func TestResolveLastSyncOffsetReturnsTheErrorToTheRetryLoop(t *testing.T) {