filer: serialize HTTP entry commits on the entry lock

gRPC writers, renames, and repack already took the per-path entry lock,
but plain HTTP overwrites committed without it: an overwrite landing
between repack's read and its update was silently replaced, orphaning
its chunks. Take the lock around the saveMetaData and format-ingest
commits, so repack's exclusive hold spans every writer.
This commit is contained in:
Chris Lu
2026-08-10 17:27:03 -07:00
parent 61348b147b
commit 2c84bb1161
2 changed files with 10 additions and 0 deletions
+4
View File
@@ -202,6 +202,10 @@ func (fs *FilerServer) formatIngest(ctx context.Context, w http.ResponseWriter,
Extended: map[string][]byte{format.LayoutKey: encoded},
}
copyStandardHeadersToExtended(r, entry.Extended)
// commit under the entry lock like saveMetaData, so ingest overwrites
// serialize with gRPC writers, renames, and repack
pathLock := fs.entryLockTable.AcquireLock("formatIngest", entry.FullPath, util.ExclusiveLock)
defer fs.entryLockTable.ReleaseLock(entry.FullPath, pathLock)
if err := fs.filer.CreateEntry(context.WithoutCancel(ctx), entry, nil, false, false, nil, skipCheckParentDirEntry(r), so.MaxFileNameLength); err != nil {
cleanup()
writeJsonError(w, r, http.StatusInternalServerError, err)
@@ -246,6 +246,12 @@ func (fs *FilerServer) saveMetaData(ctx context.Context, r *http.Request, fileNa
// fix the path
path := fs.fixFilePath(ctx, r, fileName)
// Commit under the entry lock so plain HTTP overwrites serialize with
// gRPC writers, renames, and format repack.
fullPath := util.FullPath(path)
pathLock := fs.entryLockTable.AcquireLock("saveMetaData", fullPath, util.ExclusiveLock)
defer fs.entryLockTable.ReleaseLock(fullPath, pathLock)
var entry *filer.Entry
var newChunks []*filer_pb.FileChunk
var mergedChunks []*filer_pb.FileChunk