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) {