hold granular locking for multi-pool PutObject() (#20434)

- PutObject() for multi-pooled was holding large
  region locks, which was not necessary. This affects
  almost all slowpoke clients and lengthy uploads.

- Re-arrange locks for CompleteMultipart, PutObject
  to be close to rename()
This commit is contained in:
Harshavardhana 2024-09-13 13:26:02 -07:00 committed by GitHub
parent e47d787adb
commit 5bf41aff17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 30 additions and 37 deletions

View File

@ -455,8 +455,11 @@ func (er erasureObjects) newMultipartUpload(ctx context.Context, bucket string,
}
fi.DataDir = mustGetUUID()
if userDefined[ReplicationSsecChecksumHeader] != "" {
fi.Checksum, _ = base64.StdEncoding.DecodeString(userDefined[ReplicationSsecChecksumHeader])
if ckSum := userDefined[ReplicationSsecChecksumHeader]; ckSum != "" {
v, err := base64.StdEncoding.DecodeString(ckSum)
if err == nil {
fi.Checksum = v
}
delete(userDefined, ReplicationSsecChecksumHeader)
}
@ -1331,16 +1334,6 @@ func (er erasureObjects) CompleteMultipartUpload(ctx context.Context, bucket str
}
}
if !opts.NoLock {
lk := er.NewNSLock(bucket, object)
lkctx, err := lk.GetLock(ctx, globalOperationTimeout)
if err != nil {
return ObjectInfo{}, err
}
ctx = lkctx.Context()
defer lk.Unlock(lkctx)
}
// Accept encrypted checksum from incoming request.
if opts.UserDefined[ReplicationSsecChecksumHeader] != "" {
if v, err := base64.StdEncoding.DecodeString(opts.UserDefined[ReplicationSsecChecksumHeader]); err == nil {
@ -1419,6 +1412,16 @@ func (er erasureObjects) CompleteMultipartUpload(ctx context.Context, bucket str
}
}
if !opts.NoLock {
lk := er.NewNSLock(bucket, object)
lkctx, err := lk.GetLock(ctx, globalOperationTimeout)
if err != nil {
return ObjectInfo{}, err
}
ctx = lkctx.Context()
defer lk.Unlock(lkctx)
}
er.cleanupMultipartPath(ctx, paths...) // cleanup all part.N.meta, and skipped part.N's before final rename().
defer func() {

View File

@ -1333,12 +1333,12 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
if opts.EncryptFn != nil {
fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum)
}
if userDefined[ReplicationSsecChecksumHeader] != "" {
if v, err := base64.StdEncoding.DecodeString(userDefined[ReplicationSsecChecksumHeader]); err == nil {
if ckSum := userDefined[ReplicationSsecChecksumHeader]; ckSum != "" {
if v, err := base64.StdEncoding.DecodeString(ckSum); err == nil {
fi.Checksum = v
}
delete(userDefined, ReplicationSsecChecksumHeader)
}
delete(userDefined, ReplicationSsecChecksumHeader)
uniqueID := mustGetUUID()
tempObj := uniqueID
@ -1436,15 +1436,6 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
if opts.IndexCB != nil {
compIndex = opts.IndexCB()
}
if !opts.NoLock {
lk := er.NewNSLock(bucket, object)
lkctx, err := lk.GetLock(ctx, globalOperationTimeout)
if err != nil {
return ObjectInfo{}, err
}
ctx = lkctx.Context()
defer lk.Unlock(lkctx)
}
modTime := opts.MTime
if opts.MTime.IsZero() {
@ -1521,6 +1512,16 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
}
}
if !opts.NoLock {
lk := er.NewNSLock(bucket, object)
lkctx, err := lk.GetLock(ctx, globalOperationTimeout)
if err != nil {
return ObjectInfo{}, err
}
ctx = lkctx.Context()
defer lk.Unlock(lkctx)
}
// Rename the successfully written temporary object to final location.
onlineDisks, versions, oldDataDir, err := renameData(ctx, onlineDisks, minioMetaTmpBucket, tempObj, partsMetadata, bucket, object, writeQuorum)
if err != nil {

View File

@ -1091,18 +1091,7 @@ func (z *erasureServerPools) PutObject(ctx context.Context, bucket string, objec
return z.serverPools[0].PutObject(ctx, bucket, object, data, opts)
}
if !opts.NoLock {
ns := z.NewNSLock(bucket, object)
lkctx, err := ns.GetLock(ctx, globalOperationTimeout)
if err != nil {
return ObjectInfo{}, err
}
ctx = lkctx.Context()
defer ns.Unlock(lkctx)
opts.NoLock = true
}
idx, err := z.getPoolIdxNoLock(ctx, bucket, object, data.Size())
idx, err := z.getPoolIdx(ctx, bucket, object, data.Size())
if err != nil {
return ObjectInfo{}, err
}
@ -1115,7 +1104,7 @@ func (z *erasureServerPools) PutObject(ctx context.Context, bucket string, objec
Err: errDataMovementSrcDstPoolSame,
}
}
// Overwrite the object at the right pool
return z.serverPools[idx].PutObject(ctx, bucket, object, data, opts)
}