2021-04-18 15:41:13 -04:00
|
|
|
// Copyright (c) 2015-2021 MinIO, Inc.
|
|
|
|
//
|
|
|
|
// This file is part of MinIO Object Storage stack
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2019-12-12 09:02:37 -05:00
|
|
|
|
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-07-13 13:42:11 -04:00
|
|
|
"strings"
|
2019-12-12 09:02:37 -05:00
|
|
|
|
2020-01-08 06:31:43 -05:00
|
|
|
jsoniter "github.com/json-iterator/go"
|
2021-06-01 17:59:40 -04:00
|
|
|
"github.com/minio/minio/internal/logger"
|
2019-12-12 09:02:37 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-04-28 04:16:57 -04:00
|
|
|
dataUsageRoot = SlashSeparator
|
|
|
|
dataUsageBucket = minioMetaBucket + SlashSeparator + bucketMetaPrefix
|
|
|
|
|
2022-01-03 13:22:58 -05:00
|
|
|
dataUsageObjName = ".usage.json"
|
|
|
|
dataUsageObjNamePath = bucketMetaPrefix + SlashSeparator + dataUsageObjName
|
|
|
|
dataUsageBloomName = ".bloomcycle.bin"
|
|
|
|
dataUsageBloomNamePath = bucketMetaPrefix + SlashSeparator + dataUsageBloomName
|
|
|
|
|
2020-06-12 13:28:21 -04:00
|
|
|
dataUsageCacheName = ".usage-cache.bin"
|
2019-12-12 09:02:37 -05:00
|
|
|
)
|
|
|
|
|
2020-03-18 19:19:29 -04:00
|
|
|
// storeDataUsageInBackend will store all objects sent on the gui channel until closed.
|
2021-09-18 16:31:35 -04:00
|
|
|
func storeDataUsageInBackend(ctx context.Context, objAPI ObjectLayer, dui <-chan DataUsageInfo) {
|
2020-12-07 16:47:48 -05:00
|
|
|
for dataUsageInfo := range dui {
|
2022-01-02 12:15:06 -05:00
|
|
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
2020-03-19 12:47:47 -04:00
|
|
|
dataUsageJSON, err := json.Marshal(dataUsageInfo)
|
2020-03-18 19:19:29 -04:00
|
|
|
if err != nil {
|
|
|
|
logger.LogIf(ctx, err)
|
|
|
|
continue
|
|
|
|
}
|
2022-01-03 13:22:58 -05:00
|
|
|
if err = saveConfig(ctx, objAPI, dataUsageObjNamePath, dataUsageJSON); err != nil {
|
2020-04-28 04:16:57 -04:00
|
|
|
logger.LogIf(ctx, err)
|
|
|
|
}
|
2019-12-12 09:02:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-13 13:42:11 -04:00
|
|
|
// loadPrefixUsageFromBackend returns prefix usages found in passed buckets
|
|
|
|
// e.g.: /testbucket/prefix => 355601334
|
|
|
|
func loadPrefixUsageFromBackend(ctx context.Context, objAPI ObjectLayer, bucket string) (map[string]uint64, error) {
|
|
|
|
z, ok := objAPI.(*erasureServerPools)
|
|
|
|
if !ok {
|
2021-07-17 04:17:35 -04:00
|
|
|
// Prefix usage is empty
|
|
|
|
return map[string]uint64{}, nil
|
2021-07-13 13:42:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
cache := dataUsageCache{}
|
|
|
|
|
|
|
|
m := make(map[string]uint64)
|
|
|
|
for _, pool := range z.serverPools {
|
|
|
|
for _, er := range pool.sets {
|
|
|
|
// Load bucket usage prefixes
|
|
|
|
if err := cache.load(ctx, er, bucket+slashSeparator+dataUsageCacheName); err == nil {
|
|
|
|
root := cache.find(bucket)
|
|
|
|
if root == nil {
|
|
|
|
// We dont have usage information for this bucket in this
|
|
|
|
// set, go to the next set
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for id, usageInfo := range cache.flattenChildrens(*root) {
|
2021-08-22 19:46:45 -04:00
|
|
|
prefix := decodeDirObject(strings.TrimPrefix(id, bucket+slashSeparator))
|
|
|
|
// decodeDirObject to avoid any __XL_DIR__ objects
|
2021-07-13 13:42:11 -04:00
|
|
|
m[prefix] += uint64(usageInfo.Size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
|
2021-09-18 16:31:35 -04:00
|
|
|
func loadDataUsageFromBackend(ctx context.Context, objAPI ObjectLayer) (DataUsageInfo, error) {
|
2022-01-03 13:22:58 -05:00
|
|
|
buf, err := readConfig(ctx, objAPI, dataUsageObjNamePath)
|
2019-12-12 09:02:37 -05:00
|
|
|
if err != nil {
|
2020-04-28 04:16:57 -04:00
|
|
|
if isErrObjectNotFound(err) || isErrBucketNotFound(err) {
|
2021-09-18 16:31:35 -04:00
|
|
|
return DataUsageInfo{}, nil
|
2020-01-21 17:07:49 -05:00
|
|
|
}
|
2022-01-03 13:22:58 -05:00
|
|
|
return DataUsageInfo{}, toObjectErr(err, minioMetaBucket, dataUsageObjNamePath)
|
2019-12-12 09:02:37 -05:00
|
|
|
}
|
|
|
|
|
2021-09-18 16:31:35 -04:00
|
|
|
var dataUsageInfo DataUsageInfo
|
2022-01-02 12:15:06 -05:00
|
|
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
2022-01-03 13:22:58 -05:00
|
|
|
if err = json.Unmarshal(buf, &dataUsageInfo); err != nil {
|
2021-09-18 16:31:35 -04:00
|
|
|
return DataUsageInfo{}, err
|
2019-12-12 09:02:37 -05:00
|
|
|
}
|
2020-05-27 09:45:43 -04:00
|
|
|
// For forward compatibility reasons, we need to add this code.
|
|
|
|
if len(dataUsageInfo.BucketsUsage) == 0 {
|
2021-09-18 16:31:35 -04:00
|
|
|
dataUsageInfo.BucketsUsage = make(map[string]BucketUsageInfo, len(dataUsageInfo.BucketSizes))
|
2020-05-27 09:45:43 -04:00
|
|
|
for bucket, size := range dataUsageInfo.BucketSizes {
|
2021-09-18 16:31:35 -04:00
|
|
|
dataUsageInfo.BucketsUsage[bucket] = BucketUsageInfo{Size: size}
|
2020-05-27 09:45:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For backward compatibility reasons, we need to add this code.
|
|
|
|
if len(dataUsageInfo.BucketSizes) == 0 {
|
|
|
|
dataUsageInfo.BucketSizes = make(map[string]uint64, len(dataUsageInfo.BucketsUsage))
|
|
|
|
for bucket, bui := range dataUsageInfo.BucketsUsage {
|
|
|
|
dataUsageInfo.BucketSizes[bucket] = bui.Size
|
|
|
|
}
|
|
|
|
}
|
2021-09-18 16:31:35 -04:00
|
|
|
// For forward compatibility reasons, we need to add this code.
|
|
|
|
for bucket, bui := range dataUsageInfo.BucketsUsage {
|
|
|
|
if bui.ReplicatedSizeV1 > 0 || bui.ReplicationFailedCountV1 > 0 ||
|
|
|
|
bui.ReplicationFailedSizeV1 > 0 || bui.ReplicationPendingCountV1 > 0 {
|
2021-11-19 17:46:14 -05:00
|
|
|
cfg, _ := getReplicationConfig(GlobalContext, bucket)
|
|
|
|
if cfg != nil && cfg.RoleArn != "" {
|
|
|
|
dataUsageInfo.ReplicationInfo = make(map[string]BucketTargetUsageInfo)
|
|
|
|
dataUsageInfo.ReplicationInfo[cfg.RoleArn] = BucketTargetUsageInfo{
|
|
|
|
ReplicationFailedSize: bui.ReplicationFailedSizeV1,
|
|
|
|
ReplicationFailedCount: bui.ReplicationFailedCountV1,
|
|
|
|
ReplicatedSize: bui.ReplicatedSizeV1,
|
|
|
|
ReplicationPendingCount: bui.ReplicationPendingCountV1,
|
|
|
|
ReplicationPendingSize: bui.ReplicationPendingSizeV1,
|
|
|
|
}
|
2021-09-18 16:31:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-12 09:02:37 -05:00
|
|
|
return dataUsageInfo, nil
|
|
|
|
}
|