mirror of
https://github.com/minio/minio.git
synced 2025-02-28 05:49:16 -05:00
fix: multiple pool reads parallelize when possible (#11537)
This commit is contained in:
parent
cfc8b92dff
commit
7d4a2d2b68
@ -370,12 +370,14 @@ func (er erasureObjects) getObject(ctx context.Context, bucket, object string, s
|
|||||||
|
|
||||||
// GetObjectInfo - reads object metadata and replies back ObjectInfo.
|
// GetObjectInfo - reads object metadata and replies back ObjectInfo.
|
||||||
func (er erasureObjects) GetObjectInfo(ctx context.Context, bucket, object string, opts ObjectOptions) (info ObjectInfo, err error) {
|
func (er erasureObjects) GetObjectInfo(ctx context.Context, bucket, object string, opts ObjectOptions) (info ObjectInfo, err error) {
|
||||||
|
if !opts.NoLock {
|
||||||
// Lock the object before reading.
|
// Lock the object before reading.
|
||||||
lk := er.NewNSLock(bucket, object)
|
lk := er.NewNSLock(bucket, object)
|
||||||
if err := lk.GetRLock(ctx, globalOperationTimeout); err != nil {
|
if err := lk.GetRLock(ctx, globalOperationTimeout); err != nil {
|
||||||
return ObjectInfo{}, err
|
return ObjectInfo{}, err
|
||||||
}
|
}
|
||||||
defer lk.RUnlock()
|
defer lk.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
return er.getObjectInfo(ctx, bucket, object, opts)
|
return er.getObjectInfo(ctx, bucket, object, opts)
|
||||||
}
|
}
|
||||||
|
@ -511,16 +511,71 @@ func (z *erasureServerPools) GetObjectNInfo(ctx context.Context, bucket, object
|
|||||||
|
|
||||||
object = encodeDirObject(object)
|
object = encodeDirObject(object)
|
||||||
|
|
||||||
for _, pool := range z.serverPools {
|
if z.SinglePool() {
|
||||||
gr, err = pool.GetObjectNInfo(ctx, bucket, object, rs, h, lockType, opts)
|
return z.serverPools[0].GetObjectNInfo(ctx, bucket, object, rs, h, lockType, opts)
|
||||||
if err != nil {
|
}
|
||||||
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
|
|
||||||
continue
|
var unlockOnDefer bool
|
||||||
|
var nsUnlocker = func() {}
|
||||||
|
defer func() {
|
||||||
|
if unlockOnDefer {
|
||||||
|
nsUnlocker()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Acquire lock
|
||||||
|
if lockType != noLock {
|
||||||
|
lock := z.NewNSLock(bucket, object)
|
||||||
|
switch lockType {
|
||||||
|
case writeLock:
|
||||||
|
if err = lock.GetLock(ctx, globalOperationTimeout); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nsUnlocker = lock.Unlock
|
||||||
|
case readLock:
|
||||||
|
if err = lock.GetRLock(ctx, globalOperationTimeout); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nsUnlocker = lock.RUnlock
|
||||||
|
}
|
||||||
|
unlockOnDefer = true
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := make([]error, len(z.serverPools))
|
||||||
|
grs := make([]*GetObjectReader, len(z.serverPools))
|
||||||
|
|
||||||
|
lockType = noLock // do not take locks at lower levels
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i, pool := range z.serverPools {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int, pool *erasureSets) {
|
||||||
|
defer wg.Done()
|
||||||
|
grs[i], errs[i] = pool.GetObjectNInfo(ctx, bucket, object, rs, h, lockType, opts)
|
||||||
|
}(i, pool)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
var found int = -1
|
||||||
|
for i, err := range errs {
|
||||||
|
if err == nil {
|
||||||
|
found = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !isErrObjectNotFound(err) && !isErrVersionNotFound(err) {
|
||||||
|
for _, grr := range grs {
|
||||||
|
if grr != nil {
|
||||||
|
grr.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return gr, err
|
return gr, err
|
||||||
}
|
}
|
||||||
return gr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if found >= 0 {
|
||||||
|
return grs[found], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
object = decodeDirObject(object)
|
||||||
if opts.VersionID != "" {
|
if opts.VersionID != "" {
|
||||||
return gr, VersionNotFound{Bucket: bucket, Object: object, VersionID: opts.VersionID}
|
return gr, VersionNotFound{Bucket: bucket, Object: object, VersionID: opts.VersionID}
|
||||||
}
|
}
|
||||||
@ -533,7 +588,6 @@ func (z *erasureServerPools) GetObject(ctx context.Context, bucket, object strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
object = encodeDirObject(object)
|
object = encodeDirObject(object)
|
||||||
|
|
||||||
for _, pool := range z.serverPools {
|
for _, pool := range z.serverPools {
|
||||||
if err := pool.GetObject(ctx, bucket, object, startOffset, length, writer, etag, opts); err != nil {
|
if err := pool.GetObject(ctx, bucket, object, startOffset, length, writer, etag, opts); err != nil {
|
||||||
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
|
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
|
||||||
@ -555,16 +609,49 @@ func (z *erasureServerPools) GetObjectInfo(ctx context.Context, bucket, object s
|
|||||||
}
|
}
|
||||||
|
|
||||||
object = encodeDirObject(object)
|
object = encodeDirObject(object)
|
||||||
for _, pool := range z.serverPools {
|
|
||||||
objInfo, err = pool.GetObjectInfo(ctx, bucket, object, opts)
|
if z.SinglePool() {
|
||||||
if err != nil {
|
return z.serverPools[0].GetObjectInfo(ctx, bucket, object, opts)
|
||||||
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
return objInfo, err
|
|
||||||
|
// Lock the object before reading.
|
||||||
|
lk := z.NewNSLock(bucket, object)
|
||||||
|
if err := lk.GetRLock(ctx, globalOperationTimeout); err != nil {
|
||||||
|
return ObjectInfo{}, err
|
||||||
}
|
}
|
||||||
return objInfo, nil
|
defer lk.RUnlock()
|
||||||
|
|
||||||
|
errs := make([]error, len(z.serverPools))
|
||||||
|
objInfos := make([]ObjectInfo, len(z.serverPools))
|
||||||
|
|
||||||
|
opts.NoLock = true // avoid taking locks at lower levels for multi-pool setups.
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i, pool := range z.serverPools {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int, pool *erasureSets) {
|
||||||
|
defer wg.Done()
|
||||||
|
objInfos[i], errs[i] = pool.GetObjectInfo(ctx, bucket, object, opts)
|
||||||
|
}(i, pool)
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
var found int = -1
|
||||||
|
for i, err := range errs {
|
||||||
|
if err == nil {
|
||||||
|
found = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !isErrObjectNotFound(err) && !isErrVersionNotFound(err) {
|
||||||
|
// some errors such as MethodNotAllowed for delete marker
|
||||||
|
// should be returned upwards.
|
||||||
|
return objInfos[i], err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found >= 0 {
|
||||||
|
return objInfos[found], nil
|
||||||
|
}
|
||||||
|
|
||||||
object = decodeDirObject(object)
|
object = decodeDirObject(object)
|
||||||
if opts.VersionID != "" {
|
if opts.VersionID != "" {
|
||||||
return objInfo, VersionNotFound{Bucket: bucket, Object: object, VersionID: opts.VersionID}
|
return objInfo, VersionNotFound{Bucket: bucket, Object: object, VersionID: opts.VersionID}
|
||||||
@ -600,7 +687,6 @@ func (z *erasureServerPools) DeleteObject(ctx context.Context, bucket string, ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
object = encodeDirObject(object)
|
object = encodeDirObject(object)
|
||||||
|
|
||||||
if z.SinglePool() {
|
if z.SinglePool() {
|
||||||
return z.serverPools[0].DeleteObject(ctx, bucket, object, opts)
|
return z.serverPools[0].DeleteObject(ctx, bucket, object, opts)
|
||||||
}
|
}
|
||||||
@ -1590,27 +1676,13 @@ func (z *erasureServerPools) PutObjectTags(ctx context.Context, bucket, object s
|
|||||||
return z.serverPools[0].PutObjectTags(ctx, bucket, object, tags, opts)
|
return z.serverPools[0].PutObjectTags(ctx, bucket, object, tags, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pool := range z.serverPools {
|
// We don't know the size here set 1GiB atleast.
|
||||||
objInfo, err := pool.PutObjectTags(ctx, bucket, object, tags, opts)
|
idx, err := z.getPoolIdx(ctx, bucket, object, 1<<30)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return ObjectInfo{}, err
|
return ObjectInfo{}, err
|
||||||
}
|
}
|
||||||
return objInfo, nil
|
|
||||||
}
|
return z.serverPools[idx].PutObjectTags(ctx, bucket, object, tags, opts)
|
||||||
if opts.VersionID != "" {
|
|
||||||
return ObjectInfo{}, VersionNotFound{
|
|
||||||
Bucket: bucket,
|
|
||||||
Object: object,
|
|
||||||
VersionID: opts.VersionID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ObjectInfo{}, ObjectNotFound{
|
|
||||||
Bucket: bucket,
|
|
||||||
Object: object,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteObjectTags - delete object tags from an existing object
|
// DeleteObjectTags - delete object tags from an existing object
|
||||||
@ -1619,27 +1691,14 @@ func (z *erasureServerPools) DeleteObjectTags(ctx context.Context, bucket, objec
|
|||||||
if z.SinglePool() {
|
if z.SinglePool() {
|
||||||
return z.serverPools[0].DeleteObjectTags(ctx, bucket, object, opts)
|
return z.serverPools[0].DeleteObjectTags(ctx, bucket, object, opts)
|
||||||
}
|
}
|
||||||
for _, pool := range z.serverPools {
|
|
||||||
objInfo, err := pool.DeleteObjectTags(ctx, bucket, object, opts)
|
// We don't know the size here set 1GiB atleast.
|
||||||
|
idx, err := z.getPoolIdx(ctx, bucket, object, 1<<30)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return ObjectInfo{}, err
|
return ObjectInfo{}, err
|
||||||
}
|
}
|
||||||
return objInfo, nil
|
|
||||||
}
|
return z.serverPools[idx].DeleteObjectTags(ctx, bucket, object, opts)
|
||||||
if opts.VersionID != "" {
|
|
||||||
return ObjectInfo{}, VersionNotFound{
|
|
||||||
Bucket: bucket,
|
|
||||||
Object: object,
|
|
||||||
VersionID: opts.VersionID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ObjectInfo{}, ObjectNotFound{
|
|
||||||
Bucket: bucket,
|
|
||||||
Object: object,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetObjectTags - get object tags from an existing object
|
// GetObjectTags - get object tags from an existing object
|
||||||
@ -1648,25 +1707,12 @@ func (z *erasureServerPools) GetObjectTags(ctx context.Context, bucket, object s
|
|||||||
if z.SinglePool() {
|
if z.SinglePool() {
|
||||||
return z.serverPools[0].GetObjectTags(ctx, bucket, object, opts)
|
return z.serverPools[0].GetObjectTags(ctx, bucket, object, opts)
|
||||||
}
|
}
|
||||||
for _, pool := range z.serverPools {
|
|
||||||
tags, err := pool.GetObjectTags(ctx, bucket, object, opts)
|
// We don't know the size here set 1GiB atleast.
|
||||||
|
idx, err := z.getPoolIdx(ctx, bucket, object, 1<<30)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
|
return nil, err
|
||||||
continue
|
|
||||||
}
|
|
||||||
return tags, err
|
|
||||||
}
|
|
||||||
return tags, nil
|
|
||||||
}
|
|
||||||
if opts.VersionID != "" {
|
|
||||||
return nil, VersionNotFound{
|
|
||||||
Bucket: bucket,
|
|
||||||
Object: object,
|
|
||||||
VersionID: opts.VersionID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, ObjectNotFound{
|
|
||||||
Bucket: bucket,
|
|
||||||
Object: object,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return z.serverPools[idx].GetObjectTags(ctx, bucket, object, opts)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user