diff --git a/weed/command/filer_remote_sync_dir.go b/weed/command/filer_remote_sync_dir.go index 89b3237c6a..53c9b01161 100644 --- a/weed/command/filer_remote_sync_dir.go +++ b/weed/command/filer_remote_sync_dir.go @@ -1105,7 +1105,8 @@ func collectLastSyncOffset(filerClient filer_pb.FilerClient, grpcDialOption grpc // 3. the directory's creation time // A mount lookup that fails never resolves to now: the saved offset still // orders the replay, and without one the error goes back to the caller's -// retry loop instead of skipping every event since the failure. +// retry loop instead of skipping every event since the failure. Only a +// directory that does not exist yet, with no saved offset, starts now. func resolveLastSyncOffset(mountedDir string, timeAgo time.Duration, lookupMount func() (*filer_pb.Entry, error), readOffset func() (int64, error)) (time.Time, error) { var lastOffsetTs time.Time if timeAgo == 0 { @@ -1116,6 +1117,9 @@ func resolveLastSyncOffset(mountedDir string, timeAgo time.Duration, lookupMount glog.V(0).Infof("get mounted directory %s: %v; resume from the saved offset %v", mountedDir, err, time.Unix(0, lastOffsetTsNs)) return time.Unix(0, lastOffsetTsNs), nil } + if offsetErr == nil && errors.Is(err, filer_pb.ErrNotFound) { + return time.Now(), nil + } return time.Time{}, fmt.Errorf("get mounted directory %s: %w; no saved sync offset (%v)", mountedDir, err, offsetErr) } diff --git a/weed/command/filer_remote_sync_dir_test.go b/weed/command/filer_remote_sync_dir_test.go index cb92943f4d..54ff161958 100644 --- a/weed/command/filer_remote_sync_dir_test.go +++ b/weed/command/filer_remote_sync_dir_test.go @@ -670,6 +670,13 @@ 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) } + // no directory and no saved offset yet: a first run starts now + started := time.Now() + notFound := func() (*filer_pb.Entry, error) { return nil, fmt.Errorf("lookup /buckets: %w", filer_pb.ErrNotFound) } + if got, err := resolveLastSyncOffset("/buckets", 0, notFound, noOffset); err != nil || got.Before(started) { + t.Fatalf("got %v, %v; want now and no error before the directory exists", got, 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") {