mirror of
https://github.com/pgsty/minio.git
synced 2026-09-19 17:08:28 +03:00
fix: report effective bucket quotas in metrics
Signed-off-by: mr javad seydi <seydi.birjand@gmail.com>
This commit is contained in:
+12
-8
@@ -43,6 +43,17 @@ func NewBucketQuotaSys() *BucketQuotaSys {
|
|||||||
return &BucketQuotaSys{}
|
return &BucketQuotaSys{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBucketQuotaSize returns the effective enforced hard-quota size.
|
||||||
|
func getBucketQuotaSize(quota *madmin.BucketQuota) uint64 {
|
||||||
|
if quota == nil || quota.Type != madmin.HardQuota {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if quota.Size > 0 {
|
||||||
|
return quota.Size
|
||||||
|
}
|
||||||
|
return quota.Quota
|
||||||
|
}
|
||||||
|
|
||||||
var bucketStorageCache = cachevalue.New[DataUsageInfo]()
|
var bucketStorageCache = cachevalue.New[DataUsageInfo]()
|
||||||
|
|
||||||
// Init initialize bucket quota.
|
// Init initialize bucket quota.
|
||||||
@@ -110,14 +121,7 @@ func (sys *BucketQuotaSys) enforceQuotaHard(ctx context.Context, bucket string,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var quotaSize uint64
|
quotaSize := getBucketQuotaSize(q)
|
||||||
if q != nil && q.Type == madmin.HardQuota {
|
|
||||||
if q.Size > 0 {
|
|
||||||
quotaSize = q.Size
|
|
||||||
} else if q.Quota > 0 {
|
|
||||||
quotaSize = q.Quota
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if quotaSize > 0 {
|
if quotaSize > 0 {
|
||||||
if uint64(size) >= quotaSize { // check if file size already exceeds the quota
|
if uint64(size) >= quotaSize { // check if file size already exceeds the quota
|
||||||
return BucketQuotaExceeded{Bucket: bucket}
|
return BucketQuotaExceeded{Bucket: bucket}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2015-2025 MinIO, Inc.
|
||||||
|
// Copyright (c) 2025-2026 PGSTY
|
||||||
|
//
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/minio/madmin-go/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetBucketQuotaSize(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
quota *madmin.BucketQuota
|
||||||
|
want uint64
|
||||||
|
}{
|
||||||
|
{name: "nil"},
|
||||||
|
{name: "empty", quota: &madmin.BucketQuota{}},
|
||||||
|
{name: "current size", quota: &madmin.BucketQuota{Type: madmin.HardQuota, Size: 1024}, want: 1024},
|
||||||
|
{name: "legacy quota", quota: &madmin.BucketQuota{Type: madmin.HardQuota, Quota: 2048}, want: 2048},
|
||||||
|
{name: "size takes precedence", quota: &madmin.BucketQuota{Type: madmin.HardQuota, Size: 1024, Quota: 2048}, want: 1024},
|
||||||
|
{name: "missing type", quota: &madmin.BucketQuota{Size: 1024}},
|
||||||
|
{name: "unsupported type", quota: &madmin.BucketQuota{Type: "fifo", Size: 1024}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := getBucketQuotaSize(tt.quota); got != tt.want {
|
||||||
|
t.Fatalf("getBucketQuotaSize() = %d, want %d", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsBktQuotaCfgReplicated(t *testing.T) {
|
||||||
|
hardQuota := func(size, legacy uint64) *madmin.BucketQuota {
|
||||||
|
return &madmin.BucketQuota{Type: madmin.HardQuota, Size: size, Quota: legacy}
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
quotas []*madmin.BucketQuota
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "none configured", quotas: []*madmin.BucketQuota{nil, nil}, want: true},
|
||||||
|
{name: "missing from one site", quotas: []*madmin.BucketQuota{hardQuota(1024, 0), nil}},
|
||||||
|
{name: "matching size", quotas: []*madmin.BucketQuota{hardQuota(1024, 0), hardQuota(1024, 0)}, want: true},
|
||||||
|
{name: "different size", quotas: []*madmin.BucketQuota{hardQuota(1024, 0), hardQuota(2048, 0)}},
|
||||||
|
{name: "equivalent representations", quotas: []*madmin.BucketQuota{hardQuota(1024, 0), hardQuota(0, 1024)}, want: true},
|
||||||
|
{name: "different typeless size", quotas: []*madmin.BucketQuota{{Size: 1024}, {Size: 2048}}},
|
||||||
|
{name: "different type", quotas: []*madmin.BucketQuota{hardQuota(1024, 0), {Type: "fifo", Size: 1024}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := isBktQuotaCfgReplicated(len(tt.quotas), tt.quotas); got != tt.want {
|
||||||
|
t.Fatalf("isBktQuotaCfgReplicated() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -3314,10 +3314,10 @@ func getBucketUsageMetrics(opts MetricsGroupOpts) *MetricsGroupV2 {
|
|||||||
VariableLabels: map[string]string{"bucket": bucket},
|
VariableLabels: map[string]string{"bucket": bucket},
|
||||||
})
|
})
|
||||||
|
|
||||||
if quota != nil && quota.Quota > 0 {
|
if quotaSize := getBucketQuotaSize(quota); quotaSize > 0 {
|
||||||
metrics = append(metrics, MetricV2{
|
metrics = append(metrics, MetricV2{
|
||||||
Description: getBucketUsageQuotaTotalBytesMD(),
|
Description: getBucketUsageQuotaTotalBytesMD(),
|
||||||
Value: float64(quota.Quota),
|
Value: float64(quotaSize),
|
||||||
VariableLabels: map[string]string{"bucket": bucket},
|
VariableLabels: map[string]string{"bucket": bucket},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,8 +167,8 @@ func loadClusterUsageBucketMetrics(ctx context.Context, m MetricValues, c *metri
|
|||||||
m.Set(usageBucketVersionsCount, float64(usage.VersionsCount), "bucket", bucket)
|
m.Set(usageBucketVersionsCount, float64(usage.VersionsCount), "bucket", bucket)
|
||||||
m.Set(usageBucketDeleteMarkersCount, float64(usage.DeleteMarkersCount), "bucket", bucket)
|
m.Set(usageBucketDeleteMarkersCount, float64(usage.DeleteMarkersCount), "bucket", bucket)
|
||||||
|
|
||||||
if quota != nil && quota.Quota > 0 {
|
if quotaSize := getBucketQuotaSize(quota); quotaSize > 0 {
|
||||||
m.Set(usageBucketQuotaTotalBytes, float64(quota.Quota), "bucket", bucket)
|
m.Set(usageBucketQuotaTotalBytes, float64(quotaSize), "bucket", bucket)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range usage.ObjectSizesHistogram {
|
for k, v := range usage.ObjectSizesHistogram {
|
||||||
|
|||||||
+10
-1
@@ -3863,7 +3863,16 @@ func isBktQuotaCfgReplicated(total int, quotaCfgs []*madmin.BucketQuota) bool {
|
|||||||
prev = q
|
prev = q
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if prev.Quota != q.Quota || prev.Type != q.Type {
|
if prev.Type != q.Type {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if prev.Type == madmin.HardQuota {
|
||||||
|
if getBucketQuotaSize(prev) != getBucketQuotaSize(q) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if prev.Size != q.Size || prev.Quota != q.Quota {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/minio/madmin-go/v3"
|
|
||||||
"github.com/minio/minio/internal/logger"
|
"github.com/minio/minio/internal/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -177,14 +176,7 @@ func veeamSOSAPIGetObject(ctx context.Context, bucket, object string, rs *HTTPRa
|
|||||||
Used: int64(binfo.Size),
|
Used: int64(binfo.Size),
|
||||||
}
|
}
|
||||||
|
|
||||||
var quotaSize int64
|
quotaSize := int64(getBucketQuotaSize(q))
|
||||||
if q != nil && q.Type == madmin.HardQuota {
|
|
||||||
if q.Size > 0 {
|
|
||||||
quotaSize = int64(q.Size)
|
|
||||||
} else if q.Quota > 0 {
|
|
||||||
quotaSize = int64(q.Quota)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if quotaSize == 0 {
|
if quotaSize == 0 {
|
||||||
info := objAPI.StorageInfo(ctx, true)
|
info := objAPI.StorageInfo(ctx, true)
|
||||||
|
|||||||
Reference in New Issue
Block a user