mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-14 07:48:41 +01:00
mount: keep an unpublished truncate across a peer's base change
The truncate mark was tied to the base pointer, so a peer event that moved a dirty handle's base (a merged content change or a metadata-only change) dropped it, and a later merge on a regrown file kept peer chunks inside the truncated range. Those base moves now carry the mark; a flush ack or a discarded handle state still clears it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b0cc4abb87
commit
71f4743950
3 files changed
+48
-2
No files matched your search
@@ -250,6 +250,15 @@ func (fh *FileHandle) noteTruncate(size uint64) {
|
||||
fh.truncatedTo.Store(&truncateMark{base: base, size: int64(size)})
|
||||
}
|
||||
|
||||
// adoptPeerBase moves a dirty handle's base to a peer's entry. A truncate the
|
||||
// handle has not published yet still applies over the new base.
|
||||
func (fh *FileHandle) adoptPeerBase(base *filer_pb.Entry) {
|
||||
old := fh.baseEntry.Swap(base)
|
||||
if m := fh.truncatedTo.Load(); m != nil && m.base == old {
|
||||
fh.truncatedTo.Store(&truncateMark{base: base, size: m.size})
|
||||
}
|
||||
}
|
||||
|
||||
// truncatedSince is the lowest size truncated to over base, or -1.
|
||||
func (fh *FileHandle) truncatedSince(base *filer_pb.Entry) int64 {
|
||||
if m := fh.truncatedTo.Load(); m != nil && m.base == base {
|
||||
|
||||
@@ -1052,7 +1052,7 @@ func (wfs *WFS) invalidateOpenFileHandle(invalidation meta_cache.EntryInvalidati
|
||||
if contentChanged && fh.dirtyMetadata && sameContentFile(candidate, base) {
|
||||
// An unmergeable change keeps the writes; the flush reports it.
|
||||
if fh.mergePeerContent(candidate, base) {
|
||||
fh.baseEntry.Store(proto.Clone(candidate).(*filer_pb.Entry))
|
||||
fh.adoptPeerBase(proto.Clone(candidate).(*filer_pb.Entry))
|
||||
fh.advanceEntryVersion(candidateTsNs, 0)
|
||||
}
|
||||
return
|
||||
@@ -1063,8 +1063,10 @@ func (wfs *WFS) invalidateOpenFileHandle(invalidation meta_cache.EntryInvalidati
|
||||
}
|
||||
if contentChanged || !fh.dirtyMetadata {
|
||||
fh.SetEntry(candidate)
|
||||
fh.baseEntry.Store(proto.Clone(candidate).(*filer_pb.Entry))
|
||||
} else {
|
||||
fh.adoptPeerBase(proto.Clone(candidate).(*filer_pb.Entry))
|
||||
}
|
||||
fh.baseEntry.Store(proto.Clone(candidate).(*filer_pb.Entry))
|
||||
fh.advanceEntryVersion(candidateTsNs, 0)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2159,3 +2159,38 @@ func TestUnmergeablePeerChangeKeepsDirtyHandle(t *testing.T) {
|
||||
t.Fatalf("base %v moved to the peer's entry", base)
|
||||
}
|
||||
}
|
||||
|
||||
// A peer event that moves a dirty handle's base keeps its unpublished
|
||||
// truncate, so a later merge still clips peer chunks at it.
|
||||
func TestPeerEventKeepsPendingTruncate(t *testing.T) {
|
||||
wfs := newInvalidateTestWFS(t)
|
||||
|
||||
inode := wfs.inodeToPath.Lookup(util.FullPath("/dir/file"), time.Now().Unix(), false, false, 0, false)
|
||||
fh, _, _, _ := wfs.fhMap.AcquireFileHandle(wfs, inode, flushConditionEntry(1, 2), 0, 0)
|
||||
fh.dirtyMetadata = true
|
||||
fh.noteTruncate(1)
|
||||
|
||||
chmod := flushConditionEntry(1, 2)
|
||||
chmod.Attributes.FileMode = 0600
|
||||
resp := &filer_pb.SubscribeMetadataResponse{
|
||||
Directory: "/dir",
|
||||
TsNs: 1500,
|
||||
EventNotification: &filer_pb.EventNotification{
|
||||
OldEntry: flushConditionEntry(1, 2),
|
||||
NewEntry: chmod,
|
||||
NewParentPath: "/dir",
|
||||
},
|
||||
}
|
||||
if err := wfs.metaCache.ApplyMetadataResponse(context.Background(), resp, meta_cache.SubscriberMetadataResponseApplyOptions); err != nil {
|
||||
t.Fatalf("apply: %v", err)
|
||||
}
|
||||
wfs.metaCache.WaitForEntryInvalidations()
|
||||
|
||||
base := fh.baseEntry.Load()
|
||||
if base.GetAttributes().GetFileMode() != 0600 {
|
||||
t.Fatalf("base %v did not move to the peer's entry", base)
|
||||
}
|
||||
if got := fh.truncatedSince(base); got != 1 {
|
||||
t.Fatalf("pending truncate %d after the base moved, want 1", got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user