mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-14 07:48:41 +01:00
mount: tell a shortened base chunk from a whole-file rewrite
A truncate shortens a base chunk in place, so it gets a new reference key, and an old chunk can carry no timestamp. The rewrite refusal now applies only to unstamped chunks whose file id is new to the base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
29fad5a468
commit
f44eeff31d
2 files changed
+18
-3
No files matched your search
@@ -344,6 +344,15 @@ func TestMergeContentEntry(t *testing.T) {
|
||||
if _, ok := mergeContentEntry(proto.Clone(base).(*filer_pb.Entry), base, rewritten, rewritten, -1); !ok {
|
||||
t.Fatal("refused a rewrite with no peer chunk change")
|
||||
}
|
||||
unstamped := flushConditionEntry(4)
|
||||
unstamped.Chunks[0].Size, unstamped.Chunks[0].ModifiedTsNs = 3, 0
|
||||
shortened := proto.Clone(unstamped).(*filer_pb.Entry)
|
||||
shortened.Chunks[0].Size, shortened.Attributes.FileSize = 2, 2
|
||||
peerAppend := proto.Clone(unstamped).(*filer_pb.Entry)
|
||||
peerAppend.Chunks = append(peerAppend.Chunks, &filer_pb.FileChunk{Fid: &filer_pb.FileId{VolumeId: 1, FileKey: 9, Cookie: 1}, Offset: 3, Size: 1, ModifiedTsNs: 9})
|
||||
if _, ok := mergeContentEntry(peerAppend, unstamped, shortened, shortened, 2); !ok {
|
||||
t.Fatal("refused a truncate that shortened an unstamped base chunk")
|
||||
}
|
||||
|
||||
empty := flushConditionEntry()
|
||||
inline := proto.Clone(empty).(*filer_pb.Entry)
|
||||
|
||||
@@ -395,8 +395,10 @@ func mergeContentEntry(stored, base, local, sent *filer_pb.Entry, truncatedTo in
|
||||
}
|
||||
|
||||
inBase := make(map[string]bool, len(base.Chunks))
|
||||
baseFileIds := make(map[string]bool, len(base.Chunks))
|
||||
for _, c := range base.Chunks {
|
||||
inBase[contentChunkKey(c)] = true
|
||||
baseFileIds[contentFileIdKey(c)] = true
|
||||
}
|
||||
inLocal := make(map[string]bool, len(local.Chunks))
|
||||
for _, c := range local.Chunks {
|
||||
@@ -426,7 +428,7 @@ func mergeContentEntry(stored, base, local, sent *filer_pb.Entry, truncatedTo in
|
||||
}
|
||||
for _, c := range local.Chunks {
|
||||
if !inBase[contentChunkKey(c)] {
|
||||
if peerChanged && c.ModifiedTsNs == 0 && !c.IsChunkManifest {
|
||||
if peerChanged && c.ModifiedTsNs == 0 && !c.IsChunkManifest && !baseFileIds[contentFileIdKey(c)] {
|
||||
return nil, false
|
||||
}
|
||||
merged.Chunks = append(merged.Chunks, proto.Clone(c).(*filer_pb.FileChunk))
|
||||
@@ -496,15 +498,19 @@ func sameContentFile(stored, base *filer_pb.Entry) bool {
|
||||
// place, so the same file id at another size is a different reference. Both
|
||||
// file id encodings give one key, and the chunk is left as is.
|
||||
func contentChunkKey(c *filer_pb.FileChunk) string {
|
||||
return fmt.Sprintf("%s@%d+%d", contentFileIdKey(c), c.Offset, c.Size)
|
||||
}
|
||||
|
||||
func contentFileIdKey(c *filer_pb.FileChunk) string {
|
||||
fid := c.Fid
|
||||
if fid == nil {
|
||||
if parsed, err := filer_pb.ToFileIdObject(c.FileId); err == nil {
|
||||
fid = parsed
|
||||
} else {
|
||||
return fmt.Sprintf("%s@%d+%d", c.FileId, c.Offset, c.Size)
|
||||
return c.FileId
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%d,%x,%x@%d+%d", fid.VolumeId, fid.FileKey, fid.Cookie, c.Offset, c.Size)
|
||||
return fmt.Sprintf("%d,%x,%x", fid.VolumeId, fid.FileKey, fid.Cookie)
|
||||
}
|
||||
|
||||
// ackedBase is the base an acknowledged create leaves: the entry the filer
|
||||
|
||||
Reference in new issue
Block a user