mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-24 06:50:40 +02:00
filer: bootstrap a timestamp-less peer entry onto a missing local path (#11975)
A zero local commit time conflated 'no local state' with 'state at the epoch', so a missing entry was skipped whenever the sender reported no commit time and the entry mtime was at or before the epoch. Only hold the copy off when a local entry actually exists.
This commit is contained in:
1 parent
85f2f9d2d4
commit
0d4e11a6e5
2 files changed
+53
-1
No files matched your search
@@ -788,7 +788,22 @@ func (f *Filer) applyTraversedEntry(ctx context.Context, entry *Entry, peerTsNs
|
||||
return fmt.Errorf("check local state for %s: %w", entry.FullPath, err)
|
||||
}
|
||||
if localTsNs >= peerTsNs {
|
||||
return nil
|
||||
if localTsNs != 0 {
|
||||
return nil
|
||||
}
|
||||
// Zero timestamps carry no order: keep the path only when an entry
|
||||
// exists locally — a missing one takes the peer's copy, or an
|
||||
// epoch-dated entry from a peer reporting no commit time is dropped.
|
||||
if f.Store == nil {
|
||||
return nil
|
||||
}
|
||||
local, findErr := f.Store.FindEntry(ctx, entry.FullPath)
|
||||
if findErr != nil && !errors.Is(findErr, filer_pb.ErrNotFound) {
|
||||
return fmt.Errorf("check local state for %s: %w", entry.FullPath, findErr)
|
||||
}
|
||||
if local != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if insertErr := f.Store.InsertEntry(ctx, entry); insertErr != nil {
|
||||
// Entry already exists (root dir, or partial previous bootstrap);
|
||||
|
||||
@@ -575,6 +575,43 @@ func TestBootstrapUpdatesExistingByCommitTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A missing local entry has no commit time to order against: the peer copy
|
||||
// must apply even when both sides are timestamp-less — an epoch-dated entry
|
||||
// from a peer that predates EntryTsNs is still bootstrapped, while an
|
||||
// existing zero-mtime local entry keeps its place.
|
||||
func TestBootstrapCopiesMissingEntryWithoutCommitTime(t *testing.T) {
|
||||
store := newStubFilerStore()
|
||||
f := newReplayTestFiler(store)
|
||||
missing := util.NewFullPath("/dir", "missing")
|
||||
existing := util.NewFullPath("/dir", "existing")
|
||||
|
||||
store.entries[string(existing)] = &Entry{
|
||||
FullPath: existing,
|
||||
Attr: Attr{Mtime: time.Unix(0, 0)},
|
||||
Content: []byte("zero-mtime local entry"),
|
||||
}
|
||||
for _, path := range []util.FullPath{missing, existing} {
|
||||
entry := &Entry{
|
||||
FullPath: path,
|
||||
Attr: Attr{Mtime: time.Unix(0, 0)},
|
||||
Content: []byte("epoch-dated peer entry"),
|
||||
}
|
||||
if err := f.applyTraversedEntry(context.Background(), entry, 0); err != nil {
|
||||
t.Fatalf("applyTraversedEntry %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
got, err := store.FindEntry(context.Background(), missing)
|
||||
if err != nil {
|
||||
t.Fatalf("missing local entry must take the peer copy: %v", err)
|
||||
}
|
||||
if string(got.Content) != "epoch-dated peer entry" {
|
||||
t.Fatalf("content = %q, want peer entry applied", got.Content)
|
||||
}
|
||||
if got, _ := store.FindEntry(context.Background(), existing); string(got.Content) != "zero-mtime local entry" {
|
||||
t.Fatalf("content = %q, existing local entry must be kept", got.Content)
|
||||
}
|
||||
}
|
||||
|
||||
// A delete whose commit record failed to persist still blocks a stale
|
||||
// replayed create: the pending record stands in until the retry lands it.
|
||||
func TestPendingDeleteRecordBlocksStaleReplay(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user