diff --git a/cmd/admin-handler-utils.go b/cmd/admin-handler-utils.go index ba4dd5fb9..d8404f3bb 100644 --- a/cmd/admin-handler-utils.go +++ b/cmd/admin-handler-utils.go @@ -88,6 +88,12 @@ func toAdminAPIErr(ctx context.Context, err error) APIError { } case SRError: apiErr = errorCodes.ToAPIErrWithErr(e.Code, e.Cause) + case decomError: + apiErr = APIError{ + Code: "XMinioDecommissionNotAllowed", + Description: e.Err, + HTTPStatusCode: http.StatusBadRequest, + } default: switch { case errors.Is(err, errDecommissionAlreadyRunning): diff --git a/cmd/erasure-server-pool-decom.go b/cmd/erasure-server-pool-decom.go index 4b47e40d6..a1f10a746 100644 --- a/cmd/erasure-server-pool-decom.go +++ b/cmd/erasure-server-pool-decom.go @@ -27,8 +27,6 @@ import ( "time" "github.com/dustin/go-humanize" - "github.com/minio/madmin-go" - "github.com/minio/minio/internal/config/storageclass" "github.com/minio/minio/internal/hash" "github.com/minio/minio/internal/logger" "github.com/minio/pkg/console" @@ -54,10 +52,10 @@ type PoolDecommissionInfo struct { Object string `json:"-" msg:"obj"` // Verbose information - ItemsDecommissioned uint64 `json:"-" msg:"id"` - ItemsDecommissionFailed uint64 `json:"-" msg:"idf"` - BytesDone uint64 `json:"-" msg:"bd"` - BytesFailed uint64 `json:"-" msg:"bf"` + ItemsDecommissioned int64 `json:"-" msg:"id"` + ItemsDecommissionFailed int64 `json:"-" msg:"idf"` + BytesDone int64 `json:"-" msg:"bd"` + BytesFailed int64 `json:"-" msg:"bf"` } // bucketPop should be called when a bucket is done decommissioning. @@ -144,7 +142,7 @@ func (p *poolMeta) returnResumablePools(n int) []PoolStatus { func (p *poolMeta) DecommissionComplete(idx int) bool { if p.Pools[idx].Decommission != nil { - p.Pools[idx].LastUpdate = time.Now().UTC() + p.Pools[idx].LastUpdate = UTCNow() p.Pools[idx].Decommission.Complete = true p.Pools[idx].Decommission.Failed = false p.Pools[idx].Decommission.Canceled = false @@ -155,7 +153,7 @@ func (p *poolMeta) DecommissionComplete(idx int) bool { func (p *poolMeta) DecommissionFailed(idx int) bool { if p.Pools[idx].Decommission != nil { - p.Pools[idx].LastUpdate = time.Now().UTC() + p.Pools[idx].LastUpdate = UTCNow() p.Pools[idx].Decommission.StartTime = time.Time{} p.Pools[idx].Decommission.Complete = false p.Pools[idx].Decommission.Failed = true @@ -167,7 +165,7 @@ func (p *poolMeta) DecommissionFailed(idx int) bool { func (p *poolMeta) DecommissionCancel(idx int) bool { if p.Pools[idx].Decommission != nil { - p.Pools[idx].LastUpdate = time.Now().UTC() + p.Pools[idx].LastUpdate = UTCNow() p.Pools[idx].Decommission.StartTime = time.Time{} p.Pools[idx].Decommission.Complete = false p.Pools[idx].Decommission.Failed = false @@ -227,7 +225,7 @@ var ( errDecommissionComplete = errors.New("decommission is complete, please remove the servers from command-line") ) -func (p *poolMeta) Decommission(idx int, info StorageInfo) error { +func (p *poolMeta) Decommission(idx int, pi poolSpaceInfo) error { for i, pool := range p.Pools { if idx == i { continue @@ -239,15 +237,15 @@ func (p *poolMeta) Decommission(idx int, info StorageInfo) error { return fmt.Errorf("%w at index: %d", errDecommissionAlreadyRunning, i) } } + + now := UTCNow() if p.Pools[idx].Decommission == nil { - startSize := TotalUsableCapacityFree(info) - totalSize := TotalUsableCapacity(info) - p.Pools[idx].LastUpdate = time.Now().UTC() + p.Pools[idx].LastUpdate = now p.Pools[idx].Decommission = &PoolDecommissionInfo{ - StartTime: UTCNow(), - StartSize: startSize, - CurrentSize: startSize, - TotalSize: totalSize, + StartTime: now, + StartSize: pi.Free, + CurrentSize: pi.Free, + TotalSize: pi.Total, } return nil } @@ -260,14 +258,12 @@ func (p *poolMeta) Decommission(idx int, info StorageInfo) error { // Canceled or Failed decommission can be triggered again. if p.Pools[idx].Decommission.StartTime.IsZero() { if p.Pools[idx].Decommission.Canceled || p.Pools[idx].Decommission.Failed { - startSize := TotalUsableCapacityFree(info) - totalSize := TotalUsableCapacity(info) - p.Pools[idx].LastUpdate = time.Now().UTC() + p.Pools[idx].LastUpdate = now p.Pools[idx].Decommission = &PoolDecommissionInfo{ - StartTime: UTCNow(), - StartSize: startSize, - CurrentSize: startSize, - TotalSize: totalSize, + StartTime: now, + StartSize: pi.Free, + CurrentSize: pi.Free, + TotalSize: pi.Total, } return nil } @@ -385,24 +381,31 @@ func (p *poolMeta) CountItem(idx int, size int64, failed bool) { if pd != nil { if failed { pd.ItemsDecommissionFailed++ - pd.BytesFailed += uint64(size) + pd.BytesFailed += size } else { pd.ItemsDecommissioned++ - pd.BytesDone += uint64(size) + pd.BytesDone += size } p.Pools[idx].Decommission = pd } } -func (p *poolMeta) updateAfter(ctx context.Context, idx int, pools []*erasureSets, duration time.Duration) error { +func (p *poolMeta) updateAfter(ctx context.Context, idx int, pools []*erasureSets, duration time.Duration) (bool, error) { if p.Pools[idx].Decommission == nil { - return errInvalidArgument + return false, errInvalidArgument } - if time.Since(p.Pools[idx].LastUpdate) > duration { - p.Pools[idx].LastUpdate = time.Now().UTC() - return p.save(ctx, pools) + now := UTCNow() + if now.Sub(p.Pools[idx].LastUpdate) >= duration { + if serverDebugLog { + console.Debugf("decommission: persisting poolMeta on disk: threshold:%s, poolMeta:%#v\n", now.Sub(p.Pools[idx].LastUpdate), p.Pools[idx]) + } + p.Pools[idx].LastUpdate = now + if err := p.save(ctx, pools); err != nil { + return false, err + } + return true, nil } - return nil + return false, nil } func (p poolMeta) save(ctx context.Context, pools []*erasureSets) error { @@ -464,6 +467,7 @@ func (z *erasureServerPools) Init(ctx context.Context) error { return nil } + meta = poolMeta{} // to update write poolMeta fresh. // looks like new pool was added we need to update, // or this is a fresh installation (or an existing // installation with pool removed) @@ -472,7 +476,7 @@ func (z *erasureServerPools) Init(ctx context.Context) error { meta.Pools = append(meta.Pools, PoolStatus{ CmdLine: pool.endpoints.CmdLine, ID: idx, - LastUpdate: time.Now().UTC(), + LastUpdate: UTCNow(), }) } if err = meta.save(ctx, z.serverPools); err != nil { @@ -650,7 +654,11 @@ func (z *erasureServerPools) decommissionPool(ctx context.Context, idx int, pool } z.poolMetaMutex.Lock() z.poolMeta.TrackCurrentBucketObject(idx, bName, entry.name) - logger.LogIf(ctx, z.poolMeta.updateAfter(ctx, idx, z.serverPools, time.Minute)) + ok, err := z.poolMeta.updateAfter(ctx, idx, z.serverPools, 30*time.Second) + logger.LogIf(ctx, err) + if ok { + globalNotificationSys.ReloadPoolMeta(ctx) + } z.poolMetaMutex.Unlock() } @@ -754,6 +762,51 @@ func (z *erasureServerPools) Decommission(ctx context.Context, idx int) error { return nil } +type decomError struct { + Err string +} + +func (d decomError) Error() string { + return d.Err +} + +type poolSpaceInfo struct { + Free int64 + Total int64 + Used int64 +} + +func (z *erasureServerPools) getDecommissionPoolSpaceInfo(idx int) (pi poolSpaceInfo, err error) { + if idx < 0 { + return pi, errInvalidArgument + } + if idx+1 > len(z.serverPools) { + return pi, errInvalidArgument + } + info, errs := z.serverPools[idx].StorageInfo(context.Background()) + for _, err := range errs { + if err != nil { + return pi, errInvalidArgument + } + } + info.Backend = z.BackendInfo() + for _, disk := range info.Disks { + if disk.Healing { + return pi, decomError{ + Err: fmt.Sprintf("%s drive is healing, decommission will not be started", disk.Endpoint), + } + } + } + + usableTotal := int64(GetTotalUsableCapacity(info.Disks, info)) + usableFree := int64(GetTotalUsableCapacityFree(info.Disks, info)) + return poolSpaceInfo{ + Total: usableTotal, + Free: usableFree, + Used: usableTotal - usableFree, + }, nil +} + func (z *erasureServerPools) Status(ctx context.Context, idx int) (PoolStatus, error) { if idx < 0 { return PoolStatus{}, errInvalidArgument @@ -762,35 +815,19 @@ func (z *erasureServerPools) Status(ctx context.Context, idx int) (PoolStatus, e z.poolMetaMutex.RLock() defer z.poolMetaMutex.RUnlock() - if idx+1 > len(z.poolMeta.Pools) { + pi, err := z.getDecommissionPoolSpaceInfo(idx) + if err != nil { return PoolStatus{}, errInvalidArgument } - pool := z.serverPools[idx] - info, _ := pool.StorageInfo(ctx) - info.Backend.Type = madmin.Erasure - - scParity := globalStorageClass.GetParityForSC(storageclass.STANDARD) - if scParity <= 0 { - scParity = z.serverPools[0].defaultParityCount - } - rrSCParity := globalStorageClass.GetParityForSC(storageclass.RRS) - info.Backend.StandardSCData = append(info.Backend.StandardSCData, pool.SetDriveCount()-scParity) - info.Backend.RRSCData = append(info.Backend.RRSCData, pool.SetDriveCount()-rrSCParity) - info.Backend.StandardSCParity = scParity - info.Backend.RRSCParity = rrSCParity - - currentSize := TotalUsableCapacityFree(info) - totalSize := TotalUsableCapacity(info) - poolInfo := z.poolMeta.Pools[idx] if poolInfo.Decommission != nil { - poolInfo.Decommission.TotalSize = totalSize - poolInfo.Decommission.CurrentSize = currentSize + poolInfo.Decommission.TotalSize = pi.Total + poolInfo.Decommission.CurrentSize = poolInfo.Decommission.StartSize + poolInfo.Decommission.BytesDone } else { poolInfo.Decommission = &PoolDecommissionInfo{ - CurrentSize: currentSize, - TotalSize: totalSize, + TotalSize: pi.Total, + CurrentSize: pi.Free, } } return poolInfo, nil @@ -893,7 +930,9 @@ func (z *erasureServerPools) StartDecommission(ctx context.Context, idx int) (er for _, bucket := range buckets { if lc, err := globalLifecycleSys.Get(bucket.Name); err == nil { if lc.HasTransition() { - return fmt.Errorf("Bucket is part of transitioned tier %s: decommission is not allowed in Tier'd setups", bucket.Name) + return decomError{ + Err: fmt.Sprintf("Bucket is part of transitioned tier %s: decommission is not allowed in Tier'd setups", bucket.Name), + } } } } @@ -919,23 +958,15 @@ func (z *erasureServerPools) StartDecommission(ctx context.Context, idx int) (er return errInvalidArgument } - info, _ := pool.StorageInfo(ctx) - info.Backend.Type = madmin.Erasure - - scParity := globalStorageClass.GetParityForSC(storageclass.STANDARD) - if scParity <= 0 { - scParity = z.serverPools[0].defaultParityCount + pi, err := z.getDecommissionPoolSpaceInfo(idx) + if err != nil { + return err } - rrSCParity := globalStorageClass.GetParityForSC(storageclass.RRS) - info.Backend.StandardSCData = append(info.Backend.StandardSCData, pool.SetDriveCount()-scParity) - info.Backend.RRSCData = append(info.Backend.RRSCData, pool.SetDriveCount()-rrSCParity) - info.Backend.StandardSCParity = scParity - info.Backend.RRSCParity = rrSCParity z.poolMetaMutex.Lock() defer z.poolMetaMutex.Unlock() - if err = z.poolMeta.Decommission(idx, info); err != nil { + if err = z.poolMeta.Decommission(idx, pi); err != nil { return err } z.poolMeta.QueueBuckets(idx, buckets) diff --git a/cmd/erasure-server-pool-decom_gen.go b/cmd/erasure-server-pool-decom_gen.go index 07294cd3f..df5e3134e 100644 --- a/cmd/erasure-server-pool-decom_gen.go +++ b/cmd/erasure-server-pool-decom_gen.go @@ -117,25 +117,25 @@ func (z *PoolDecommissionInfo) DecodeMsg(dc *msgp.Reader) (err error) { return } case "id": - z.ItemsDecommissioned, err = dc.ReadUint64() + z.ItemsDecommissioned, err = dc.ReadInt64() if err != nil { err = msgp.WrapError(err, "ItemsDecommissioned") return } case "idf": - z.ItemsDecommissionFailed, err = dc.ReadUint64() + z.ItemsDecommissionFailed, err = dc.ReadInt64() if err != nil { err = msgp.WrapError(err, "ItemsDecommissionFailed") return } case "bd": - z.BytesDone, err = dc.ReadUint64() + z.BytesDone, err = dc.ReadInt64() if err != nil { err = msgp.WrapError(err, "BytesDone") return } case "bf": - z.BytesFailed, err = dc.ReadUint64() + z.BytesFailed, err = dc.ReadInt64() if err != nil { err = msgp.WrapError(err, "BytesFailed") return @@ -283,7 +283,7 @@ func (z *PoolDecommissionInfo) EncodeMsg(en *msgp.Writer) (err error) { if err != nil { return } - err = en.WriteUint64(z.ItemsDecommissioned) + err = en.WriteInt64(z.ItemsDecommissioned) if err != nil { err = msgp.WrapError(err, "ItemsDecommissioned") return @@ -293,7 +293,7 @@ func (z *PoolDecommissionInfo) EncodeMsg(en *msgp.Writer) (err error) { if err != nil { return } - err = en.WriteUint64(z.ItemsDecommissionFailed) + err = en.WriteInt64(z.ItemsDecommissionFailed) if err != nil { err = msgp.WrapError(err, "ItemsDecommissionFailed") return @@ -303,7 +303,7 @@ func (z *PoolDecommissionInfo) EncodeMsg(en *msgp.Writer) (err error) { if err != nil { return } - err = en.WriteUint64(z.BytesDone) + err = en.WriteInt64(z.BytesDone) if err != nil { err = msgp.WrapError(err, "BytesDone") return @@ -313,7 +313,7 @@ func (z *PoolDecommissionInfo) EncodeMsg(en *msgp.Writer) (err error) { if err != nil { return } - err = en.WriteUint64(z.BytesFailed) + err = en.WriteInt64(z.BytesFailed) if err != nil { err = msgp.WrapError(err, "BytesFailed") return @@ -366,16 +366,16 @@ func (z *PoolDecommissionInfo) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.AppendString(o, z.Object) // string "id" o = append(o, 0xa2, 0x69, 0x64) - o = msgp.AppendUint64(o, z.ItemsDecommissioned) + o = msgp.AppendInt64(o, z.ItemsDecommissioned) // string "idf" o = append(o, 0xa3, 0x69, 0x64, 0x66) - o = msgp.AppendUint64(o, z.ItemsDecommissionFailed) + o = msgp.AppendInt64(o, z.ItemsDecommissionFailed) // string "bd" o = append(o, 0xa2, 0x62, 0x64) - o = msgp.AppendUint64(o, z.BytesDone) + o = msgp.AppendInt64(o, z.BytesDone) // string "bf" o = append(o, 0xa2, 0x62, 0x66) - o = msgp.AppendUint64(o, z.BytesFailed) + o = msgp.AppendInt64(o, z.BytesFailed) return } @@ -490,25 +490,25 @@ func (z *PoolDecommissionInfo) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "id": - z.ItemsDecommissioned, bts, err = msgp.ReadUint64Bytes(bts) + z.ItemsDecommissioned, bts, err = msgp.ReadInt64Bytes(bts) if err != nil { err = msgp.WrapError(err, "ItemsDecommissioned") return } case "idf": - z.ItemsDecommissionFailed, bts, err = msgp.ReadUint64Bytes(bts) + z.ItemsDecommissionFailed, bts, err = msgp.ReadInt64Bytes(bts) if err != nil { err = msgp.WrapError(err, "ItemsDecommissionFailed") return } case "bd": - z.BytesDone, bts, err = msgp.ReadUint64Bytes(bts) + z.BytesDone, bts, err = msgp.ReadInt64Bytes(bts) if err != nil { err = msgp.WrapError(err, "BytesDone") return } case "bf": - z.BytesFailed, bts, err = msgp.ReadUint64Bytes(bts) + z.BytesFailed, bts, err = msgp.ReadInt64Bytes(bts) if err != nil { err = msgp.WrapError(err, "BytesFailed") return @@ -535,7 +535,7 @@ func (z *PoolDecommissionInfo) Msgsize() (s int) { for za0002 := range z.DecommissionedBuckets { s += msgp.StringPrefixSize + len(z.DecommissionedBuckets[za0002]) } - s += 4 + msgp.StringPrefixSize + len(z.Bucket) + 4 + msgp.StringPrefixSize + len(z.Object) + 3 + msgp.Uint64Size + 4 + msgp.Uint64Size + 3 + msgp.Uint64Size + 3 + msgp.Uint64Size + s += 4 + msgp.StringPrefixSize + len(z.Bucket) + 4 + msgp.StringPrefixSize + len(z.Object) + 3 + msgp.Int64Size + 4 + msgp.Int64Size + 3 + msgp.Int64Size + 3 + msgp.Int64Size return } @@ -760,6 +760,109 @@ func (z *PoolStatus) Msgsize() (s int) { return } +// DecodeMsg implements msgp.Decodable +func (z *decomError) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "Err": + z.Err, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Err") + return + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z decomError) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 1 + // write "Err" + err = en.Append(0x81, 0xa3, 0x45, 0x72, 0x72) + if err != nil { + return + } + err = en.WriteString(z.Err) + if err != nil { + err = msgp.WrapError(err, "Err") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z decomError) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 1 + // string "Err" + o = append(o, 0x81, 0xa3, 0x45, 0x72, 0x72) + o = msgp.AppendString(o, z.Err) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *decomError) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "Err": + z.Err, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Err") + return + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z decomError) Msgsize() (s int) { + s = 1 + 4 + msgp.StringPrefixSize + len(z.Err) + return +} + // DecodeMsg implements msgp.Decodable func (z *poolMeta) DecodeMsg(dc *msgp.Reader) (err error) { var field []byte @@ -930,3 +1033,156 @@ func (z *poolMeta) Msgsize() (s int) { } return } + +// DecodeMsg implements msgp.Decodable +func (z *poolSpaceInfo) DecodeMsg(dc *msgp.Reader) (err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, err = dc.ReadMapKeyPtr() + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "Free": + z.Free, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "Free") + return + } + case "Total": + z.Total, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "Total") + return + } + case "Used": + z.Used, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "Used") + return + } + default: + err = dc.Skip() + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z poolSpaceInfo) EncodeMsg(en *msgp.Writer) (err error) { + // map header, size 3 + // write "Free" + err = en.Append(0x83, 0xa4, 0x46, 0x72, 0x65, 0x65) + if err != nil { + return + } + err = en.WriteInt64(z.Free) + if err != nil { + err = msgp.WrapError(err, "Free") + return + } + // write "Total" + err = en.Append(0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c) + if err != nil { + return + } + err = en.WriteInt64(z.Total) + if err != nil { + err = msgp.WrapError(err, "Total") + return + } + // write "Used" + err = en.Append(0xa4, 0x55, 0x73, 0x65, 0x64) + if err != nil { + return + } + err = en.WriteInt64(z.Used) + if err != nil { + err = msgp.WrapError(err, "Used") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z poolSpaceInfo) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // map header, size 3 + // string "Free" + o = append(o, 0x83, 0xa4, 0x46, 0x72, 0x65, 0x65) + o = msgp.AppendInt64(o, z.Free) + // string "Total" + o = append(o, 0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c) + o = msgp.AppendInt64(o, z.Total) + // string "Used" + o = append(o, 0xa4, 0x55, 0x73, 0x65, 0x64) + o = msgp.AppendInt64(o, z.Used) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *poolSpaceInfo) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 uint32 + zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch msgp.UnsafeString(field) { + case "Free": + z.Free, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "Free") + return + } + case "Total": + z.Total, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "Total") + return + } + case "Used": + z.Used, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "Used") + return + } + default: + bts, err = msgp.Skip(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z poolSpaceInfo) Msgsize() (s int) { + s = 1 + 5 + msgp.Int64Size + 6 + msgp.Int64Size + 5 + msgp.Int64Size + return +} diff --git a/cmd/erasure-server-pool-decom_gen_test.go b/cmd/erasure-server-pool-decom_gen_test.go index b479ceb1e..56d4aedbb 100644 --- a/cmd/erasure-server-pool-decom_gen_test.go +++ b/cmd/erasure-server-pool-decom_gen_test.go @@ -235,6 +235,119 @@ func BenchmarkDecodePoolStatus(b *testing.B) { } } +func TestMarshalUnmarshaldecomError(t *testing.T) { + v := decomError{} + bts, err := v.MarshalMsg(nil) + if err != nil { + t.Fatal(err) + } + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func BenchmarkMarshalMsgdecomError(b *testing.B) { + v := decomError{} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.MarshalMsg(nil) + } +} + +func BenchmarkAppendMsgdecomError(b *testing.B) { + v := decomError{} + bts := make([]byte, 0, v.Msgsize()) + bts, _ = v.MarshalMsg(bts[0:0]) + b.SetBytes(int64(len(bts))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + bts, _ = v.MarshalMsg(bts[0:0]) + } +} + +func BenchmarkUnmarshaldecomError(b *testing.B) { + v := decomError{} + bts, _ := v.MarshalMsg(nil) + b.ReportAllocs() + b.SetBytes(int64(len(bts))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := v.UnmarshalMsg(bts) + if err != nil { + b.Fatal(err) + } + } +} + +func TestEncodeDecodedecomError(t *testing.T) { + v := decomError{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + + m := v.Msgsize() + if buf.Len() > m { + t.Log("WARNING: TestEncodeDecodedecomError Msgsize() is inaccurate") + } + + vn := decomError{} + err := msgp.Decode(&buf, &vn) + if err != nil { + t.Error(err) + } + + buf.Reset() + msgp.Encode(&buf, &v) + err = msgp.NewReader(&buf).Skip() + if err != nil { + t.Error(err) + } +} + +func BenchmarkEncodedecomError(b *testing.B) { + v := decomError{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + en := msgp.NewWriter(msgp.Nowhere) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.EncodeMsg(en) + } + en.Flush() +} + +func BenchmarkDecodedecomError(b *testing.B) { + v := decomError{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + rd := msgp.NewEndlessReader(buf.Bytes(), b) + dc := msgp.NewReader(rd) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := v.DecodeMsg(dc) + if err != nil { + b.Fatal(err) + } + } +} + func TestMarshalUnmarshalpoolMeta(t *testing.T) { v := poolMeta{} bts, err := v.MarshalMsg(nil) @@ -347,3 +460,116 @@ func BenchmarkDecodepoolMeta(b *testing.B) { } } } + +func TestMarshalUnmarshalpoolSpaceInfo(t *testing.T) { + v := poolSpaceInfo{} + bts, err := v.MarshalMsg(nil) + if err != nil { + t.Fatal(err) + } + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func BenchmarkMarshalMsgpoolSpaceInfo(b *testing.B) { + v := poolSpaceInfo{} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.MarshalMsg(nil) + } +} + +func BenchmarkAppendMsgpoolSpaceInfo(b *testing.B) { + v := poolSpaceInfo{} + bts := make([]byte, 0, v.Msgsize()) + bts, _ = v.MarshalMsg(bts[0:0]) + b.SetBytes(int64(len(bts))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + bts, _ = v.MarshalMsg(bts[0:0]) + } +} + +func BenchmarkUnmarshalpoolSpaceInfo(b *testing.B) { + v := poolSpaceInfo{} + bts, _ := v.MarshalMsg(nil) + b.ReportAllocs() + b.SetBytes(int64(len(bts))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := v.UnmarshalMsg(bts) + if err != nil { + b.Fatal(err) + } + } +} + +func TestEncodeDecodepoolSpaceInfo(t *testing.T) { + v := poolSpaceInfo{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + + m := v.Msgsize() + if buf.Len() > m { + t.Log("WARNING: TestEncodeDecodepoolSpaceInfo Msgsize() is inaccurate") + } + + vn := poolSpaceInfo{} + err := msgp.Decode(&buf, &vn) + if err != nil { + t.Error(err) + } + + buf.Reset() + msgp.Encode(&buf, &v) + err = msgp.NewReader(&buf).Skip() + if err != nil { + t.Error(err) + } +} + +func BenchmarkEncodepoolSpaceInfo(b *testing.B) { + v := poolSpaceInfo{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + en := msgp.NewWriter(msgp.Nowhere) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.EncodeMsg(en) + } + en.Flush() +} + +func BenchmarkDecodepoolSpaceInfo(b *testing.B) { + v := poolSpaceInfo{} + var buf bytes.Buffer + msgp.Encode(&buf, &v) + b.SetBytes(int64(buf.Len())) + rd := msgp.NewEndlessReader(buf.Bytes(), b) + dc := msgp.NewReader(rd) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := v.DecodeMsg(dc) + if err != nil { + b.Fatal(err) + } + } +} diff --git a/cmd/object-api-datatypes.go b/cmd/object-api-datatypes.go index 84c759527..6bf4bfd45 100644 --- a/cmd/object-api-datatypes.go +++ b/cmd/object-api-datatypes.go @@ -46,16 +46,6 @@ const ( // StorageInfo - represents total capacity of underlying storage. type StorageInfo = madmin.StorageInfo -// TotalUsableCapacity - total usable capacity -func TotalUsableCapacity(s StorageInfo) int64 { - return int64(GetTotalUsableCapacity(s.Disks, s)) -} - -// TotalUsableCapacityFree - total usable capacity free -func TotalUsableCapacityFree(s StorageInfo) int64 { - return int64(GetTotalUsableCapacityFree(s.Disks, s)) -} - // objectHistogramInterval is an interval that will be // used to report the histogram of objects data sizes type objectHistogramInterval struct {