filer: stamp the rename event with the deferred copy's result

A remote-only rename over a remote-only target queued the new entry's
event with the source's stamp before the deferred copy ran. Peers
replaying it saved a stamp the copy had already superseded, and the
sync serving such a peer rejected the destination as a match and tried
to copy the deleted source. The event now carries the copy's result
and drops the pending-source marker once it lands.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Chris LuandDevin authored and Alex Russell committed 2026-10-12 05:38:35 +02:00
1 parent 68109213a4
commit 1c003d0e52
2 files changed
+10 -2

No files matched your search

+5 -2
View File
@@ -208,8 +208,9 @@ func (fs *FilerServer) finishRemoteCopies(ctx context.Context, pendings []*pendi
// applyRemoteCopies brings the queued rename events in line with the deferred
// copies. The stamp is written with a plain UpdateEntry, which publishes no
// event, so the rename event carries it to peer filers and subscribers. A
// failed copy keeps the old object, which the entry still describes.
// event, so the rename event carries it, without the pending-source marker,
// to peer filers and subscribers. A failed copy keeps the old object, which
// the entry still reads through the marker.
func applyRemoteCopies(events []metadataEvent, pendings []*pendingRemoteCopy) {
for i := range events {
event := &events[i]
@@ -222,6 +223,8 @@ func applyRemoteCopies(events []metadataEvent, pendings []*pendingRemoteCopy) {
} else if pending.copied != nil && event.newEntry != nil {
newEntry := event.newEntry.ShallowClone()
newEntry.Remote = pending.copied
newEntry.Extended = maps.Clone(newEntry.Extended)
delete(newEntry.Extended, filer.ExtRemoteRenameSourceKey)
event.newEntry = newEntry
}
}
@@ -154,6 +154,11 @@ func TestRenameRemoteOnlyEntryOverTargetKeepsTheCopy(t *testing.T) {
assert.Equal(t, uint64(101), dst.Attr.Inode)
assert.Equal(t, `"copy"`, dst.Remote.RemoteETag)
assert.Empty(t, dst.Extended[filer.ExtRemoteRenameSourceKey])
// peers replay the post-copy state, not the source's stamp the entry
// committed with
newEvent := events[1].notification.NewEntry
assert.Equal(t, `"copy"`, newEvent.RemoteEntry.RemoteETag)
assert.Empty(t, newEvent.Extended[filer.ExtRemoteRenameSourceKey])
}
func TestRenameRemoteOnlyEntryCopyFailureKeepsTheOldObject(t *testing.T) {