From 0a1b6c2944fe5e491b861f85a8bc070d00b5d22f Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Fri, 6 Nov 2026 01:07:52 -0800 Subject: [PATCH] filer.remote.sync: an unread offset never resolves to the mount's creation time With the offset read now bounded, a timed-out read fell through to the directory's creation time and replayed every event already synced. The error goes back to the startup retry loop, as with -timeAgo; a missing offset still reads as zero without an error. Co-Authored-By: Claude Opus 5.5 --- weed/command/filer_remote_sync_dir.go | 5 ++++- weed/command/filer_remote_sync_dir_test.go | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/weed/command/filer_remote_sync_dir.go b/weed/command/filer_remote_sync_dir.go index b5c97af92a..132ddae395 100644 --- a/weed/command/filer_remote_sync_dir.go +++ b/weed/command/filer_remote_sync_dir.go @@ -1120,8 +1120,11 @@ func resolveLastSyncOffset(mountedDir string, timeAgo time.Duration, lookupMount } lastOffsetTsNs, err := readOffset() + if err != nil { + return time.Time{}, fmt.Errorf("read the sync offset of %s: %w", mountedDir, err) + } if mountedDirEntry != nil { - if err == nil && mountedDirEntry.Attributes.Crtime < lastOffsetTsNs/1000000 { + if mountedDirEntry.Attributes.Crtime < lastOffsetTsNs/1000000 { 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 ccbd25166b..4eb9740edf 100644 --- a/weed/command/filer_remote_sync_dir_test.go +++ b/weed/command/filer_remote_sync_dir_test.go @@ -665,6 +665,12 @@ func TestResolveLastSyncOffsetReturnsTheErrorToTheRetryLoop(t *testing.T) { t.Fatalf("got %v, want the lookup error: without a saved offset the caller's retry loop decides, not an exit", err) } + // the mount answers but the saved offset is unreadable: never its creation time + mount := &filer_pb.Entry{Name: "x", Attributes: &filer_pb.FuseAttributes{Crtime: 1}} + if _, err := resolveLastSyncOffset("/buckets/x", 0, func() (*filer_pb.Entry, error) { return mount, nil }, readFails); err == nil || !strings.Contains(err.Error(), "filer unavailable") { + t.Fatalf("got %v, want the offset read error: the creation time would replay everything already synced", err) + } + // -timeAgo set, the saved offset unreadable: never now minus timeAgo if _, err := resolveLastSyncOffset("/buckets/x", time.Hour, func() (*filer_pb.Entry, error) { return nil, nil }, readFails); err == nil || !strings.Contains(err.Error(), "filer unavailable") { t.Fatalf("got %v, want the offset read error", err)