Compare commits

..
Author SHA1 Message Date
Chris Lu 5f72c4532e filer: test IsSameData leaves input chunk order unchanged
Guards the clone-then-sort fix: a regression back to in-place sorting would reorder caller-owned chunk slices and reintroduce the remote-sync IF_ENTRY_EQUAL mismatch.
2026-10-04 01:25:26 +08:00
Chris Lu b3bd6c013c filer: stop isSameChunks from sorting caller-owned chunk slices
slices.SortFunc reorders the input in place. filer.remote.sync calls IsSameData on a metadata event's NewEntry inside isMetadataOnlyUpdate and later stamps the filer entry under an IF_ENTRY_EQUAL precondition carrying that same entry. The ETag-sorted chunk list never matches the stored entry, so every stamp of a multi-chunk object fails, synced_mtime_ns stays zero, and dirty objects are re-uploaded forever. Sort clones of the slices instead.
2026-10-04 01:14:52 +08:00
2 changed files with 34 additions and 4 deletions
+6 -4
View File
@@ -85,14 +85,16 @@ func isSameChunks(a, b []*filer_pb.FileChunk) bool {
if len(a) != len(b) {
return false
}
slices.SortFunc(a, func(i, j *filer_pb.FileChunk) int {
sortedA := slices.Clone(a)
sortedB := slices.Clone(b)
slices.SortFunc(sortedA, func(i, j *filer_pb.FileChunk) int {
return strings.Compare(i.ETag, j.ETag)
})
slices.SortFunc(b, func(i, j *filer_pb.FileChunk) int {
slices.SortFunc(sortedB, func(i, j *filer_pb.FileChunk) int {
return strings.Compare(i.ETag, j.ETag)
})
for i := 0; i < len(a); i++ {
if a[i].ETag != b[i].ETag {
for i := 0; i < len(sortedA); i++ {
if sortedA[i].ETag != sortedB[i].ETag {
return false
}
}
+28
View File
@@ -0,0 +1,28 @@
package filer
import (
"testing"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/stretchr/testify/assert"
)
// IsSameData must not reorder the caller's chunk slices: filer.remote.sync
// stamps the filer entry an event described under an IF_ENTRY_EQUAL guard,
// and an in-place sort leaves the event entry ordered differently from the
// stored one, so the stamp never matches.
func TestIsSameDataLeavesChunkOrderAlone(t *testing.T) {
chunkA := &filer_pb.FileChunk{FileId: "1,aaa", ETag: "zzzz", Size: 4}
chunkB := &filer_pb.FileChunk{FileId: "2,bbb", ETag: "aaaa", Size: 2}
a := &filer_pb.Entry{Chunks: []*filer_pb.FileChunk{chunkA, chunkB}}
b := &filer_pb.Entry{Chunks: []*filer_pb.FileChunk{
{FileId: "3,ccc", ETag: "zzzz", Size: 4},
{FileId: "4,ddd", ETag: "aaaa", Size: 2},
}}
assert.True(t, IsSameData(a, b))
assert.Equal(t, "1,aaa", a.Chunks[0].FileId)
assert.Equal(t, "2,bbb", a.Chunks[1].FileId)
assert.Equal(t, "3,ccc", b.Chunks[0].FileId)
assert.Equal(t, "4,ddd", b.Chunks[1].FileId)
}