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() fi.DataDir = mustGetUUID()
if userDefined[ReplicationSsecChecksumHeader] != "" { if ckSum := userDefined[ReplicationSsecChecksumHeader]; ckSum != "" {
fi.Checksum, _ = base64.StdEncoding.DecodeString(userDefined[ReplicationSsecChecksumHeader]) v, err := base64.StdEncoding.DecodeString(ckSum)
if err == nil {
fi.Checksum = v
}
delete(userDefined, ReplicationSsecChecksumHeader) 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. // Accept encrypted checksum from incoming request.
if opts.UserDefined[ReplicationSsecChecksumHeader] != "" { if opts.UserDefined[ReplicationSsecChecksumHeader] != "" {
if v, err := base64.StdEncoding.DecodeString(opts.UserDefined[ReplicationSsecChecksumHeader]); err == nil { 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(). er.cleanupMultipartPath(ctx, paths...) // cleanup all part.N.meta, and skipped part.N's before final rename().
defer func() { defer func() {

View File

@ -1333,12 +1333,12 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
if opts.EncryptFn != nil { if opts.EncryptFn != nil {
fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum) fi.Checksum = opts.EncryptFn("object-checksum", fi.Checksum)
} }
if userDefined[ReplicationSsecChecksumHeader] != "" { if ckSum := userDefined[ReplicationSsecChecksumHeader]; ckSum != "" {
if v, err := base64.StdEncoding.DecodeString(userDefined[ReplicationSsecChecksumHeader]); err == nil { if v, err := base64.StdEncoding.DecodeString(ckSum); err == nil {
fi.Checksum = v fi.Checksum = v
} }
}
delete(userDefined, ReplicationSsecChecksumHeader) delete(userDefined, ReplicationSsecChecksumHeader)
}
uniqueID := mustGetUUID() uniqueID := mustGetUUID()
tempObj := uniqueID tempObj := uniqueID
@ -1436,15 +1436,6 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
if opts.IndexCB != nil { if opts.IndexCB != nil {
compIndex = opts.IndexCB() 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 modTime := opts.MTime
if opts.MTime.IsZero() { 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. // Rename the successfully written temporary object to final location.
onlineDisks, versions, oldDataDir, err := renameData(ctx, onlineDisks, minioMetaTmpBucket, tempObj, partsMetadata, bucket, object, writeQuorum) onlineDisks, versions, oldDataDir, err := renameData(ctx, onlineDisks, minioMetaTmpBucket, tempObj, partsMetadata, bucket, object, writeQuorum)
if err != nil { 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) return z.serverPools[0].PutObject(ctx, bucket, object, data, opts)
} }
if !opts.NoLock { idx, err := z.getPoolIdx(ctx, bucket, object, data.Size())
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())
if err != nil { if err != nil {
return ObjectInfo{}, err return ObjectInfo{}, err
} }
@ -1115,7 +1104,7 @@ func (z *erasureServerPools) PutObject(ctx context.Context, bucket string, objec
Err: errDataMovementSrcDstPoolSame, Err: errDataMovementSrcDstPoolSame,
} }
} }
// Overwrite the object at the right pool
return z.serverPools[idx].PutObject(ctx, bucket, object, data, opts) return z.serverPools[idx].PutObject(ctx, bucket, object, data, opts)
} }