From 2c84bb11617b15843fd5f32ace57a4186cace191 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 10 Aug 2026 17:27:03 -0700 Subject: [PATCH] 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. --- weed/server/filer_server_format.go | 4 ++++ weed/server/filer_server_handlers_write_autochunk.go | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/weed/server/filer_server_format.go b/weed/server/filer_server_format.go index e1415ef81..ec52dabc6 100644 --- a/weed/server/filer_server_format.go +++ b/weed/server/filer_server_format.go @@ -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) diff --git a/weed/server/filer_server_handlers_write_autochunk.go b/weed/server/filer_server_handlers_write_autochunk.go index 34a70d3ef..1ff96891d 100644 --- a/weed/server/filer_server_handlers_write_autochunk.go +++ b/weed/server/filer_server_handlers_write_autochunk.go @@ -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