| 
									
										
										
										
											2021-04-19 03:41:13 +08: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 22:02:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-01-12 00:43:18 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-08 19:31:43 +08:00
										 |  |  | 	jsoniter "github.com/json-iterator/go" | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2020-04-28 16:16:57 +08:00
										 |  |  | 	dataUsageRoot   = SlashSeparator | 
					
						
							|  |  |  | 	dataUsageBucket = minioMetaBucket + SlashSeparator + bucketMetaPrefix | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 02:22:58 +08:00
										 |  |  | 	dataUsageObjName       = ".usage.json" | 
					
						
							|  |  |  | 	dataUsageObjNamePath   = bucketMetaPrefix + SlashSeparator + dataUsageObjName | 
					
						
							|  |  |  | 	dataUsageBloomName     = ".bloomcycle.bin" | 
					
						
							|  |  |  | 	dataUsageBloomNamePath = bucketMetaPrefix + SlashSeparator + dataUsageBloomName | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-07 23:10:40 +08:00
										 |  |  | 	backgroundHealInfoPath = bucketMetaPrefix + SlashSeparator + ".background-heal.json" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 01:28:21 +08:00
										 |  |  | 	dataUsageCacheName = ".usage-cache.bin" | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 07:19:29 +08:00
										 |  |  | // storeDataUsageInBackend will store all objects sent on the gui channel until closed.
 | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | func storeDataUsageInBackend(ctx context.Context, objAPI ObjectLayer, dui <-chan DataUsageInfo) { | 
					
						
							| 
									
										
										
										
											2023-09-15 02:53:52 +08:00
										 |  |  | 	attempts := 1 | 
					
						
							| 
									
										
										
										
											2020-12-08 05:47:48 +08:00
										 |  |  | 	for dataUsageInfo := range dui { | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 		json := jsoniter.ConfigCompatibleWithStandardLibrary | 
					
						
							| 
									
										
										
										
											2020-03-20 00:47:47 +08:00
										 |  |  | 		dataUsageJSON, err := json.Marshal(dataUsageInfo) | 
					
						
							| 
									
										
										
										
											2020-03-19 07:19:29 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-09-15 02:53:52 +08:00
										 |  |  | 		if attempts > 10 { | 
					
						
							|  |  |  | 			saveConfig(ctx, objAPI, dataUsageObjNamePath+".bkp", dataUsageJSON) // Save a backup every 10th update.
 | 
					
						
							|  |  |  | 			attempts = 1 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-01-04 02:22:58 +08:00
										 |  |  | 		if err = saveConfig(ctx, objAPI, dataUsageObjNamePath, dataUsageJSON); err != nil { | 
					
						
							| 
									
										
										
										
											2020-04-28 16:16:57 +08:00
										 |  |  | 			logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-09-15 02:53:52 +08:00
										 |  |  | 		attempts++ | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | var prefixUsageCache timedValue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | // loadPrefixUsageFromBackend returns prefix usages found in passed buckets
 | 
					
						
							| 
									
										
										
										
											2022-08-27 03:52:29 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | //	e.g.:  /testbucket/prefix => 355601334
 | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | func loadPrefixUsageFromBackend(ctx context.Context, objAPI ObjectLayer, bucket string) (map[string]uint64, error) { | 
					
						
							|  |  |  | 	z, ok := objAPI.(*erasureServerPools) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2021-07-17 16:17:35 +08:00
										 |  |  | 		// Prefix usage is empty
 | 
					
						
							|  |  |  | 		return map[string]uint64{}, nil | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cache := dataUsageCache{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 	prefixUsageCache.Once.Do(func() { | 
					
						
							|  |  |  | 		prefixUsageCache.TTL = 30 * time.Second | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 		// No need to fail upon Update() error, fallback to old value.
 | 
					
						
							|  |  |  | 		prefixUsageCache.Relax = true | 
					
						
							|  |  |  | 		prefixUsageCache.Update = func() (interface{}, error) { | 
					
						
							|  |  |  | 			m := make(map[string]uint64) | 
					
						
							|  |  |  | 			for _, pool := range z.serverPools { | 
					
						
							|  |  |  | 				for _, er := range pool.sets { | 
					
						
							|  |  |  | 					// Load bucket usage prefixes
 | 
					
						
							|  |  |  | 					ctx, done := context.WithTimeout(context.Background(), 2*time.Second) | 
					
						
							|  |  |  | 					ok := cache.load(ctx, er, bucket+slashSeparator+dataUsageCacheName) == nil | 
					
						
							|  |  |  | 					done() | 
					
						
							|  |  |  | 					if ok { | 
					
						
							|  |  |  | 						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) { | 
					
						
							|  |  |  | 							prefix := decodeDirObject(strings.TrimPrefix(id, bucket+slashSeparator)) | 
					
						
							|  |  |  | 							// decodeDirObject to avoid any __XLDIR__ objects
 | 
					
						
							|  |  |  | 							m[prefix] += uint64(usageInfo.Size) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 			return m, nil | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v, _ := prefixUsageCache.Get() | 
					
						
							|  |  |  | 	if v != nil { | 
					
						
							|  |  |  | 		return v.(map[string]uint64), nil | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 13:13:03 +08:00
										 |  |  | 	return map[string]uint64{}, nil | 
					
						
							| 
									
										
										
										
											2021-07-14 01:42:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | func loadDataUsageFromBackend(ctx context.Context, objAPI ObjectLayer) (DataUsageInfo, error) { | 
					
						
							| 
									
										
										
										
											2022-01-04 02:22:58 +08:00
										 |  |  | 	buf, err := readConfig(ctx, objAPI, dataUsageObjNamePath) | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2023-09-15 02:53:52 +08:00
										 |  |  | 		buf, err = readConfig(ctx, objAPI, dataUsageObjNamePath+".bkp") | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if errors.Is(err, errConfigNotFound) { | 
					
						
							|  |  |  | 				return DataUsageInfo{}, nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return DataUsageInfo{}, toObjectErr(err, minioMetaBucket, dataUsageObjNamePath) | 
					
						
							| 
									
										
										
										
											2020-01-22 06:07:49 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | 	var dataUsageInfo DataUsageInfo | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | 	json := jsoniter.ConfigCompatibleWithStandardLibrary | 
					
						
							| 
									
										
										
										
											2022-01-04 02:22:58 +08:00
										 |  |  | 	if err = json.Unmarshal(buf, &dataUsageInfo); err != nil { | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | 		return DataUsageInfo{}, err | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-27 21:45:43 +08:00
										 |  |  | 	// For forward compatibility reasons, we need to add this code.
 | 
					
						
							|  |  |  | 	if len(dataUsageInfo.BucketsUsage) == 0 { | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | 		dataUsageInfo.BucketsUsage = make(map[string]BucketUsageInfo, len(dataUsageInfo.BucketSizes)) | 
					
						
							| 
									
										
										
										
											2020-05-27 21:45:43 +08:00
										 |  |  | 		for bucket, size := range dataUsageInfo.BucketSizes { | 
					
						
							| 
									
										
										
										
											2021-09-19 04:31:35 +08:00
										 |  |  | 			dataUsageInfo.BucketsUsage[bucket] = BucketUsageInfo{Size: size} | 
					
						
							| 
									
										
										
										
											2020-05-27 21:45:43 +08: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-19 04:31:35 +08: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-20 06:46:14 +08: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-19 04:31:35 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-12 22:02:37 +08:00
										 |  |  | 	return dataUsageInfo, nil | 
					
						
							|  |  |  | } |