mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-15 10:38:35 +02:00
s3: route multipart-upload completion off the distributed lock (#9632)
completeMultipartUpload routes its writes to the object's owner filer when an owner is known, off the distributed lock. Idempotent replay is handled gateway-side in prepareMultipartCompletionState (it returns the existing result when the object already carries this UploadId), so the lock is not needed to dedupe retries; with no owner yet, the lock remains as the bootstrap path. Versioned completion flips the .versions pointer via routedVersionedFinalize (RECOMPUTE_LATEST). Non-versioned and suspended completion write the object via routedMkFile (a routed PUT) so the write serializes with concurrent writes to the same key on the owner's per-path lock. The version file itself is a unique path and stays a plain mkFile.
This commit is contained in:
1 parent
4b9d46b5ad
commit
eeda7181aa
2 files changed
+72
-7
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
@@ -159,6 +160,45 @@ func (s3a *S3ApiServer) routedPut(owner pb.ServerAddress, filePath string, entry
|
||||
})
|
||||
}
|
||||
|
||||
// routedMkFile builds an entry like filer_pb.MkFile and writes it through a
|
||||
// routed PUT on the owner filer, for callers that would otherwise mkFile to the
|
||||
// default filer (e.g. multipart completion of a non-versioned object).
|
||||
func (s3a *S3ApiServer) routedMkFile(owner pb.ServerAddress, parentDir, name string, chunks []*filer_pb.FileChunk, fn func(*filer_pb.Entry)) error {
|
||||
now := time.Now().Unix()
|
||||
entry := &filer_pb.Entry{
|
||||
Name: name,
|
||||
Attributes: &filer_pb.FuseAttributes{
|
||||
Mtime: now,
|
||||
Crtime: now,
|
||||
FileMode: uint32(0770),
|
||||
Uid: filer_pb.OS_UID,
|
||||
Gid: filer_pb.OS_GID,
|
||||
},
|
||||
Chunks: chunks,
|
||||
}
|
||||
if fn != nil {
|
||||
fn(entry)
|
||||
}
|
||||
resp, err := s3a.routedPut(owner, parentDir+"/"+name, entry, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Error != "" {
|
||||
return fmt.Errorf("routed mkfile %s/%s: %s", parentDir, name, resp.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeMultipartObject writes a completed multipart object entry, routed to the
|
||||
// owner when known (so it serializes with concurrent writes to the same key)
|
||||
// and falling back to a plain mkFile otherwise.
|
||||
func (s3a *S3ApiServer) writeMultipartObject(owner pb.ServerAddress, dir, name string, chunks []*filer_pb.FileChunk, fn func(*filer_pb.Entry)) error {
|
||||
if owner != "" {
|
||||
return s3a.routedMkFile(owner, dir, name, chunks, fn)
|
||||
}
|
||||
return s3a.mkFile(dir, name, chunks, fn)
|
||||
}
|
||||
|
||||
func (s3a *S3ApiServer) routedDelete(owner pb.ServerAddress, bucket, object string, cond *filer_pb.WriteCondition) (*filer_pb.ObjectTransactionResponse, error) {
|
||||
// NewFullPath normalizes a trailing-slash directory-marker key (e.g. "dir/")
|
||||
// to the entry name "dir", matching deleteUnversionedObjectWithClient.
|
||||
|
||||
Reference in new issue
Block a user