filer: fingerprint every read-relevant chunk field

The layout binding hashed only offset and file id, so a mutation that
kept both - a truncate shrinking chunk.Size, then a sparse extend back
to the original length - passed both the size and fingerprint checks
and served a stale view. Digest size, modification timestamp, cipher
key, compression, manifest status, and SSE type as well.
This commit is contained in:
Chris Lu
2026-08-10 18:42:53 -07:00
parent 35e9f84334
commit 17fe96e620
2 changed files with 28 additions and 2 deletions
+6 -2
View File
@@ -45,11 +45,15 @@ const (
defaultFormatChunkSizeMB = 4
)
// formatChunkIdentity digests the chunk list a layout was written against.
// formatChunkIdentity digests the chunk list a layout was written against,
// covering every field that changes what a read returns: a FUSE truncate, for
// one, mutates Size while keeping the chunk's id.
func formatChunkIdentity(chunks []*filer_pb.FileChunk) []byte {
digest := md5.New()
for _, chunk := range chunks {
fmt.Fprintf(digest, "%d:%s;", chunk.Offset, chunk.GetFileIdString())
fmt.Fprintf(digest, "%d:%s:%d:%d:%x:%t:%t:%d;",
chunk.Offset, chunk.GetFileIdString(), chunk.Size, chunk.ModifiedTsNs,
chunk.CipherKey, chunk.IsCompressed, chunk.IsChunkManifest, chunk.SseType)
}
return digest.Sum(nil)
}
+22
View File
@@ -68,4 +68,26 @@ func TestFormatChunkIdentity(t *testing.T) {
if bytes.Equal(identity, formatChunkIdentity(changedOffset)) {
t.Fatalf("identity ignored an offset change")
}
// a truncate mutates Size while keeping the chunk id
changedSize := []*filer_pb.FileChunk{
{FileId: "1,ab", Offset: 0, Size: 10},
{FileId: "2,cd", Offset: 10, Size: 15},
}
if bytes.Equal(identity, formatChunkIdentity(changedSize)) {
t.Fatalf("identity ignored a size change")
}
changedMtime := []*filer_pb.FileChunk{
{FileId: "1,ab", Offset: 0, Size: 10},
{FileId: "2,cd", Offset: 10, Size: 20, ModifiedTsNs: 7},
}
if bytes.Equal(identity, formatChunkIdentity(changedMtime)) {
t.Fatalf("identity ignored a modification timestamp change")
}
changedManifest := []*filer_pb.FileChunk{
{FileId: "1,ab", Offset: 0, Size: 10},
{FileId: "2,cd", Offset: 10, Size: 20, IsChunkManifest: true},
}
if bytes.Equal(identity, formatChunkIdentity(changedManifest)) {
t.Fatalf("identity ignored a manifest flag change")
}
}