Compare commits

..

25 Commits

Author SHA1 Message Date
Harshavardhana 92788e4cf4 fix: re-arrange console-sys to log properly in k8s/docker (#19129)
fixes #19125
2024-02-26 01:33:48 -08:00
Harshavardhana 8a698fef71 fix: crash in ResourceMetrics RPC handling concurrent writers (#19123)
Continuation of #19103 that had fixed the crash in peer metrics for cluster endpoint.
2024-02-25 00:51:38 -08:00
Minio Trusted b49ce1713f Update yaml files to latest version RELEASE.2024-02-24T17-11-14Z 2024-02-25 05:23:21 +00:00
Harshavardhana c2b54d92f6 allow all disk full errors to be handled (#19117) 2024-02-24 09:11:14 -08:00
Harshavardhana f965434022 fix: re-use endpoint strings to avoid allocation during audit (#19116) 2024-02-23 16:19:13 -08:00
Harshavardhana a3ac62596c move timedValue -> cachevalue package (#19114) 2024-02-23 13:28:14 -08:00
Harshavardhana 2faba02d6b fix: allow diskInfo at storageRPC to be cached (#19112)
Bonus: convert timedValue into a typed implementation
2024-02-23 09:21:38 -08:00
Krishnan Parthasarathi ee158e1610 ilm: Update action count only on success (#19093)
It also fixes a long-standing bug in expiring transitioned objects.
The expiration action was deleting the current version in the case'
of tiered objects instead of adding a delete marker.
2024-02-22 15:00:32 -08:00
Anis Eleuch fa68efb1e7 s3: CopyObject to disallow invalid dest object names (#19110)
By not doing so, objects can risk being in a wrong erasure set if the
destination object name contains e.g. '//'
2024-02-22 10:05:17 -08:00
Anis Eleuch 8c53a4405a Add audit for folder excess (#19109)
Also replace ilm:expiry with scanner to avoid user confusion
2024-02-22 08:18:13 -08:00
Harshavardhana c32f699105 turn-off md5sum for SSE-KMS/SSE-C as optimization for multipart (#19106)
only enable md5sum if explicitly asked by the client, otherwise
its not necessary to compute md5sum when SSE-KMS/SSE-C is enabled.

this is continuation of #17958
2024-02-22 04:24:11 -08:00
Harshavardhana 53aa8f5650 use typos instead of codespell (#19088) 2024-02-21 22:26:06 -08:00
Shubhendu 56887f3208 Add DeleteAll with expiry days non zero value only (#19095)
Signed-off-by: Shubhendu Ram Tripathi <shubhendu@minio.io>
2024-02-21 12:28:34 -08:00
Klaus Post 92180bc793 Add array recycling safety (#19103)
Nil entries when recycling arrays.
2024-02-21 12:27:35 -08:00
Klaus Post 22aa16ab12 Fix grid reconnection deadlock (#19101)
If network conditions have filled the output queue before a reconnect happens blocked sends could stop reconnects from happening. In short `respMu` would be held for a mux client while sending - if the queue is full this will never get released and closing the mux client will hang.

A) Use the mux client context instead of connection context for sends, so sends are unblocked when the mux client is canceled.

B) Use a `TryLock` on "close" and cancel the request if we cannot get the lock at once. This will unblock any attempts to send.
2024-02-21 07:49:34 -08:00
Poorna 526b829a09 site replication: Disallow removal of site-replicator account (#19092) 2024-02-21 02:09:33 -08:00
schmittey c44f311c4f Add missing yaml syntax highlighting in prometheus README.md (#19087) 2024-02-20 16:22:37 -08:00
Anis Eleuch 9ea5d08ecd site-repl: Fix endpoint in the error with unexpected deployment-id (#19086) 2024-02-20 15:02:35 -08:00
Harshavardhana 35deb1a8e2 do not block on send channels under high load (#19090)
all send channels must compete with `ctx` if not
they will perpetually stay alive.
2024-02-20 15:00:35 -08:00
Harshavardhana c7f7c47388 allow renames() for inlined writes without data-dir (#18801)
data-dir not being present is okay, however we can still
rely on the `rename()` atomic call instead of relying on
write xl.meta write which may truncate the io.EOF.
2024-02-20 07:05:57 -08:00
Shubhendu cb7dab17cb Graph cluster and bucket replication proxied requests (#19078)
Signed-off-by: Shubhendu Ram Tripathi <shubhendu@minio.io>
2024-02-20 01:45:00 -08:00
Harshavardhana cd419a35fe simplify broker healthcheck by following kafka guidelines (#19082)
fixes #19081
2024-02-20 00:16:35 -08:00
Klaus Post e06168596f Convert more peer <--> peer REST calls (#19004)
* Convert more peer <--> peer REST calls
* Clean up in general.
* Add JSON wrapper.
* Add slice wrapper.
* Add option to make handler return nil error if no connection is given, `IgnoreNilConn`.

Converts the following:

```
+	HandlerGetMetrics
+	HandlerGetResourceMetrics
+	HandlerGetMemInfo
+	HandlerGetProcInfo
+	HandlerGetOSInfo
+	HandlerGetPartitions
+	HandlerGetNetInfo
+	HandlerGetCPUs
+	HandlerServerInfo
+	HandlerGetSysConfig
+	HandlerGetSysServices
+	HandlerGetSysErrors
+	HandlerGetAllBucketStats
+	HandlerGetBucketStats
+	HandlerGetSRMetrics
+	HandlerGetPeerMetrics
+	HandlerGetMetacacheListing
+	HandlerUpdateMetacacheListing
+	HandlerGetPeerBucketMetrics
+	HandlerStorageInfo
+	HandlerGetLocks
+	HandlerBackgroundHealStatus
+	HandlerGetLastDayTierStats
+	HandlerSignalService
+	HandlerGetBandwidth
```
2024-02-19 14:54:46 -08:00
Harshavardhana 4c8197a119 reject expired STS credentials early without decoding sessionToken (#19072) 2024-02-19 07:34:10 -08:00
Minio Trusted 23c10350f3 Update yaml files to latest version RELEASE.2024-02-17T01-15-57Z 2024-02-17 01:37:10 +00:00
97 changed files with 7482 additions and 1699 deletions
-8
View File
@@ -1,8 +0,0 @@
[codespell]
# certs_test.go - has lots of ceritificates.
skip = go.mod,go.sum,*.txt,LICENSE,*.zip,.git,*.pdf,*.svg,.codespellrc,CREDITS,certs_test.go
check-hidden = true
ignore-regex = \b(newfolder/afile|filterIn|HelpES)\b
ignore-words-list = inout,bui,to,bu,te,ot,toi,ist,parms,flate
-20
View File
@@ -1,20 +0,0 @@
---
name: Codespell
on:
pull_request:
branches: [master]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Codespell
uses: codespell-project/actions-codespell@v2
+15
View File
@@ -0,0 +1,15 @@
---
name: Test GitHub Action
on: [pull_request]
jobs:
run:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v4
- name: Check spelling of repo
uses: crate-ci/typos@master
+31
View File
@@ -0,0 +1,31 @@
[files]
extend-exclude = [
".git/",
"docs/",
]
ignore-hidden = false
[default]
extend-ignore-re = [
"Patrick Collison",
"Copyright 2014 Unknwon",
"[0-9A-Za-z/+=]{64}",
"ZXJuZXQxDjAMBgNVBA-some-junk-Q4wDAYDVQQLEwVNaW5pbzEOMAwGA1UEAxMF",
"eyJmb28iOiJiYXIifQ",
'http\.Header\{"X-Amz-Server-Side-Encryptio":',
'sessionToken',
]
[default.extend-words]
"encrypter" = "encrypter"
"requestor" = "requestor"
[default.extend-identifiers]
"bui" = "bui"
"toi" = "toi"
"ot" = "ot"
"dm2nd" = "dm2nd"
"HashiCorp" = "HashiCorp"
"ParseND" = "ParseND"
"ParseNDStream" = "ParseNDStream"
"TestGetPartialObjectMisAligned" = "TestGetPartialObjectMisAligned"
+6 -6
View File
@@ -1072,6 +1072,10 @@ func (a adminAPIHandlers) DeleteServiceAccount(w http.ResponseWriter, r *http.Re
return
}
if serviceAccount == siteReplicatorSvcAcc && globalSiteReplicationSys.isEnabled() {
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidArgument), r.URL)
return
}
// We do not care if service account is readable or not at this point,
// since this is a delete call we shall allow it to be deleted if possible.
svcAccount, _, err := globalIAMSys.GetServiceAccount(ctx, serviceAccount)
@@ -1200,7 +1204,7 @@ func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Requ
// Rely on older value if usage loading fails from disk.
bucketStorageCache.Relax = true
bucketStorageCache.Update = func() (interface{}, error) {
bucketStorageCache.Update = func() (DataUsageInfo, error) {
ctx, done := context.WithTimeout(context.Background(), 2*time.Second)
defer done()
@@ -1208,11 +1212,7 @@ func (a adminAPIHandlers) AccountInfoHandler(w http.ResponseWriter, r *http.Requ
}
})
var dataUsageInfo DataUsageInfo
v, _ := bucketStorageCache.Get()
if v != nil {
dataUsageInfo, _ = v.(DataUsageInfo)
}
dataUsageInfo, _ := bucketStorageCache.Get()
// If etcd, dns federation configured list buckets from etcd.
var err error
+42 -22
View File
@@ -1192,7 +1192,7 @@ type healInitParams struct {
}
// extractHealInitParams - Validates params for heal init API.
func extractHealInitParams(vars map[string]string, qParms url.Values, r io.Reader) (hip healInitParams, err APIErrorCode) {
func extractHealInitParams(vars map[string]string, qParams url.Values, r io.Reader) (hip healInitParams, err APIErrorCode) {
hip.bucket = vars[mgmtBucket]
hip.objPrefix = vars[mgmtPrefix]
@@ -1213,13 +1213,13 @@ func extractHealInitParams(vars map[string]string, qParms url.Values, r io.Reade
return
}
if len(qParms[mgmtClientToken]) > 0 {
hip.clientToken = qParms[mgmtClientToken][0]
if len(qParams[mgmtClientToken]) > 0 {
hip.clientToken = qParams[mgmtClientToken][0]
}
if _, ok := qParms[mgmtForceStart]; ok {
if _, ok := qParams[mgmtForceStart]; ok {
hip.forceStart = true
}
if _, ok := qParms[mgmtForceStop]; ok {
if _, ok := qParams[mgmtForceStop]; ok {
hip.forceStop = true
}
@@ -1984,7 +1984,6 @@ func (a adminAPIHandlers) TraceHandler(w http.ResponseWriter, r *http.Request) {
// The ConsoleLogHandler handler sends console logs to the connected HTTP client.
func (a adminAPIHandlers) ConsoleLogHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
objectAPI, _ := validateAdminReq(ctx, w, r, policy.ConsoleLogAdminAction)
if objectAPI == nil {
return
@@ -2009,44 +2008,65 @@ func (a adminAPIHandlers) ConsoleLogHandler(w http.ResponseWriter, r *http.Reque
setEventStreamHeaders(w)
logCh := make(chan log.Info, 4000)
logCh := make(chan log.Info, 1000)
peers, _ := newPeerRestClients(globalEndpoints)
encodedCh := make(chan []byte, 1000+len(peers)*1000)
err = globalConsoleSys.Subscribe(logCh, ctx.Done(), node, limitLines, logKind, nil)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
// Convert local entries to JSON
go func() {
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
for {
select {
case <-ctx.Done():
return
case li := <-logCh:
if !li.SendLog(node, logKind) {
continue
}
buf.Reset()
if err := enc.Encode(li); err != nil {
continue
}
select {
case <-ctx.Done():
return
case encodedCh <- append(grid.GetByteBuffer()[:0], buf.Bytes()...):
}
}
}
}()
// Collect from matching peers
for _, peer := range peers {
if peer == nil {
continue
}
if node == "" || strings.EqualFold(peer.host.Name, node) {
peer.ConsoleLog(logCh, ctx.Done())
peer.ConsoleLog(ctx, logKind, encodedCh)
}
}
enc := json.NewEncoder(w)
keepAliveTicker := time.NewTicker(500 * time.Millisecond)
defer keepAliveTicker.Stop()
for {
select {
case log, ok := <-logCh:
case log, ok := <-encodedCh:
if !ok {
return
}
if log.SendLog(node, logKind) {
if err := enc.Encode(log); err != nil {
return
}
if len(logCh) == 0 {
// Flush if nothing is queued
w.(http.Flusher).Flush()
}
_, err = w.Write(log)
if err != nil {
return
}
grid.PutByteBuffer(log)
if len(logCh) == 0 {
// Flush if nothing is queued
w.(http.Flusher).Flush()
}
case <-keepAliveTicker.C:
if len(logCh) > 0 {
+3 -3
View File
@@ -348,7 +348,7 @@ func TestExtractHealInitParams(t *testing.T) {
}
return v
}
qParmsArr := []url.Values{
qParamsArr := []url.Values{
// Invalid cases
mkParams("", true, true),
mkParams("111", true, true),
@@ -373,9 +373,9 @@ func TestExtractHealInitParams(t *testing.T) {
body := `{"recursive": false, "dryRun": true, "remove": false, "scanMode": 0}`
// Test all combinations!
for pIdx, parms := range qParmsArr {
for pIdx, params := range qParamsArr {
for vIdx, vars := range varsArr {
_, err := extractHealInitParams(vars, parms, bytes.NewReader([]byte(body)))
_, err := extractHealInitParams(vars, params, bytes.NewReader([]byte(body)))
isErrCase := false
if pIdx < 4 || vIdx < 1 {
isErrCase = true
+3 -3
View File
@@ -390,7 +390,7 @@ const (
ErrParseExpectedIdentForGroupName
ErrParseExpectedIdentForAlias
ErrParseUnsupportedCallWithStar
ErrParseNonUnaryAgregateFunctionCall
ErrParseNonUnaryAggregateFunctionCall
ErrParseMalformedJoin
ErrParseExpectedIdentForAt
ErrParseAsteriskIsNotAloneInSelectList
@@ -1899,8 +1899,8 @@ var errorCodes = errorCodeMap{
Description: "Only COUNT with (*) as a parameter is supported in the SQL expression.",
HTTPStatusCode: http.StatusBadRequest,
},
ErrParseNonUnaryAgregateFunctionCall: {
Code: "ParseNonUnaryAgregateFunctionCall",
ErrParseNonUnaryAggregateFunctionCall: {
Code: "ParseNonUnaryAggregateFunctionCall",
Description: "Only one argument is supported for aggregate functions in the SQL expression.",
HTTPStatusCode: http.StatusBadRequest,
},
+1 -1
View File
@@ -944,7 +944,7 @@ func writeSuccessResponseHeadersOnly(w http.ResponseWriter) {
writeResponse(w, http.StatusOK, nil, mimeNone)
}
// writeErrorRespone writes error headers
// writeErrorResponse writes error headers
func writeErrorResponse(ctx context.Context, w http.ResponseWriter, err APIError, reqURL *url.URL) {
if err.HTTPStatusCode == http.StatusServiceUnavailable {
// Set retry-after header to indicate user-agents to retry request after 120secs.
File diff suppressed because one or more lines are too long
+5
View File
@@ -294,6 +294,11 @@ func checkClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]in
return nil, ErrInvalidToken
}
// Expired credentials must return error right away.
if cred.IsTemp() && cred.IsExpired() {
return nil, toAPIErrorCode(r.Context(), errInvalidAccessKeyID)
}
secret := globalActiveCred.SecretKey
if cred.IsServiceAccount() {
token = cred.SessionToken
+1 -1
View File
@@ -237,7 +237,7 @@ func TestIsRequestPresignedSignatureV2(t *testing.T) {
}
}
// TestIsRequestPresignedSignatureV4 - Test validates the logic for presign signature verision v4 detection.
// TestIsRequestPresignedSignatureV4 - Test validates the logic for presign signature version v4 detection.
func TestIsRequestPresignedSignatureV4(t *testing.T) {
testCases := []struct {
inputQueryKey string
+1 -1
View File
@@ -580,7 +580,7 @@ func testListBucketsHandler(obj ObjectLayer, instanceType, bucketName string, ap
expectedRespStatus: http.StatusOK,
},
// Test case - 2.
// Test case with invalid accessKey to produce and validate Signature MisMatch error.
// Test case with invalid accessKey to produce and validate Signature Mismatch error.
{
bucketName: bucketName,
accessKey: "abcd",
+19 -9
View File
@@ -395,12 +395,15 @@ func enqueueTransitionImmediate(obj ObjectInfo, src lcEventSrc) {
//
// 1. when a restored (via PostRestoreObject API) object expires.
// 2. when a transitioned object expires (based on an ILM rule).
func expireTransitionedObject(ctx context.Context, objectAPI ObjectLayer, oi *ObjectInfo, lcOpts lifecycle.ObjectOpts, lcEvent lifecycle.Event, src lcEventSrc) error {
func expireTransitionedObject(ctx context.Context, objectAPI ObjectLayer, oi *ObjectInfo, lcEvent lifecycle.Event, src lcEventSrc) error {
traceFn := globalLifecycleSys.trace(*oi)
var opts ObjectOptions
opts.Versioned = globalBucketVersioningSys.PrefixEnabled(oi.Bucket, oi.Name)
opts.VersionID = lcOpts.VersionID
opts.Expiration = ExpirationOptions{Expire: true}
opts := ObjectOptions{
Versioned: globalBucketVersioningSys.PrefixEnabled(oi.Bucket, oi.Name),
Expiration: ExpirationOptions{Expire: true},
}
if lcEvent.Action.DeleteVersioned() {
opts.VersionID = oi.VersionID
}
tags := newLifecycleAuditEvent(src, lcEvent).Tags()
if lcEvent.Action.DeleteRestored() {
// delete locally restored copy of object or object version
@@ -435,13 +438,13 @@ func expireTransitionedObject(ctx context.Context, objectAPI ObjectLayer, oi *Ob
defer auditLogLifecycle(ctx, *oi, ILMExpiry, tags, traceFn)
eventName := event.ObjectRemovedDelete
if lcOpts.DeleteMarker {
if oi.DeleteMarker {
eventName = event.ObjectRemovedDeleteMarkerCreated
}
objInfo := ObjectInfo{
Name: oi.Name,
VersionID: lcOpts.VersionID,
DeleteMarker: lcOpts.DeleteMarker,
VersionID: oi.VersionID,
DeleteMarker: oi.DeleteMarker,
}
// Notify object deleted event.
sendEvent(eventArgs{
@@ -471,7 +474,14 @@ func genTransitionObjName(bucket string) (string, error) {
// storage specified by the transition ARN, the metadata is left behind on source cluster and original content
// is moved to the transition tier. Note that in the case of encrypted objects, entire encrypted stream is moved
// to the transition tier without decrypting or re-encrypting.
func transitionObject(ctx context.Context, objectAPI ObjectLayer, oi ObjectInfo, lae lcAuditEvent) error {
func transitionObject(ctx context.Context, objectAPI ObjectLayer, oi ObjectInfo, lae lcAuditEvent) (err error) {
defer func() {
if err != nil {
return
}
globalScannerMetrics.timeILM(lae.Action)(1)
}()
opts := ObjectOptions{
Transition: TransitionOptions{
Status: lifecycle.TransitionPending,
+1 -1
View File
@@ -289,7 +289,7 @@ func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http
return
}
// Extract all the litsObjectsV1 query params to their native values.
// Extract all the listObjectsV1 query params to their native values.
prefix, marker, delimiter, maxKeys, encodingType, s3Error := getListObjectsV1Args(r.Form)
if s3Error != ErrNone {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL)
+11 -10
View File
@@ -25,6 +25,7 @@ import (
"time"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio/internal/cachevalue"
"github.com/minio/minio/internal/logger"
)
@@ -42,7 +43,7 @@ func NewBucketQuotaSys() *BucketQuotaSys {
return &BucketQuotaSys{}
}
var bucketStorageCache timedValue
var bucketStorageCache = cachevalue.New[DataUsageInfo]()
// Init initialize bucket quota.
func (sys *BucketQuotaSys) Init(objAPI ObjectLayer) {
@@ -52,7 +53,7 @@ func (sys *BucketQuotaSys) Init(objAPI ObjectLayer) {
bucketStorageCache.TTL = 10 * time.Second
// Rely on older value if usage loading fails from disk.
bucketStorageCache.Relax = true
bucketStorageCache.Update = func() (interface{}, error) {
bucketStorageCache.Update = func() (DataUsageInfo, error) {
ctx, done := context.WithTimeout(context.Background(), 2*time.Second)
defer done()
@@ -63,23 +64,23 @@ func (sys *BucketQuotaSys) Init(objAPI ObjectLayer) {
// GetBucketUsageInfo return bucket usage info for a given bucket
func (sys *BucketQuotaSys) GetBucketUsageInfo(bucket string) (BucketUsageInfo, error) {
v, err := bucketStorageCache.Get()
dui, err := bucketStorageCache.Get()
timedout := OperationTimedOut{}
if err != nil && !errors.Is(err, context.DeadlineExceeded) && !errors.As(err, &timedout) {
if v != nil {
if len(dui.BucketsUsage) > 0 {
logger.LogOnceIf(GlobalContext, fmt.Errorf("unable to retrieve usage information for bucket: %s, relying on older value cached in-memory: err(%v)", bucket, err), "bucket-usage-cache-"+bucket)
} else {
logger.LogOnceIf(GlobalContext, errors.New("unable to retrieve usage information for bucket: %s, no reliable usage value available - quota will not be enforced"), "bucket-usage-empty-"+bucket)
}
}
var bui BucketUsageInfo
dui, ok := v.(DataUsageInfo)
if ok {
bui = dui.BucketsUsage[bucket]
if len(dui.BucketsUsage) > 0 {
bui, ok := dui.BucketsUsage[bucket]
if ok {
return bui, nil
}
}
return bui, nil
return BucketUsageInfo{}, nil
}
// parseBucketQuota parses BucketQuota from json
+1 -1
View File
@@ -464,7 +464,7 @@ func (r *ReplicationStats) getLatestReplicationStats(bucket string) (s BucketSta
return r.calculateBucketReplicationStats(bucket, bucketStats)
}
func (r *ReplicationStats) incQ(bucket string, sz int64, isDeleleRepl bool, opType replication.Type) {
func (r *ReplicationStats) incQ(bucket string, sz int64, isDeleteRepl bool, opType replication.Type) {
r.qCache.Lock()
defer r.qCache.Unlock()
v, ok := r.qCache.bucketStats[bucket]
+47 -19
View File
@@ -529,17 +529,27 @@ func (f *folderScanner) scanFolder(ctx context.Context, folder cachedFolder, int
len(existingFolders)+len(newFolders) >= dataScannerCompactAtFolders ||
len(existingFolders)+len(newFolders) >= dataScannerForceCompactAtFolders
if len(existingFolders)+len(newFolders) > int(scannerExcessFolders.Load()) {
if totalFolders := len(existingFolders) + len(newFolders); totalFolders > int(scannerExcessFolders.Load()) {
prefixName := strings.TrimSuffix(folder.name, "/") + "/"
sendEvent(eventArgs{
EventName: event.PrefixManyFolders,
BucketName: f.root,
Object: ObjectInfo{
Name: strings.TrimSuffix(folder.name, "/") + "/",
Size: int64(len(existingFolders) + len(newFolders)),
Name: prefixName,
Size: int64(totalFolders),
},
UserAgent: "scanner",
UserAgent: "Scanner",
Host: globalMinioHost,
})
auditLogInternal(context.Background(), AuditLogOptions{
Event: "scanner:manyprefixes",
APIName: "Scanner",
Bucket: f.root,
Object: prefixName,
Tags: map[string]interface{}{
"x-minio-prefixes-total": strconv.Itoa(totalFolders),
},
})
}
if !into.Compacted && shouldCompact {
into.Compacted = true
@@ -953,15 +963,6 @@ func (i *scannerItem) applyLifecycle(ctx context.Context, o ObjectLayer, oi Obje
console.Debugf(applyActionsLogPrefix+" lifecycle: %q Initial scan: %v\n", i.objectPath(), lcEvt.Action)
}
}
defer func() {
if lcEvt.Action != lifecycle.NoneAction {
numVersions := uint64(1)
if lcEvt.Action == lifecycle.DeleteAllVersionsAction {
numVersions = uint64(oi.NumVersions)
}
globalScannerMetrics.timeILM(lcEvt.Action)(numVersions)
}
}()
switch lcEvt.Action {
// This version doesn't contribute towards sizeS only when it is permanently deleted.
@@ -1107,18 +1108,18 @@ func (i *scannerItem) applyVersionActions(ctx context.Context, o ObjectLayer, fi
Object: ObjectInfo{
Name: i.objectPath(),
},
UserAgent: "Internal: [Scanner]",
UserAgent: "Scanner",
Host: globalLocalNodeName,
RespElements: map[string]string{"x-minio-versions": strconv.Itoa(len(fivs))},
RespElements: map[string]string{"x-minio-versions": strconv.Itoa(len(objInfos))},
})
auditLogInternal(context.Background(), AuditLogOptions{
Event: "scanner:manyversions",
APIName: ILMExpiry,
APIName: "Scanner",
Bucket: i.bucket,
Object: i.objectPath(),
Tags: map[string]interface{}{
"x-minio-versions": strconv.Itoa(len(fivs)),
"x-minio-versions": strconv.Itoa(len(objInfos)),
},
})
}
@@ -1218,7 +1219,17 @@ func applyTransitionRule(event lifecycle.Event, src lcEventSrc, obj ObjectInfo)
}
func applyExpiryOnTransitionedObject(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, lcEvent lifecycle.Event, src lcEventSrc) bool {
if err := expireTransitionedObject(ctx, objLayer, &obj, obj.ToLifecycleOpts(), lcEvent, src); err != nil {
var err error
defer func() {
if err != nil {
return
}
// Note: DeleteAllVersions action is not supported for
// transitioned objects
globalScannerMetrics.timeILM(lcEvent.Action)(1)
}()
if err = expireTransitionedObject(ctx, objLayer, &obj, lcEvent, src); err != nil {
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
return false
}
@@ -1245,8 +1256,25 @@ func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLay
if lcEvent.Action.DeleteAll() {
opts.DeletePrefix = true
}
var (
dobj ObjectInfo
err error
)
defer func() {
if err != nil {
return
}
dobj, err := objLayer.DeleteObject(ctx, obj.Bucket, obj.Name, opts)
if lcEvent.Action != lifecycle.NoneAction {
numVersions := uint64(1)
if lcEvent.Action == lifecycle.DeleteAllVersionsAction {
numVersions = uint64(obj.NumVersions)
}
globalScannerMetrics.timeILM(lcEvent.Action)(numVersions)
}
}()
dobj, err = objLayer.DeleteObject(ctx, obj.Bucket, obj.Name, opts)
if err != nil {
if isErrObjectNotFound(err) || isErrVersionNotFound(err) {
return false
+4 -8
View File
@@ -24,6 +24,7 @@ import (
"time"
jsoniter "github.com/json-iterator/go"
"github.com/minio/minio/internal/cachevalue"
"github.com/minio/minio/internal/logger"
)
@@ -62,7 +63,7 @@ func storeDataUsageInBackend(ctx context.Context, objAPI ObjectLayer, dui <-chan
}
}
var prefixUsageCache timedValue
var prefixUsageCache = cachevalue.New[map[string]uint64]()
// loadPrefixUsageFromBackend returns prefix usages found in passed buckets
//
@@ -81,7 +82,7 @@ func loadPrefixUsageFromBackend(ctx context.Context, objAPI ObjectLayer, bucket
// No need to fail upon Update() error, fallback to old value.
prefixUsageCache.Relax = true
prefixUsageCache.Update = func() (interface{}, error) {
prefixUsageCache.Update = func() (map[string]uint64, error) {
m := make(map[string]uint64)
for _, pool := range z.serverPools {
for _, er := range pool.sets {
@@ -109,12 +110,7 @@ func loadPrefixUsageFromBackend(ctx context.Context, objAPI ObjectLayer, bucket
}
})
v, _ := prefixUsageCache.Get()
if v != nil {
return v.(map[string]uint64), nil
}
return map[string]uint64{}, nil
return prefixUsageCache.Get()
}
func loadDataUsageFromBackend(ctx context.Context, objAPI ObjectLayer) (DataUsageInfo, error) {
+1 -8
View File
@@ -567,13 +567,6 @@ func (endpoints Endpoints) GetAllStrings() (all []string) {
func hostResolveToLocalhost(endpoint Endpoint) bool {
hostIPs, err := getHostIP(endpoint.Hostname())
if err != nil {
// Log the message to console about the host resolving
reqInfo := (&logger.ReqInfo{}).AppendTags(
"host",
endpoint.Hostname(),
)
ctx := logger.SetReqInfo(GlobalContext, reqInfo)
logger.LogOnceIf(ctx, err, endpoint.Hostname(), logger.ErrorKind)
return false
}
var loopback int
@@ -867,7 +860,7 @@ func (p PoolEndpointList) UpdateIsLocal() error {
))
ctx := logger.SetReqInfo(GlobalContext,
reqInfo)
logger.LogOnceIf(ctx, err, endpoint.Hostname(), logger.ErrorKind)
logger.LogOnceIf(ctx, fmt.Errorf("Unable to resolve DNS for %s: %w", endpoint, err), endpoint.Hostname(), logger.ErrorKind)
}
} else {
resolvedList[endpoint] = true
+7 -7
View File
@@ -58,8 +58,8 @@ func commonETags(etags []string) (etag string, maxima int) {
}
// commonTime returns a maximally occurring time from a list of time.
func commonTimeAndOccurence(times []time.Time, group time.Duration) (maxTime time.Time, maxima int) {
timeOccurenceMap := make(map[int64]int, len(times))
func commonTimeAndOccurrence(times []time.Time, group time.Duration) (maxTime time.Time, maxima int) {
timeOccurrenceMap := make(map[int64]int, len(times))
groupNano := group.Nanoseconds()
// Ignore the uuid sentinel and count the rest.
for _, t := range times {
@@ -68,7 +68,7 @@ func commonTimeAndOccurence(times []time.Time, group time.Duration) (maxTime tim
}
nano := t.UnixNano()
if group > 0 {
for k := range timeOccurenceMap {
for k := range timeOccurrenceMap {
if k == nano {
// We add to ourself later
continue
@@ -79,12 +79,12 @@ func commonTimeAndOccurence(times []time.Time, group time.Duration) (maxTime tim
}
// We are within the limit
if diff < groupNano {
timeOccurenceMap[k]++
timeOccurrenceMap[k]++
}
}
}
// Add ourself...
timeOccurenceMap[nano]++
timeOccurrenceMap[nano]++
}
maxima = 0 // Counter for remembering max occurrence of elements.
@@ -92,7 +92,7 @@ func commonTimeAndOccurence(times []time.Time, group time.Duration) (maxTime tim
// Find the common cardinality from previously collected
// occurrences of elements.
for nano, count := range timeOccurenceMap {
for nano, count := range timeOccurrenceMap {
if count < maxima {
continue
}
@@ -111,7 +111,7 @@ func commonTimeAndOccurence(times []time.Time, group time.Duration) (maxTime tim
// commonTime returns a maximally occurring time from a list of time if it
// occurs >= quorum, else return timeSentinel
func commonTime(modTimes []time.Time, quorum int) time.Time {
if modTime, count := commonTimeAndOccurence(modTimes, 0); count >= quorum {
if modTime, count := commonTimeAndOccurrence(modTimes, 0); count >= quorum {
return modTime
}
+1 -1
View File
@@ -614,7 +614,7 @@ func TestHealingDanglingObject(t *testing.T) {
resetGlobalHealState()
defer resetGlobalHealState()
// Set globalStoragClass.STANDARD to EC:4 for this test
// Set globalStorageClass.STANDARD to EC:4 for this test
saveSC := globalStorageClass
defer func() {
globalStorageClass.Update(saveSC)
+6 -2
View File
@@ -937,7 +937,11 @@ func (er erasureObjects) getObjectFileInfo(ctx context.Context, bucket, object s
onlineDisks[i] = nil
}
mrfCheck <- fi.ShallowCopy()
select {
case mrfCheck <- fi.ShallowCopy():
case <-ctx.Done():
return fi, onlineMeta, onlineDisks, toObjectErr(ctx.Err(), bucket, object)
}
return fi, onlineMeta, onlineDisks, nil
}
@@ -960,7 +964,7 @@ func (er erasureObjects) getObjectInfo(ctx context.Context, bucket, object strin
return objInfo, nil
}
// getObjectInfoAndQuroum - wrapper for reading object metadata and constructs ObjectInfo, additionally returns write quorum for the object.
// getObjectInfoAndQuorum - wrapper for reading object metadata and constructs ObjectInfo, additionally returns write quorum for the object.
func (er erasureObjects) getObjectInfoAndQuorum(ctx context.Context, bucket, object string, opts ObjectOptions) (objInfo ObjectInfo, wquorum int, err error) {
fi, _, _, err := er.getObjectFileInfo(ctx, bucket, object, opts, false)
if err != nil {
+19 -36
View File
@@ -39,6 +39,7 @@ import (
"github.com/minio/minio-go/v7/pkg/set"
"github.com/minio/minio-go/v7/pkg/tags"
"github.com/minio/minio/internal/bpool"
"github.com/minio/minio/internal/cachevalue"
"github.com/minio/minio/internal/config/storageclass"
xioutil "github.com/minio/minio/internal/ioutil"
"github.com/minio/minio/internal/logger"
@@ -1001,20 +1002,10 @@ func (z *erasureServerPools) PutObject(ctx context.Context, bucket string, objec
}
object = encodeDirObject(object)
if z.SinglePool() {
if !isMinioMetaBucketName(bucket) {
avail, err := hasSpaceFor(getDiskInfos(ctx, z.serverPools[0].getHashedSet(object).getDisks()...), data.Size())
if err != nil {
logger.LogOnceIf(ctx, err, "erasure-write-quorum")
return ObjectInfo{}, toObjectErr(errErasureWriteQuorum)
}
if !avail {
return ObjectInfo{}, toObjectErr(errDiskFull)
}
}
return z.serverPools[0].PutObject(ctx, bucket, object, data, opts)
}
if !opts.NoLock {
ns := z.NewNSLock(bucket, object)
lkctx, err := ns.GetLock(ctx, globalOperationTimeout)
@@ -1196,6 +1187,13 @@ func (z *erasureServerPools) DeleteObjects(ctx context.Context, bucket string, o
}
func (z *erasureServerPools) CopyObject(ctx context.Context, srcBucket, srcObject, dstBucket, dstObject string, srcInfo ObjectInfo, srcOpts, dstOpts ObjectOptions) (objInfo ObjectInfo, err error) {
if err := checkCopyObjArgs(ctx, srcBucket, srcObject); err != nil {
return ObjectInfo{}, err
}
if err := checkCopyObjArgs(ctx, dstBucket, dstObject); err != nil {
return ObjectInfo{}, err
}
srcObject = encodeDirObject(srcObject)
dstObject = encodeDirObject(dstObject)
@@ -1574,21 +1572,11 @@ func (z *erasureServerPools) ListMultipartUploads(ctx context.Context, bucket, p
// Initiate a new multipart upload on a hashedSet based on object name.
func (z *erasureServerPools) NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (*NewMultipartUploadResult, error) {
if err := checkNewMultipartArgs(ctx, bucket, object, z); err != nil {
if err := checkNewMultipartArgs(ctx, bucket, object); err != nil {
return nil, err
}
if z.SinglePool() {
if !isMinioMetaBucketName(bucket) {
avail, err := hasSpaceFor(getDiskInfos(ctx, z.serverPools[0].getHashedSet(object).getDisks()...), -1)
if err != nil {
logger.LogIf(ctx, err)
return nil, toObjectErr(errErasureWriteQuorum)
}
if !avail {
return nil, toObjectErr(errDiskFull)
}
}
return z.serverPools[0].NewMultipartUpload(ctx, bucket, object, opts)
}
@@ -1621,7 +1609,7 @@ func (z *erasureServerPools) NewMultipartUpload(ctx context.Context, bucket, obj
// Copies a part of an object from source hashedSet to destination hashedSet.
func (z *erasureServerPools) CopyObjectPart(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, uploadID string, partID int, startOffset int64, length int64, srcInfo ObjectInfo, srcOpts, dstOpts ObjectOptions) (PartInfo, error) {
if err := checkNewMultipartArgs(ctx, srcBucket, srcObject, z); err != nil {
if err := checkNewMultipartArgs(ctx, srcBucket, srcObject); err != nil {
return PartInfo{}, err
}
@@ -1631,7 +1619,7 @@ func (z *erasureServerPools) CopyObjectPart(ctx context.Context, srcBucket, srcO
// PutObjectPart - writes part of an object to hashedSet based on the object name.
func (z *erasureServerPools) PutObjectPart(ctx context.Context, bucket, object, uploadID string, partID int, data *PutObjReader, opts ObjectOptions) (PartInfo, error) {
if err := checkPutObjectPartArgs(ctx, bucket, object, uploadID, z); err != nil {
if err := checkPutObjectPartArgs(ctx, bucket, object, uploadID); err != nil {
return PartInfo{}, err
}
@@ -1663,7 +1651,7 @@ func (z *erasureServerPools) PutObjectPart(ctx context.Context, bucket, object,
}
func (z *erasureServerPools) GetMultipartInfo(ctx context.Context, bucket, object, uploadID string, opts ObjectOptions) (MultipartInfo, error) {
if err := checkListPartsArgs(ctx, bucket, object, uploadID, z); err != nil {
if err := checkListPartsArgs(ctx, bucket, object, uploadID); err != nil {
return MultipartInfo{}, err
}
@@ -1694,7 +1682,7 @@ func (z *erasureServerPools) GetMultipartInfo(ctx context.Context, bucket, objec
// ListObjectParts - lists all uploaded parts to an object in hashedSet.
func (z *erasureServerPools) ListObjectParts(ctx context.Context, bucket, object, uploadID string, partNumberMarker int, maxParts int, opts ObjectOptions) (ListPartsInfo, error) {
if err := checkListPartsArgs(ctx, bucket, object, uploadID, z); err != nil {
if err := checkListPartsArgs(ctx, bucket, object, uploadID); err != nil {
return ListPartsInfo{}, err
}
@@ -1723,7 +1711,7 @@ func (z *erasureServerPools) ListObjectParts(ctx context.Context, bucket, object
// Aborts an in-progress multipart operation on hashedSet based on the object name.
func (z *erasureServerPools) AbortMultipartUpload(ctx context.Context, bucket, object, uploadID string, opts ObjectOptions) error {
if err := checkAbortMultipartArgs(ctx, bucket, object, uploadID, z); err != nil {
if err := checkAbortMultipartArgs(ctx, bucket, object, uploadID); err != nil {
return err
}
@@ -1754,7 +1742,7 @@ func (z *erasureServerPools) AbortMultipartUpload(ctx context.Context, bucket, o
// CompleteMultipartUpload - completes a pending multipart transaction, on hashedSet based on object name.
func (z *erasureServerPools) CompleteMultipartUpload(ctx context.Context, bucket, object, uploadID string, uploadedParts []CompletePart, opts ObjectOptions) (objInfo ObjectInfo, err error) {
if err = checkCompleteMultipartArgs(ctx, bucket, object, uploadID, z); err != nil {
if err = checkCompleteMultipartArgs(ctx, bucket, object, uploadID); err != nil {
return objInfo, err
}
@@ -1853,7 +1841,7 @@ func (z *erasureServerPools) deleteAll(ctx context.Context, bucket, prefix strin
}
}
var listBucketsCache timedValue
var listBucketsCache = cachevalue.New[[]BucketInfo]()
// List all buckets from one of the serverPools, we are not doing merge
// sort here just for simplification. As per design it is assumed
@@ -1864,7 +1852,7 @@ func (z *erasureServerPools) ListBuckets(ctx context.Context, opts BucketOptions
listBucketsCache.TTL = time.Second
listBucketsCache.Relax = true
listBucketsCache.Update = func() (interface{}, error) {
listBucketsCache.Update = func() ([]BucketInfo, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
buckets, err = z.s3Peer.ListBuckets(ctx, opts)
cancel()
@@ -1881,12 +1869,7 @@ func (z *erasureServerPools) ListBuckets(ctx context.Context, opts BucketOptions
}
})
v, _ := listBucketsCache.Get()
if v != nil {
return v.([]BucketInfo), nil
}
return buckets, nil
return listBucketsCache.Get()
}
buckets, err = z.s3Peer.ListBuckets(ctx, opts)
+12 -16
View File
@@ -325,15 +325,18 @@ func (s *erasureSets) GetLockers(setIndex int) func() ([]dsync.NetLocker, string
}
}
func (s *erasureSets) GetEndpointStrings(setIndex int) func() []string {
return func() []string {
eps := make([]string, s.setDriveCount)
copy(eps, s.endpointStrings[setIndex*s.setDriveCount:setIndex*s.setDriveCount+s.setDriveCount])
return eps
}
}
func (s *erasureSets) GetEndpoints(setIndex int) func() []Endpoint {
return func() []Endpoint {
s.erasureDisksMu.RLock()
defer s.erasureDisksMu.RUnlock()
eps := make([]Endpoint, s.setDriveCount)
for i := 0; i < s.setDriveCount; i++ {
eps[i] = s.endpoints.Endpoints[setIndex*s.setDriveCount+i]
}
copy(eps, s.endpoints.Endpoints[setIndex*s.setDriveCount:setIndex*s.setDriveCount+s.setDriveCount])
return eps
}
}
@@ -463,7 +466,6 @@ func newErasureSets(ctx context.Context, endpoints PoolEndpoints, storageDisks [
return
}
disk.SetDiskLoc(s.poolIndex, m, n)
s.endpointStrings[m*setDriveCount+n] = disk.String()
s.erasureDisks[m][n] = disk
}(disk, i, j)
}
@@ -478,6 +480,7 @@ func newErasureSets(ctx context.Context, endpoints PoolEndpoints, storageDisks [
getDisks: s.GetDisks(i),
getLockers: s.GetLockers(i),
getEndpoints: s.GetEndpoints(i),
getEndpointStrings: s.GetEndpointStrings(i),
nsMutex: mutex,
}
}(i)
@@ -571,18 +574,11 @@ func auditObjectErasureSet(ctx context.Context, object string, set *erasureObjec
return
}
object = decodeDirObject(object)
endpoints := set.getEndpoints()
disksEndpoints := make([]string, 0, len(endpoints))
for _, endpoint := range endpoints {
disksEndpoints = append(disksEndpoints, endpoint.String())
}
op := auditObjectOp{
Name: object,
Name: decodeDirObject(object),
Pool: set.poolIndex + 1,
Set: set.setIndex + 1,
Disks: disksEndpoints,
Disks: set.getEndpointStrings(),
}
logger.GetReqInfo(ctx).AppendTags("objectLocation", op)
+5 -1
View File
@@ -58,10 +58,14 @@ type erasureObjects struct {
// getLockers returns list of remote and local lockers.
getLockers func() ([]dsync.NetLocker, string)
// getEndpoints returns list of endpoint strings belonging this set.
// getEndpoints returns list of endpoint belonging this set.
// some may be local and some remote.
getEndpoints func() []Endpoint
// getEndpoints returns list of endpoint strings belonging this set.
// some may be local and some remote.
getEndpointStrings func() []string
// Locker mutex map.
nsMutex *nsLockMap
}
+1 -1
View File
@@ -32,7 +32,7 @@ import (
)
// Tests validate bucket LocationConstraint.
func TestIsValidLocationContraint(t *testing.T) {
func TestIsValidLocationConstraint(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
+4
View File
@@ -113,6 +113,10 @@ func metricsRequestAuthenticate(req *http.Request) (*xjwt.MapClaims, []string, b
return nil, errInvalidAccessKeyID
}
cred := u.Credentials
// Expired credentials return error.
if cred.IsTemp() && cred.IsExpired() {
return nil, errInvalidAccessKeyID
}
return []byte(cred.SecretKey), nil
} // this means claims.AccessKey == rootAccessKey
if !globalAPIConfig.permitRootAccess() {
+10 -7
View File
@@ -17,6 +17,8 @@
package cmd
//go:generate msgp -file=$GOFILE -unexported
import (
"context"
"fmt"
@@ -36,12 +38,9 @@ type lockRequesterInfo struct {
TimeLastRefresh time.Time // Timestamp for last lock refresh.
Source string // Contains line, function and filename requesting the lock.
Group bool // indicates if it was a group lock.
// Owner represents the UUID of the owner who originally requested the lock
// useful in expiry.
Owner string
// Quorum represents the quorum required for this lock to be active.
Quorum int
idx int
Owner string // Owner represents the UUID of the owner who originally requested the lock.
Quorum int // Quorum represents the quorum required for this lock to be active.
idx int `msg:"-"` // index of the lock in the lockMap.
}
// isWriteLock returns whether the lock is a write or read lock.
@@ -50,6 +49,8 @@ func isWriteLock(lri []lockRequesterInfo) bool {
}
// localLocker implements Dsync.NetLocker
//
//msgp:ignore localLocker
type localLocker struct {
mutex sync.Mutex
lockMap map[string][]lockRequesterInfo
@@ -238,7 +239,9 @@ func (l *localLocker) stats() lockStats {
return st
}
func (l *localLocker) DupLockMap() map[string][]lockRequesterInfo {
type localLockMap map[string][]lockRequesterInfo
func (l *localLocker) DupLockMap() localLockMap {
l.mutex.Lock()
defer l.mutex.Unlock()
+620
View File
@@ -0,0 +1,620 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"github.com/tinylib/msgp/msgp"
)
// DecodeMsg implements msgp.Decodable
func (z *localLockMap) DecodeMsg(dc *msgp.Reader) (err error) {
var zb0004 uint32
zb0004, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err)
return
}
if (*z) == nil {
(*z) = make(localLockMap, zb0004)
} else if len((*z)) > 0 {
for key := range *z {
delete((*z), key)
}
}
for zb0004 > 0 {
zb0004--
var zb0001 string
var zb0002 []lockRequesterInfo
zb0001, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err)
return
}
var zb0005 uint32
zb0005, err = dc.ReadArrayHeader()
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
if cap(zb0002) >= int(zb0005) {
zb0002 = (zb0002)[:zb0005]
} else {
zb0002 = make([]lockRequesterInfo, zb0005)
}
for zb0003 := range zb0002 {
err = zb0002[zb0003].DecodeMsg(dc)
if err != nil {
err = msgp.WrapError(err, zb0001, zb0003)
return
}
}
(*z)[zb0001] = zb0002
}
return
}
// EncodeMsg implements msgp.Encodable
func (z localLockMap) EncodeMsg(en *msgp.Writer) (err error) {
err = en.WriteMapHeader(uint32(len(z)))
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0006, zb0007 := range z {
err = en.WriteString(zb0006)
if err != nil {
err = msgp.WrapError(err)
return
}
err = en.WriteArrayHeader(uint32(len(zb0007)))
if err != nil {
err = msgp.WrapError(err, zb0006)
return
}
for zb0008 := range zb0007 {
err = zb0007[zb0008].EncodeMsg(en)
if err != nil {
err = msgp.WrapError(err, zb0006, zb0008)
return
}
}
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z localLockMap) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
o = msgp.AppendMapHeader(o, uint32(len(z)))
for zb0006, zb0007 := range z {
o = msgp.AppendString(o, zb0006)
o = msgp.AppendArrayHeader(o, uint32(len(zb0007)))
for zb0008 := range zb0007 {
o, err = zb0007[zb0008].MarshalMsg(o)
if err != nil {
err = msgp.WrapError(err, zb0006, zb0008)
return
}
}
}
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *localLockMap) UnmarshalMsg(bts []byte) (o []byte, err error) {
var zb0004 uint32
zb0004, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
if (*z) == nil {
(*z) = make(localLockMap, zb0004)
} else if len((*z)) > 0 {
for key := range *z {
delete((*z), key)
}
}
for zb0004 > 0 {
var zb0001 string
var zb0002 []lockRequesterInfo
zb0004--
zb0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
var zb0005 uint32
zb0005, bts, err = msgp.ReadArrayHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
if cap(zb0002) >= int(zb0005) {
zb0002 = (zb0002)[:zb0005]
} else {
zb0002 = make([]lockRequesterInfo, zb0005)
}
for zb0003 := range zb0002 {
bts, err = zb0002[zb0003].UnmarshalMsg(bts)
if err != nil {
err = msgp.WrapError(err, zb0001, zb0003)
return
}
}
(*z)[zb0001] = zb0002
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z localLockMap) Msgsize() (s int) {
s = msgp.MapHeaderSize
if z != nil {
for zb0006, zb0007 := range z {
_ = zb0007
s += msgp.StringPrefixSize + len(zb0006) + msgp.ArrayHeaderSize
for zb0008 := range zb0007 {
s += zb0007[zb0008].Msgsize()
}
}
}
return
}
// DecodeMsg implements msgp.Decodable
func (z *lockRequesterInfo) 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 "Name":
z.Name, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Name")
return
}
case "Writer":
z.Writer, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "Writer")
return
}
case "UID":
z.UID, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "UID")
return
}
case "Timestamp":
z.Timestamp, err = dc.ReadTime()
if err != nil {
err = msgp.WrapError(err, "Timestamp")
return
}
case "TimeLastRefresh":
z.TimeLastRefresh, err = dc.ReadTime()
if err != nil {
err = msgp.WrapError(err, "TimeLastRefresh")
return
}
case "Source":
z.Source, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Source")
return
}
case "Group":
z.Group, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "Group")
return
}
case "Owner":
z.Owner, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Owner")
return
}
case "Quorum":
z.Quorum, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "Quorum")
return
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *lockRequesterInfo) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 9
// write "Name"
err = en.Append(0x89, 0xa4, 0x4e, 0x61, 0x6d, 0x65)
if err != nil {
return
}
err = en.WriteString(z.Name)
if err != nil {
err = msgp.WrapError(err, "Name")
return
}
// write "Writer"
err = en.Append(0xa6, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72)
if err != nil {
return
}
err = en.WriteBool(z.Writer)
if err != nil {
err = msgp.WrapError(err, "Writer")
return
}
// write "UID"
err = en.Append(0xa3, 0x55, 0x49, 0x44)
if err != nil {
return
}
err = en.WriteString(z.UID)
if err != nil {
err = msgp.WrapError(err, "UID")
return
}
// write "Timestamp"
err = en.Append(0xa9, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70)
if err != nil {
return
}
err = en.WriteTime(z.Timestamp)
if err != nil {
err = msgp.WrapError(err, "Timestamp")
return
}
// write "TimeLastRefresh"
err = en.Append(0xaf, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68)
if err != nil {
return
}
err = en.WriteTime(z.TimeLastRefresh)
if err != nil {
err = msgp.WrapError(err, "TimeLastRefresh")
return
}
// write "Source"
err = en.Append(0xa6, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65)
if err != nil {
return
}
err = en.WriteString(z.Source)
if err != nil {
err = msgp.WrapError(err, "Source")
return
}
// write "Group"
err = en.Append(0xa5, 0x47, 0x72, 0x6f, 0x75, 0x70)
if err != nil {
return
}
err = en.WriteBool(z.Group)
if err != nil {
err = msgp.WrapError(err, "Group")
return
}
// write "Owner"
err = en.Append(0xa5, 0x4f, 0x77, 0x6e, 0x65, 0x72)
if err != nil {
return
}
err = en.WriteString(z.Owner)
if err != nil {
err = msgp.WrapError(err, "Owner")
return
}
// write "Quorum"
err = en.Append(0xa6, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d)
if err != nil {
return
}
err = en.WriteInt(z.Quorum)
if err != nil {
err = msgp.WrapError(err, "Quorum")
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *lockRequesterInfo) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 9
// string "Name"
o = append(o, 0x89, 0xa4, 0x4e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, z.Name)
// string "Writer"
o = append(o, 0xa6, 0x57, 0x72, 0x69, 0x74, 0x65, 0x72)
o = msgp.AppendBool(o, z.Writer)
// string "UID"
o = append(o, 0xa3, 0x55, 0x49, 0x44)
o = msgp.AppendString(o, z.UID)
// string "Timestamp"
o = append(o, 0xa9, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70)
o = msgp.AppendTime(o, z.Timestamp)
// string "TimeLastRefresh"
o = append(o, 0xaf, 0x54, 0x69, 0x6d, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68)
o = msgp.AppendTime(o, z.TimeLastRefresh)
// string "Source"
o = append(o, 0xa6, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65)
o = msgp.AppendString(o, z.Source)
// string "Group"
o = append(o, 0xa5, 0x47, 0x72, 0x6f, 0x75, 0x70)
o = msgp.AppendBool(o, z.Group)
// string "Owner"
o = append(o, 0xa5, 0x4f, 0x77, 0x6e, 0x65, 0x72)
o = msgp.AppendString(o, z.Owner)
// string "Quorum"
o = append(o, 0xa6, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d)
o = msgp.AppendInt(o, z.Quorum)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *lockRequesterInfo) 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 "Name":
z.Name, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Name")
return
}
case "Writer":
z.Writer, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Writer")
return
}
case "UID":
z.UID, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "UID")
return
}
case "Timestamp":
z.Timestamp, bts, err = msgp.ReadTimeBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Timestamp")
return
}
case "TimeLastRefresh":
z.TimeLastRefresh, bts, err = msgp.ReadTimeBytes(bts)
if err != nil {
err = msgp.WrapError(err, "TimeLastRefresh")
return
}
case "Source":
z.Source, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Source")
return
}
case "Group":
z.Group, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Group")
return
}
case "Owner":
z.Owner, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Owner")
return
}
case "Quorum":
z.Quorum, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Quorum")
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 *lockRequesterInfo) Msgsize() (s int) {
s = 1 + 5 + msgp.StringPrefixSize + len(z.Name) + 7 + msgp.BoolSize + 4 + msgp.StringPrefixSize + len(z.UID) + 10 + msgp.TimeSize + 16 + msgp.TimeSize + 7 + msgp.StringPrefixSize + len(z.Source) + 6 + msgp.BoolSize + 6 + msgp.StringPrefixSize + len(z.Owner) + 7 + msgp.IntSize
return
}
// DecodeMsg implements msgp.Decodable
func (z *lockStats) 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 "Total":
z.Total, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "Total")
return
}
case "Writes":
z.Writes, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "Writes")
return
}
case "Reads":
z.Reads, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "Reads")
return
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z lockStats) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 3
// write "Total"
err = en.Append(0x83, 0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c)
if err != nil {
return
}
err = en.WriteInt(z.Total)
if err != nil {
err = msgp.WrapError(err, "Total")
return
}
// write "Writes"
err = en.Append(0xa6, 0x57, 0x72, 0x69, 0x74, 0x65, 0x73)
if err != nil {
return
}
err = en.WriteInt(z.Writes)
if err != nil {
err = msgp.WrapError(err, "Writes")
return
}
// write "Reads"
err = en.Append(0xa5, 0x52, 0x65, 0x61, 0x64, 0x73)
if err != nil {
return
}
err = en.WriteInt(z.Reads)
if err != nil {
err = msgp.WrapError(err, "Reads")
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z lockStats) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 3
// string "Total"
o = append(o, 0x83, 0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c)
o = msgp.AppendInt(o, z.Total)
// string "Writes"
o = append(o, 0xa6, 0x57, 0x72, 0x69, 0x74, 0x65, 0x73)
o = msgp.AppendInt(o, z.Writes)
// string "Reads"
o = append(o, 0xa5, 0x52, 0x65, 0x61, 0x64, 0x73)
o = msgp.AppendInt(o, z.Reads)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *lockStats) 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 "Total":
z.Total, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Total")
return
}
case "Writes":
z.Writes, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Writes")
return
}
case "Reads":
z.Reads, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Reads")
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 lockStats) Msgsize() (s int) {
s = 1 + 6 + msgp.IntSize + 7 + msgp.IntSize + 6 + msgp.IntSize
return
}
+349
View File
@@ -0,0 +1,349 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"bytes"
"testing"
"github.com/tinylib/msgp/msgp"
)
func TestMarshalUnmarshallocalLockMap(t *testing.T) {
v := localLockMap{}
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 BenchmarkMarshalMsglocalLockMap(b *testing.B) {
v := localLockMap{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsglocalLockMap(b *testing.B) {
v := localLockMap{}
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 BenchmarkUnmarshallocalLockMap(b *testing.B) {
v := localLockMap{}
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 TestEncodeDecodelocalLockMap(t *testing.T) {
v := localLockMap{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodelocalLockMap Msgsize() is inaccurate")
}
vn := localLockMap{}
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 BenchmarkEncodelocalLockMap(b *testing.B) {
v := localLockMap{}
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 BenchmarkDecodelocalLockMap(b *testing.B) {
v := localLockMap{}
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 TestMarshalUnmarshallockRequesterInfo(t *testing.T) {
v := lockRequesterInfo{}
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 BenchmarkMarshalMsglockRequesterInfo(b *testing.B) {
v := lockRequesterInfo{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsglockRequesterInfo(b *testing.B) {
v := lockRequesterInfo{}
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 BenchmarkUnmarshallockRequesterInfo(b *testing.B) {
v := lockRequesterInfo{}
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 TestEncodeDecodelockRequesterInfo(t *testing.T) {
v := lockRequesterInfo{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodelockRequesterInfo Msgsize() is inaccurate")
}
vn := lockRequesterInfo{}
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 BenchmarkEncodelockRequesterInfo(b *testing.B) {
v := lockRequesterInfo{}
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 BenchmarkDecodelockRequesterInfo(b *testing.B) {
v := lockRequesterInfo{}
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 TestMarshalUnmarshallockStats(t *testing.T) {
v := lockStats{}
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 BenchmarkMarshalMsglockStats(b *testing.B) {
v := lockStats{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsglockStats(b *testing.B) {
v := lockStats{}
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 BenchmarkUnmarshallockStats(b *testing.B) {
v := lockStats{}
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 TestEncodeDecodelockStats(t *testing.T) {
v := lockStats{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodelockStats Msgsize() is inaccurate")
}
vn := lockStats{}
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 BenchmarkEncodelockStats(b *testing.B) {
v := lockStats{}
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 BenchmarkDecodelockStats(b *testing.B) {
v := lockStats{}
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)
}
}
}
+12 -5
View File
@@ -42,6 +42,8 @@ import (
"github.com/minio/pkg/v2/console"
)
//go:generate msgp -file $GOFILE -unexported
type listPathOptions struct {
// ID of the listing.
// This will be used to persist the list.
@@ -99,18 +101,18 @@ type listPathOptions struct {
// Versioning config is used for if the path
// has versioning enabled.
Versioning *versioning.Versioning
Versioning *versioning.Versioning `msg:"-"`
// Lifecycle performs filtering based on lifecycle.
// This will filter out objects if the most recent version should be deleted by lifecycle.
// Is not transferred across request calls.
Lifecycle *lifecycle.Lifecycle
Lifecycle *lifecycle.Lifecycle `msg:"-"`
// Retention configuration, needed to be passed along with lifecycle if set.
Retention lock.Retention
Retention lock.Retention `msg:"-"`
// Replication configuration
Replication replicationConfig
Replication replicationConfig `msg:"-"`
// StopDiskAtLimit will stop listing on each disk when limit number off objects has been returned.
StopDiskAtLimit bool
@@ -217,7 +219,10 @@ func (o *listPathOptions) gatherResults(ctx context.Context, in <-chan metaCache
// Do not return io.EOF
if resCh != nil {
resErr = nil
resCh <- results
select {
case resCh <- results:
case <-ctx.Done():
}
resCh = nil
returned = true
}
@@ -767,6 +772,7 @@ func (er *erasureObjects) listPath(ctx context.Context, o listPathOptions, resul
})
}
//msgp:ignore metaCacheRPC
type metaCacheRPC struct {
o listPathOptions
mu sync.Mutex
@@ -917,6 +923,7 @@ func (er *erasureObjects) saveMetaCacheStream(ctx context.Context, mc *metaCache
return nil
}
//msgp:ignore listPathRawOptions
type listPathRawOptions struct {
disks []StorageAPI
fallbackDisks []StorageAPI
+535
View File
@@ -0,0 +1,535 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"github.com/tinylib/msgp/msgp"
)
// DecodeMsg implements msgp.Decodable
func (z *listPathOptions) 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 "ID":
z.ID, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "ID")
return
}
case "Bucket":
z.Bucket, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Bucket")
return
}
case "BaseDir":
z.BaseDir, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "BaseDir")
return
}
case "Prefix":
z.Prefix, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Prefix")
return
}
case "FilterPrefix":
z.FilterPrefix, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "FilterPrefix")
return
}
case "Marker":
z.Marker, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Marker")
return
}
case "Limit":
z.Limit, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "Limit")
return
}
case "AskDisks":
z.AskDisks, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "AskDisks")
return
}
case "InclDeleted":
z.InclDeleted, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "InclDeleted")
return
}
case "Recursive":
z.Recursive, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "Recursive")
return
}
case "Separator":
z.Separator, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Separator")
return
}
case "Create":
z.Create, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "Create")
return
}
case "IncludeDirectories":
z.IncludeDirectories, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "IncludeDirectories")
return
}
case "Transient":
z.Transient, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "Transient")
return
}
case "Versioned":
z.Versioned, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "Versioned")
return
}
case "StopDiskAtLimit":
z.StopDiskAtLimit, err = dc.ReadBool()
if err != nil {
err = msgp.WrapError(err, "StopDiskAtLimit")
return
}
case "pool":
z.pool, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "pool")
return
}
case "set":
z.set, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "set")
return
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *listPathOptions) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 18
// write "ID"
err = en.Append(0xde, 0x0, 0x12, 0xa2, 0x49, 0x44)
if err != nil {
return
}
err = en.WriteString(z.ID)
if err != nil {
err = msgp.WrapError(err, "ID")
return
}
// write "Bucket"
err = en.Append(0xa6, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74)
if err != nil {
return
}
err = en.WriteString(z.Bucket)
if err != nil {
err = msgp.WrapError(err, "Bucket")
return
}
// write "BaseDir"
err = en.Append(0xa7, 0x42, 0x61, 0x73, 0x65, 0x44, 0x69, 0x72)
if err != nil {
return
}
err = en.WriteString(z.BaseDir)
if err != nil {
err = msgp.WrapError(err, "BaseDir")
return
}
// write "Prefix"
err = en.Append(0xa6, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78)
if err != nil {
return
}
err = en.WriteString(z.Prefix)
if err != nil {
err = msgp.WrapError(err, "Prefix")
return
}
// write "FilterPrefix"
err = en.Append(0xac, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78)
if err != nil {
return
}
err = en.WriteString(z.FilterPrefix)
if err != nil {
err = msgp.WrapError(err, "FilterPrefix")
return
}
// write "Marker"
err = en.Append(0xa6, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x72)
if err != nil {
return
}
err = en.WriteString(z.Marker)
if err != nil {
err = msgp.WrapError(err, "Marker")
return
}
// write "Limit"
err = en.Append(0xa5, 0x4c, 0x69, 0x6d, 0x69, 0x74)
if err != nil {
return
}
err = en.WriteInt(z.Limit)
if err != nil {
err = msgp.WrapError(err, "Limit")
return
}
// write "AskDisks"
err = en.Append(0xa8, 0x41, 0x73, 0x6b, 0x44, 0x69, 0x73, 0x6b, 0x73)
if err != nil {
return
}
err = en.WriteString(z.AskDisks)
if err != nil {
err = msgp.WrapError(err, "AskDisks")
return
}
// write "InclDeleted"
err = en.Append(0xab, 0x49, 0x6e, 0x63, 0x6c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64)
if err != nil {
return
}
err = en.WriteBool(z.InclDeleted)
if err != nil {
err = msgp.WrapError(err, "InclDeleted")
return
}
// write "Recursive"
err = en.Append(0xa9, 0x52, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65)
if err != nil {
return
}
err = en.WriteBool(z.Recursive)
if err != nil {
err = msgp.WrapError(err, "Recursive")
return
}
// write "Separator"
err = en.Append(0xa9, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72)
if err != nil {
return
}
err = en.WriteString(z.Separator)
if err != nil {
err = msgp.WrapError(err, "Separator")
return
}
// write "Create"
err = en.Append(0xa6, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65)
if err != nil {
return
}
err = en.WriteBool(z.Create)
if err != nil {
err = msgp.WrapError(err, "Create")
return
}
// write "IncludeDirectories"
err = en.Append(0xb2, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73)
if err != nil {
return
}
err = en.WriteBool(z.IncludeDirectories)
if err != nil {
err = msgp.WrapError(err, "IncludeDirectories")
return
}
// write "Transient"
err = en.Append(0xa9, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x65, 0x6e, 0x74)
if err != nil {
return
}
err = en.WriteBool(z.Transient)
if err != nil {
err = msgp.WrapError(err, "Transient")
return
}
// write "Versioned"
err = en.Append(0xa9, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64)
if err != nil {
return
}
err = en.WriteBool(z.Versioned)
if err != nil {
err = msgp.WrapError(err, "Versioned")
return
}
// write "StopDiskAtLimit"
err = en.Append(0xaf, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x69, 0x73, 0x6b, 0x41, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74)
if err != nil {
return
}
err = en.WriteBool(z.StopDiskAtLimit)
if err != nil {
err = msgp.WrapError(err, "StopDiskAtLimit")
return
}
// write "pool"
err = en.Append(0xa4, 0x70, 0x6f, 0x6f, 0x6c)
if err != nil {
return
}
err = en.WriteInt(z.pool)
if err != nil {
err = msgp.WrapError(err, "pool")
return
}
// write "set"
err = en.Append(0xa3, 0x73, 0x65, 0x74)
if err != nil {
return
}
err = en.WriteInt(z.set)
if err != nil {
err = msgp.WrapError(err, "set")
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *listPathOptions) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 18
// string "ID"
o = append(o, 0xde, 0x0, 0x12, 0xa2, 0x49, 0x44)
o = msgp.AppendString(o, z.ID)
// string "Bucket"
o = append(o, 0xa6, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74)
o = msgp.AppendString(o, z.Bucket)
// string "BaseDir"
o = append(o, 0xa7, 0x42, 0x61, 0x73, 0x65, 0x44, 0x69, 0x72)
o = msgp.AppendString(o, z.BaseDir)
// string "Prefix"
o = append(o, 0xa6, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78)
o = msgp.AppendString(o, z.Prefix)
// string "FilterPrefix"
o = append(o, 0xac, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78)
o = msgp.AppendString(o, z.FilterPrefix)
// string "Marker"
o = append(o, 0xa6, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x72)
o = msgp.AppendString(o, z.Marker)
// string "Limit"
o = append(o, 0xa5, 0x4c, 0x69, 0x6d, 0x69, 0x74)
o = msgp.AppendInt(o, z.Limit)
// string "AskDisks"
o = append(o, 0xa8, 0x41, 0x73, 0x6b, 0x44, 0x69, 0x73, 0x6b, 0x73)
o = msgp.AppendString(o, z.AskDisks)
// string "InclDeleted"
o = append(o, 0xab, 0x49, 0x6e, 0x63, 0x6c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64)
o = msgp.AppendBool(o, z.InclDeleted)
// string "Recursive"
o = append(o, 0xa9, 0x52, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65)
o = msgp.AppendBool(o, z.Recursive)
// string "Separator"
o = append(o, 0xa9, 0x53, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x72)
o = msgp.AppendString(o, z.Separator)
// string "Create"
o = append(o, 0xa6, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65)
o = msgp.AppendBool(o, z.Create)
// string "IncludeDirectories"
o = append(o, 0xb2, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73)
o = msgp.AppendBool(o, z.IncludeDirectories)
// string "Transient"
o = append(o, 0xa9, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x65, 0x6e, 0x74)
o = msgp.AppendBool(o, z.Transient)
// string "Versioned"
o = append(o, 0xa9, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64)
o = msgp.AppendBool(o, z.Versioned)
// string "StopDiskAtLimit"
o = append(o, 0xaf, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x69, 0x73, 0x6b, 0x41, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74)
o = msgp.AppendBool(o, z.StopDiskAtLimit)
// string "pool"
o = append(o, 0xa4, 0x70, 0x6f, 0x6f, 0x6c)
o = msgp.AppendInt(o, z.pool)
// string "set"
o = append(o, 0xa3, 0x73, 0x65, 0x74)
o = msgp.AppendInt(o, z.set)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *listPathOptions) 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 "ID":
z.ID, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "ID")
return
}
case "Bucket":
z.Bucket, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Bucket")
return
}
case "BaseDir":
z.BaseDir, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "BaseDir")
return
}
case "Prefix":
z.Prefix, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Prefix")
return
}
case "FilterPrefix":
z.FilterPrefix, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "FilterPrefix")
return
}
case "Marker":
z.Marker, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Marker")
return
}
case "Limit":
z.Limit, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Limit")
return
}
case "AskDisks":
z.AskDisks, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "AskDisks")
return
}
case "InclDeleted":
z.InclDeleted, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "InclDeleted")
return
}
case "Recursive":
z.Recursive, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Recursive")
return
}
case "Separator":
z.Separator, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Separator")
return
}
case "Create":
z.Create, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Create")
return
}
case "IncludeDirectories":
z.IncludeDirectories, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "IncludeDirectories")
return
}
case "Transient":
z.Transient, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Transient")
return
}
case "Versioned":
z.Versioned, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Versioned")
return
}
case "StopDiskAtLimit":
z.StopDiskAtLimit, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "StopDiskAtLimit")
return
}
case "pool":
z.pool, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "pool")
return
}
case "set":
z.set, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "set")
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 *listPathOptions) Msgsize() (s int) {
s = 3 + 3 + msgp.StringPrefixSize + len(z.ID) + 7 + msgp.StringPrefixSize + len(z.Bucket) + 8 + msgp.StringPrefixSize + len(z.BaseDir) + 7 + msgp.StringPrefixSize + len(z.Prefix) + 13 + msgp.StringPrefixSize + len(z.FilterPrefix) + 7 + msgp.StringPrefixSize + len(z.Marker) + 6 + msgp.IntSize + 9 + msgp.StringPrefixSize + len(z.AskDisks) + 12 + msgp.BoolSize + 10 + msgp.BoolSize + 10 + msgp.StringPrefixSize + len(z.Separator) + 7 + msgp.BoolSize + 19 + msgp.BoolSize + 10 + msgp.BoolSize + 10 + msgp.BoolSize + 16 + msgp.BoolSize + 5 + msgp.IntSize + 4 + msgp.IntSize
return
}
+123
View File
@@ -0,0 +1,123 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"bytes"
"testing"
"github.com/tinylib/msgp/msgp"
)
func TestMarshalUnmarshallistPathOptions(t *testing.T) {
v := listPathOptions{}
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 BenchmarkMarshalMsglistPathOptions(b *testing.B) {
v := listPathOptions{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsglistPathOptions(b *testing.B) {
v := listPathOptions{}
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 BenchmarkUnmarshallistPathOptions(b *testing.B) {
v := listPathOptions{}
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 TestEncodeDecodelistPathOptions(t *testing.T) {
v := listPathOptions{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodelistPathOptions Msgsize() is inaccurate")
}
vn := listPathOptions{}
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 BenchmarkEncodelistPathOptions(b *testing.B) {
v := listPathOptions{}
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 BenchmarkDecodelistPathOptions(b *testing.B) {
v := listPathOptions{}
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)
}
}
}
+10 -2
View File
@@ -299,7 +299,11 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
// If directory entry on stack before this, pop it now.
for len(dirStack) > 0 && dirStack[len(dirStack)-1] < meta.name {
pop := dirStack[len(dirStack)-1]
out <- metaCacheEntry{name: pop}
select {
case <-ctx.Done():
return ctx.Err()
case out <- metaCacheEntry{name: pop}:
}
if opts.Recursive {
// Scan folder we found. Should be in correct sort order where we are.
err := scanDir(pop)
@@ -368,7 +372,11 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ
return ctx.Err()
}
pop := dirStack[len(dirStack)-1]
out <- metaCacheEntry{name: pop}
select {
case <-ctx.Done():
return ctx.Err()
case out <- metaCacheEntry{name: pop}:
}
if opts.Recursive {
// Scan folder we found. Should be in correct sort order where we are.
logger.LogIf(ctx, scanDir(pop))
+19 -12
View File
@@ -32,6 +32,7 @@ import (
"github.com/minio/kes-go"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio/internal/bucket/lifecycle"
"github.com/minio/minio/internal/cachevalue"
xioutil "github.com/minio/minio/internal/ioutil"
"github.com/minio/minio/internal/logger"
"github.com/minio/minio/internal/mcontext"
@@ -42,6 +43,8 @@ import (
"github.com/prometheus/procfs"
)
//go:generate msgp -file=$GOFILE -unexported -io=false
var (
nodeCollector *minioNodeCollector
clusterCollector *minioClusterCollector
@@ -328,7 +331,7 @@ type Metric struct {
// MetricsGroup are a group of metrics that are initialized together.
type MetricsGroup struct {
metricsCache timedValue
metricsCache *cachevalue.Cache[[]Metric] `msg:"-"`
cacheInterval time.Duration
metricsGroupOpts MetricsGroupOpts
}
@@ -352,10 +355,11 @@ type MetricsGroupOpts struct {
// RegisterRead register the metrics populator function to be used
// to populate new values upon cache invalidation.
func (g *MetricsGroup) RegisterRead(read func(ctx context.Context) []Metric) {
g.metricsCache = cachevalue.New[[]Metric]()
g.metricsCache.Once.Do(func() {
g.metricsCache.Relax = true
g.metricsCache.TTL = g.cacheInterval
g.metricsCache.Update = func() (interface{}, error) {
g.metricsCache.Update = func() ([]Metric, error) {
if g.metricsGroupOpts.dependGlobalObjectAPI {
objLayer := newObjectLayerFn()
// Service not initialized yet
@@ -418,14 +422,14 @@ func (g *MetricsGroup) RegisterRead(read func(ctx context.Context) []Metric) {
})
}
func (m *Metric) copyMetric() Metric {
func (m *Metric) clone() Metric {
metric := Metric{
Description: m.Description,
Value: m.Value,
HistogramBucketLabel: m.HistogramBucketLabel,
StaticLabels: make(map[string]string),
VariableLabels: make(map[string]string),
Histogram: make(map[string]uint64),
StaticLabels: make(map[string]string, len(m.StaticLabels)),
VariableLabels: make(map[string]string, len(m.VariableLabels)),
Histogram: make(map[string]uint64, len(m.Histogram)),
}
for k, v := range m.StaticLabels {
metric.StaticLabels[k] = v
@@ -443,15 +447,14 @@ func (m *Metric) copyMetric() Metric {
// once the TTL expires "read()" registered function is called
// to return the new values and updated.
func (g *MetricsGroup) Get() (metrics []Metric) {
c, _ := g.metricsCache.Get()
m, ok := c.([]Metric)
if !ok {
m, _ := g.metricsCache.Get()
if len(m) == 0 {
return []Metric{}
}
metrics = make([]Metric, 0, len(m))
for i := range m {
metrics = append(metrics, m[i].copyMetric())
metrics = append(metrics, m[i].clone())
}
return metrics
}
@@ -536,7 +539,7 @@ func getNodeDriveTimeoutErrorsMD() MetricDescription {
}
}
func getNodeDriveAvailablityErrorsMD() MetricDescription {
func getNodeDriveAvailabilityErrorsMD() MetricDescription {
return MetricDescription{
Namespace: nodeMetricNamespace,
Subsystem: driveSubsystem,
@@ -3464,7 +3467,7 @@ func getLocalStorageMetrics(opts MetricsGroupOpts) *MetricsGroup {
})
metrics = append(metrics, Metric{
Description: getNodeDriveAvailablityErrorsMD(),
Description: getNodeDriveAvailabilityErrorsMD(),
Value: float64(disk.Metrics.TotalErrorsAvailability),
VariableLabels: map[string]string{"drive": disk.DrivePath},
})
@@ -3989,6 +3992,7 @@ func collectMetric(metric Metric, labels []string, values []string, metricName s
}
}
//msgp:ignore minioBucketCollector
type minioBucketCollector struct {
metricsGroups []*MetricsGroup
desc *prometheus.Desc
@@ -4024,6 +4028,7 @@ func (c *minioBucketCollector) Collect(out chan<- prometheus.Metric) {
wg.Wait()
}
//msgp:ignore minioClusterCollector
type minioClusterCollector struct {
metricsGroups []*MetricsGroup
desc *prometheus.Desc
@@ -4083,6 +4088,8 @@ func ReportMetrics(ctx context.Context, metricsGroups []*MetricsGroup) <-chan Me
}
// minioNodeCollector is the Custom Collector
//
//msgp:ignore minioNodeCollector
type minioNodeCollector struct {
metricsGroups []*MetricsGroup
desc *prometheus.Desc
+644
View File
@@ -0,0 +1,644 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"github.com/tinylib/msgp/msgp"
)
// MarshalMsg implements msgp.Marshaler
func (z *Metric) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 6
// string "Description"
o = append(o, 0x86, 0xab, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e)
o, err = z.Description.MarshalMsg(o)
if err != nil {
err = msgp.WrapError(err, "Description")
return
}
// string "StaticLabels"
o = append(o, 0xac, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73)
o = msgp.AppendMapHeader(o, uint32(len(z.StaticLabels)))
for za0001, za0002 := range z.StaticLabels {
o = msgp.AppendString(o, za0001)
o = msgp.AppendString(o, za0002)
}
// string "Value"
o = append(o, 0xa5, 0x56, 0x61, 0x6c, 0x75, 0x65)
o = msgp.AppendFloat64(o, z.Value)
// string "VariableLabels"
o = append(o, 0xae, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73)
o = msgp.AppendMapHeader(o, uint32(len(z.VariableLabels)))
for za0003, za0004 := range z.VariableLabels {
o = msgp.AppendString(o, za0003)
o = msgp.AppendString(o, za0004)
}
// string "HistogramBucketLabel"
o = append(o, 0xb4, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c)
o = msgp.AppendString(o, z.HistogramBucketLabel)
// string "Histogram"
o = append(o, 0xa9, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d)
o = msgp.AppendMapHeader(o, uint32(len(z.Histogram)))
for za0005, za0006 := range z.Histogram {
o = msgp.AppendString(o, za0005)
o = msgp.AppendUint64(o, za0006)
}
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Metric) 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 "Description":
bts, err = z.Description.UnmarshalMsg(bts)
if err != nil {
err = msgp.WrapError(err, "Description")
return
}
case "StaticLabels":
var zb0002 uint32
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, "StaticLabels")
return
}
if z.StaticLabels == nil {
z.StaticLabels = make(map[string]string, zb0002)
} else if len(z.StaticLabels) > 0 {
for key := range z.StaticLabels {
delete(z.StaticLabels, key)
}
}
for zb0002 > 0 {
var za0001 string
var za0002 string
zb0002--
za0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "StaticLabels")
return
}
za0002, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "StaticLabels", za0001)
return
}
z.StaticLabels[za0001] = za0002
}
case "Value":
z.Value, bts, err = msgp.ReadFloat64Bytes(bts)
if err != nil {
err = msgp.WrapError(err, "Value")
return
}
case "VariableLabels":
var zb0003 uint32
zb0003, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, "VariableLabels")
return
}
if z.VariableLabels == nil {
z.VariableLabels = make(map[string]string, zb0003)
} else if len(z.VariableLabels) > 0 {
for key := range z.VariableLabels {
delete(z.VariableLabels, key)
}
}
for zb0003 > 0 {
var za0003 string
var za0004 string
zb0003--
za0003, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "VariableLabels")
return
}
za0004, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "VariableLabels", za0003)
return
}
z.VariableLabels[za0003] = za0004
}
case "HistogramBucketLabel":
z.HistogramBucketLabel, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "HistogramBucketLabel")
return
}
case "Histogram":
var zb0004 uint32
zb0004, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Histogram")
return
}
if z.Histogram == nil {
z.Histogram = make(map[string]uint64, zb0004)
} else if len(z.Histogram) > 0 {
for key := range z.Histogram {
delete(z.Histogram, key)
}
}
for zb0004 > 0 {
var za0005 string
var za0006 uint64
zb0004--
za0005, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Histogram")
return
}
za0006, bts, err = msgp.ReadUint64Bytes(bts)
if err != nil {
err = msgp.WrapError(err, "Histogram", za0005)
return
}
z.Histogram[za0005] = za0006
}
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 *Metric) Msgsize() (s int) {
s = 1 + 12 + z.Description.Msgsize() + 13 + msgp.MapHeaderSize
if z.StaticLabels != nil {
for za0001, za0002 := range z.StaticLabels {
_ = za0002
s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002)
}
}
s += 6 + msgp.Float64Size + 15 + msgp.MapHeaderSize
if z.VariableLabels != nil {
for za0003, za0004 := range z.VariableLabels {
_ = za0004
s += msgp.StringPrefixSize + len(za0003) + msgp.StringPrefixSize + len(za0004)
}
}
s += 21 + msgp.StringPrefixSize + len(z.HistogramBucketLabel) + 10 + msgp.MapHeaderSize
if z.Histogram != nil {
for za0005, za0006 := range z.Histogram {
_ = za0006
s += msgp.StringPrefixSize + len(za0005) + msgp.Uint64Size
}
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *MetricDescription) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 5
// string "Namespace"
o = append(o, 0x85, 0xa9, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65)
o = msgp.AppendString(o, string(z.Namespace))
// string "Subsystem"
o = append(o, 0xa9, 0x53, 0x75, 0x62, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d)
o = msgp.AppendString(o, string(z.Subsystem))
// string "Name"
o = append(o, 0xa4, 0x4e, 0x61, 0x6d, 0x65)
o = msgp.AppendString(o, string(z.Name))
// string "Help"
o = append(o, 0xa4, 0x48, 0x65, 0x6c, 0x70)
o = msgp.AppendString(o, z.Help)
// string "Type"
o = append(o, 0xa4, 0x54, 0x79, 0x70, 0x65)
o = msgp.AppendString(o, string(z.Type))
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MetricDescription) 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 "Namespace":
{
var zb0002 string
zb0002, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Namespace")
return
}
z.Namespace = MetricNamespace(zb0002)
}
case "Subsystem":
{
var zb0003 string
zb0003, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Subsystem")
return
}
z.Subsystem = MetricSubsystem(zb0003)
}
case "Name":
{
var zb0004 string
zb0004, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Name")
return
}
z.Name = MetricName(zb0004)
}
case "Help":
z.Help, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Help")
return
}
case "Type":
{
var zb0005 string
zb0005, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Type")
return
}
z.Type = MetricType(zb0005)
}
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 *MetricDescription) Msgsize() (s int) {
s = 1 + 10 + msgp.StringPrefixSize + len(string(z.Namespace)) + 10 + msgp.StringPrefixSize + len(string(z.Subsystem)) + 5 + msgp.StringPrefixSize + len(string(z.Name)) + 5 + msgp.StringPrefixSize + len(z.Help) + 5 + msgp.StringPrefixSize + len(string(z.Type))
return
}
// MarshalMsg implements msgp.Marshaler
func (z MetricName) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
o = msgp.AppendString(o, string(z))
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MetricName) UnmarshalMsg(bts []byte) (o []byte, err error) {
{
var zb0001 string
zb0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
(*z) = MetricName(zb0001)
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z MetricName) Msgsize() (s int) {
s = msgp.StringPrefixSize + len(string(z))
return
}
// MarshalMsg implements msgp.Marshaler
func (z MetricNamespace) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
o = msgp.AppendString(o, string(z))
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MetricNamespace) UnmarshalMsg(bts []byte) (o []byte, err error) {
{
var zb0001 string
zb0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
(*z) = MetricNamespace(zb0001)
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z MetricNamespace) Msgsize() (s int) {
s = msgp.StringPrefixSize + len(string(z))
return
}
// MarshalMsg implements msgp.Marshaler
func (z MetricSubsystem) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
o = msgp.AppendString(o, string(z))
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MetricSubsystem) UnmarshalMsg(bts []byte) (o []byte, err error) {
{
var zb0001 string
zb0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
(*z) = MetricSubsystem(zb0001)
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z MetricSubsystem) Msgsize() (s int) {
s = msgp.StringPrefixSize + len(string(z))
return
}
// MarshalMsg implements msgp.Marshaler
func (z MetricType) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
o = msgp.AppendString(o, string(z))
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MetricType) UnmarshalMsg(bts []byte) (o []byte, err error) {
{
var zb0001 string
zb0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
(*z) = MetricType(zb0001)
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z MetricType) Msgsize() (s int) {
s = msgp.StringPrefixSize + len(string(z))
return
}
// MarshalMsg implements msgp.Marshaler
func (z *MetricsGroup) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 2
// string "cacheInterval"
o = append(o, 0x82, 0xad, 0x63, 0x61, 0x63, 0x68, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c)
o = msgp.AppendDuration(o, z.cacheInterval)
// string "metricsGroupOpts"
o = append(o, 0xb0, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4f, 0x70, 0x74, 0x73)
o, err = z.metricsGroupOpts.MarshalMsg(o)
if err != nil {
err = msgp.WrapError(err, "metricsGroupOpts")
return
}
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MetricsGroup) 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 "cacheInterval":
z.cacheInterval, bts, err = msgp.ReadDurationBytes(bts)
if err != nil {
err = msgp.WrapError(err, "cacheInterval")
return
}
case "metricsGroupOpts":
bts, err = z.metricsGroupOpts.UnmarshalMsg(bts)
if err != nil {
err = msgp.WrapError(err, "metricsGroupOpts")
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 *MetricsGroup) Msgsize() (s int) {
s = 1 + 14 + msgp.DurationSize + 17 + z.metricsGroupOpts.Msgsize()
return
}
// MarshalMsg implements msgp.Marshaler
func (z *MetricsGroupOpts) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 12
// string "dependGlobalObjectAPI"
o = append(o, 0x8c, 0xb5, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x50, 0x49)
o = msgp.AppendBool(o, z.dependGlobalObjectAPI)
// string "dependGlobalAuthNPlugin"
o = append(o, 0xb7, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x4e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e)
o = msgp.AppendBool(o, z.dependGlobalAuthNPlugin)
// string "dependGlobalSiteReplicationSys"
o = append(o, 0xbe, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x79, 0x73)
o = msgp.AppendBool(o, z.dependGlobalSiteReplicationSys)
// string "dependGlobalNotificationSys"
o = append(o, 0xbb, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x79, 0x73)
o = msgp.AppendBool(o, z.dependGlobalNotificationSys)
// string "dependGlobalKMS"
o = append(o, 0xaf, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4b, 0x4d, 0x53)
o = msgp.AppendBool(o, z.dependGlobalKMS)
// string "bucketOnly"
o = append(o, 0xaa, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4f, 0x6e, 0x6c, 0x79)
o = msgp.AppendBool(o, z.bucketOnly)
// string "dependGlobalLambdaTargetList"
o = append(o, 0xbc, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4c, 0x61, 0x6d, 0x62, 0x64, 0x61, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74)
o = msgp.AppendBool(o, z.dependGlobalLambdaTargetList)
// string "dependGlobalIAMSys"
o = append(o, 0xb2, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, 0x41, 0x4d, 0x53, 0x79, 0x73)
o = msgp.AppendBool(o, z.dependGlobalIAMSys)
// string "dependGlobalLockServer"
o = append(o, 0xb6, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4c, 0x6f, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72)
o = msgp.AppendBool(o, z.dependGlobalLockServer)
// string "dependGlobalIsDistErasure"
o = append(o, 0xb9, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, 0x73, 0x44, 0x69, 0x73, 0x74, 0x45, 0x72, 0x61, 0x73, 0x75, 0x72, 0x65)
o = msgp.AppendBool(o, z.dependGlobalIsDistErasure)
// string "dependGlobalBackgroundHealState"
o = append(o, 0xbf, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x65, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65)
o = msgp.AppendBool(o, z.dependGlobalBackgroundHealState)
// string "dependBucketTargetSys"
o = append(o, 0xb5, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x79, 0x73)
o = msgp.AppendBool(o, z.dependBucketTargetSys)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *MetricsGroupOpts) 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 "dependGlobalObjectAPI":
z.dependGlobalObjectAPI, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalObjectAPI")
return
}
case "dependGlobalAuthNPlugin":
z.dependGlobalAuthNPlugin, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalAuthNPlugin")
return
}
case "dependGlobalSiteReplicationSys":
z.dependGlobalSiteReplicationSys, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalSiteReplicationSys")
return
}
case "dependGlobalNotificationSys":
z.dependGlobalNotificationSys, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalNotificationSys")
return
}
case "dependGlobalKMS":
z.dependGlobalKMS, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalKMS")
return
}
case "bucketOnly":
z.bucketOnly, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "bucketOnly")
return
}
case "dependGlobalLambdaTargetList":
z.dependGlobalLambdaTargetList, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalLambdaTargetList")
return
}
case "dependGlobalIAMSys":
z.dependGlobalIAMSys, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalIAMSys")
return
}
case "dependGlobalLockServer":
z.dependGlobalLockServer, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalLockServer")
return
}
case "dependGlobalIsDistErasure":
z.dependGlobalIsDistErasure, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalIsDistErasure")
return
}
case "dependGlobalBackgroundHealState":
z.dependGlobalBackgroundHealState, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependGlobalBackgroundHealState")
return
}
case "dependBucketTargetSys":
z.dependBucketTargetSys, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
err = msgp.WrapError(err, "dependBucketTargetSys")
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 *MetricsGroupOpts) Msgsize() (s int) {
s = 1 + 22 + msgp.BoolSize + 24 + msgp.BoolSize + 31 + msgp.BoolSize + 28 + msgp.BoolSize + 16 + msgp.BoolSize + 11 + msgp.BoolSize + 29 + msgp.BoolSize + 19 + msgp.BoolSize + 23 + msgp.BoolSize + 26 + msgp.BoolSize + 32 + msgp.BoolSize + 22 + msgp.BoolSize
return
}
+241
View File
@@ -0,0 +1,241 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"testing"
"github.com/tinylib/msgp/msgp"
)
func TestMarshalUnmarshalMetric(t *testing.T) {
v := Metric{}
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 BenchmarkMarshalMsgMetric(b *testing.B) {
v := Metric{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgMetric(b *testing.B) {
v := Metric{}
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 BenchmarkUnmarshalMetric(b *testing.B) {
v := Metric{}
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 TestMarshalUnmarshalMetricDescription(t *testing.T) {
v := MetricDescription{}
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 BenchmarkMarshalMsgMetricDescription(b *testing.B) {
v := MetricDescription{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgMetricDescription(b *testing.B) {
v := MetricDescription{}
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 BenchmarkUnmarshalMetricDescription(b *testing.B) {
v := MetricDescription{}
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 TestMarshalUnmarshalMetricsGroup(t *testing.T) {
v := MetricsGroup{}
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 BenchmarkMarshalMsgMetricsGroup(b *testing.B) {
v := MetricsGroup{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgMetricsGroup(b *testing.B) {
v := MetricsGroup{}
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 BenchmarkUnmarshalMetricsGroup(b *testing.B) {
v := MetricsGroup{}
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 TestMarshalUnmarshalMetricsGroupOpts(t *testing.T) {
v := MetricsGroupOpts{}
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 BenchmarkMarshalMsgMetricsGroupOpts(b *testing.B) {
v := MetricsGroupOpts{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgMetricsGroupOpts(b *testing.B) {
v := MetricsGroupOpts{}
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 BenchmarkUnmarshalMetricsGroupOpts(b *testing.B) {
v := MetricsGroupOpts{}
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)
}
}
}
+2 -2
View File
@@ -680,13 +680,13 @@ func isErrBucketNotFound(err error) bool {
return errors.As(err, &bkNotFound)
}
// isErrReadQuorum check if the error type is InsufficentReadQuorum
// isErrReadQuorum check if the error type is InsufficientReadQuorum
func isErrReadQuorum(err error) bool {
var rquorum InsufficientReadQuorum
return errors.As(err, &rquorum)
}
// isErrWriteQuorum check if the error type is InsufficentWriteQuorum
// isErrWriteQuorum check if the error type is InsufficientWriteQuorum
func isErrWriteQuorum(err error) bool {
var rquorum InsufficientWriteQuorum
return errors.As(err, &rquorum)
+18 -13
View File
@@ -27,6 +27,11 @@ import (
"github.com/minio/minio/internal/logger"
)
// Checks on CopyObject arguments, bucket and object.
func checkCopyObjArgs(ctx context.Context, bucket, object string) error {
return checkBucketAndObjectNames(ctx, bucket, object)
}
// Checks on GetObject arguments, bucket and object.
func checkGetObjArgs(ctx context.Context, bucket, object string) error {
return checkBucketAndObjectNames(ctx, bucket, object)
@@ -106,42 +111,42 @@ func checkListMultipartArgs(ctx context.Context, bucket, prefix, keyMarker, uplo
}
// Checks for NewMultipartUpload arguments validity, also validates if bucket exists.
func checkNewMultipartArgs(ctx context.Context, bucket, object string, obj ObjectLayer) error {
return checkObjectArgs(ctx, bucket, object, obj)
func checkNewMultipartArgs(ctx context.Context, bucket, object string) error {
return checkObjectArgs(ctx, bucket, object)
}
func checkMultipartObjectArgs(ctx context.Context, bucket, object, uploadID string, obj ObjectLayer) error {
func checkMultipartObjectArgs(ctx context.Context, bucket, object, uploadID string) error {
_, err := base64.RawURLEncoding.DecodeString(uploadID)
if err != nil {
return MalformedUploadID{
UploadID: uploadID,
}
}
return checkObjectArgs(ctx, bucket, object, obj)
return checkObjectArgs(ctx, bucket, object)
}
// Checks for PutObjectPart arguments validity, also validates if bucket exists.
func checkPutObjectPartArgs(ctx context.Context, bucket, object, uploadID string, obj ObjectLayer) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID, obj)
func checkPutObjectPartArgs(ctx context.Context, bucket, object, uploadID string) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID)
}
// Checks for ListParts arguments validity, also validates if bucket exists.
func checkListPartsArgs(ctx context.Context, bucket, object, uploadID string, obj ObjectLayer) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID, obj)
func checkListPartsArgs(ctx context.Context, bucket, object, uploadID string) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID)
}
// Checks for CompleteMultipartUpload arguments validity, also validates if bucket exists.
func checkCompleteMultipartArgs(ctx context.Context, bucket, object, uploadID string, obj ObjectLayer) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID, obj)
func checkCompleteMultipartArgs(ctx context.Context, bucket, object, uploadID string) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID)
}
// Checks for AbortMultipartUpload arguments validity, also validates if bucket exists.
func checkAbortMultipartArgs(ctx context.Context, bucket, object, uploadID string, obj ObjectLayer) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID, obj)
func checkAbortMultipartArgs(ctx context.Context, bucket, object, uploadID string) error {
return checkMultipartObjectArgs(ctx, bucket, object, uploadID)
}
// Checks Object arguments validity.
func checkObjectArgs(ctx context.Context, bucket, object string, obj ObjectLayer) error {
func checkObjectArgs(ctx context.Context, bucket, object string) error {
// Verify if bucket is valid.
if !isMinioMetaBucketName(bucket) && s3utils.CheckValidBucketNameStrict(bucket) != nil {
return BucketNameInvalid{Bucket: bucket}
+16 -16
View File
@@ -227,7 +227,7 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH
inputReaderData string
inputMd5 string
inputSHA256 string
intputDataSize int64
inputDataSize int64
// flag indicating whether the test should pass.
shouldPass bool
// expected error output.
@@ -287,27 +287,27 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH
// Test case - 14.
// Input with size more than the size of actual data inside the reader.
{
bucketName: bucket, objName: object, uploadID: uploadID, PartID: 1, inputReaderData: "abcd", inputMd5: "e2fc714c4727ee9395f324cd2e7f3335", intputDataSize: int64(len("abcd") + 1),
bucketName: bucket, objName: object, uploadID: uploadID, PartID: 1, inputReaderData: "abcd", inputMd5: "e2fc714c4727ee9395f324cd2e7f3335", inputDataSize: int64(len("abcd") + 1),
expectedError: hash.BadDigest{ExpectedMD5: "e2fc714c4727ee9395f324cd2e7f3335", CalculatedMD5: "e2fc714c4727ee9395f324cd2e7f331f"},
},
// Test case - 15.
// Input with size less than the size of actual data inside the reader.
{
bucketName: bucket, objName: object, uploadID: uploadID, PartID: 1, inputReaderData: "abcd", inputMd5: "900150983cd24fb0d6963f7d28e17f73", intputDataSize: int64(len("abcd") - 1),
bucketName: bucket, objName: object, uploadID: uploadID, PartID: 1, inputReaderData: "abcd", inputMd5: "900150983cd24fb0d6963f7d28e17f73", inputDataSize: int64(len("abcd") - 1),
expectedError: ioutil.ErrOverread,
},
// Test case - 16-19.
// Validating for success cases.
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 1, inputReaderData: "abcd", inputMd5: "e2fc714c4727ee9395f324cd2e7f331f", inputSHA256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", intputDataSize: int64(len("abcd")), shouldPass: true},
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 2, inputReaderData: "efgh", inputMd5: "1f7690ebdd9b4caf8fab49ca1757bf27", inputSHA256: "e5e088a0b66163a0a26a5e053d2a4496dc16ab6e0e3dd1adf2d16aa84a078c9d", intputDataSize: int64(len("efgh")), shouldPass: true},
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 3, inputReaderData: "ijkl", inputMd5: "09a0877d04abf8759f99adec02baf579", inputSHA256: "005c19658919186b85618c5870463eec8d9b8c1a9d00208a5352891ba5bbe086", intputDataSize: int64(len("abcd")), shouldPass: true},
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 4, inputReaderData: "mnop", inputMd5: "e132e96a5ddad6da8b07bba6f6131fef", inputSHA256: "f1afc31479522d6cff1ed068f93998f05a8cd3b22f5c37d7f307084f62d1d270", intputDataSize: int64(len("abcd")), shouldPass: true},
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 1, inputReaderData: "abcd", inputMd5: "e2fc714c4727ee9395f324cd2e7f331f", inputSHA256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", inputDataSize: int64(len("abcd")), shouldPass: true},
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 2, inputReaderData: "efgh", inputMd5: "1f7690ebdd9b4caf8fab49ca1757bf27", inputSHA256: "e5e088a0b66163a0a26a5e053d2a4496dc16ab6e0e3dd1adf2d16aa84a078c9d", inputDataSize: int64(len("efgh")), shouldPass: true},
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 3, inputReaderData: "ijkl", inputMd5: "09a0877d04abf8759f99adec02baf579", inputSHA256: "005c19658919186b85618c5870463eec8d9b8c1a9d00208a5352891ba5bbe086", inputDataSize: int64(len("abcd")), shouldPass: true},
{bucketName: bucket, objName: object, uploadID: uploadID, PartID: 4, inputReaderData: "mnop", inputMd5: "e132e96a5ddad6da8b07bba6f6131fef", inputSHA256: "f1afc31479522d6cff1ed068f93998f05a8cd3b22f5c37d7f307084f62d1d270", inputDataSize: int64(len("abcd")), shouldPass: true},
}
// Validate all the test cases.
for i, testCase := range testCases {
actualInfo, actualErr := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.intputDataSize, testCase.inputMd5, testCase.inputSHA256), opts)
actualInfo, actualErr := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.inputDataSize, testCase.inputMd5, testCase.inputSHA256), opts)
// All are test cases above are expected to fail.
if actualErr != nil && testCase.shouldPass {
t.Errorf("Test %d: %s: Expected to pass, but failed with: <ERROR> %s.", i+1, instanceType, actualErr.Error())
@@ -410,7 +410,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
PartID int
inputReaderData string
inputMd5 string
intputDataSize int64
inputDataSize int64
expectedMd5 string
}{
// Case 1-4.
@@ -439,7 +439,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan
sha256sum := ""
// Iterating over creatPartCases to generate multipart chunks.
for _, testCase := range createPartCases {
_, err := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.intputDataSize, testCase.inputMd5, sha256sum), opts)
_, err := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.inputDataSize, testCase.inputMd5, sha256sum), opts)
if err != nil {
t.Fatalf("%s : %s", instanceType, err.Error())
}
@@ -1263,7 +1263,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks
PartID int
inputReaderData string
inputMd5 string
intputDataSize int64
inputDataSize int64
expectedMd5 string
}{
// Case 1-4.
@@ -1277,7 +1277,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks
sha256sum := ""
// Iterating over creatPartCases to generate multipart chunks.
for _, testCase := range createPartCases {
_, err := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.intputDataSize, testCase.inputMd5, sha256sum), opts)
_, err := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.inputDataSize, testCase.inputMd5, sha256sum), opts)
if err != nil {
t.Fatalf("%s : %s", instanceType, err.Error())
}
@@ -1500,7 +1500,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler)
PartID int
inputReaderData string
inputMd5 string
intputDataSize int64
inputDataSize int64
expectedMd5 string
}{
// Case 1-4.
@@ -1514,7 +1514,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler)
sha256sum := ""
// Iterating over creatPartCases to generate multipart chunks.
for _, testCase := range createPartCases {
_, err := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.intputDataSize, testCase.inputMd5, sha256sum), opts)
_, err := obj.PutObjectPart(context.Background(), testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, mustGetPutObjReader(t, bytes.NewBufferString(testCase.inputReaderData), testCase.inputDataSize, testCase.inputMd5, sha256sum), opts)
if err != nil {
t.Fatalf("%s : %s", instanceType, err.Error())
}
@@ -1744,7 +1744,7 @@ func testObjectCompleteMultipartUpload(obj ObjectLayer, instanceType string, t T
PartID int
inputReaderData string
inputMd5 string
intputDataSize int64
inputDataSize int64
}{
// Case 1-4.
// Creating sequence of parts for same uploadID.
@@ -1761,7 +1761,7 @@ func testObjectCompleteMultipartUpload(obj ObjectLayer, instanceType string, t T
var opts ObjectOptions
// Iterating over creatPartCases to generate multipart chunks.
for _, part := range parts {
_, err = obj.PutObjectPart(context.Background(), part.bucketName, part.objName, part.uploadID, part.PartID, mustGetPutObjReader(t, bytes.NewBufferString(part.inputReaderData), part.intputDataSize, part.inputMd5, sha256sum), opts)
_, err = obj.PutObjectPart(context.Background(), part.bucketName, part.objName, part.uploadID, part.PartID, mustGetPutObjReader(t, bytes.NewBufferString(part.inputReaderData), part.inputDataSize, part.inputMd5, sha256sum), opts)
if err != nil {
t.Fatalf("%s : %s", instanceType, err)
}
+44 -44
View File
@@ -70,12 +70,12 @@ func testObjectAPIPutObject(obj ObjectLayer, instanceType string, t TestErrHandl
invalidMD5Header := md5Header([]byte("meh"))
testCases := []struct {
bucketName string
objName string
inputData []byte
inputMeta map[string]string
inputSHA256 string
intputDataSize int64
bucketName string
objName string
inputData []byte
inputMeta map[string]string
inputSHA256 string
inputDataSize int64
// expected error output.
expectedMd5 string
expectedError error
@@ -106,7 +106,7 @@ func testObjectAPIPutObject(obj ObjectLayer, instanceType string, t TestErrHandl
7: {
bucketName: bucket, objName: object, inputData: []byte("abcd"),
inputMeta: map[string]string{"etag": "e2fc714c4727ee9395f324cd2e7f331f"},
inputSHA256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031580", intputDataSize: int64(len("abcd")),
inputSHA256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031580", inputDataSize: int64(len("abcd")),
expectedError: hash.SHA256Mismatch{
ExpectedSHA256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031580",
CalculatedSHA256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
@@ -116,76 +116,76 @@ func testObjectAPIPutObject(obj ObjectLayer, instanceType string, t TestErrHandl
// Input with size more than the size of actual data inside the reader.
8: {
bucketName: bucket, objName: object, inputData: []byte("abcd"),
inputMeta: map[string]string{"etag": "e2fc714c4727ee9395f324cd2e7f331e"}, intputDataSize: int64(len("abcd") + 1),
inputMeta: map[string]string{"etag": "e2fc714c4727ee9395f324cd2e7f331e"}, inputDataSize: int64(len("abcd") + 1),
expectedError: hash.BadDigest{ExpectedMD5: "e2fc714c4727ee9395f324cd2e7f331e", CalculatedMD5: "e2fc714c4727ee9395f324cd2e7f331f"},
},
// Input with size less than the size of actual data inside the reader.
9: {
bucketName: bucket, objName: object, inputData: []byte("abcd"),
inputMeta: map[string]string{"etag": "900150983cd24fb0d6963f7d28e17f73"}, intputDataSize: int64(len("abcd") - 1),
inputMeta: map[string]string{"etag": "900150983cd24fb0d6963f7d28e17f73"}, inputDataSize: int64(len("abcd") - 1),
expectedError: ioutil.ErrOverread,
},
// Validating for success cases.
10: {bucketName: bucket, objName: object, inputData: []byte("abcd"), inputMeta: map[string]string{"etag": "e2fc714c4727ee9395f324cd2e7f331f"}, intputDataSize: int64(len("abcd"))},
11: {bucketName: bucket, objName: object, inputData: []byte("efgh"), inputMeta: map[string]string{"etag": "1f7690ebdd9b4caf8fab49ca1757bf27"}, intputDataSize: int64(len("efgh"))},
12: {bucketName: bucket, objName: object, inputData: []byte("ijkl"), inputMeta: map[string]string{"etag": "09a0877d04abf8759f99adec02baf579"}, intputDataSize: int64(len("ijkl"))},
13: {bucketName: bucket, objName: object, inputData: []byte("mnop"), inputMeta: map[string]string{"etag": "e132e96a5ddad6da8b07bba6f6131fef"}, intputDataSize: int64(len("mnop"))},
10: {bucketName: bucket, objName: object, inputData: []byte("abcd"), inputMeta: map[string]string{"etag": "e2fc714c4727ee9395f324cd2e7f331f"}, inputDataSize: int64(len("abcd"))},
11: {bucketName: bucket, objName: object, inputData: []byte("efgh"), inputMeta: map[string]string{"etag": "1f7690ebdd9b4caf8fab49ca1757bf27"}, inputDataSize: int64(len("efgh"))},
12: {bucketName: bucket, objName: object, inputData: []byte("ijkl"), inputMeta: map[string]string{"etag": "09a0877d04abf8759f99adec02baf579"}, inputDataSize: int64(len("ijkl"))},
13: {bucketName: bucket, objName: object, inputData: []byte("mnop"), inputMeta: map[string]string{"etag": "e132e96a5ddad6da8b07bba6f6131fef"}, inputDataSize: int64(len("mnop"))},
// With no metadata
14: {bucketName: bucket, objName: object, inputData: data, intputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
15: {bucketName: bucket, objName: object, inputData: nilBytes, intputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes)},
16: {bucketName: bucket, objName: object, inputData: fiveMBBytes, intputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes)},
14: {bucketName: bucket, objName: object, inputData: data, inputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
15: {bucketName: bucket, objName: object, inputData: nilBytes, inputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes)},
16: {bucketName: bucket, objName: object, inputData: fiveMBBytes, inputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes)},
// With arbitrary metadata
17: {bucketName: bucket, objName: object, inputData: data, inputMeta: map[string]string{"answer": "42"}, intputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
18: {bucketName: bucket, objName: object, inputData: nilBytes, inputMeta: map[string]string{"answer": "42"}, intputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes)},
19: {bucketName: bucket, objName: object, inputData: fiveMBBytes, inputMeta: map[string]string{"answer": "42"}, intputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes)},
17: {bucketName: bucket, objName: object, inputData: data, inputMeta: map[string]string{"answer": "42"}, inputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
18: {bucketName: bucket, objName: object, inputData: nilBytes, inputMeta: map[string]string{"answer": "42"}, inputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes)},
19: {bucketName: bucket, objName: object, inputData: fiveMBBytes, inputMeta: map[string]string{"answer": "42"}, inputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes)},
// With valid md5sum and sha256.
20: {bucketName: bucket, objName: object, inputData: data, inputMeta: md5Header(data), inputSHA256: getSHA256Hash(data), intputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
21: {bucketName: bucket, objName: object, inputData: nilBytes, inputMeta: md5Header(nilBytes), inputSHA256: getSHA256Hash(nilBytes), intputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes)},
22: {bucketName: bucket, objName: object, inputData: fiveMBBytes, inputMeta: md5Header(fiveMBBytes), inputSHA256: getSHA256Hash(fiveMBBytes), intputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes)},
20: {bucketName: bucket, objName: object, inputData: data, inputMeta: md5Header(data), inputSHA256: getSHA256Hash(data), inputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
21: {bucketName: bucket, objName: object, inputData: nilBytes, inputMeta: md5Header(nilBytes), inputSHA256: getSHA256Hash(nilBytes), inputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes)},
22: {bucketName: bucket, objName: object, inputData: fiveMBBytes, inputMeta: md5Header(fiveMBBytes), inputSHA256: getSHA256Hash(fiveMBBytes), inputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes)},
// data with invalid md5sum in header
23: {
bucketName: bucket, objName: object, inputData: data, inputMeta: invalidMD5Header, intputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data),
bucketName: bucket, objName: object, inputData: data, inputMeta: invalidMD5Header, inputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data),
expectedError: hash.BadDigest{ExpectedMD5: invalidMD5, CalculatedMD5: getMD5Hash(data)},
},
24: {
bucketName: bucket, objName: object, inputData: nilBytes, inputMeta: invalidMD5Header, intputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes),
bucketName: bucket, objName: object, inputData: nilBytes, inputMeta: invalidMD5Header, inputDataSize: int64(len(nilBytes)), expectedMd5: getMD5Hash(nilBytes),
expectedError: hash.BadDigest{ExpectedMD5: invalidMD5, CalculatedMD5: getMD5Hash(nilBytes)},
},
25: {
bucketName: bucket, objName: object, inputData: fiveMBBytes, inputMeta: invalidMD5Header, intputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes),
bucketName: bucket, objName: object, inputData: fiveMBBytes, inputMeta: invalidMD5Header, inputDataSize: int64(len(fiveMBBytes)), expectedMd5: getMD5Hash(fiveMBBytes),
expectedError: hash.BadDigest{ExpectedMD5: invalidMD5, CalculatedMD5: getMD5Hash(fiveMBBytes)},
},
// data with size different from the actual number of bytes available in the reader
26: {bucketName: bucket, objName: object, inputData: data, intputDataSize: int64(len(data) - 1), expectedMd5: getMD5Hash(data[:len(data)-1]), expectedError: ioutil.ErrOverread},
27: {bucketName: bucket, objName: object, inputData: nilBytes, intputDataSize: int64(len(nilBytes) + 1), expectedMd5: getMD5Hash(nilBytes), expectedError: IncompleteBody{Bucket: bucket, Object: object}},
26: {bucketName: bucket, objName: object, inputData: data, inputDataSize: int64(len(data) - 1), expectedMd5: getMD5Hash(data[:len(data)-1]), expectedError: ioutil.ErrOverread},
27: {bucketName: bucket, objName: object, inputData: nilBytes, inputDataSize: int64(len(nilBytes) + 1), expectedMd5: getMD5Hash(nilBytes), expectedError: IncompleteBody{Bucket: bucket, Object: object}},
28: {bucketName: bucket, objName: object, inputData: fiveMBBytes, expectedMd5: getMD5Hash(fiveMBBytes), expectedError: ioutil.ErrOverread},
// valid data with X-Amz-Meta- meta
29: {bucketName: bucket, objName: object, inputData: data, inputMeta: map[string]string{"X-Amz-Meta-AppID": "a42"}, intputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
29: {bucketName: bucket, objName: object, inputData: data, inputMeta: map[string]string{"X-Amz-Meta-AppID": "a42"}, inputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
// Put an empty object with a trailing slash
30: {bucketName: bucket, objName: "emptydir/", inputData: []byte{}, expectedMd5: getMD5Hash([]byte{})},
// Put an object inside the empty directory
31: {bucketName: bucket, objName: "emptydir/" + object, inputData: data, intputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
31: {bucketName: bucket, objName: "emptydir/" + object, inputData: data, inputDataSize: int64(len(data)), expectedMd5: getMD5Hash(data)},
// Put the empty object with a trailing slash again (refer to Test case 30), this needs to succeed
32: {bucketName: bucket, objName: "emptydir/", inputData: []byte{}, expectedMd5: getMD5Hash([]byte{})},
// With invalid crc32.
33: {
bucketName: bucket, objName: object, inputData: []byte("abcd"),
inputMeta: map[string]string{"etag": "e2fc714c4727ee9395f324cd2e7f331f", "x-amz-checksum-crc32": "abcd"},
intputDataSize: int64(len("abcd")),
inputMeta: map[string]string{"etag": "e2fc714c4727ee9395f324cd2e7f331f", "x-amz-checksum-crc32": "abcd"},
inputDataSize: int64(len("abcd")),
},
}
for i, testCase := range testCases {
in := mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], testCase.inputSHA256)
in := mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.inputDataSize, testCase.inputMeta["etag"], testCase.inputSHA256)
objInfo, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, in, ObjectOptions{UserDefined: testCase.inputMeta})
if actualErr != nil && testCase.expectedError == nil {
t.Errorf("Test %d: %s: Expected to pass, but failed with: error %s.", i, instanceType, actualErr.Error())
@@ -243,11 +243,11 @@ func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, di
}
testCases := []struct {
bucketName string
objName string
inputData []byte
inputMeta map[string]string
intputDataSize int64
bucketName string
objName string
inputData []byte
inputMeta map[string]string
inputDataSize int64
// flag indicating whether the test should pass.
shouldPass bool
// expected error output.
@@ -263,7 +263,7 @@ func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, di
sha256sum := ""
for i, testCase := range testCases {
objInfo, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], sha256sum), ObjectOptions{UserDefined: testCase.inputMeta})
objInfo, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.inputDataSize, testCase.inputMeta["etag"], sha256sum), ObjectOptions{UserDefined: testCase.inputMeta})
if actualErr != nil && testCase.shouldPass {
t.Errorf("Test %d: %s: Expected to pass, but failed with: <ERROR> %s.", i+1, instanceType, actualErr.Error())
}
@@ -291,11 +291,11 @@ func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, di
// Validate the last test.
testCase := struct {
bucketName string
objName string
inputData []byte
inputMeta map[string]string
intputDataSize int64
bucketName string
objName string
inputData []byte
inputMeta map[string]string
inputDataSize int64
// flag indicating whether the test should pass.
shouldPass bool
// expected error output.
@@ -312,7 +312,7 @@ func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, di
errErasureWriteQuorum,
}
_, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], sha256sum), ObjectOptions{UserDefined: testCase.inputMeta})
_, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.inputDataSize, testCase.inputMeta["etag"], sha256sum), ObjectOptions{UserDefined: testCase.inputMeta})
if actualErr != nil && testCase.shouldPass {
t.Errorf("Test %d: %s: Expected to pass, but failed with: <ERROR> %s.", len(testCases)+1, instanceType, actualErr.Error())
}
+2 -2
View File
@@ -149,7 +149,7 @@ func TestIsValidBucketName(t *testing.T) {
{"192.168.1.1", false},
{"$this-is-not-valid-too", false},
{"contains-$-dollar", false},
{"contains-^-carret", false},
{"contains-^-caret", false},
{"contains-$-dollar", false},
{"contains-$-dollar", false},
{"......", false},
@@ -195,7 +195,7 @@ func TestIsValidObjectName(t *testing.T) {
{"117Gn8rfHL2ACARPAhaFd0AGzic9pUbIA/5OCn5A", true},
{"SHØRT", true},
{"f*le", true},
{"contains-^-carret", true},
{"contains-^-caret", true},
{"contains-|-pipe", true},
{"contains-`-tick", true},
{"..test", true},
+52 -43
View File
@@ -1302,7 +1302,7 @@ func testAPIPutObjectHandler(obj ObjectLayer, instanceType, bucketName string, a
copySourceHeader := map[string]string{"X-Amz-Copy-Source": "somewhere"}
invalidMD5Header := map[string]string{"Content-Md5": "42"}
inalidStorageClassHeader := map[string]string{xhttp.AmzStorageClass: "INVALID"}
invalidStorageClassHeader := map[string]string{xhttp.AmzStorageClass: "INVALID"}
addCustomHeaders := func(req *http.Request, customHeaders map[string]string) {
for k, value := range customHeaders {
@@ -1350,7 +1350,7 @@ func testAPIPutObjectHandler(obj ObjectLayer, instanceType, bucketName string, a
objectName: objectName,
data: bytesData,
dataLen: len(bytesData),
accessKey: "Wrong-AcessID",
accessKey: "Wrong-AccessID",
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusForbidden,
@@ -1408,7 +1408,7 @@ func testAPIPutObjectHandler(obj ObjectLayer, instanceType, bucketName string, a
6: {
bucketName: bucketName,
objectName: objectName,
headers: inalidStorageClassHeader,
headers: invalidStorageClassHeader,
data: bytesData,
dataLen: len(bytesData),
accessKey: credentials.AccessKey,
@@ -2225,10 +2225,19 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusBadRequest,
},
// Test case - 3.
// Test case with new object name is same as object to be copied.
// Test case with invalid source object.
3: {
bucketName: bucketName,
newObjectName: "dir//newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
accessKey: credentials.AccessKey,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusBadRequest,
},
// Test case - 4.
// Test case with new object name is same as object to be copied.
4: {
bucketName: bucketName,
newObjectName: objectName,
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2239,10 +2248,10 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusBadRequest,
},
// Test case - 4.
// Test case - 5.
// Test case with new object name is same as object to be copied.
// But source copy is without leading slash
4: {
5: {
bucketName: bucketName,
newObjectName: objectName,
copySourceSame: true,
@@ -2253,10 +2262,10 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusBadRequest,
},
// Test case - 5.
// Test case - 6.
// Test case with new object name is same as object to be copied
// but metadata is updated.
5: {
6: {
bucketName: bucketName,
newObjectName: objectName,
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2270,9 +2279,9 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusOK,
},
// Test case - 6.
// Test case - 7.
// Test case with invalid metadata-directive.
6: {
7: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2286,10 +2295,10 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusBadRequest,
},
// Test case - 7.
// Test case - 8.
// Test case with new object name is same as object to be copied
// fail with BadRequest.
7: {
8: {
bucketName: bucketName,
newObjectName: objectName,
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2304,11 +2313,11 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusBadRequest,
},
// Test case - 8.
// Test case - 9.
// Test case with non-existent source file.
// Case for the purpose of failing `api.ObjectAPI.GetObjectInfo`.
// Expecting the response status code to http.StatusNotFound (404).
8: {
9: {
bucketName: bucketName,
newObjectName: objectName,
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + "non-existent-object"),
@@ -2318,11 +2327,11 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusNotFound,
},
// Test case - 9.
// Test case - 10.
// Test case with non-existent source file.
// Case for the purpose of failing `api.ObjectAPI.PutObject`.
// Expecting the response status code to http.StatusNotFound (404).
9: {
10: {
bucketName: "non-existent-destination-bucket",
newObjectName: objectName,
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2332,9 +2341,9 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusNotFound,
},
// Test case - 10.
// Test case - 11.
// Case with invalid AccessKey.
10: {
11: {
bucketName: bucketName,
newObjectName: objectName,
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2343,8 +2352,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
expectedRespStatus: http.StatusForbidden,
},
// Test case - 11, copy metadata from newObject1 with satisfying modified header.
11: {
// Test case - 12, copy metadata from newObject1 with satisfying modified header.
12: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2353,8 +2362,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusOK,
},
// Test case - 12, copy metadata from newObject1 with unsatisfying modified header.
12: {
// Test case - 13, copy metadata from newObject1 with unsatisfying modified header.
13: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2363,8 +2372,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusPreconditionFailed,
},
// Test case - 13, copy metadata from newObject1 with wrong modified header format
13: {
// Test case - 14, copy metadata from newObject1 with wrong modified header format
14: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2373,8 +2382,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusOK,
},
// Test case - 14, copy metadata from newObject1 with satisfying unmodified header.
14: {
// Test case - 15, copy metadata from newObject1 with satisfying unmodified header.
15: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2383,8 +2392,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusOK,
},
// Test case - 15, copy metadata from newObject1 with unsatisfying unmodified header.
15: {
// Test case - 16, copy metadata from newObject1 with unsatisfying unmodified header.
16: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2393,8 +2402,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusPreconditionFailed,
},
// Test case - 16, copy metadata from newObject1 with incorrect unmodified header format.
16: {
// Test case - 17, copy metadata from newObject1 with incorrect unmodified header format.
17: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
@@ -2403,8 +2412,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusOK,
},
// Test case - 17, copy metadata from newObject1 with null versionId
17: {
// Test case - 18, copy metadata from newObject1 with null versionId
18: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator+bucketName+SlashSeparator+objectName) + "?versionId=null",
@@ -2412,8 +2421,8 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
secretKey: credentials.SecretKey,
expectedRespStatus: http.StatusOK,
},
// Test case - 18, copy metadata from newObject1 with non null versionId
18: {
// Test case - 19, copy metadata from newObject1 with non null versionId
19: {
bucketName: bucketName,
newObjectName: "newObject1",
copySourceHeader: url.QueryEscape(SlashSeparator+bucketName+SlashSeparator+objectName) + "?versionId=17",
@@ -2574,7 +2583,7 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
}
// Wrapper for calling NewMultipartUpload tests for both Erasure multiple disks and single node setup.
// First register the HTTP handler for NewMutlipartUpload, then a HTTP request for NewMultipart upload is made.
// First register the HTTP handler for NewMultipartUpload, then a HTTP request for NewMultipart upload is made.
// The UploadID from the response body is parsed and its existence is asserted with an attempt to ListParts using it.
func TestAPINewMultipartHandler(t *testing.T) {
defer DetectTestLeak(t)()
@@ -2614,7 +2623,7 @@ func testAPINewMultipartHandler(obj ObjectLayer, instanceType, bucketName string
t.Fatalf("Invalid UploadID: <ERROR> %s", err)
}
// Testing the response for Invalid AcccessID.
// Testing the response for Invalid AccessID.
// Forcing the signature check to fail.
rec = httptest.NewRecorder()
// construct HTTP request for NewMultipart upload.
@@ -2664,7 +2673,7 @@ func testAPINewMultipartHandler(obj ObjectLayer, instanceType, bucketName string
t.Fatalf("Invalid UploadID: <ERROR> %s", err)
}
// Testing the response for invalid AcccessID.
// Testing the response for invalid AccessID.
// Forcing the V2 signature check to fail.
recV2 = httptest.NewRecorder()
// construct HTTP request for NewMultipartUpload endpoint.
@@ -2819,7 +2828,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s
PartID int
inputReaderData string
inputMd5 string
intputDataSize int64
inputDataSize int64
}{
// Case 1-4.
// Creating sequence of parts for same uploadID.
@@ -2839,7 +2848,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s
// Iterating over creatPartCases to generate multipart chunks.
for _, part := range parts {
_, err = obj.PutObjectPart(context.Background(), part.bucketName, part.objName, part.uploadID, part.PartID,
mustGetPutObjReader(t, strings.NewReader(part.inputReaderData), part.intputDataSize, part.inputMd5, ""), opts)
mustGetPutObjReader(t, strings.NewReader(part.inputReaderData), part.inputDataSize, part.inputMd5, ""), opts)
if err != nil {
t.Fatalf("%s : %s", instanceType, err)
}
@@ -3187,7 +3196,7 @@ func testAPIAbortMultipartHandler(obj ObjectLayer, instanceType, bucketName stri
PartID int
inputReaderData string
inputMd5 string
intputDataSize int64
inputDataSize int64
}{
// Case 1-4.
// Creating sequence of parts for same uploadID.
@@ -3207,7 +3216,7 @@ func testAPIAbortMultipartHandler(obj ObjectLayer, instanceType, bucketName stri
// Iterating over createPartCases to generate multipart chunks.
for _, part := range parts {
_, err = obj.PutObjectPart(context.Background(), part.bucketName, part.objName, part.uploadID, part.PartID,
mustGetPutObjReader(t, strings.NewReader(part.inputReaderData), part.intputDataSize, part.inputMd5, ""), opts)
mustGetPutObjReader(t, strings.NewReader(part.inputReaderData), part.inputDataSize, part.inputMd5, ""), opts)
if err != nil {
t.Fatalf("%s : %s", instanceType, err)
}
@@ -3233,7 +3242,7 @@ func testAPIAbortMultipartHandler(obj ObjectLayer, instanceType, bucketName stri
expectedRespStatus: http.StatusNoContent,
},
// Test case - 2.
// Abort non-existng upload ID.
// Abort non-existing upload ID.
{
bucket: bucketName,
object: objectName,
+8 -1
View File
@@ -729,13 +729,20 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
sha256hex = ""
}
var forceMD5 []byte
// Optimization: If SSE-KMS and SSE-C did not request Content-Md5. Use uuid as etag. Optionally enable this also
// for server that is started with `--no-compat`.
if !etag.ContentMD5Requested(r.Header) && (crypto.S3KMS.IsEncrypted(mi.UserDefined) || crypto.SSEC.IsRequested(r.Header) || !globalServerCtxt.StrictS3Compat) {
forceMD5 = mustGetUUIDBytes()
}
hashReader, err := hash.NewReaderWithOpts(ctx, reader, hash.Options{
Size: size,
MD5Hex: md5hex,
SHA256Hex: sha256hex,
ActualSize: actualSize,
DisableMD5: false,
ForceMD5: nil,
ForceMD5: forceMD5,
})
if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
+14 -14
View File
@@ -473,13 +473,13 @@ func testObjectOverwriteWorks(obj ObjectLayer, instanceType string, t TestErrHan
}
}
// Wrapper for calling testNonExistantBucketOperations for both Erasure and FS.
func TestNonExistantBucketOperations(t *testing.T) {
ExecObjectLayerTest(t, testNonExistantBucketOperations)
// Wrapper for calling testNonExistentBucketOperations for both Erasure and FS.
func TestNonExistentBucketOperations(t *testing.T) {
ExecObjectLayerTest(t, testNonExistentBucketOperations)
}
// Tests validate that bucket operation on non-existent bucket fails.
func testNonExistantBucketOperations(obj ObjectLayer, instanceType string, t TestErrHandler) {
func testNonExistentBucketOperations(obj ObjectLayer, instanceType string, t TestErrHandler) {
var opts ObjectOptions
_, err := obj.PutObject(context.Background(), "bucket1", "object", mustGetPutObjReader(t, bytes.NewBufferString("one"), int64(len("one")), "", ""), opts)
if err == nil {
@@ -529,7 +529,7 @@ func enableCompression(t *testing.T, encrypt bool) {
}
}
func enableEncrytion(t *testing.T) {
func enableEncryption(t *testing.T) {
// Exec with default settings...
globalCompressConfigMu.Lock()
globalCompressConfig.Enabled = false
@@ -572,7 +572,7 @@ func execExtended(t *testing.T, fn func(t *testing.T)) {
t.Run("encrypted", func(t *testing.T) {
resetCompressEncryption()
enableEncrytion(t)
enableEncryption(t)
fn(t)
})
@@ -760,13 +760,13 @@ func testListBucketsOrder(obj ObjectLayer, instanceType string, t TestErrHandler
}
}
// Wrapper for calling testListObjectsTestsForNonExistantBucket for both Erasure and FS.
func TestListObjectsTestsForNonExistantBucket(t *testing.T) {
ExecObjectLayerTest(t, testListObjectsTestsForNonExistantBucket)
// Wrapper for calling testListObjectsTestsForNonExistentBucket for both Erasure and FS.
func TestListObjectsTestsForNonExistentBucket(t *testing.T) {
ExecObjectLayerTest(t, testListObjectsTestsForNonExistentBucket)
}
// Tests validate that ListObjects operation on a non-existent bucket fails as expected.
func testListObjectsTestsForNonExistantBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
func testListObjectsTestsForNonExistentBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
result, err := obj.ListObjects(context.Background(), "bucket", "", "", "", 1000)
if err == nil {
t.Fatalf("%s: Expected error but found nil.", instanceType)
@@ -782,13 +782,13 @@ func testListObjectsTestsForNonExistantBucket(obj ObjectLayer, instanceType stri
}
}
// Wrapper for calling testNonExistantObjectInBucket for both Erasure and FS.
func TestNonExistantObjectInBucket(t *testing.T) {
ExecObjectLayerTest(t, testNonExistantObjectInBucket)
// Wrapper for calling testNonExistentObjectInBucket for both Erasure and FS.
func TestNonExistentObjectInBucket(t *testing.T) {
ExecObjectLayerTest(t, testNonExistentObjectInBucket)
}
// Tests validate that GetObject fails on a non-existent bucket as expected.
func testNonExistantObjectInBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
func testNonExistentObjectInBucket(obj ObjectLayer, instanceType string, t TestErrHandler) {
err := obj.MakeBucket(context.Background(), "bucket", MakeBucketOptions{})
if err != nil {
t.Fatalf("%s: <ERROR> %s", instanceType, err)
+127 -333
View File
@@ -18,7 +18,6 @@
package cmd
import (
"bytes"
"context"
"encoding/gob"
"encoding/hex"
@@ -28,7 +27,6 @@ import (
"io"
"net/url"
"strconv"
"strings"
"sync/atomic"
"time"
@@ -38,9 +36,7 @@ import (
xhttp "github.com/minio/minio/internal/http"
"github.com/minio/minio/internal/logger"
"github.com/minio/minio/internal/rest"
"github.com/minio/pkg/v2/logger/message/log"
xnet "github.com/minio/pkg/v2/net"
"github.com/tinylib/msgp/msgp"
)
// client to talk to peer Nodes.
@@ -154,111 +150,65 @@ func (client *peerRESTClient) Close() error {
// GetLocks - fetch older locks for a remote node.
func (client *peerRESTClient) GetLocks() (lockMap map[string][]lockRequesterInfo, err error) {
respBody, err := client.call(peerRESTMethodGetLocks, nil, nil, -1)
if err != nil {
return
resp, err := getLocksRPC.Call(context.Background(), client.gridConn(), grid.NewMSS())
if err != nil || resp == nil {
return nil, err
}
lockMap = map[string][]lockRequesterInfo{}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&lockMap)
return lockMap, err
return *resp, nil
}
// LocalStorageInfo - fetch server information for a remote node.
func (client *peerRESTClient) LocalStorageInfo(metrics bool) (info StorageInfo, err error) {
values := make(url.Values)
values.Set(peerRESTMetrics, strconv.FormatBool(metrics))
respBody, err := client.call(peerRESTMethodLocalStorageInfo, values, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := localStorageInfoRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTMetrics: strconv.FormatBool(metrics),
}))
return resp.ValueOrZero(), err
}
// ServerInfo - fetch server information for a remote node.
func (client *peerRESTClient) ServerInfo(metrics bool) (info madmin.ServerProperties, err error) {
values := make(url.Values)
values.Set(peerRESTMetrics, strconv.FormatBool(metrics))
respBody, err := client.call(peerRESTMethodServerInfo, values, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := serverInfoRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{peerRESTMetrics: strconv.FormatBool(metrics)}))
return resp.ValueOrZero(), err
}
// GetCPUs - fetch CPU information for a remote node.
func (client *peerRESTClient) GetCPUs(ctx context.Context) (info madmin.CPUs, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodCPUInfo, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getCPUsHandler.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetNetInfo - fetch network information for a remote node.
func (client *peerRESTClient) GetNetInfo(ctx context.Context) (info madmin.NetInfo, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodNetHwInfo, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getNetInfoRPC.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetPartitions - fetch disk partition information for a remote node.
func (client *peerRESTClient) GetPartitions(ctx context.Context) (info madmin.Partitions, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodDiskHwInfo, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getPartitionsRPC.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetOSInfo - fetch OS information for a remote node.
func (client *peerRESTClient) GetOSInfo(ctx context.Context) (info madmin.OSInfo, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodOsInfo, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getOSInfoRPC.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetSELinuxInfo - fetch SELinux information for a remote node.
func (client *peerRESTClient) GetSELinuxInfo(ctx context.Context) (info madmin.SysServices, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodSysServices, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getSysServicesRPC.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetSysConfig - fetch sys config for a remote node.
func (client *peerRESTClient) GetSysConfig(ctx context.Context) (info madmin.SysConfig, err error) {
sent := time.Now()
respBody, err := client.callWithContext(ctx, peerRESTMethodSysConfig, nil, nil, -1)
if err != nil {
return
}
roundtrip := int32(time.Since(sent).Milliseconds())
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
resp, err := getSysConfigRPC.Call(ctx, client.gridConn(), grid.NewMSS())
info = resp.ValueOrZero()
if ti, ok := info.Config["time-info"].(madmin.TimeInfo); ok {
ti.RoundtripDuration = roundtrip
rt := int32(time.Since(sent).Milliseconds())
ti.RoundtripDuration = rt
info.Config["time-info"] = ti
}
return info, err
@@ -266,24 +216,14 @@ func (client *peerRESTClient) GetSysConfig(ctx context.Context) (info madmin.Sys
// GetSysErrors - fetch sys errors for a remote node.
func (client *peerRESTClient) GetSysErrors(ctx context.Context) (info madmin.SysErrors, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodSysErrors, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getSysErrorsRPC.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetMemInfo - fetch memory information for a remote node.
func (client *peerRESTClient) GetMemInfo(ctx context.Context) (info madmin.MemInfo, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodMemInfo, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getMemInfoRPC.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetMetrics - fetch metrics from a remote node.
@@ -298,52 +238,14 @@ func (client *peerRESTClient) GetMetrics(ctx context.Context, t madmin.MetricTyp
}
values.Set(peerRESTJobID, opts.jobID)
values.Set(peerRESTDepID, opts.depID)
respBody, err := client.callWithContext(ctx, peerRESTMethodMetrics, values, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
}
func (client *peerRESTClient) GetResourceMetrics(ctx context.Context) (<-chan Metric, error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodResourceMetrics, nil, nil, -1)
if err != nil {
return nil, err
}
dec := gob.NewDecoder(respBody)
ch := make(chan Metric)
go func(ch chan<- Metric) {
defer func() {
xhttp.DrainBody(respBody)
close(ch)
}()
for {
var metric Metric
if err := dec.Decode(&metric); err != nil {
return
}
select {
case <-ctx.Done():
return
case ch <- metric:
}
}
}(ch)
return ch, nil
v, err := getMetricsRPC.Call(ctx, client.gridConn(), grid.NewURLValuesWith(values))
return v.ValueOrZero(), err
}
// GetProcInfo - fetch MinIO process information for a remote node.
func (client *peerRESTClient) GetProcInfo(ctx context.Context) (info madmin.ProcInfo, err error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodProcInfo, nil, nil, -1)
if err != nil {
return
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&info)
return info, err
resp, err := getProcInfoRPC.Call(ctx, client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// StartProfiling - Issues profiling command on the peer node.
@@ -371,51 +273,36 @@ func (client *peerRESTClient) DownloadProfileData() (data map[string][]byte, err
// GetBucketStats - load bucket statistics
func (client *peerRESTClient) GetBucketStats(bucket string) (BucketStats, error) {
values := make(url.Values)
values.Set(peerRESTBucket, bucket)
respBody, err := client.call(peerRESTMethodGetBucketStats, values, nil, -1)
if err != nil {
resp, err := getBucketStatsRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTBucket: bucket,
}))
if err != nil || resp == nil {
return BucketStats{}, err
}
var bs BucketStats
defer xhttp.DrainBody(respBody)
return bs, msgp.Decode(respBody, &bs)
return *resp, nil
}
// GetSRMetrics- loads site replication metrics, optionally for a specific bucket
// GetSRMetrics loads site replication metrics, optionally for a specific bucket
func (client *peerRESTClient) GetSRMetrics() (SRMetricsSummary, error) {
values := make(url.Values)
respBody, err := client.call(peerRESTMethodGetSRMetrics, values, nil, -1)
if err != nil {
resp, err := getSRMetricsRPC.Call(context.Background(), client.gridConn(), grid.NewMSS())
if err != nil || resp == nil {
return SRMetricsSummary{}, err
}
var sm SRMetricsSummary
defer xhttp.DrainBody(respBody)
return sm, msgp.Decode(respBody, &sm)
return *resp, nil
}
// GetAllBucketStats - load replication stats for all buckets
func (client *peerRESTClient) GetAllBucketStats() (BucketStatsMap, error) {
values := make(url.Values)
respBody, err := client.call(peerRESTMethodGetAllBucketStats, values, nil, -1)
if err != nil {
resp, err := getAllBucketStatsRPC.Call(context.Background(), client.gridConn(), grid.NewMSS())
if err != nil || resp == nil {
return BucketStatsMap{}, err
}
bsMap := BucketStatsMap{}
defer xhttp.DrainBody(respBody)
return bsMap, msgp.Decode(respBody, &bsMap)
return *resp, nil
}
// LoadBucketMetadata - load bucket metadata
func (client *peerRESTClient) LoadBucketMetadata(bucket string) error {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err := loadBucketMetadataHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err := loadBucketMetadataRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTBucket: bucket,
}))
return err
@@ -423,11 +310,7 @@ func (client *peerRESTClient) LoadBucketMetadata(bucket string) error {
// DeleteBucketMetadata - Delete bucket metadata
func (client *peerRESTClient) DeleteBucketMetadata(bucket string) error {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err := deleteBucketMetadataHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err := deleteBucketMetadataRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTBucket: bucket,
}))
return err
@@ -435,12 +318,7 @@ func (client *peerRESTClient) DeleteBucketMetadata(bucket string) error {
// DeletePolicy - delete a specific canned policy.
func (client *peerRESTClient) DeletePolicy(policyName string) (err error) {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err = deletePolicyHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err = deletePolicyRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTPolicy: policyName,
}))
return err
@@ -448,12 +326,7 @@ func (client *peerRESTClient) DeletePolicy(policyName string) (err error) {
// LoadPolicy - reload a specific canned policy.
func (client *peerRESTClient) LoadPolicy(policyName string) (err error) {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err = loadPolicyHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err = loadPolicyRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTPolicy: policyName,
}))
return err
@@ -461,12 +334,7 @@ func (client *peerRESTClient) LoadPolicy(policyName string) (err error) {
// LoadPolicyMapping - reload a specific policy mapping
func (client *peerRESTClient) LoadPolicyMapping(userOrGroup string, userType IAMUserType, isGroup bool) error {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err := loadPolicyMappingHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err := loadPolicyMappingRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTUserOrGroup: userOrGroup,
peerRESTUserType: strconv.Itoa(int(userType)),
peerRESTIsGroup: strconv.FormatBool(isGroup),
@@ -476,12 +344,7 @@ func (client *peerRESTClient) LoadPolicyMapping(userOrGroup string, userType IAM
// DeleteUser - delete a specific user.
func (client *peerRESTClient) DeleteUser(accessKey string) (err error) {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err = deleteUserHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err = deleteUserRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTUser: accessKey,
}))
return err
@@ -489,12 +352,7 @@ func (client *peerRESTClient) DeleteUser(accessKey string) (err error) {
// DeleteServiceAccount - delete a specific service account.
func (client *peerRESTClient) DeleteServiceAccount(accessKey string) (err error) {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err = deleteSvcActHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err = deleteSvcActRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTUser: accessKey,
}))
return err
@@ -502,12 +360,7 @@ func (client *peerRESTClient) DeleteServiceAccount(accessKey string) (err error)
// LoadUser - reload a specific user.
func (client *peerRESTClient) LoadUser(accessKey string, temp bool) (err error) {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err = loadUserHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err = loadUserRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTUser: accessKey,
peerRESTUserTemp: strconv.FormatBool(temp),
}))
@@ -516,12 +369,7 @@ func (client *peerRESTClient) LoadUser(accessKey string, temp bool) (err error)
// LoadServiceAccount - reload a specific service account.
func (client *peerRESTClient) LoadServiceAccount(accessKey string) (err error) {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err = loadSvcActHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err = loadSvcActRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTUser: accessKey,
}))
return err
@@ -529,12 +377,7 @@ func (client *peerRESTClient) LoadServiceAccount(accessKey string) (err error) {
// LoadGroup - send load group command to peers.
func (client *peerRESTClient) LoadGroup(group string) error {
conn := client.gridConn()
if conn == nil {
return nil
}
_, err := loadGroupHandler.Call(context.Background(), conn, grid.NewMSSWith(map[string]string{
_, err := loadGroupRPC.Call(context.Background(), client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTGroup: group,
}))
return err
@@ -546,7 +389,7 @@ func (client *peerRESTClient) ReloadSiteReplicationConfig(ctx context.Context) e
return nil
}
_, err := reloadSiteReplicationConfigHandler.Call(ctx, conn, grid.NewMSSWith(map[string]string{}))
_, err := reloadSiteReplicationConfigRPC.Call(ctx, conn, grid.NewMSS())
return err
}
@@ -577,28 +420,17 @@ func (client *peerRESTClient) CommitBinary(ctx context.Context) error {
// SignalService - sends signal to peer nodes.
func (client *peerRESTClient) SignalService(sig serviceSignal, subSys string, dryRun bool) error {
values := make(url.Values)
values := grid.NewMSS()
values.Set(peerRESTSignal, strconv.Itoa(int(sig)))
values.Set(peerRESTDryRun, strconv.FormatBool(dryRun))
values.Set(peerRESTSubSys, subSys)
respBody, err := client.call(peerRESTMethodSignalService, values, nil, -1)
if err != nil {
return err
}
defer xhttp.DrainBody(respBody)
return nil
_, err := signalServiceRPC.Call(context.Background(), client.gridConn(), values)
return err
}
func (client *peerRESTClient) BackgroundHealStatus() (madmin.BgHealState, error) {
respBody, err := client.call(peerRESTMethodBackgroundHealStatus, nil, nil, -1)
if err != nil {
return madmin.BgHealState{}, err
}
defer xhttp.DrainBody(respBody)
state := madmin.BgHealState{}
err = gob.NewDecoder(respBody).Decode(&state)
return state, err
resp, err := getBackgroundHealStatusRPC.Call(context.Background(), client.gridConn(), grid.NewMSS())
return resp.ValueOrZero(), err
}
// GetMetacacheListing - get a new or existing metacache.
@@ -607,19 +439,7 @@ func (client *peerRESTClient) GetMetacacheListing(ctx context.Context, o listPat
resp := localMetacacheMgr.getBucket(ctx, o.Bucket).findCache(o)
return &resp, nil
}
var reader bytes.Buffer
err := gob.NewEncoder(&reader).Encode(o)
if err != nil {
return nil, err
}
respBody, err := client.callWithContext(ctx, peerRESTMethodGetMetacacheListing, nil, &reader, int64(reader.Len()))
if err != nil {
return nil, err
}
var resp metacache
defer xhttp.DrainBody(respBody)
return &resp, msgp.Decode(respBody, &resp)
return getMetacacheListingRPC.Call(ctx, client.gridConn(), &o)
}
// UpdateMetacacheListing - update an existing metacache it will unconditionally be updated to the new state.
@@ -627,17 +447,11 @@ func (client *peerRESTClient) UpdateMetacacheListing(ctx context.Context, m meta
if client == nil {
return localMetacacheMgr.updateCacheEntry(m)
}
b, err := m.MarshalMsg(nil)
if err != nil {
return m, err
resp, err := updateMetacacheListingRPC.Call(ctx, client.gridConn(), &m)
if err != nil || resp == nil {
return metacache{}, err
}
respBody, err := client.callWithContext(ctx, peerRESTMethodUpdateMetacacheListing, nil, bytes.NewBuffer(b), int64(len(b)))
if err != nil {
return m, err
}
defer xhttp.DrainBody(respBody)
var resp metacache
return resp, msgp.Decode(respBody, &resp)
return *resp, nil
}
func (client *peerRESTClient) ReloadPoolMeta(ctx context.Context) error {
@@ -645,7 +459,7 @@ func (client *peerRESTClient) ReloadPoolMeta(ctx context.Context) error {
if conn == nil {
return nil
}
_, err := reloadPoolMetaHandler.Call(ctx, conn, grid.NewMSSWith(map[string]string{}))
_, err := reloadPoolMetaRPC.Call(ctx, conn, grid.NewMSSWith(map[string]string{}))
return err
}
@@ -654,7 +468,7 @@ func (client *peerRESTClient) StopRebalance(ctx context.Context) error {
if conn == nil {
return nil
}
_, err := stopRebalanceHandler.Call(ctx, conn, grid.NewMSSWith(map[string]string{}))
_, err := stopRebalanceRPC.Call(ctx, conn, grid.NewMSSWith(map[string]string{}))
return err
}
@@ -663,7 +477,7 @@ func (client *peerRESTClient) LoadRebalanceMeta(ctx context.Context, startRebala
if conn == nil {
return nil
}
_, err := loadRebalanceMetaHandler.Call(ctx, conn, grid.NewMSSWith(map[string]string{
_, err := loadRebalanceMetaRPC.Call(ctx, conn, grid.NewMSSWith(map[string]string{
peerRESTStartRebalance: strconv.FormatBool(startRebalance),
}))
return err
@@ -674,7 +488,7 @@ func (client *peerRESTClient) LoadTransitionTierConfig(ctx context.Context) erro
if conn == nil {
return nil
}
_, err := loadTransitionTierConfigHandler.Call(ctx, conn, grid.NewMSSWith(map[string]string{}))
_, err := loadTransitionTierConfigRPC.Call(ctx, conn, grid.NewMSSWith(map[string]string{}))
return err
}
@@ -711,7 +525,7 @@ func (client *peerRESTClient) doListen(ctx context.Context, listenCh chan<- []by
if conn == nil {
return
}
st, err := listenHandler.Call(ctx, conn, grid.NewURLValuesWith(v))
st, err := listenRPC.Call(ctx, conn, grid.NewURLValuesWith(v))
if err != nil {
return
}
@@ -759,48 +573,31 @@ func (client *peerRESTClient) Trace(ctx context.Context, traceCh chan<- []byte,
}()
}
func (client *peerRESTClient) doConsoleLog(logCh chan log.Info, doneCh <-chan struct{}) {
// To cancel the REST request in case doneCh gets closed.
ctx, cancel := context.WithCancel(GlobalContext)
cancelCh := make(chan struct{})
defer close(cancelCh)
go func() {
select {
case <-doneCh:
case <-cancelCh:
// There was an error in the REST request.
}
cancel()
}()
respBody, err := client.callWithContext(ctx, peerRESTMethodLog, nil, nil, -1)
defer xhttp.DrainBody(respBody)
func (client *peerRESTClient) doConsoleLog(ctx context.Context, kind madmin.LogMask, logCh chan<- []byte) {
st, err := consoleLogRPC.Call(ctx, client.gridConn(), grid.NewMSSWith(map[string]string{
peerRESTLogMask: strconv.Itoa(int(kind)),
}))
if err != nil {
return
}
dec := gob.NewDecoder(respBody)
for {
var lg log.Info
if err = dec.Decode(&lg); err != nil {
break
}
st.Results(func(b *grid.Bytes) error {
select {
case logCh <- lg:
case logCh <- *b:
default:
consoleLogRPC.PutResponse(b)
// Do not block on slow receivers.
}
}
return nil
})
}
// ConsoleLog - sends request to peer nodes to get console logs
func (client *peerRESTClient) ConsoleLog(logCh chan log.Info, doneCh <-chan struct{}) {
func (client *peerRESTClient) ConsoleLog(ctx context.Context, kind madmin.LogMask, logCh chan<- []byte) {
go func() {
for {
client.doConsoleLog(logCh, doneCh)
client.doConsoleLog(ctx, kind, logCh)
select {
case <-doneCh:
case <-ctx.Done():
return
default:
// There was error in the REST request, retry after sometime as probably the peer is down.
@@ -838,71 +635,75 @@ func newPeerRestClients(endpoints EndpointServerPools) (remote, all []*peerRESTC
// MonitorBandwidth - send http trace request to peer nodes
func (client *peerRESTClient) MonitorBandwidth(ctx context.Context, buckets []string) (*bandwidth.BucketBandwidthReport, error) {
values := make(url.Values)
values.Set(peerRESTBuckets, strings.Join(buckets, ","))
respBody, err := client.callWithContext(ctx, peerRESTMethodGetBandwidth, values, nil, -1)
if err != nil {
return nil, err
}
defer xhttp.DrainBody(respBody)
dec := gob.NewDecoder(respBody)
var bandwidthReport bandwidth.BucketBandwidthReport
err = dec.Decode(&bandwidthReport)
return &bandwidthReport, err
values := grid.NewURLValuesWith(map[string][]string{
peerRESTBuckets: buckets,
})
return getBandwidthRPC.Call(ctx, client.gridConn(), values)
}
func (client *peerRESTClient) GetPeerMetrics(ctx context.Context) (<-chan Metric, error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodGetPeerMetrics, nil, nil, -1)
func (client *peerRESTClient) GetResourceMetrics(ctx context.Context) (<-chan Metric, error) {
resp, err := getResourceMetricsRPC.Call(ctx, client.gridConn(), grid.NewMSS())
if err != nil {
return nil, err
}
dec := gob.NewDecoder(respBody)
ch := make(chan Metric)
go func(ch chan<- Metric) {
defer func() {
xhttp.DrainBody(respBody)
close(ch)
}()
for {
var metric Metric
if err := dec.Decode(&metric); err != nil {
return
defer close(ch)
for _, m := range resp.Value() {
if m == nil {
continue
}
select {
case <-ctx.Done():
return
case ch <- metric:
case ch <- *m:
}
}
}(ch)
return ch, nil
}
func (client *peerRESTClient) GetPeerBucketMetrics(ctx context.Context) (<-chan Metric, error) {
respBody, err := client.callWithContext(ctx, peerRESTMethodGetPeerBucketMetrics, nil, nil, -1)
func (client *peerRESTClient) GetPeerMetrics(ctx context.Context) (<-chan Metric, error) {
resp, err := getPeerMetricsRPC.Call(ctx, client.gridConn(), grid.NewMSS())
if err != nil {
return nil, err
}
dec := gob.NewDecoder(respBody)
ch := make(chan Metric)
go func(ch chan<- Metric) {
defer func() {
xhttp.DrainBody(respBody)
close(ch)
}()
for {
var metric Metric
if err := dec.Decode(&metric); err != nil {
return
go func() {
defer close(ch)
for _, m := range resp.Value() {
if m == nil {
continue
}
select {
case <-ctx.Done():
return
case ch <- metric:
case ch <- *m:
}
}
}(ch)
}()
return ch, nil
}
func (client *peerRESTClient) GetPeerBucketMetrics(ctx context.Context) (<-chan Metric, error) {
resp, err := getPeerBucketMetricsRPC.Call(ctx, client.gridConn(), grid.NewMSS())
if err != nil {
return nil, err
}
ch := make(chan Metric)
go func() {
defer close(ch)
for _, m := range resp.Value() {
if m == nil {
continue
}
select {
case <-ctx.Done():
return
case ch <- *m:
}
}
}()
return ch, nil
}
@@ -966,18 +767,11 @@ func (client *peerRESTClient) DriveSpeedTest(ctx context.Context, opts madmin.Dr
}
func (client *peerRESTClient) GetLastDayTierStats(ctx context.Context) (DailyAllTierStats, error) {
var result map[string]lastDayTierStats
respBody, err := client.callWithContext(context.Background(), peerRESTMethodGetLastDayTierStats, nil, nil, -1)
if err != nil {
return result, err
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&result)
if err != nil {
resp, err := getLastDayTierStatsRPC.Call(ctx, client.gridConn(), grid.NewMSS())
if err != nil || resp == nil {
return DailyAllTierStats{}, err
}
return DailyAllTierStats(result), nil
return *resp, nil
}
// DevNull - Used by netperf to pump data to peer
+18 -38
View File
@@ -18,50 +18,29 @@
package cmd
const (
peerRESTVersion = "v37" // Add 'metrics' option for ServerInfo
peerRESTVersion = "v38" // Convert RPC calls
peerRESTVersionPrefix = SlashSeparator + peerRESTVersion
peerRESTPrefix = minioReservedBucketPath + "/peer"
peerRESTPath = peerRESTPrefix + peerRESTVersionPrefix
)
const (
peerRESTMethodHealth = "/health"
peerRESTMethodServerInfo = "/serverinfo"
peerRESTMethodLocalStorageInfo = "/localstorageinfo"
peerRESTMethodCPUInfo = "/cpuinfo"
peerRESTMethodDiskHwInfo = "/diskhwinfo"
peerRESTMethodNetHwInfo = "/nethwinfo"
peerRESTMethodOsInfo = "/osinfo"
peerRESTMethodMemInfo = "/meminfo"
peerRESTMethodProcInfo = "/procinfo"
peerRESTMethodSysErrors = "/syserrors"
peerRESTMethodSysServices = "/sysservices"
peerRESTMethodSysConfig = "/sysconfig"
peerRESTMethodGetBucketStats = "/getbucketstats"
peerRESTMethodGetAllBucketStats = "/getallbucketstats"
peerRESTMethodVerifyBinary = "/verifybinary"
peerRESTMethodCommitBinary = "/commitbinary"
peerRESTMethodSignalService = "/signalservice"
peerRESTMethodBackgroundHealStatus = "/backgroundhealstatus"
peerRESTMethodGetLocks = "/getlocks"
peerRESTMethodStartProfiling = "/startprofiling"
peerRESTMethodDownloadProfilingData = "/downloadprofilingdata"
peerRESTMethodLog = "/log"
peerRESTMethodGetBandwidth = "/bandwidth"
peerRESTMethodGetMetacacheListing = "/getmetacache"
peerRESTMethodUpdateMetacacheListing = "/updatemetacache"
peerRESTMethodGetPeerMetrics = "/peermetrics"
peerRESTMethodGetPeerBucketMetrics = "/peerbucketmetrics"
peerRESTMethodSpeedTest = "/speedtest"
peerRESTMethodDriveSpeedTest = "/drivespeedtest"
peerRESTMethodStopRebalance = "/stoprebalance"
peerRESTMethodGetLastDayTierStats = "/getlastdaytierstats"
peerRESTMethodDevNull = "/devnull"
peerRESTMethodNetperf = "/netperf"
peerRESTMethodMetrics = "/metrics"
peerRESTMethodResourceMetrics = "/resourcemetrics"
peerRESTMethodGetReplicationMRF = "/getreplicationmrf"
peerRESTMethodGetSRMetrics = "/getsrmetrics"
peerRESTMethodHealth = "/health"
peerRESTMethodVerifyBinary = "/verifybinary"
peerRESTMethodCommitBinary = "/commitbinary"
peerRESTMethodSignalService = "/signalservice"
peerRESTMethodBackgroundHealStatus = "/backgroundhealstatus"
peerRESTMethodGetLocks = "/getlocks"
peerRESTMethodStartProfiling = "/startprofiling"
peerRESTMethodDownloadProfilingData = "/downloadprofilingdata"
peerRESTMethodGetBandwidth = "/bandwidth"
peerRESTMethodSpeedTest = "/speedtest"
peerRESTMethodDriveSpeedTest = "/drivespeedtest"
peerRESTMethodReloadSiteReplicationConfig = "/reloadsitereplicationconfig"
peerRESTMethodGetLastDayTierStats = "/getlastdaytierstats"
peerRESTMethodDevNull = "/devnull"
peerRESTMethodNetperf = "/netperf"
peerRESTMethodGetReplicationMRF = "/getreplicationmrf"
)
const (
@@ -99,4 +78,5 @@ const (
peerRESTListenPrefix = "prefix"
peerRESTListenSuffix = "suffix"
peerRESTListenEvents = "events"
peerRESTLogMask = "log-mask"
)
+262 -456
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -376,7 +376,7 @@ func (client *remotePeerS3Client) HealBucket(ctx context.Context, bucket string,
peerS3BucketDeleted: strconv.FormatBool(opts.Remove),
})
_, err := healBucketHandler.Call(ctx, conn, mss)
_, err := healBucketRPC.Call(ctx, conn, mss)
// Initialize heal result info
return madmin.HealResultItem{
@@ -398,7 +398,7 @@ func (client *remotePeerS3Client) GetBucketInfo(ctx context.Context, bucket stri
peerS3BucketDeleted: strconv.FormatBool(opts.Deleted),
})
volInfo, err := headBucketHandler.Call(ctx, conn, mss)
volInfo, err := headBucketRPC.Call(ctx, conn, mss)
if err != nil {
return BucketInfo{}, toStorageErr(err)
}
@@ -449,7 +449,7 @@ func (client *remotePeerS3Client) MakeBucket(ctx context.Context, bucket string,
peerS3BucketForceCreate: strconv.FormatBool(opts.ForceCreate),
})
_, err := makeBucketHandler.Call(ctx, conn, mss)
_, err := makeBucketRPC.Call(ctx, conn, mss)
return toStorageErr(err)
}
@@ -498,7 +498,7 @@ func (client *remotePeerS3Client) DeleteBucket(ctx context.Context, bucket strin
peerS3BucketForceDelete: strconv.FormatBool(opts.Force),
})
_, err := deleteBucketHandler.Call(ctx, conn, mss)
_, err := deleteBucketRPC.Call(ctx, conn, mss)
return toStorageErr(err)
}
+9 -9
View File
@@ -651,6 +651,15 @@ func serverMain(ctx *cli.Context) {
setDefaultProfilerRates()
// Initialize globalConsoleSys system
bootstrapTrace("newConsoleLogger", func() {
globalConsoleSys = NewConsoleLogger(GlobalContext)
logger.AddSystemTarget(GlobalContext, globalConsoleSys)
// Set node name, only set for distributed setup.
globalConsoleSys.SetNodeName(globalLocalNodeName)
})
// Always load ENV variables from files first.
loadEnvVarsFromFiles()
@@ -672,15 +681,6 @@ func serverMain(ctx *cli.Context) {
// the config file if not defined, set the default one.
loadRootCredentials()
// Initialize globalConsoleSys system
bootstrapTrace("newConsoleLogger", func() {
globalConsoleSys = NewConsoleLogger(GlobalContext)
logger.AddSystemTarget(GlobalContext, globalConsoleSys)
// Set node name, only set for distributed setup.
globalConsoleSys.SetNodeName(globalLocalNodeName)
})
// Perform any self-tests
bootstrapTrace("selftests", func() {
bitrotSelfTest()
+2 -2
View File
@@ -1974,8 +1974,8 @@ func (s *TestSuiteCommon) TestGetObjectLarge11MiB(c *check) {
c.Assert(putMD5, getMD5)
}
// TestGetPartialObjectMisAligned - tests get object partially mis-aligned.
// create a large buffer of mis-aligned data and upload it.
// TestGetPartialObjectMisAligned - tests get object partially miss-aligned.
// create a large buffer of miss-aligned data and upload it.
// then make partial range requests to while fetching it back and assert the response content.
func (s *TestSuiteCommon) TestGetPartialObjectMisAligned(c *check) {
// generate a random bucket name.
+4 -4
View File
@@ -258,7 +258,7 @@ func TestParseSignature(t *testing.T) {
expectedErrCode APIErrorCode
}{
// Test case - 1.
// SignElemenet doesn't have 2 parts on an attempt to split at '='.
// SignElement doesn't have 2 parts on an attempt to split at '='.
// ErrMissingFields expected.
{
inputSignElement: "Signature",
@@ -274,7 +274,7 @@ func TestParseSignature(t *testing.T) {
expectedErrCode: ErrMissingFields,
},
// Test case - 3.
// SignElemenet with missing "SignatureTag",ErrMissingSignTag expected.
// SignElement with missing "SignatureTag",ErrMissingSignTag expected.
{
inputSignElement: "Sign=",
expectedSignStr: "",
@@ -310,7 +310,7 @@ func TestParseSignedHeaders(t *testing.T) {
expectedErrCode APIErrorCode
}{
// Test case - 1.
// SignElemenet doesn't have 2 parts on an attempt to split at '='.
// SignElement doesn't have 2 parts on an attempt to split at '='.
// ErrMissingFields expected.
{
inputSignElement: "SignedHeaders",
@@ -318,7 +318,7 @@ func TestParseSignedHeaders(t *testing.T) {
expectedErrCode: ErrMissingFields,
},
// Test case - 2.
// SignElemenet with missing "SigHeaderTag",ErrMissingSignHeadersTag expected.
// SignElement with missing "SigHeaderTag",ErrMissingSignHeadersTag expected.
{
inputSignElement: "Sign=",
expectedSignedHeaders: nil,
+1 -1
View File
@@ -3946,7 +3946,7 @@ func (c *SiteReplicationSys) EditPeerCluster(ctx context.Context, peer madmin.Pe
return madmin.ReplicateEditStatus{}, errSRInvalidRequest(fmt.Errorf("Endpoint %s not reachable: %w", peer.Endpoint, err))
}
if info.DeploymentID != v.DeploymentID {
return madmin.ReplicateEditStatus{}, errSRInvalidRequest(fmt.Errorf("Endpoint %s does not belong to deployment expected: %s (found %s) ", v.Endpoint, v.DeploymentID, info.DeploymentID))
return madmin.ReplicateEditStatus{}, errSRInvalidRequest(fmt.Errorf("Endpoint %s does not belong to deployment expected: %s (found %s) ", peer.Endpoint, v.DeploymentID, info.DeploymentID))
}
}
}
+7 -2
View File
@@ -21,6 +21,8 @@ import (
"time"
)
//go:generate msgp -file=$GOFILE
// DeleteOptions represents the disk level delete options available for the APIs
type DeleteOptions struct {
BaseOptions
@@ -44,8 +46,6 @@ type DiskInfoOptions struct {
NoOp bool `msg:"np"`
}
//go:generate msgp -file=$GOFILE
// DiskInfo is an extended type which returns current
// disk usage per path.
// The above means that any added/deleted fields are incompatible.
@@ -445,3 +445,8 @@ type RenameDataResp struct {
type LocalDiskIDs struct {
IDs []string
}
// ListDirResult - ListDir()'s response.
type ListDirResult struct {
Entries []string `msg:"e"`
}
+142
View File
@@ -2871,6 +2871,148 @@ func (z *FilesInfo) Msgsize() (s int) {
return
}
// DecodeMsg implements msgp.Decodable
func (z *ListDirResult) 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 "e":
var zb0002 uint32
zb0002, err = dc.ReadArrayHeader()
if err != nil {
err = msgp.WrapError(err, "Entries")
return
}
if cap(z.Entries) >= int(zb0002) {
z.Entries = (z.Entries)[:zb0002]
} else {
z.Entries = make([]string, zb0002)
}
for za0001 := range z.Entries {
z.Entries[za0001], err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err, "Entries", za0001)
return
}
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *ListDirResult) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 1
// write "e"
err = en.Append(0x81, 0xa1, 0x65)
if err != nil {
return
}
err = en.WriteArrayHeader(uint32(len(z.Entries)))
if err != nil {
err = msgp.WrapError(err, "Entries")
return
}
for za0001 := range z.Entries {
err = en.WriteString(z.Entries[za0001])
if err != nil {
err = msgp.WrapError(err, "Entries", za0001)
return
}
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *ListDirResult) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 1
// string "e"
o = append(o, 0x81, 0xa1, 0x65)
o = msgp.AppendArrayHeader(o, uint32(len(z.Entries)))
for za0001 := range z.Entries {
o = msgp.AppendString(o, z.Entries[za0001])
}
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *ListDirResult) 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 "e":
var zb0002 uint32
zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Entries")
return
}
if cap(z.Entries) >= int(zb0002) {
z.Entries = (z.Entries)[:zb0002]
} else {
z.Entries = make([]string, zb0002)
}
for za0001 := range z.Entries {
z.Entries[za0001], bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Entries", za0001)
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 *ListDirResult) Msgsize() (s int) {
s = 1 + 2 + msgp.ArrayHeaderSize
for za0001 := range z.Entries {
s += msgp.StringPrefixSize + len(z.Entries[za0001])
}
return
}
// DecodeMsg implements msgp.Decodable
func (z *LocalDiskIDs) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
+113
View File
@@ -1252,6 +1252,119 @@ func BenchmarkDecodeFilesInfo(b *testing.B) {
}
}
func TestMarshalUnmarshalListDirResult(t *testing.T) {
v := ListDirResult{}
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 BenchmarkMarshalMsgListDirResult(b *testing.B) {
v := ListDirResult{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgListDirResult(b *testing.B) {
v := ListDirResult{}
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 BenchmarkUnmarshalListDirResult(b *testing.B) {
v := ListDirResult{}
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 TestEncodeDecodeListDirResult(t *testing.T) {
v := ListDirResult{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodeListDirResult Msgsize() is inaccurate")
}
vn := ListDirResult{}
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 BenchmarkEncodeListDirResult(b *testing.B) {
v := ListDirResult{}
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 BenchmarkDecodeListDirResult(b *testing.B) {
v := ListDirResult{}
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 TestMarshalUnmarshalLocalDiskIDs(t *testing.T) {
v := LocalDiskIDs{}
bts, err := v.MarshalMsg(nil)
+67 -33
View File
@@ -35,6 +35,7 @@ import (
"time"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio/internal/cachevalue"
"github.com/minio/minio/internal/grid"
xhttp "github.com/minio/minio/internal/http"
xioutil "github.com/minio/minio/internal/ioutil"
@@ -166,6 +167,8 @@ type storageRESTClient struct {
formatData []byte
formatMutex sync.RWMutex
diskInfoCache *cachevalue.Cache[DiskInfo]
// Indexes, will be -1 until assigned a set.
poolIndex, setIndex, diskIndex int
}
@@ -237,7 +240,7 @@ func (client *storageRESTClient) NSScanner(ctx context.Context, cache dataUsageC
defer atomic.AddInt32(&client.scanning, -1)
defer xioutil.SafeClose(updates)
st, err := storageNSScannerHandler.Call(ctx, client.gridConn, &nsScannerOptions{
st, err := storageNSScannerRPC.Call(ctx, client.gridConn, &nsScannerOptions{
DiskID: client.diskID,
ScanMode: int(scanMode),
Cache: &cache,
@@ -306,21 +309,48 @@ func (client *storageRESTClient) DiskInfo(ctx context.Context, opts DiskInfoOpti
// transport is already down.
return info, errDiskNotFound
}
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
opts.DiskID = client.diskID
// if metrics was asked, or it was a NoOp we do not need to cache the value.
if opts.Metrics || opts.NoOp {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
infop, err := storageDiskInfoHandler.Call(ctx, client.gridConn, &opts)
if err != nil {
return info, toStorageErr(err)
}
info = *infop
if info.Error != "" {
return info, toStorageErr(errors.New(info.Error))
}
opts.DiskID = client.diskID
infop, err := storageDiskInfoRPC.Call(ctx, client.gridConn, &opts)
if err != nil {
return info, toStorageErr(err)
}
info = *infop
if info.Error != "" {
return info, toStorageErr(errors.New(info.Error))
}
info.Scanning = atomic.LoadInt32(&client.scanning) == 1
return info, nil
} // In all other cases cache the value upto 1sec.
client.diskInfoCache.Once.Do(func() {
client.diskInfoCache.TTL = time.Second
client.diskInfoCache.Update = func() (info DiskInfo, err error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
nopts := DiskInfoOptions{DiskID: client.diskID}
infop, err := storageDiskInfoRPC.Call(ctx, client.gridConn, &nopts)
if err != nil {
return info, toStorageErr(err)
}
info = *infop
if info.Error != "" {
return info, toStorageErr(errors.New(info.Error))
}
return info, nil
}
})
info, err = client.diskInfoCache.Get()
info.Scanning = atomic.LoadInt32(&client.scanning) == 1
return info, nil
return info, err
}
// MakeVolBulk - create multiple volumes in a bulk operation.
@@ -340,7 +370,7 @@ func (client *storageRESTClient) ListVols(ctx context.Context) (vols []VolInfo,
// StatVol - get volume info over the network.
func (client *storageRESTClient) StatVol(ctx context.Context, volume string) (vol VolInfo, err error) {
v, err := storageStatVolHandler.Call(ctx, client.gridConn, grid.NewMSSWith(map[string]string{
v, err := storageStatVolRPC.Call(ctx, client.gridConn, grid.NewMSSWith(map[string]string{
storageRESTDiskID: client.diskID,
storageRESTVolume: volume,
}))
@@ -349,7 +379,7 @@ func (client *storageRESTClient) StatVol(ctx context.Context, volume string) (vo
}
vol = *v
// Performs shallow copy, so we can reuse.
storageStatVolHandler.PutResponse(v)
storageStatVolRPC.PutResponse(v)
return vol, nil
}
@@ -386,7 +416,7 @@ func (client *storageRESTClient) CreateFile(ctx context.Context, origvolume, vol
}
func (client *storageRESTClient) WriteMetadata(ctx context.Context, origvolume, volume, path string, fi FileInfo) error {
_, err := storageWriteMetadataHandler.Call(ctx, client.gridConn, &MetadataHandlerParams{
_, err := storageWriteMetadataRPC.Call(ctx, client.gridConn, &MetadataHandlerParams{
DiskID: client.diskID,
OrigVolume: origvolume,
Volume: volume,
@@ -397,7 +427,7 @@ func (client *storageRESTClient) WriteMetadata(ctx context.Context, origvolume,
}
func (client *storageRESTClient) UpdateMetadata(ctx context.Context, volume, path string, fi FileInfo, opts UpdateMetadataOpts) error {
_, err := storageUpdateMetadataHandler.Call(ctx, client.gridConn, &MetadataHandlerParams{
_, err := storageUpdateMetadataRPC.Call(ctx, client.gridConn, &MetadataHandlerParams{
DiskID: client.diskID,
Volume: volume,
FilePath: path,
@@ -408,7 +438,7 @@ func (client *storageRESTClient) UpdateMetadata(ctx context.Context, volume, pat
}
func (client *storageRESTClient) DeleteVersion(ctx context.Context, volume, path string, fi FileInfo, forceDelMarker bool, opts DeleteOptions) (err error) {
_, err = storageDeleteVersionHandler.Call(ctx, client.gridConn, &DeleteVersionHandlerParams{
_, err = storageDeleteVersionRPC.Call(ctx, client.gridConn, &DeleteVersionHandlerParams{
DiskID: client.diskID,
Volume: volume,
FilePath: path,
@@ -431,7 +461,7 @@ func (client *storageRESTClient) WriteAll(ctx context.Context, volume string, pa
// CheckParts - stat all file parts.
func (client *storageRESTClient) CheckParts(ctx context.Context, volume string, path string, fi FileInfo) error {
_, err := storageCheckPartsHandler.Call(ctx, client.gridConn, &CheckPartsHandlerParams{
_, err := storageCheckPartsRPC.Call(ctx, client.gridConn, &CheckPartsHandlerParams{
DiskID: client.diskID,
Volume: volume,
FilePath: path,
@@ -442,7 +472,7 @@ func (client *storageRESTClient) CheckParts(ctx context.Context, volume string,
// RenameData - rename source path to destination path atomically, metadata and data file.
func (client *storageRESTClient) RenameData(ctx context.Context, srcVolume, srcPath string, fi FileInfo, dstVolume, dstPath string, opts RenameOptions) (sign uint64, err error) {
resp, err := storageRenameDataHandler.Call(ctx, client.gridConn, &RenameDataHandlerParams{
resp, err := storageRenameDataRPC.Call(ctx, client.gridConn, &RenameDataHandlerParams{
DiskID: client.diskID,
SrcVolume: srcVolume,
SrcPath: srcPath,
@@ -454,7 +484,7 @@ func (client *storageRESTClient) RenameData(ctx context.Context, srcVolume, srcP
if err != nil {
return 0, toStorageErr(err)
}
defer storageRenameDataHandler.PutResponse(resp)
defer storageRenameDataRPC.PutResponse(resp)
return resp.Signature, nil
}
@@ -484,7 +514,7 @@ func readMsgpReaderPoolPut(r *msgp.Reader) {
func (client *storageRESTClient) ReadVersion(ctx context.Context, origvolume, volume, path, versionID string, opts ReadOptions) (fi FileInfo, err error) {
// Use websocket when not reading data.
if !opts.ReadData {
resp, err := storageReadVersionHandler.Call(ctx, client.gridConn, grid.NewMSSWith(map[string]string{
resp, err := storageReadVersionRPC.Call(ctx, client.gridConn, grid.NewMSSWith(map[string]string{
storageRESTDiskID: client.diskID,
storageRESTOrigVolume: origvolume,
storageRESTVolume: volume,
@@ -524,7 +554,7 @@ func (client *storageRESTClient) ReadVersion(ctx context.Context, origvolume, vo
func (client *storageRESTClient) ReadXL(ctx context.Context, volume string, path string, readData bool) (rf RawFileInfo, err error) {
// Use websocket when not reading data.
if !readData {
resp, err := storageReadXLHandler.Call(ctx, client.gridConn, grid.NewMSSWith(map[string]string{
resp, err := storageReadXLRPC.Call(ctx, client.gridConn, grid.NewMSSWith(map[string]string{
storageRESTDiskID: client.diskID,
storageRESTVolume: volume,
storageRESTFilePath: path,
@@ -567,7 +597,7 @@ func (client *storageRESTClient) ReadAll(ctx context.Context, volume string, pat
}
}
gridBytes, err := storageReadAllHandler.Call(ctx, client.gridConn, &ReadAllHandlerParams{
gridBytes, err := storageReadAllRPC.Call(ctx, client.gridConn, &ReadAllHandlerParams{
DiskID: client.diskID,
Volume: volume,
FilePath: path,
@@ -618,24 +648,27 @@ func (client *storageRESTClient) ReadFile(ctx context.Context, volume string, pa
// ListDir - lists a directory.
func (client *storageRESTClient) ListDir(ctx context.Context, origvolume, volume, dirPath string, count int) (entries []string, err error) {
values := make(url.Values)
values := grid.NewMSS()
values.Set(storageRESTVolume, volume)
values.Set(storageRESTDirPath, dirPath)
values.Set(storageRESTCount, strconv.Itoa(count))
values.Set(storageRESTOrigVolume, origvolume)
values.Set(storageRESTDiskID, client.diskID)
respBody, err := client.call(ctx, storageRESTMethodListDir, values, nil, -1)
st, err := storageListDirRPC.Call(ctx, client.gridConn, values)
if err != nil {
return nil, err
return nil, toStorageErr(err)
}
defer xhttp.DrainBody(respBody)
err = gob.NewDecoder(respBody).Decode(&entries)
return entries, err
err = st.Results(func(resp *ListDirResult) error {
entries = resp.Entries
return nil
})
return entries, toStorageErr(err)
}
// DeleteFile - deletes a file.
func (client *storageRESTClient) Delete(ctx context.Context, volume string, path string, deleteOpts DeleteOptions) error {
_, err := storageDeleteFileHandler.Call(ctx, client.gridConn, &DeleteFileHandlerParams{
_, err := storageDeleteFileRPC.Call(ctx, client.gridConn, &DeleteFileHandlerParams{
DiskID: client.diskID,
Volume: volume,
FilePath: path,
@@ -700,7 +733,7 @@ func (client *storageRESTClient) DeleteVersions(ctx context.Context, volume stri
// RenameFile - renames a file.
func (client *storageRESTClient) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolume, dstPath string) (err error) {
_, err = storageRenameFileHandler.Call(ctx, client.gridConn, &RenameFileHandlerParams{
_, err = storageRenameFileRPC.Call(ctx, client.gridConn, &RenameFileHandlerParams{
DiskID: client.diskID,
SrcVolume: srcVolume,
SrcFilePath: srcPath,
@@ -860,6 +893,7 @@ func newStorageRESTClient(endpoint Endpoint, healthCheck bool, gm *grid.Manager)
}
return &storageRESTClient{
endpoint: endpoint, restClient: restClient, poolIndex: -1, setIndex: -1, diskIndex: -1,
gridConn: conn,
gridConn: conn,
diskInfoCache: cachevalue.New[DiskInfo](),
}, nil
}
+45 -98
View File
@@ -57,6 +57,23 @@ type storageRESTServer struct {
poolIndex, setIndex, diskIndex int
}
var (
storageCheckPartsRPC = grid.NewSingleHandler[*CheckPartsHandlerParams, grid.NoPayload](grid.HandlerCheckParts, func() *CheckPartsHandlerParams { return &CheckPartsHandlerParams{} }, grid.NewNoPayload)
storageDeleteFileRPC = grid.NewSingleHandler[*DeleteFileHandlerParams, grid.NoPayload](grid.HandlerDeleteFile, func() *DeleteFileHandlerParams { return &DeleteFileHandlerParams{} }, grid.NewNoPayload).AllowCallRequestPool(true)
storageDeleteVersionRPC = grid.NewSingleHandler[*DeleteVersionHandlerParams, grid.NoPayload](grid.HandlerDeleteVersion, func() *DeleteVersionHandlerParams { return &DeleteVersionHandlerParams{} }, grid.NewNoPayload)
storageDiskInfoRPC = grid.NewSingleHandler[*DiskInfoOptions, *DiskInfo](grid.HandlerDiskInfo, func() *DiskInfoOptions { return &DiskInfoOptions{} }, func() *DiskInfo { return &DiskInfo{} }).WithSharedResponse().AllowCallRequestPool(true)
storageNSScannerRPC = grid.NewStream[*nsScannerOptions, grid.NoPayload, *nsScannerResp](grid.HandlerNSScanner, func() *nsScannerOptions { return &nsScannerOptions{} }, nil, func() *nsScannerResp { return &nsScannerResp{} })
storageReadAllRPC = grid.NewSingleHandler[*ReadAllHandlerParams, *grid.Bytes](grid.HandlerReadAll, func() *ReadAllHandlerParams { return &ReadAllHandlerParams{} }, grid.NewBytes).AllowCallRequestPool(true)
storageReadVersionRPC = grid.NewSingleHandler[*grid.MSS, *FileInfo](grid.HandlerReadVersion, grid.NewMSS, func() *FileInfo { return &FileInfo{} })
storageReadXLRPC = grid.NewSingleHandler[*grid.MSS, *RawFileInfo](grid.HandlerReadXL, grid.NewMSS, func() *RawFileInfo { return &RawFileInfo{} })
storageRenameDataRPC = grid.NewSingleHandler[*RenameDataHandlerParams, *RenameDataResp](grid.HandlerRenameData, func() *RenameDataHandlerParams { return &RenameDataHandlerParams{} }, func() *RenameDataResp { return &RenameDataResp{} })
storageRenameFileRPC = grid.NewSingleHandler[*RenameFileHandlerParams, grid.NoPayload](grid.HandlerRenameFile, func() *RenameFileHandlerParams { return &RenameFileHandlerParams{} }, grid.NewNoPayload).AllowCallRequestPool(true)
storageStatVolRPC = grid.NewSingleHandler[*grid.MSS, *VolInfo](grid.HandlerStatVol, grid.NewMSS, func() *VolInfo { return &VolInfo{} })
storageUpdateMetadataRPC = grid.NewSingleHandler[*MetadataHandlerParams, grid.NoPayload](grid.HandlerUpdateMetadata, func() *MetadataHandlerParams { return &MetadataHandlerParams{} }, grid.NewNoPayload)
storageWriteMetadataRPC = grid.NewSingleHandler[*MetadataHandlerParams, grid.NoPayload](grid.HandlerWriteMetadata, func() *MetadataHandlerParams { return &MetadataHandlerParams{} }, grid.NewNoPayload)
storageListDirRPC = grid.NewStream[*grid.MSS, grid.NoPayload, *ListDirResult](grid.HandlerListDir, grid.NewMSS, nil, func() *ListDirResult { return &ListDirResult{} }).WithOutCapacity(1)
)
func (s *storageRESTServer) getStorage() StorageAPI {
globalLocalDrivesMu.RLock()
defer globalLocalDrivesMu.RUnlock()
@@ -198,11 +215,6 @@ func (s *storageRESTServer) HealthHandler(w http.ResponseWriter, r *http.Request
s.IsValid(w, r)
}
// DiskInfo types.
// DiskInfo.Metrics elements are shared, so we cannot reuse.
var storageDiskInfoHandler = grid.NewSingleHandler[*DiskInfoOptions, *DiskInfo](grid.HandlerDiskInfo, func() *DiskInfoOptions { return &DiskInfoOptions{} },
func() *DiskInfo { return &DiskInfo{} }).WithSharedResponse().AllowCallRequestPool(true)
// DiskInfoHandler - returns disk info.
func (s *storageRESTServer) DiskInfoHandler(opts *DiskInfoOptions) (*DiskInfo, *grid.RemoteErr) {
if !s.checkID(opts.DiskID) {
@@ -215,12 +227,6 @@ func (s *storageRESTServer) DiskInfoHandler(opts *DiskInfoOptions) (*DiskInfo, *
return &info, nil
}
// scanner rpc handler.
var storageNSScannerHandler = grid.NewStream[*nsScannerOptions, grid.NoPayload, *nsScannerResp](grid.HandlerNSScanner,
func() *nsScannerOptions { return &nsScannerOptions{} },
nil,
func() *nsScannerResp { return &nsScannerResp{} })
func (s *storageRESTServer) NSScannerHandler(ctx context.Context, params *nsScannerOptions, out chan<- *nsScannerResp) *grid.RemoteErr {
if !s.checkID(params.DiskID) {
return grid.NewRemoteErr(errDiskNotFound)
@@ -236,7 +242,7 @@ func (s *storageRESTServer) NSScannerHandler(ctx context.Context, params *nsScan
go func() {
defer wg.Done()
for update := range updates {
resp := storageNSScannerHandler.NewResponse()
resp := storageNSScannerRPC.NewResponse()
resp.Update = &update
out <- resp
}
@@ -247,7 +253,7 @@ func (s *storageRESTServer) NSScannerHandler(ctx context.Context, params *nsScan
return grid.NewRemoteErr(err)
}
// Send final response.
resp := storageNSScannerHandler.NewResponse()
resp := storageNSScannerRPC.NewResponse()
resp.Final = &ui
out <- resp
return nil
@@ -277,22 +283,6 @@ func (s *storageRESTServer) MakeVolBulkHandler(w http.ResponseWriter, r *http.Re
}
}
// ListVolsHandler - list volumes.
func (s *storageRESTServer) ListVolsHandler(w http.ResponseWriter, r *http.Request) {
if !s.IsValid(w, r) {
return
}
infos, err := s.getStorage().ListVols(r.Context())
if err != nil {
s.writeErrorResponse(w, err)
return
}
logger.LogIf(r.Context(), msgp.Encode(w, VolsInfo(infos)))
}
// statvol types.
var storageStatVolHandler = grid.NewSingleHandler[*grid.MSS, *VolInfo](grid.HandlerStatVol, grid.NewMSS, func() *VolInfo { return &VolInfo{} })
// StatVolHandler - stat a volume.
func (s *storageRESTServer) StatVolHandler(params *grid.MSS) (*VolInfo, *grid.RemoteErr) {
if !s.checkID(params.Get(storageRESTDiskID)) {
@@ -346,10 +336,6 @@ func (s *storageRESTServer) CreateFileHandler(w http.ResponseWriter, r *http.Req
done(s.getStorage().CreateFile(r.Context(), origvolume, volume, filePath, int64(fileSize), body))
}
var storageDeleteVersionHandler = grid.NewSingleHandler[*DeleteVersionHandlerParams, grid.NoPayload](grid.HandlerDeleteVersion, func() *DeleteVersionHandlerParams {
return &DeleteVersionHandlerParams{}
}, grid.NewNoPayload)
// DeleteVersionHandler delete updated metadata.
func (s *storageRESTServer) DeleteVersionHandler(p *DeleteVersionHandlerParams) (np grid.NoPayload, gerr *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -364,10 +350,6 @@ func (s *storageRESTServer) DeleteVersionHandler(p *DeleteVersionHandlerParams)
return np, grid.NewRemoteErr(err)
}
var storageReadVersionHandler = grid.NewSingleHandler[*grid.MSS, *FileInfo](grid.HandlerReadVersion, grid.NewMSS, func() *FileInfo {
return &FileInfo{}
})
// ReadVersionHandlerWS read metadata of versionID
func (s *storageRESTServer) ReadVersionHandlerWS(params *grid.MSS) (*FileInfo, *grid.RemoteErr) {
if !s.checkID(params.Get(storageRESTDiskID)) {
@@ -422,10 +404,6 @@ func (s *storageRESTServer) ReadVersionHandler(w http.ResponseWriter, r *http.Re
logger.LogIf(r.Context(), msgp.Encode(w, &fi))
}
var storageWriteMetadataHandler = grid.NewSingleHandler[*MetadataHandlerParams, grid.NoPayload](grid.HandlerWriteMetadata, func() *MetadataHandlerParams {
return &MetadataHandlerParams{}
}, grid.NewNoPayload)
// WriteMetadataHandler rpc handler to write new updated metadata.
func (s *storageRESTServer) WriteMetadataHandler(p *MetadataHandlerParams) (np grid.NoPayload, gerr *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -440,10 +418,6 @@ func (s *storageRESTServer) WriteMetadataHandler(p *MetadataHandlerParams) (np g
return np, grid.NewRemoteErr(err)
}
var storageUpdateMetadataHandler = grid.NewSingleHandler[*MetadataHandlerParams, grid.NoPayload](grid.HandlerUpdateMetadata, func() *MetadataHandlerParams {
return &MetadataHandlerParams{}
}, grid.NewNoPayload)
// UpdateMetadataHandler update new updated metadata.
func (s *storageRESTServer) UpdateMetadataHandler(p *MetadataHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -479,10 +453,6 @@ func (s *storageRESTServer) WriteAllHandler(w http.ResponseWriter, r *http.Reque
}
}
var storageCheckPartsHandler = grid.NewSingleHandler[*CheckPartsHandlerParams, grid.NoPayload](grid.HandlerCheckParts, func() *CheckPartsHandlerParams {
return &CheckPartsHandlerParams{}
}, grid.NewNoPayload)
// CheckPartsHandler - check if a file metadata exists.
func (s *storageRESTServer) CheckPartsHandler(p *CheckPartsHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -493,10 +463,6 @@ func (s *storageRESTServer) CheckPartsHandler(p *CheckPartsHandlerParams) (grid.
return grid.NewNPErr(s.getStorage().CheckParts(context.Background(), volume, filePath, p.FI))
}
var storageReadAllHandler = grid.NewSingleHandler[*ReadAllHandlerParams, *grid.Bytes](grid.HandlerReadAll, func() *ReadAllHandlerParams {
return &ReadAllHandlerParams{}
}, grid.NewBytes).AllowCallRequestPool(true)
// ReadAllHandler - read all the contents of a file.
func (s *storageRESTServer) ReadAllHandler(p *ReadAllHandlerParams) (*grid.Bytes, *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -532,10 +498,6 @@ func (s *storageRESTServer) ReadXLHandler(w http.ResponseWriter, r *http.Request
logger.LogIf(r.Context(), msgp.Encode(w, &rf))
}
var storageReadXLHandler = grid.NewSingleHandler[*grid.MSS, *RawFileInfo](grid.HandlerReadXL, grid.NewMSS, func() *RawFileInfo {
return &RawFileInfo{}
})
// ReadXLHandlerWS - read xl.meta for an object at path.
func (s *storageRESTServer) ReadXLHandlerWS(params *grid.MSS) (*RawFileInfo, *grid.RemoteErr) {
if !s.checkID(params.Get(storageRESTDiskID)) {
@@ -650,31 +612,26 @@ func (s *storageRESTServer) ReadFileStreamHandler(w http.ResponseWriter, r *http
}
// ListDirHandler - list a directory.
func (s *storageRESTServer) ListDirHandler(w http.ResponseWriter, r *http.Request) {
if !s.IsValid(w, r) {
return
func (s *storageRESTServer) ListDirHandler(ctx context.Context, params *grid.MSS, out chan<- *ListDirResult) *grid.RemoteErr {
if !s.checkID(params.Get(storageRESTDiskID)) {
return grid.NewRemoteErr(errDiskNotFound)
}
volume := r.Form.Get(storageRESTVolume)
dirPath := r.Form.Get(storageRESTDirPath)
origvolume := r.Form.Get(storageRESTOrigVolume)
count, err := strconv.Atoi(r.Form.Get(storageRESTCount))
volume := params.Get(storageRESTVolume)
dirPath := params.Get(storageRESTDirPath)
origvolume := params.Get(storageRESTOrigVolume)
count, err := strconv.Atoi(params.Get(storageRESTCount))
if err != nil {
s.writeErrorResponse(w, err)
return
return grid.NewRemoteErr(err)
}
entries, err := s.getStorage().ListDir(r.Context(), origvolume, volume, dirPath, count)
entries, err := s.getStorage().ListDir(ctx, origvolume, volume, dirPath, count)
if err != nil {
s.writeErrorResponse(w, err)
return
return grid.NewRemoteErr(err)
}
gob.NewEncoder(w).Encode(&entries)
out <- &ListDirResult{Entries: entries}
return nil
}
var storageDeleteFileHandler = grid.NewSingleHandler[*DeleteFileHandlerParams, grid.NoPayload](grid.HandlerDeleteFile, func() *DeleteFileHandlerParams {
return &DeleteFileHandlerParams{}
}, grid.NewNoPayload).AllowCallRequestPool(true)
// DeleteFileHandler - delete a file.
func (s *storageRESTServer) DeleteFileHandler(p *DeleteFileHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -730,12 +687,6 @@ func (s *storageRESTServer) DeleteVersionsHandler(w http.ResponseWriter, r *http
encoder.Encode(dErrsResp)
}
var storageRenameDataHandler = grid.NewSingleHandler[*RenameDataHandlerParams, *RenameDataResp](grid.HandlerRenameData, func() *RenameDataHandlerParams {
return &RenameDataHandlerParams{}
}, func() *RenameDataResp {
return &RenameDataResp{}
})
// RenameDataHandler - renames a meta object and data dir to destination.
func (s *storageRESTServer) RenameDataHandler(p *RenameDataHandlerParams) (*RenameDataResp, *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -749,10 +700,6 @@ func (s *storageRESTServer) RenameDataHandler(p *RenameDataHandlerParams) (*Rena
return resp, grid.NewRemoteErr(err)
}
var storageRenameFileHandler = grid.NewSingleHandler[*RenameFileHandlerParams, grid.NoPayload](grid.HandlerRenameFile, func() *RenameFileHandlerParams {
return &RenameFileHandlerParams{}
}, grid.NewNoPayload).AllowCallRequestPool(true)
// RenameFileHandler - rename a file from source to destination
func (s *storageRESTServer) RenameFileHandler(p *RenameFileHandlerParams) (grid.NoPayload, *grid.RemoteErr) {
if !s.checkID(p.DiskID) {
@@ -1356,26 +1303,26 @@ func registerStorageRESTHandlers(router *mux.Router, endpointServerPools Endpoin
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCreateFile).HandlerFunc(h(server.CreateFileHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFile).HandlerFunc(h(server.ReadFileHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadFileStream).HandlerFunc(h(server.ReadFileStreamHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodListDir).HandlerFunc(h(server.ListDirHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodDeleteVersions).HandlerFunc(h(server.DeleteVersionsHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodVerifyFile).HandlerFunc(h(server.VerifyFileHandler))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodStatInfoFile).HandlerFunc(h(server.StatInfoFile))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodReadMultiple).HandlerFunc(h(server.ReadMultiple))
subrouter.Methods(http.MethodPost).Path(storageRESTVersionPrefix + storageRESTMethodCleanAbandoned).HandlerFunc(h(server.CleanAbandonedDataHandler))
logger.FatalIf(storageReadAllHandler.Register(gm, server.ReadAllHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageRenameFileHandler.Register(gm, server.RenameFileHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageRenameDataHandler.Register(gm, server.RenameDataHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageDeleteFileHandler.Register(gm, server.DeleteFileHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageCheckPartsHandler.Register(gm, server.CheckPartsHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageReadVersionHandler.Register(gm, server.ReadVersionHandlerWS, endpoint.Path), "unable to register handler")
logger.FatalIf(storageWriteMetadataHandler.Register(gm, server.WriteMetadataHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageUpdateMetadataHandler.Register(gm, server.UpdateMetadataHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageDeleteVersionHandler.Register(gm, server.DeleteVersionHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageReadXLHandler.Register(gm, server.ReadXLHandlerWS, endpoint.Path), "unable to register handler")
logger.FatalIf(storageNSScannerHandler.RegisterNoInput(gm, server.NSScannerHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageDiskInfoHandler.Register(gm, server.DiskInfoHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageStatVolHandler.Register(gm, server.StatVolHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageListDirRPC.RegisterNoInput(gm, server.ListDirHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageReadAllRPC.Register(gm, server.ReadAllHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageRenameFileRPC.Register(gm, server.RenameFileHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageRenameDataRPC.Register(gm, server.RenameDataHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageDeleteFileRPC.Register(gm, server.DeleteFileHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageCheckPartsRPC.Register(gm, server.CheckPartsHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageReadVersionRPC.Register(gm, server.ReadVersionHandlerWS, endpoint.Path), "unable to register handler")
logger.FatalIf(storageWriteMetadataRPC.Register(gm, server.WriteMetadataHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageUpdateMetadataRPC.Register(gm, server.UpdateMetadataHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageDeleteVersionRPC.Register(gm, server.DeleteVersionHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageReadXLRPC.Register(gm, server.ReadXLHandlerWS, endpoint.Path), "unable to register handler")
logger.FatalIf(storageNSScannerRPC.RegisterNoInput(gm, server.NSScannerHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageDiskInfoRPC.Register(gm, server.DiskInfoHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(storageStatVolRPC.Register(gm, server.StatVolHandler, endpoint.Path), "unable to register handler")
logger.FatalIf(gm.RegisterStreamingHandler(grid.HandlerWalkDir, grid.StreamHandler{
Subroute: endpoint.Path,
Handle: server.WalkDirHandler,
+1 -1
View File
@@ -26,7 +26,7 @@ import (
"github.com/minio/minio/internal/logger"
)
// writeSTSErrorRespone writes error headers
// writeSTSErrorResponse writes error headers
func writeSTSErrorResponse(ctx context.Context, w http.ResponseWriter, errCode STSErrorCode, err error) {
stsErr := stsErrCodes.ToSTSErr(errCode)
+2
View File
@@ -23,6 +23,8 @@ import (
"github.com/minio/madmin-go/v3"
)
//go:generate msgp -file=$GOFILE -unexported
type lastDayTierStats struct {
Bins [24]tierStats
UpdatedAt time.Time
+417
View File
@@ -0,0 +1,417 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"github.com/tinylib/msgp/msgp"
)
// DecodeMsg implements msgp.Decodable
func (z *DailyAllTierStats) DecodeMsg(dc *msgp.Reader) (err error) {
var zb0004 uint32
zb0004, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err)
return
}
if (*z) == nil {
(*z) = make(DailyAllTierStats, zb0004)
} else if len((*z)) > 0 {
for key := range *z {
delete((*z), key)
}
}
for zb0004 > 0 {
zb0004--
var zb0001 string
var zb0002 lastDayTierStats
zb0001, err = dc.ReadString()
if err != nil {
err = msgp.WrapError(err)
return
}
var field []byte
_ = field
var zb0005 uint32
zb0005, err = dc.ReadMapHeader()
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
for zb0005 > 0 {
zb0005--
field, err = dc.ReadMapKeyPtr()
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
switch msgp.UnsafeString(field) {
case "Bins":
var zb0006 uint32
zb0006, err = dc.ReadArrayHeader()
if err != nil {
err = msgp.WrapError(err, zb0001, "Bins")
return
}
if zb0006 != uint32(24) {
err = msgp.ArrayError{Wanted: uint32(24), Got: zb0006}
return
}
for zb0003 := range zb0002.Bins {
err = zb0002.Bins[zb0003].DecodeMsg(dc)
if err != nil {
err = msgp.WrapError(err, zb0001, "Bins", zb0003)
return
}
}
case "UpdatedAt":
zb0002.UpdatedAt, err = dc.ReadTime()
if err != nil {
err = msgp.WrapError(err, zb0001, "UpdatedAt")
return
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
}
}
(*z)[zb0001] = zb0002
}
return
}
// EncodeMsg implements msgp.Encodable
func (z DailyAllTierStats) EncodeMsg(en *msgp.Writer) (err error) {
err = en.WriteMapHeader(uint32(len(z)))
if err != nil {
err = msgp.WrapError(err)
return
}
for zb0007, zb0008 := range z {
err = en.WriteString(zb0007)
if err != nil {
err = msgp.WrapError(err)
return
}
// map header, size 2
// write "Bins"
err = en.Append(0x82, 0xa4, 0x42, 0x69, 0x6e, 0x73)
if err != nil {
return
}
err = en.WriteArrayHeader(uint32(24))
if err != nil {
err = msgp.WrapError(err, zb0007, "Bins")
return
}
for zb0009 := range zb0008.Bins {
err = zb0008.Bins[zb0009].EncodeMsg(en)
if err != nil {
err = msgp.WrapError(err, zb0007, "Bins", zb0009)
return
}
}
// write "UpdatedAt"
err = en.Append(0xa9, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74)
if err != nil {
return
}
err = en.WriteTime(zb0008.UpdatedAt)
if err != nil {
err = msgp.WrapError(err, zb0007, "UpdatedAt")
return
}
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z DailyAllTierStats) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
o = msgp.AppendMapHeader(o, uint32(len(z)))
for zb0007, zb0008 := range z {
o = msgp.AppendString(o, zb0007)
// map header, size 2
// string "Bins"
o = append(o, 0x82, 0xa4, 0x42, 0x69, 0x6e, 0x73)
o = msgp.AppendArrayHeader(o, uint32(24))
for zb0009 := range zb0008.Bins {
o, err = zb0008.Bins[zb0009].MarshalMsg(o)
if err != nil {
err = msgp.WrapError(err, zb0007, "Bins", zb0009)
return
}
}
// string "UpdatedAt"
o = append(o, 0xa9, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74)
o = msgp.AppendTime(o, zb0008.UpdatedAt)
}
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *DailyAllTierStats) UnmarshalMsg(bts []byte) (o []byte, err error) {
var zb0004 uint32
zb0004, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
if (*z) == nil {
(*z) = make(DailyAllTierStats, zb0004)
} else if len((*z)) > 0 {
for key := range *z {
delete((*z), key)
}
}
for zb0004 > 0 {
var zb0001 string
var zb0002 lastDayTierStats
zb0004--
zb0001, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
err = msgp.WrapError(err)
return
}
var field []byte
_ = field
var zb0005 uint32
zb0005, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
for zb0005 > 0 {
zb0005--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
switch msgp.UnsafeString(field) {
case "Bins":
var zb0006 uint32
zb0006, bts, err = msgp.ReadArrayHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, zb0001, "Bins")
return
}
if zb0006 != uint32(24) {
err = msgp.ArrayError{Wanted: uint32(24), Got: zb0006}
return
}
for zb0003 := range zb0002.Bins {
bts, err = zb0002.Bins[zb0003].UnmarshalMsg(bts)
if err != nil {
err = msgp.WrapError(err, zb0001, "Bins", zb0003)
return
}
}
case "UpdatedAt":
zb0002.UpdatedAt, bts, err = msgp.ReadTimeBytes(bts)
if err != nil {
err = msgp.WrapError(err, zb0001, "UpdatedAt")
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
err = msgp.WrapError(err, zb0001)
return
}
}
}
(*z)[zb0001] = zb0002
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z DailyAllTierStats) Msgsize() (s int) {
s = msgp.MapHeaderSize
if z != nil {
for zb0007, zb0008 := range z {
_ = zb0008
s += msgp.StringPrefixSize + len(zb0007) + 1 + 5 + msgp.ArrayHeaderSize
for zb0009 := range zb0008.Bins {
s += zb0008.Bins[zb0009].Msgsize()
}
s += 10 + msgp.TimeSize
}
}
return
}
// DecodeMsg implements msgp.Decodable
func (z *lastDayTierStats) 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 "Bins":
var zb0002 uint32
zb0002, err = dc.ReadArrayHeader()
if err != nil {
err = msgp.WrapError(err, "Bins")
return
}
if zb0002 != uint32(24) {
err = msgp.ArrayError{Wanted: uint32(24), Got: zb0002}
return
}
for za0001 := range z.Bins {
err = z.Bins[za0001].DecodeMsg(dc)
if err != nil {
err = msgp.WrapError(err, "Bins", za0001)
return
}
}
case "UpdatedAt":
z.UpdatedAt, err = dc.ReadTime()
if err != nil {
err = msgp.WrapError(err, "UpdatedAt")
return
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *lastDayTierStats) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 2
// write "Bins"
err = en.Append(0x82, 0xa4, 0x42, 0x69, 0x6e, 0x73)
if err != nil {
return
}
err = en.WriteArrayHeader(uint32(24))
if err != nil {
err = msgp.WrapError(err, "Bins")
return
}
for za0001 := range z.Bins {
err = z.Bins[za0001].EncodeMsg(en)
if err != nil {
err = msgp.WrapError(err, "Bins", za0001)
return
}
}
// write "UpdatedAt"
err = en.Append(0xa9, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74)
if err != nil {
return
}
err = en.WriteTime(z.UpdatedAt)
if err != nil {
err = msgp.WrapError(err, "UpdatedAt")
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *lastDayTierStats) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 2
// string "Bins"
o = append(o, 0x82, 0xa4, 0x42, 0x69, 0x6e, 0x73)
o = msgp.AppendArrayHeader(o, uint32(24))
for za0001 := range z.Bins {
o, err = z.Bins[za0001].MarshalMsg(o)
if err != nil {
err = msgp.WrapError(err, "Bins", za0001)
return
}
}
// string "UpdatedAt"
o = append(o, 0xa9, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74)
o = msgp.AppendTime(o, z.UpdatedAt)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *lastDayTierStats) 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 "Bins":
var zb0002 uint32
zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts)
if err != nil {
err = msgp.WrapError(err, "Bins")
return
}
if zb0002 != uint32(24) {
err = msgp.ArrayError{Wanted: uint32(24), Got: zb0002}
return
}
for za0001 := range z.Bins {
bts, err = z.Bins[za0001].UnmarshalMsg(bts)
if err != nil {
err = msgp.WrapError(err, "Bins", za0001)
return
}
}
case "UpdatedAt":
z.UpdatedAt, bts, err = msgp.ReadTimeBytes(bts)
if err != nil {
err = msgp.WrapError(err, "UpdatedAt")
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 *lastDayTierStats) Msgsize() (s int) {
s = 1 + 5 + msgp.ArrayHeaderSize
for za0001 := range z.Bins {
s += z.Bins[za0001].Msgsize()
}
s += 10 + msgp.TimeSize
return
}
+236
View File
@@ -0,0 +1,236 @@
package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"bytes"
"testing"
"github.com/tinylib/msgp/msgp"
)
func TestMarshalUnmarshalDailyAllTierStats(t *testing.T) {
v := DailyAllTierStats{}
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 BenchmarkMarshalMsgDailyAllTierStats(b *testing.B) {
v := DailyAllTierStats{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgDailyAllTierStats(b *testing.B) {
v := DailyAllTierStats{}
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 BenchmarkUnmarshalDailyAllTierStats(b *testing.B) {
v := DailyAllTierStats{}
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 TestEncodeDecodeDailyAllTierStats(t *testing.T) {
v := DailyAllTierStats{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodeDailyAllTierStats Msgsize() is inaccurate")
}
vn := DailyAllTierStats{}
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 BenchmarkEncodeDailyAllTierStats(b *testing.B) {
v := DailyAllTierStats{}
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 BenchmarkDecodeDailyAllTierStats(b *testing.B) {
v := DailyAllTierStats{}
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 TestMarshalUnmarshallastDayTierStats(t *testing.T) {
v := lastDayTierStats{}
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 BenchmarkMarshalMsglastDayTierStats(b *testing.B) {
v := lastDayTierStats{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsglastDayTierStats(b *testing.B) {
v := lastDayTierStats{}
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 BenchmarkUnmarshallastDayTierStats(b *testing.B) {
v := lastDayTierStats{}
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 TestEncodeDecodelastDayTierStats(t *testing.T) {
v := lastDayTierStats{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodelastDayTierStats Msgsize() is inaccurate")
}
vn := lastDayTierStats{}
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 BenchmarkEncodelastDayTierStats(b *testing.B) {
v := lastDayTierStats{}
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 BenchmarkDecodelastDayTierStats(b *testing.B) {
v := lastDayTierStats{}
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)
}
}
}
-85
View File
@@ -926,91 +926,6 @@ func iamPolicyClaimNameSA() string {
return "sa-policy"
}
// timedValue contains a synchronized value that is considered valid
// for a specific amount of time.
// An Update function must be set to provide an updated value when needed.
type timedValue struct {
// Update must return an updated value.
// If an error is returned the cached value is not set.
// Only one caller will call this function at any time, others will be blocking.
// The returned value can no longer be modified once returned.
// Should be set before calling Get().
Update func() (interface{}, error)
// TTL for a cached value.
// If not set 1 second TTL is assumed.
// Should be set before calling Get().
TTL time.Duration
// When set to true, return the last cached value
// even if updating the value errors out
Relax bool
// Once can be used to initialize values for lazy initialization.
// Should be set before calling Get().
Once sync.Once
// Managed values.
value interface{}
lastUpdate time.Time
mu sync.RWMutex
}
// Get will return a cached value or fetch a new one.
// If the Update function returns an error the value is forwarded as is and not cached.
func (t *timedValue) Get() (interface{}, error) {
v := t.get(t.ttl())
if v != nil {
return v, nil
}
v, err := t.Update()
if err != nil {
if t.Relax {
// if update fails, return current
// cached value along with error.
//
// Let the caller decide if they want
// to use the returned value based
// on error.
v = t.get(0)
return v, err
}
return v, err
}
t.update(v)
return v, nil
}
func (t *timedValue) ttl() time.Duration {
ttl := t.TTL
if ttl <= 0 {
ttl = time.Second
}
return ttl
}
func (t *timedValue) get(ttl time.Duration) (v interface{}) {
t.mu.RLock()
defer t.mu.RUnlock()
v = t.value
if ttl <= 0 {
return v
}
if time.Since(t.lastUpdate) < ttl {
return v
}
return nil
}
func (t *timedValue) update(v interface{}) {
t.mu.Lock()
defer t.mu.Unlock()
t.value = v
t.lastUpdate = time.Now()
}
// On MinIO a directory object is stored as a regular object with "__XLDIR__" suffix.
// For ex. "prefix/" is stored as "prefix__XLDIR__"
func encodeDirObject(object string) string {
-30
View File
@@ -26,7 +26,6 @@ import (
"reflect"
"strings"
"testing"
"time"
)
// Tests maximum object size.
@@ -400,32 +399,3 @@ func TestGetMinioMode(t *testing.T) {
globalIsDistErasure, globalIsErasure = false, false
testMinioMode(globalMinioModeFS)
}
func TestTimedValue(t *testing.T) {
var cache timedValue
t.Parallel()
cache.Once.Do(func() {
cache.TTL = 2 * time.Second
cache.Update = func() (interface{}, error) {
return time.Now(), nil
}
})
i, _ := cache.Get()
t1 := i.(time.Time)
j, _ := cache.Get()
t2 := j.(time.Time)
if !t1.Equal(t2) {
t.Fatalf("expected time to be equal: %s != %s", t1, t2)
}
time.Sleep(3 * time.Second)
k, _ := cache.Get()
t3 := k.(time.Time)
if t1.Equal(t3) {
t.Fatalf("expected time to be un-equal: %s == %s", t1, t3)
}
}
+8 -10
View File
@@ -31,6 +31,7 @@ import (
"time"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio/internal/cachevalue"
xioutil "github.com/minio/minio/internal/ioutil"
"github.com/minio/minio/internal/logger"
)
@@ -89,7 +90,7 @@ type xlStorageDiskIDCheck struct {
health *diskHealthTracker
healthCheck bool
metricsCache timedValue
metricsCache *cachevalue.Cache[DiskMetrics]
diskCtx context.Context
diskCancel context.CancelFunc
}
@@ -97,7 +98,7 @@ type xlStorageDiskIDCheck struct {
func (p *xlStorageDiskIDCheck) getMetrics() DiskMetrics {
p.metricsCache.Once.Do(func() {
p.metricsCache.TTL = 5 * time.Second
p.metricsCache.Update = func() (interface{}, error) {
p.metricsCache.Update = func() (DiskMetrics, error) {
diskMetric := DiskMetrics{
LastMinute: make(map[string]AccElem, len(p.apiLatencies)),
APICalls: make(map[string]uint64, len(p.apiCalls)),
@@ -111,12 +112,8 @@ func (p *xlStorageDiskIDCheck) getMetrics() DiskMetrics {
return diskMetric, nil
}
})
m, _ := p.metricsCache.Get()
diskMetric := DiskMetrics{}
if m != nil {
diskMetric = m.(DiskMetrics)
}
diskMetric, _ := p.metricsCache.Get()
// Do not need this value to be cached.
diskMetric.TotalErrorsTimeout = p.totalErrsTimeout.Load()
diskMetric.TotalErrorsAvailability = p.totalErrsAvailability.Load()
@@ -180,9 +177,10 @@ func (e *lockedLastMinuteLatency) total() AccElem {
func newXLStorageDiskIDCheck(storage *xlStorage, healthCheck bool) *xlStorageDiskIDCheck {
xl := xlStorageDiskIDCheck{
storage: storage,
health: newDiskHealthTracker(),
healthCheck: healthCheck && globalDriveMonitoring,
storage: storage,
health: newDiskHealthTracker(),
healthCheck: healthCheck && globalDriveMonitoring,
metricsCache: cachevalue.New[DiskMetrics](),
}
xl.totalWrites.Store(xl.storage.getWriteAttribute())
+1 -1
View File
@@ -147,7 +147,7 @@ func getSampleXLMeta(totalParts int) xlMetaV1Object {
// Compare the unmarshaled XLMetaV1 with the one obtained from jsoniter parsing.
func compareXLMetaV1(t *testing.T, unMarshalXLMeta, jsoniterXLMeta xlMetaV1Object) {
// Start comparing the fields of xlMetaV1Object obtained from jsoniter parsing with one parsed using json unmarshaling.
// Start comparing the fields of xlMetaV1Object obtained from jsoniter parsing with one parsed using json unmarshalling.
if unMarshalXLMeta.Version != jsoniterXLMeta.Version {
t.Errorf("Expected the Version to be \"%s\", but got \"%s\".", unMarshalXLMeta.Version, jsoniterXLMeta.Version)
}
+54 -62
View File
@@ -43,6 +43,7 @@ import (
"github.com/klauspost/filepathx"
"github.com/minio/madmin-go/v3"
"github.com/minio/minio/internal/bucket/lifecycle"
"github.com/minio/minio/internal/cachevalue"
"github.com/minio/minio/internal/config/storageclass"
"github.com/minio/minio/internal/disk"
xioutil "github.com/minio/minio/internal/ioutil"
@@ -112,7 +113,7 @@ type xlStorage struct {
formatLegacy bool
formatLastCheck time.Time
diskInfoCache timedValue
diskInfoCache *cachevalue.Cache[DiskInfo]
sync.RWMutex
formatData []byte
@@ -230,12 +231,13 @@ func makeFormatErasureMetaVolumes(disk StorageAPI) error {
// Initialize a new storage disk.
func newXLStorage(ep Endpoint, cleanUp bool) (s *xlStorage, err error) {
s = &xlStorage{
drivePath: ep.Path,
endpoint: ep,
globalSync: globalFSOSync,
poolIndex: -1,
setIndex: -1,
diskIndex: -1,
drivePath: ep.Path,
endpoint: ep,
globalSync: globalFSOSync,
diskInfoCache: cachevalue.New[DiskInfo](),
poolIndex: -1,
setIndex: -1,
diskIndex: -1,
}
s.drivePath, err = getValidPath(ep.Path)
@@ -732,7 +734,7 @@ func (s *xlStorage) setWriteAttribute(writeCount uint64) error {
func (s *xlStorage) DiskInfo(_ context.Context, _ DiskInfoOptions) (info DiskInfo, err error) {
s.diskInfoCache.Once.Do(func() {
s.diskInfoCache.TTL = time.Second
s.diskInfoCache.Update = func() (interface{}, error) {
s.diskInfoCache.Update = func() (DiskInfo, error) {
dcinfo := DiskInfo{}
di, err := getDiskInfo(s.drivePath)
if err != nil {
@@ -758,11 +760,7 @@ func (s *xlStorage) DiskInfo(_ context.Context, _ DiskInfoOptions) (info DiskInf
}
})
v, err := s.diskInfoCache.Get()
if v != nil {
info = v.(DiskInfo)
}
info, err = s.diskInfoCache.Get()
info.MountPath = s.drivePath
info.Endpoint = s.endpoint.String()
info.Scanning = atomic.LoadInt32(&s.scanning) == 1
@@ -1186,7 +1184,7 @@ func (s *xlStorage) moveToTrash(filePath string, recursive, immediatePurge bool)
}
// ENOSPC is a valid error from rename(); remove instead of rename in that case
if err == errDiskFull {
if errors.Is(err, errDiskFull) || isSysErrNoSpace(err) {
if recursive {
err = removeAll(filePath)
} else {
@@ -1702,7 +1700,7 @@ func (s *xlStorage) readAllData(ctx context.Context, volume, volumeDir string, f
}
if discard {
// This discard is mostly true for DELETEs
// This discard is mostly true for DELETEEs
// so we need to make sure we do not keep
// page-cache references after.
defer disk.Fdatasync(f)
@@ -2617,67 +2615,53 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f
defer metaDataPoolPut(dstBuf)
if err != nil {
if legacyPreserved {
// Any failed rename calls un-roll previous transaction.
s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
}
return 0, errFileCorrupt
}
if srcDataPath != "" {
if err = s.WriteAll(ctx, srcVolume, pathJoin(srcPath, xlStorageFormatFile), dstBuf); err != nil {
if legacyPreserved {
// Any failed rename calls un-roll previous transaction.
s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
}
return 0, osErrToFileErr(err)
if err = s.WriteAll(ctx, srcVolume, pathJoin(srcPath, xlStorageFormatFile), dstBuf); err != nil {
if legacyPreserved {
s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
}
diskHealthCheckOK(ctx, err)
return 0, osErrToFileErr(err)
}
diskHealthCheckOK(ctx, err)
if srcDataPath != "" && len(fi.Data) == 0 && fi.Size > 0 {
// renameAll only for objects that have xl.meta not saved inline.
if len(fi.Data) == 0 && fi.Size > 0 {
s.moveToTrash(dstDataPath, true, false)
if healing {
// If we are healing we should purge any legacyDataPath content,
// that was previously preserved during PutObject() call
// on a versioned bucket.
s.moveToTrash(legacyDataPath, true, false)
}
if err = renameAll(srcDataPath, dstDataPath, dstVolumeDir); err != nil {
if legacyPreserved {
// Any failed rename calls un-roll previous transaction.
s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
}
s.deleteFile(dstVolumeDir, dstDataPath, false, false)
return 0, osErrToFileErr(err)
}
s.moveToTrash(dstDataPath, true, false)
if healing {
// If we are healing we should purge any legacyDataPath content,
// that was previously preserved during PutObject() call
// on a versioned bucket.
s.moveToTrash(legacyDataPath, true, false)
}
// Commit meta-file
if err = renameAll(srcFilePath, dstFilePath, dstVolumeDir); err != nil {
if err = renameAll(srcDataPath, dstDataPath, dstVolumeDir); err != nil {
if legacyPreserved {
// Any failed rename calls un-roll previous transaction.
s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
}
s.deleteFile(dstVolumeDir, dstFilePath, false, false)
s.deleteFile(dstVolumeDir, dstDataPath, false, false)
return 0, osErrToFileErr(err)
}
}
// additionally only purge older data at the end of the transaction of new data-dir
// movement, this is to ensure that previous data references can co-exist for
// any recoverability.
if oldDstDataPath != "" {
s.moveToTrash(oldDstDataPath, true, false)
}
} else {
// Write meta-file directly, no data
if err = s.WriteAll(ctx, dstVolume, pathJoin(dstPath, xlStorageFormatFile), dstBuf); err != nil {
if legacyPreserved {
// Any failed rename calls un-roll previous transaction.
s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
}
s.deleteFile(dstVolumeDir, dstFilePath, false, false)
return 0, err
// Commit meta-file
if err = renameAll(srcFilePath, dstFilePath, dstVolumeDir); err != nil {
if legacyPreserved {
// Any failed rename calls un-roll previous transaction.
s.deleteFile(dstVolumeDir, legacyDataPath, true, false)
}
s.deleteFile(dstVolumeDir, dstDataPath, false, false)
return 0, osErrToFileErr(err)
}
// additionally only purge older data at the end of the transaction of new data-dir
// movement, this is to ensure that previous data references can co-exist for
// any recoverability.
if oldDstDataPath != "" {
s.moveToTrash(oldDstDataPath, true, false)
}
if srcVolume != minioMetaMultipartBucket {
@@ -2883,14 +2867,22 @@ func (s *xlStorage) ReadMultiple(ctx context.Context, req ReadMultipleReq, resp
if req.MaxSize > 0 && int64(len(data)) > req.MaxSize {
r.Exists = true
r.Error = fmt.Sprintf("max size (%d) exceeded: %d", req.MaxSize, len(data))
resp <- r
continue
select {
case <-ctx.Done():
return ctx.Err()
case resp <- r:
continue
}
}
found++
r.Exists = true
r.Data = data
r.Modtime = mt
resp <- r
select {
case <-ctx.Done():
return ctx.Err()
case resp <- r:
}
if req.MaxResults > 0 && found >= req.MaxResults {
return nil
}
+1 -2
View File
@@ -67,14 +67,13 @@ scrape_configs:
##### Bucket centric
```
```yaml
- job_name: minio-job-bucket
bearer_token: <secret>
metrics_path: /minio/v2/metrics/bucket
scheme: http
static_configs:
- targets: ['localhost:9000']
```
#### 3.2 Public Prometheus config
@@ -2205,6 +2205,926 @@
],
"title": "Replication Latency (millis)",
"type": "bargauge"
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 0,
"y": 42
},
"hiddenSeries": false,
"id": 76,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "sum by (bucket) (minio_bucket_replication_proxied_head_requests_total{job=\"$scrape_jobs\"})",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{bucket}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Head Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 6,
"y": 42
},
"hiddenSeries": false,
"id": 77,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_bucket_replication_proxied_head_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Head Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 12,
"y": 42
},
"hiddenSeries": false,
"id": 78,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "sum by (bucket) (minio_bucket_replication_proxied_put_tagging_requests_total{job=\"$scrape_jobs\"})",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{bucket}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Put Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 18,
"y": 42
},
"hiddenSeries": false,
"id": 79,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_bucket_replication_proxied_put_tagging_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Put Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 0,
"y": 48
},
"hiddenSeries": false,
"id": 80,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "sum by (bucket) (minio_bucket_replication_proxied_get_tagging_requests_total{job=\"$scrape_jobs\"})",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{bucket}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Get Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 6,
"y": 48
},
"hiddenSeries": false,
"id": 81,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_bucket_replication_proxied_get_tagging_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Get Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 12,
"y": 48
},
"hiddenSeries": false,
"id": 82,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "sum by (bucket) (minio_bucket_replication_proxied_delete_tagging_requests_total{job=\"$scrape_jobs\"})",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{bucket}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Delete Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 18,
"y": 48
},
"hiddenSeries": false,
"id": 83,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_bucket_replication_proxied_delete_tagging_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Delete Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 12,
"x": 0,
"y": 54
},
"hiddenSeries": false,
"id": 84,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "sum by (bucket) (minio_bucket_replication_proxied_get_requests_total{job=\"$scrape_jobs\"})",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{bucket}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Get Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 12,
"x": 12,
"y": 54
},
"hiddenSeries": false,
"id": 85,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_bucket_replication_proxied_get_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Get Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
}
],
"refresh": "",
@@ -1812,6 +1812,926 @@
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 18,
"y": 24
},
"hiddenSeries": false,
"id": 75,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_head_requests_total{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Head Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 0,
"y": 30
},
"hiddenSeries": false,
"id": 76,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_head_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Head Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 6,
"y": 30
},
"hiddenSeries": false,
"id": 77,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_put_tagging_requests_total{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Put Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 12,
"y": 30
},
"hiddenSeries": false,
"id": 78,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_put_tagging_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Put Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 18,
"y": 30
},
"hiddenSeries": false,
"id": 79,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_get_tagging_requests_total{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Get Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 0,
"y": 36
},
"hiddenSeries": false,
"id": 80,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_get_tagging_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Get Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 6,
"y": 36
},
"hiddenSeries": false,
"id": 81,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_delete_tagging_requests_total{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Delete Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 12,
"y": 36
},
"hiddenSeries": false,
"id": 82,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_delete_tagging_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Delete Tag Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 6,
"x": 18,
"y": 36
},
"hiddenSeries": false,
"id": 83,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_get_requests_total{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Proxied Get Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {
"Replication Errors": "light-red",
"Replication Requests": "light-green"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 6,
"w": 12,
"x": 0,
"y": 42
},
"hiddenSeries": false,
"id": 84,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "10.0.2",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"exemplar": true,
"expr": "minio_cluster_replication_proxied_get_requests_failures{job=\"$scrape_jobs\"}",
"interval": "1m",
"intervalFactor": 2,
"legendFormat": "{{instance}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Total Failed Proxied Get Requests",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:331",
"format": "short",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:332",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
}
],
"refresh": "",
@@ -2,7 +2,7 @@ version: '3.7'
# Settings and configurations that are common for all containers
x-minio-common: &minio-common
image: quay.io/minio/minio:RELEASE.2024-02-14T21-36-02Z
image: quay.io/minio/minio:RELEASE.2024-02-24T17-11-14Z
command: server --console-address ":9001" http://minio{1...4}/data{1...2}
expose:
- "9000"
+4
View File
@@ -17,6 +17,8 @@
package bandwidth
//go:generate msgp -file=$GOFILE -unexported
import (
"context"
"sync"
@@ -25,6 +27,8 @@ import (
"golang.org/x/time/rate"
)
//msgp:ignore bucketThrottle Monitor
type bucketThrottle struct {
*rate.Limiter
NodeBandwidthPerSec int64
+218
View File
@@ -0,0 +1,218 @@
package bandwidth
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"github.com/tinylib/msgp/msgp"
)
// DecodeMsg implements msgp.Decodable
func (z *BucketBandwidthReport) 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) {
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z BucketBandwidthReport) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 0
err = en.Append(0x80)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z BucketBandwidthReport) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 0
o = append(o, 0x80)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *BucketBandwidthReport) 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) {
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 BucketBandwidthReport) Msgsize() (s int) {
s = 1
return
}
// DecodeMsg implements msgp.Decodable
func (z *Details) 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 "LimitInBytesPerSecond":
z.LimitInBytesPerSecond, err = dc.ReadInt64()
if err != nil {
err = msgp.WrapError(err, "LimitInBytesPerSecond")
return
}
case "CurrentBandwidthInBytesPerSecond":
z.CurrentBandwidthInBytesPerSecond, err = dc.ReadFloat64()
if err != nil {
err = msgp.WrapError(err, "CurrentBandwidthInBytesPerSecond")
return
}
default:
err = dc.Skip()
if err != nil {
err = msgp.WrapError(err)
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z Details) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 2
// write "LimitInBytesPerSecond"
err = en.Append(0x82, 0xb5, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x49, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64)
if err != nil {
return
}
err = en.WriteInt64(z.LimitInBytesPerSecond)
if err != nil {
err = msgp.WrapError(err, "LimitInBytesPerSecond")
return
}
// write "CurrentBandwidthInBytesPerSecond"
err = en.Append(0xd9, 0x20, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x49, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64)
if err != nil {
return
}
err = en.WriteFloat64(z.CurrentBandwidthInBytesPerSecond)
if err != nil {
err = msgp.WrapError(err, "CurrentBandwidthInBytesPerSecond")
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z Details) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 2
// string "LimitInBytesPerSecond"
o = append(o, 0x82, 0xb5, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x49, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64)
o = msgp.AppendInt64(o, z.LimitInBytesPerSecond)
// string "CurrentBandwidthInBytesPerSecond"
o = append(o, 0xd9, 0x20, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x77, 0x69, 0x64, 0x74, 0x68, 0x49, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64)
o = msgp.AppendFloat64(o, z.CurrentBandwidthInBytesPerSecond)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Details) 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 "LimitInBytesPerSecond":
z.LimitInBytesPerSecond, bts, err = msgp.ReadInt64Bytes(bts)
if err != nil {
err = msgp.WrapError(err, "LimitInBytesPerSecond")
return
}
case "CurrentBandwidthInBytesPerSecond":
z.CurrentBandwidthInBytesPerSecond, bts, err = msgp.ReadFloat64Bytes(bts)
if err != nil {
err = msgp.WrapError(err, "CurrentBandwidthInBytesPerSecond")
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 Details) Msgsize() (s int) {
s = 1 + 22 + msgp.Int64Size + 34 + msgp.Float64Size
return
}
@@ -0,0 +1,236 @@
package bandwidth
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"bytes"
"testing"
"github.com/tinylib/msgp/msgp"
)
func TestMarshalUnmarshalBucketBandwidthReport(t *testing.T) {
v := BucketBandwidthReport{}
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 BenchmarkMarshalMsgBucketBandwidthReport(b *testing.B) {
v := BucketBandwidthReport{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgBucketBandwidthReport(b *testing.B) {
v := BucketBandwidthReport{}
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 BenchmarkUnmarshalBucketBandwidthReport(b *testing.B) {
v := BucketBandwidthReport{}
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 TestEncodeDecodeBucketBandwidthReport(t *testing.T) {
v := BucketBandwidthReport{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodeBucketBandwidthReport Msgsize() is inaccurate")
}
vn := BucketBandwidthReport{}
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 BenchmarkEncodeBucketBandwidthReport(b *testing.B) {
v := BucketBandwidthReport{}
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 BenchmarkDecodeBucketBandwidthReport(b *testing.B) {
v := BucketBandwidthReport{}
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 TestMarshalUnmarshalDetails(t *testing.T) {
v := Details{}
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 BenchmarkMarshalMsgDetails(b *testing.B) {
v := Details{}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
v.MarshalMsg(nil)
}
}
func BenchmarkAppendMsgDetails(b *testing.B) {
v := Details{}
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 BenchmarkUnmarshalDetails(b *testing.B) {
v := Details{}
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 TestEncodeDecodeDetails(t *testing.T) {
v := Details{}
var buf bytes.Buffer
msgp.Encode(&buf, &v)
m := v.Msgsize()
if buf.Len() > m {
t.Log("WARNING: TestEncodeDecodeDetails Msgsize() is inaccurate")
}
vn := Details{}
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 BenchmarkEncodeDetails(b *testing.B) {
v := Details{}
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 BenchmarkDecodeDetails(b *testing.B) {
v := Details{}
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)
}
}
}
+6
View File
@@ -28,6 +28,7 @@ var (
errLifecycleInvalidExpiration = Errorf("Exactly one of Days (positive integer) or Date (positive ISO 8601 format) should be present inside Expiration.")
errLifecycleInvalidDeleteMarker = Errorf("Delete marker cannot be specified with Days or Date in a Lifecycle Expiration Policy")
errLifecycleDateNotMidnight = Errorf("'Date' must be at midnight GMT")
errLifecycleInvalidDeleteAll = Errorf("Days (positive integer) should be present inside Expiration with ExpiredObjectAllVersions.")
)
// ExpirationDays is a type alias to unmarshal Days in Expiration
@@ -186,6 +187,11 @@ func (e Expiration) Validate() error {
return errLifecycleInvalidExpiration
}
// DeleteAll set without expiration days
if e.DeleteAll.set && e.IsDaysNull() {
return errLifecycleInvalidDeleteAll
}
return nil
}
+1 -1
View File
@@ -106,7 +106,7 @@ func TestInvalidExpiration(t *testing.T) {
<Date>2019-04-20T00:00:00Z</Date>
<ExpiredObjectAllVersions>true</ExpiredObjectAllVersions>
</Expiration>`,
expectedErr: nil,
expectedErr: errLifecycleInvalidDeleteAll,
},
}
for i, tc := range validationTestCases {
+1 -1
View File
@@ -84,7 +84,7 @@ func TestParseLegalHoldStatus(t *testing.T) {
}
// TestUnmarshalDefaultRetention checks if default retention
// marshaling and unmarshaling work as expected
// marshaling and unmarshalling work as expected
func TestUnmarshalDefaultRetention(t *testing.T) {
days := uint64(4)
years := uint64(1)
+119
View File
@@ -0,0 +1,119 @@
// Copyright (c) 2015-2024 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/>.
package cachevalue
import (
"sync"
"time"
)
// Cache contains a synchronized value that is considered valid
// for a specific amount of time.
// An Update function must be set to provide an updated value when needed.
type Cache[I any] struct {
// Update must return an updated value.
// If an error is returned the cached value is not set.
// Only one caller will call this function at any time, others will be blocking.
// The returned value can no longer be modified once returned.
// Should be set before calling Get().
Update func() (item I, err error)
// TTL for a cached value.
// If not set 1 second TTL is assumed.
// Should be set before calling Get().
TTL time.Duration
// When set to true, return the last cached value
// even if updating the value errors out
Relax bool
// Once can be used to initialize values for lazy initialization.
// Should be set before calling Get().
Once sync.Once
// Managed values.
value I // our cached value
valueSet bool // 'true' if the value 'I' has a value
lastUpdate time.Time // indicates when value 'I' was updated last, used for invalidation.
mu sync.RWMutex
}
// New initializes a new cached value instance.
func New[I any]() *Cache[I] {
return &Cache[I]{}
}
// Get will return a cached value or fetch a new one.
// If the Update function returns an error the value is forwarded as is and not cached.
func (t *Cache[I]) Get() (item I, err error) {
item, ok := t.get(t.ttl())
if ok {
return item, nil
}
item, err = t.Update()
if err != nil {
if t.Relax {
// if update fails, return current
// cached value along with error.
//
// Let the caller decide if they want
// to use the returned value based
// on error.
item, ok = t.get(0)
if ok {
return item, err
}
}
return item, err
}
t.update(item)
return item, nil
}
func (t *Cache[_]) ttl() time.Duration {
ttl := t.TTL
if ttl <= 0 {
ttl = time.Second
}
return ttl
}
func (t *Cache[I]) get(ttl time.Duration) (item I, ok bool) {
t.mu.RLock()
defer t.mu.RUnlock()
if t.valueSet {
item = t.value
if ttl <= 0 {
return item, true
}
if time.Since(t.lastUpdate) < ttl {
return item, true
}
}
return item, false
}
func (t *Cache[I]) update(item I) {
t.mu.Lock()
defer t.mu.Unlock()
t.value = item
t.valueSet = true
t.lastUpdate = time.Now()
}
+68
View File
@@ -0,0 +1,68 @@
// Copyright (c) 2015-2024 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/>.
package cachevalue
import (
"testing"
"time"
)
func TestCache(t *testing.T) {
cache := New[time.Time]()
t.Parallel()
cache.Once.Do(func() {
cache.TTL = 2 * time.Second
cache.Update = func() (time.Time, error) {
return time.Now(), nil
}
})
t1, _ := cache.Get()
t2, _ := cache.Get()
if !t1.Equal(t2) {
t.Fatalf("expected time to be equal: %s != %s", t1, t2)
}
time.Sleep(3 * time.Second)
t3, _ := cache.Get()
if t1.Equal(t3) {
t.Fatalf("expected time to be un-equal: %s == %s", t1, t3)
}
}
func BenchmarkCache(b *testing.B) {
cache := New[time.Time]()
cache.Once.Do(func() {
cache.TTL = 1 * time.Microsecond
cache.Update = func() (time.Time, error) {
return time.Now(), nil
}
})
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
cache.Get()
}
})
}
+1 -1
View File
@@ -159,7 +159,7 @@ var NotifySubSystems = set.CreateStringSet(
NotifyWebhookSubSys,
)
// LambdaSubSystems - all lambda sub-systesm
// LambdaSubSystems - all lambda sub-systems
var LambdaSubSystems = set.CreateStringSet(
LambdaWebhookSubSys,
)
+1 -1
View File
@@ -299,7 +299,7 @@ func checkValidNotificationKeysForSubSys(subSys string, tgt map[string]config.KV
return nil
}
// DefaultKakfaKVS - default KV for kafka target
// DefaultKafkaKVS - default KV for kafka target
var (
DefaultKafkaKVS = config.KVS{
config.KV{
+1 -1
View File
@@ -28,7 +28,7 @@ import (
// RemoveSensitiveHeaders removes confidential encryption
// information - e.g. the SSE-C key - from the HTTP headers.
// It has the same semantics as RemoveSensitiveEntires.
// It has the same semantics as RemoveSensitiveEntries.
func RemoveSensitiveHeaders(h http.Header) {
h.Del(xhttp.AmzServerSideEncryptionCustomerKey)
h.Del(xhttp.AmzServerSideEncryptionCopyCustomerKey)
+2 -2
View File
@@ -254,7 +254,7 @@ func (dm *DRWMutex) lockBlocking(ctx context.Context, lockLossCallback func(), i
log("lockBlocking %s/%s for %#v: granted\n", id, source, dm.Names)
// Refresh lock continuously and cancel if there is no quorum in the lock anymore
dm.startContinousLockRefresh(lockLossCallback, id, source, quorum)
dm.startContinuousLockRefresh(lockLossCallback, id, source, quorum)
return locked
}
@@ -272,7 +272,7 @@ func (dm *DRWMutex) lockBlocking(ctx context.Context, lockLossCallback func(), i
}
}
func (dm *DRWMutex) startContinousLockRefresh(lockLossCallback func(), id, source string, quorum int) {
func (dm *DRWMutex) startContinuousLockRefresh(lockLossCallback func(), id, source string, quorum int) {
ctx, cancel := context.WithCancel(context.Background())
dm.m.Lock()
+32 -65
View File
@@ -24,12 +24,10 @@ import (
"encoding/json"
"errors"
"fmt"
"net"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/minio/minio/internal/event"
@@ -154,15 +152,15 @@ func (k KafkaArgs) Validate() error {
type KafkaTarget struct {
initOnce once.Init
id event.TargetID
args KafkaArgs
producer sarama.SyncProducer
config *sarama.Config
store store.Store[event.Event]
batch *store.Batch[string, *sarama.ProducerMessage]
loggerOnce logger.LogOnce
brokerConns map[string]net.Conn
quitCh chan struct{}
id event.TargetID
args KafkaArgs
client sarama.Client
producer sarama.SyncProducer
config *sarama.Config
store store.Store[event.Event]
batch *store.Batch[string, *sarama.ProducerMessage]
loggerOnce logger.LogOnce
quitCh chan struct{}
}
// ID - returns target ID.
@@ -189,7 +187,9 @@ func (target *KafkaTarget) IsActive() (bool, error) {
}
func (target *KafkaTarget) isActive() (bool, error) {
if err := target.pingBrokers(); err != nil {
// Refer https://github.com/IBM/sarama/issues/1341
brokers := target.client.Brokers()
if len(brokers) == 0 {
return false, store.ErrNotConnected
}
return true, nil
@@ -317,56 +317,15 @@ func (target *KafkaTarget) toProducerMessage(eventData event.Event) (*sarama.Pro
// Close - closes underneath kafka connection.
func (target *KafkaTarget) Close() error {
close(target.quitCh)
if target.producer != nil {
return target.producer.Close()
}
for _, conn := range target.brokerConns {
if conn != nil {
conn.Close()
}
target.producer.Close()
return target.client.Close()
}
return nil
}
// Check if at least one broker in cluster is active
func (target *KafkaTarget) pingBrokers() (err error) {
d := net.Dialer{Timeout: 1 * time.Second}
errs := make([]error, len(target.args.Brokers))
var wg sync.WaitGroup
for idx, broker := range target.args.Brokers {
broker := broker
idx := idx
wg.Add(1)
go func(broker xnet.Host, idx int) {
defer wg.Done()
conn, ok := target.brokerConns[broker.String()]
if !ok || conn == nil {
conn, errs[idx] = d.Dial("tcp", broker.String())
if errs[idx] != nil {
return
}
target.brokerConns[broker.String()] = conn
}
if _, errs[idx] = conn.Write([]byte("")); errs[idx] != nil {
conn.Close()
target.brokerConns[broker.String()] = nil
}
}(broker, idx)
}
wg.Wait()
var retErr error
for _, err := range errs {
if err == nil {
// if one of them is active we are good.
return nil
}
retErr = err
}
return retErr
}
func (target *KafkaTarget) init() error {
return target.initOnce.Do(target.initKafka)
}
@@ -431,13 +390,22 @@ func (target *KafkaTarget) initKafka() error {
brokers = append(brokers, broker.String())
}
producer, err := sarama.NewSyncProducer(brokers, config)
client, err := sarama.NewClient(brokers, config)
if err != nil {
if err != sarama.ErrOutOfBrokers {
if !errors.Is(err, sarama.ErrOutOfBrokers) {
target.loggerOnce(context.Background(), err, target.ID().String())
}
return err
}
producer, err := sarama.NewSyncProducerFromClient(client)
if err != nil {
if !errors.Is(err, sarama.ErrOutOfBrokers) {
target.loggerOnce(context.Background(), err, target.ID().String())
}
return err
}
target.client = client
target.producer = producer
yes, err := target.isActive()
@@ -463,12 +431,11 @@ func NewKafkaTarget(id string, args KafkaArgs, loggerOnce logger.LogOnce) (*Kafk
}
target := &KafkaTarget{
id: event.TargetID{ID: id, Name: "kafka"},
args: args,
store: queueStore,
loggerOnce: loggerOnce,
quitCh: make(chan struct{}),
brokerConns: make(map[string]net.Conn, len(args.Brokers)),
id: event.TargetID{ID: id, Name: "kafka"},
args: args,
store: queueStore,
loggerOnce: loggerOnce,
quitCh: make(chan struct{}),
}
if target.store != nil {
+5 -4
View File
@@ -531,10 +531,11 @@ func (c *Connection) shouldConnect() bool {
return h0 < h1
}
func (c *Connection) send(msg []byte) error {
func (c *Connection) send(ctx context.Context, msg []byte) error {
select {
case <-c.ctx.Done():
return context.Cause(c.ctx)
case <-ctx.Done():
// Returning error here is too noisy.
return nil
case c.outQueue <- msg:
return nil
}
@@ -570,7 +571,7 @@ func (c *Connection) queueMsg(msg message, payload sender) error {
h := xxh3.Hash(dst)
dst = binary.LittleEndian.AppendUint32(dst, uint32(h))
}
return c.send(dst)
return c.send(c.ctx, dst)
}
// sendMsg will send
+1 -1
View File
@@ -184,12 +184,12 @@ func (m *lockedClientMap) Delete(id uint64) {
func (m *lockedClientMap) Range(fn func(key uint64, value *muxClient) bool) {
m.mu.Lock()
defer m.mu.Unlock()
for k, v := range m.m {
if !fn(k, v) {
break
}
}
m.mu.Unlock()
}
func (m *lockedClientMap) Clear() {
+74 -5
View File
@@ -36,6 +36,7 @@ import (
// HandlerID is a handler identifier.
// It is used to determine request routing on the server.
// Handlers can be registered with a static subroute.
// Do NOT remove or change the order of existing handlers.
const (
// handlerInvalid is reserved to check for uninitialized values.
handlerInvalid HandlerID = iota
@@ -69,7 +70,6 @@ const (
HandlerStopRebalance
HandlerLoadRebalanceMeta
HandlerLoadTransitionTierConfig
HandlerDeletePolicy
HandlerLoadPolicy
HandlerLoadPolicyMapping
@@ -78,11 +78,37 @@ const (
HandlerDeleteUser
HandlerLoadUser
HandlerLoadGroup
HandlerHealBucket
HandlerMakeBucket
HandlerHeadBucket
HandlerDeleteBucket
HandlerGetMetrics
HandlerGetResourceMetrics
HandlerGetMemInfo
HandlerGetProcInfo
HandlerGetOSInfo
HandlerGetPartitions
HandlerGetNetInfo
HandlerGetCPUs
HandlerServerInfo
HandlerGetSysConfig
HandlerGetSysServices
HandlerGetSysErrors
HandlerGetAllBucketStats
HandlerGetBucketStats
HandlerGetSRMetrics
HandlerGetPeerMetrics
HandlerGetMetacacheListing
HandlerUpdateMetacacheListing
HandlerGetPeerBucketMetrics
HandlerStorageInfo
HandlerConsoleLog
HandlerListDir
HandlerGetLocks
HandlerBackgroundHealStatus
HandlerGetLastDayTierStats
HandlerSignalService
HandlerGetBandwidth
// Add more above here ^^^
// If all handlers are used, the type of Handler can be changed.
@@ -137,6 +163,28 @@ var handlerPrefixes = [handlerLast]string{
HandlerHeadBucket: peerPrefixS3,
HandlerDeleteBucket: peerPrefixS3,
HandlerHealBucket: healPrefix,
HandlerGetMetrics: peerPrefix,
HandlerGetResourceMetrics: peerPrefix,
HandlerGetMemInfo: peerPrefix,
HandlerGetProcInfo: peerPrefix,
HandlerGetOSInfo: peerPrefix,
HandlerGetPartitions: peerPrefix,
HandlerGetNetInfo: peerPrefix,
HandlerGetCPUs: peerPrefix,
HandlerServerInfo: peerPrefix,
HandlerGetSysConfig: peerPrefix,
HandlerGetSysServices: peerPrefix,
HandlerGetSysErrors: peerPrefix,
HandlerGetAllBucketStats: peerPrefix,
HandlerGetBucketStats: peerPrefix,
HandlerGetSRMetrics: peerPrefix,
HandlerGetPeerMetrics: peerPrefix,
HandlerGetMetacacheListing: peerPrefix,
HandlerUpdateMetacacheListing: peerPrefix,
HandlerGetPeerBucketMetrics: peerPrefix,
HandlerStorageInfo: peerPrefix,
HandlerConsoleLog: peerPrefix,
HandlerListDir: storagePrefix,
}
const (
@@ -344,9 +392,10 @@ type RoundTripper interface {
// SingleHandler is a type safe handler for single roundtrip requests.
type SingleHandler[Req, Resp RoundTripper] struct {
id HandlerID
sharedResp bool
callReuseReq bool
id HandlerID
sharedResp bool
callReuseReq bool
ignoreNilConn bool
newReq func() Req
newResp func() Resp
@@ -407,6 +456,17 @@ func (h *SingleHandler[Req, Resp]) AllowCallRequestPool(b bool) *SingleHandler[R
return h
}
// IgnoreNilConn will ignore nil connections when calling.
// This will make Call return nil instead of ErrDisconnected when the connection is nil.
// This may only be set ONCE before use.
func (h *SingleHandler[Req, Resp]) IgnoreNilConn() *SingleHandler[Req, Resp] {
if h.ignoreNilConn {
logger.LogOnceIf(context.Background(), fmt.Errorf("%s: IgnoreNilConn called twice", h.id.String()), h.id.String()+"IgnoreNilConn")
}
h.ignoreNilConn = true
return h
}
// WithSharedResponse indicates it is unsafe to reuse the response
// when it has been returned on a handler.
// This will disable automatic response recycling/pooling.
@@ -476,6 +536,12 @@ type Requester interface {
// The response should be returned with PutResponse when no error.
// If no deadline is set, a 1-minute deadline is added.
func (h *SingleHandler[Req, Resp]) Call(ctx context.Context, c Requester, req Req) (resp Resp, err error) {
if c == nil {
if h.ignoreNilConn {
return resp, nil
}
return resp, ErrDisconnected
}
payload, err := req.MarshalMsg(GetByteBuffer()[:0])
if err != nil {
return resp, err
@@ -777,6 +843,9 @@ type Streamer interface {
// Call the remove with the request and
func (h *StreamTypeHandler[Payload, Req, Resp]) Call(ctx context.Context, c Streamer, payload Payload) (st *TypedStream[Req, Resp], err error) {
if c == nil {
return nil, ErrDisconnected
}
var payloadB []byte
if h.WithPayload {
var err error
+32 -5
View File
@@ -51,14 +51,41 @@ func _() {
_ = x[HandlerMakeBucket-40]
_ = x[HandlerHeadBucket-41]
_ = x[HandlerDeleteBucket-42]
_ = x[handlerTest-43]
_ = x[handlerTest2-44]
_ = x[handlerLast-45]
_ = x[HandlerGetMetrics-43]
_ = x[HandlerGetResourceMetrics-44]
_ = x[HandlerGetMemInfo-45]
_ = x[HandlerGetProcInfo-46]
_ = x[HandlerGetOSInfo-47]
_ = x[HandlerGetPartitions-48]
_ = x[HandlerGetNetInfo-49]
_ = x[HandlerGetCPUs-50]
_ = x[HandlerServerInfo-51]
_ = x[HandlerGetSysConfig-52]
_ = x[HandlerGetSysServices-53]
_ = x[HandlerGetSysErrors-54]
_ = x[HandlerGetAllBucketStats-55]
_ = x[HandlerGetBucketStats-56]
_ = x[HandlerGetSRMetrics-57]
_ = x[HandlerGetPeerMetrics-58]
_ = x[HandlerGetMetacacheListing-59]
_ = x[HandlerUpdateMetacacheListing-60]
_ = x[HandlerGetPeerBucketMetrics-61]
_ = x[HandlerStorageInfo-62]
_ = x[HandlerConsoleLog-63]
_ = x[HandlerListDir-64]
_ = x[HandlerGetLocks-65]
_ = x[HandlerBackgroundHealStatus-66]
_ = x[HandlerGetLastDayTierStats-67]
_ = x[HandlerSignalService-68]
_ = x[HandlerGetBandwidth-69]
_ = x[handlerTest-70]
_ = x[handlerTest2-71]
_ = x[handlerLast-72]
}
const _HandlerID_name = "handlerInvalidLockLockLockRLockLockUnlockLockRUnlockLockRefreshLockForceUnlockWalkDirStatVolDiskInfoNSScannerReadXLReadVersionDeleteFileDeleteVersionUpdateMetadataWriteMetadataCheckPartsRenameDataRenameFileReadAllServerVerifyTraceListenDeleteBucketMetadataLoadBucketMetadataReloadSiteReplicationConfigReloadPoolMetaStopRebalanceLoadRebalanceMetaLoadTransitionTierConfigDeletePolicyLoadPolicyLoadPolicyMappingDeleteServiceAccountLoadServiceAccountDeleteUserLoadUserLoadGroupHealBucketMakeBucketHeadBucketDeleteBuckethandlerTesthandlerTest2handlerLast"
const _HandlerID_name = "handlerInvalidLockLockLockRLockLockUnlockLockRUnlockLockRefreshLockForceUnlockWalkDirStatVolDiskInfoNSScannerReadXLReadVersionDeleteFileDeleteVersionUpdateMetadataWriteMetadataCheckPartsRenameDataRenameFileReadAllServerVerifyTraceListenDeleteBucketMetadataLoadBucketMetadataReloadSiteReplicationConfigReloadPoolMetaStopRebalanceLoadRebalanceMetaLoadTransitionTierConfigDeletePolicyLoadPolicyLoadPolicyMappingDeleteServiceAccountLoadServiceAccountDeleteUserLoadUserLoadGroupHealBucketMakeBucketHeadBucketDeleteBucketGetMetricsGetResourceMetricsGetMemInfoGetProcInfoGetOSInfoGetPartitionsGetNetInfoGetCPUsServerInfoGetSysConfigGetSysServicesGetSysErrorsGetAllBucketStatsGetBucketStatsGetSRMetricsGetPeerMetricsGetMetacacheListingUpdateMetacacheListingGetPeerBucketMetricsStorageInfoConsoleLogListDirGetLocksBackgroundHealStatusGetLastDayTierStatsSignalServiceGetBandwidthhandlerTesthandlerTest2handlerLast"
var _HandlerID_index = [...]uint16{0, 14, 22, 31, 41, 52, 63, 78, 85, 92, 100, 109, 115, 126, 136, 149, 163, 176, 186, 196, 206, 213, 225, 230, 236, 256, 274, 301, 315, 328, 345, 369, 381, 391, 408, 428, 446, 456, 464, 473, 483, 493, 503, 515, 526, 538, 549}
var _HandlerID_index = [...]uint16{0, 14, 22, 31, 41, 52, 63, 78, 85, 92, 100, 109, 115, 126, 136, 149, 163, 176, 186, 196, 206, 213, 225, 230, 236, 256, 274, 301, 315, 328, 345, 369, 381, 391, 408, 428, 446, 456, 464, 473, 483, 493, 503, 515, 525, 543, 553, 564, 573, 586, 596, 603, 613, 625, 639, 651, 668, 682, 694, 708, 727, 749, 769, 780, 790, 797, 805, 825, 844, 857, 869, 880, 892, 903}
func (i HandlerID) String() string {
if i >= HandlerID(len(_HandlerID_index)-1) {
+2 -2
View File
@@ -250,7 +250,7 @@ func (m *Manager) RegisterSingleHandler(id HandlerID, h SingleHandlerFn, subrout
if len(subroute) == 0 {
if m.handlers.hasAny(id) && !id.isTestHandler() {
return ErrHandlerAlreadyExists
return fmt.Errorf("handler %v: %w", id.String(), ErrHandlerAlreadyExists)
}
m.handlers.single[id] = h
@@ -258,7 +258,7 @@ func (m *Manager) RegisterSingleHandler(id HandlerID, h SingleHandlerFn, subrout
}
subID := makeSubHandlerID(id, s)
if m.handlers.hasSubhandler(subID) && !id.isTestHandler() {
return ErrHandlerAlreadyExists
return fmt.Errorf("handler %v, subroute:%v: %w", id.String(), s, ErrHandlerAlreadyExists)
}
m.handlers.subSingle[subID] = h
// Copy so clients can also pick it up for other subpaths.
+10 -2
View File
@@ -173,7 +173,7 @@ func (m *muxClient) sendLocked(msg message) error {
h := xxh3.Hash(dst)
dst = binary.LittleEndian.AppendUint32(dst, uint32(h))
}
return m.parent.send(dst)
return m.parent.send(m.ctx, dst)
}
// RequestStateless will send a single payload request and stream back results.
@@ -552,7 +552,15 @@ func (m *muxClient) close() {
if debugPrint {
fmt.Println("closing outgoing mux", m.MuxID)
}
m.respMu.Lock()
if !m.respMu.TryLock() {
// Cancel before locking - will unblock any pending sends.
if m.cancelFn != nil {
m.cancelFn(context.Canceled)
}
// Wait for senders to release.
m.respMu.Lock()
}
defer m.respMu.Unlock()
m.closeLocked()
}
+289
View File
@@ -18,7 +18,10 @@
package grid
import (
"bytes"
"encoding/json"
"errors"
"math"
"net/url"
"sort"
"strings"
@@ -394,6 +397,137 @@ func (u URLValues) Msgsize() (s int) {
return
}
// JSONPool is a pool for JSON objects that unmarshal into T.
type JSONPool[T any] struct {
pool sync.Pool
emptySz int
}
// NewJSONPool returns a new JSONPool.
func NewJSONPool[T any]() *JSONPool[T] {
var t T
sz := 128
if b, err := json.Marshal(t); err != nil {
sz = len(b)
}
return &JSONPool[T]{
pool: sync.Pool{
New: func() interface{} {
var t T
return &t
},
},
emptySz: sz,
}
}
func (p *JSONPool[T]) new() *T {
var zero T
t := p.pool.Get().(*T)
*t = zero
return t
}
// JSON is a wrapper around a T object that can be serialized.
// There is an internal value
type JSON[T any] struct {
p *JSONPool[T]
val *T
}
// NewJSON returns a new JSONPool.
// No initial value is set.
func (p *JSONPool[T]) NewJSON() *JSON[T] {
var j JSON[T]
j.p = p
return &j
}
// NewJSONWith returns a new JSON with the provided value.
func (p *JSONPool[T]) NewJSONWith(val *T) *JSON[T] {
var j JSON[T]
j.p = p
j.val = val
return &j
}
// Value returns the underlying value.
// If not set yet, a new value is created.
func (j *JSON[T]) Value() *T {
if j.val == nil {
j.val = j.p.new()
}
return j.val
}
// ValueOrZero returns the underlying value.
// If the underlying value is nil, a zero value is returned.
func (j *JSON[T]) ValueOrZero() T {
if j == nil || j.val == nil {
var t T
return t
}
return *j.val
}
// Set the underlying value.
func (j *JSON[T]) Set(v *T) {
j.val = v
}
// Recycle the underlying value.
func (j *JSON[T]) Recycle() {
if j.val != nil {
j.p.pool.Put(j.val)
j.val = nil
}
}
// MarshalMsg implements msgp.Marshaler
func (j *JSON[T]) MarshalMsg(b []byte) (o []byte, err error) {
if j.val == nil {
return msgp.AppendNil(b), nil
}
buf := bytes.NewBuffer(GetByteBuffer()[:0])
defer func() {
PutByteBuffer(buf.Bytes())
}()
enc := json.NewEncoder(buf)
err = enc.Encode(j.val)
if err != nil {
return b, err
}
return msgp.AppendBytes(b, buf.Bytes()), nil
}
// UnmarshalMsg will JSON marshal the value and wrap as a msgp byte array.
// Nil values are supported.
func (j *JSON[T]) UnmarshalMsg(bytes []byte) ([]byte, error) {
if bytes, err := msgp.ReadNilBytes(bytes); err == nil {
if j.val != nil {
j.p.pool.Put(j.val)
}
j.val = nil
return bytes, nil
}
val, bytes, err := msgp.ReadBytesZC(bytes)
if err != nil {
return bytes, err
}
if j.val == nil {
j.val = j.p.new()
} else {
var t T
*j.val = t
}
return bytes, json.Unmarshal(val, j.val)
}
// Msgsize returns the size of an empty JSON object.
func (j *JSON[T]) Msgsize() int {
return j.p.emptySz
}
// NoPayload is a type that can be used for handlers that do not use a payload.
type NoPayload struct{}
@@ -419,3 +553,158 @@ func NewNoPayload() NoPayload {
// Recycle is a no-op.
func (NoPayload) Recycle() {}
// ArrayOf wraps an array of Messagepack compatible objects.
type ArrayOf[T RoundTripper] struct {
aPool sync.Pool // Arrays
ePool sync.Pool // Elements
}
// NewArrayOf returns a new ArrayOf.
// You must provide a function that returns a new instance of T.
func NewArrayOf[T RoundTripper](newFn func() T) *ArrayOf[T] {
return &ArrayOf[T]{
ePool: sync.Pool{New: func() any {
return newFn()
}},
}
}
// New returns a new empty Array.
func (p *ArrayOf[T]) New() *Array[T] {
return &Array[T]{
p: p,
}
}
// NewWith returns a new Array with the provided value (not copied).
func (p *ArrayOf[T]) NewWith(val []T) *Array[T] {
return &Array[T]{
p: p,
val: val,
}
}
func (p *ArrayOf[T]) newA(sz uint32) []T {
t, ok := p.aPool.Get().(*[]T)
if !ok || t == nil {
return make([]T, 0, sz)
}
t2 := *t
return t2[:0]
}
func (p *ArrayOf[T]) putA(v []T) {
var zero T // nil
for i, t := range v {
p.ePool.Put(t)
v[i] = zero
}
if v != nil {
v = v[:0]
p.aPool.Put(&v)
}
}
func (p *ArrayOf[T]) newE() T {
return p.ePool.Get().(T)
}
// Array provides a wrapper for an underlying array of serializable objects.
type Array[T RoundTripper] struct {
p *ArrayOf[T]
val []T
}
// Msgsize returns the size of the array in bytes.
func (j *Array[T]) Msgsize() int {
if j.val == nil {
return msgp.NilSize
}
sz := msgp.ArrayHeaderSize
for _, v := range j.val {
sz += v.Msgsize()
}
return sz
}
// Value returns the underlying value.
// Regular append mechanics should be observed.
// If no value has been set yet, a new array is created.
func (j *Array[T]) Value() []T {
if j.val == nil {
j.val = j.p.newA(10)
}
return j.val
}
// Append a value to the underlying array.
// The returned Array is always the same as the one called.
func (j *Array[T]) Append(v ...T) *Array[T] {
if j.val == nil {
j.val = j.p.newA(uint32(len(v)))
}
j.val = append(j.val, v...)
return j
}
// Set the underlying value.
func (j *Array[T]) Set(val []T) {
j.val = val
}
// Recycle the underlying value.
func (j *Array[T]) Recycle() {
if j.val != nil {
j.p.putA(j.val)
j.val = nil
}
}
// MarshalMsg implements msgp.Marshaler
func (j *Array[T]) MarshalMsg(b []byte) (o []byte, err error) {
if j.val == nil {
return msgp.AppendNil(b), nil
}
if uint64(len(j.val)) > math.MaxUint32 {
return b, errors.New("array: length of array exceeds math.MaxUint32")
}
b = msgp.AppendArrayHeader(b, uint32(len(j.val)))
for _, v := range j.val {
b, err = v.MarshalMsg(b)
if err != nil {
return b, err
}
}
return b, err
}
// UnmarshalMsg will JSON marshal the value and wrap as a msgp byte array.
// Nil values are supported.
func (j *Array[T]) UnmarshalMsg(bytes []byte) ([]byte, error) {
if bytes, err := msgp.ReadNilBytes(bytes); err == nil {
if j.val != nil {
j.p.putA(j.val)
}
j.val = nil
return bytes, nil
}
l, bytes, err := msgp.ReadArrayHeaderBytes(bytes)
if err != nil {
return bytes, err
}
if j.val == nil {
j.val = j.p.newA(l)
} else {
j.val = j.val[:0]
}
for i := uint32(0); i < l; i++ {
v := j.p.newE()
bytes, err = v.UnmarshalMsg(bytes)
if err != nil {
return bytes, err
}
j.val = append(j.val, v)
}
return bytes, nil
}
+6 -6
View File
@@ -124,17 +124,17 @@ func Init(goPath string, goRoot string) {
var goRootList []string
var defaultgoPathList []string
var defaultgoRootList []string
pathSeperator := ":"
pathSeparator := ":"
// Add all possible GOPATH paths into trimStrings
// Split GOPATH depending on the OS type
if runtime.GOOS == "windows" {
pathSeperator = ";"
pathSeparator = ";"
}
goPathList = strings.Split(goPath, pathSeperator)
goRootList = strings.Split(goRoot, pathSeperator)
defaultgoPathList = strings.Split(build.Default.GOPATH, pathSeperator)
defaultgoRootList = strings.Split(build.Default.GOROOT, pathSeperator)
goPathList = strings.Split(goPath, pathSeparator)
goRootList = strings.Split(goRoot, pathSeparator)
defaultgoPathList = strings.Split(build.Default.GOPATH, pathSeparator)
defaultgoRootList = strings.Split(build.Default.GOROOT, pathSeparator)
// Add trim string "{GOROOT}/src/" into trimStrings
trimStrings = []string{filepath.Join(runtime.GOROOT(), "src") + string(filepath.Separator)}
+22 -61
View File
@@ -24,7 +24,6 @@ import (
"encoding/json"
"errors"
"fmt"
"net"
"os"
"path/filepath"
"sync"
@@ -78,44 +77,6 @@ type Config struct {
LogOnce func(ctx context.Context, err error, id string, errKind ...interface{}) `json:"-"`
}
func (h *Target) pingBrokers() (err error) {
d := net.Dialer{Timeout: 1 * time.Second}
errs := make([]error, len(h.kconfig.Brokers))
var wg sync.WaitGroup
for idx, broker := range h.kconfig.Brokers {
broker := broker
idx := idx
wg.Add(1)
go func(broker xnet.Host, idx int) {
defer wg.Done()
conn, ok := h.brokerConns[broker.String()]
if !ok || conn == nil {
conn, errs[idx] = d.Dial("tcp", broker.String())
if errs[idx] != nil {
return
}
h.brokerConns[broker.String()] = conn
}
if _, errs[idx] = conn.Write([]byte("")); errs[idx] != nil {
conn.Close()
h.brokerConns[broker.String()] = nil
}
}(broker, idx)
}
wg.Wait()
var retErr error
for _, err := range errs {
if err == nil {
// if one of them is active we are good.
return nil
}
retErr = err
}
return retErr
}
// Target - Kafka target.
type Target struct {
status int32
@@ -139,10 +100,10 @@ type Target struct {
initKafkaOnce once.Init
initQueueStoreOnce once.Init
producer sarama.SyncProducer
kconfig Config
config *sarama.Config
brokerConns map[string]net.Conn
client sarama.Client
producer sarama.SyncProducer
kconfig Config
config *sarama.Config
}
func (h *Target) validate() error {
@@ -202,7 +163,7 @@ func (h *Target) Init(ctx context.Context) error {
if err := h.init(); err != nil {
return err
}
go h.startKakfaLogger()
go h.startKafkaLogger()
return nil
}
@@ -220,7 +181,7 @@ func (h *Target) initQueueStore(ctx context.Context) (err error) {
return
}
func (h *Target) startKakfaLogger() {
func (h *Target) startKafkaLogger() {
h.logChMu.RLock()
logCh := h.logCh
if logCh != nil {
@@ -273,10 +234,6 @@ func (h *Target) send(entry interface{}) error {
// Init initialize kafka target
func (h *Target) init() error {
if err := h.pingBrokers(); err != nil {
return err
}
sconfig := sarama.NewConfig()
if h.kconfig.Version != "" {
kafkaVersion, err := sarama.ParseKafkaVersion(h.kconfig.Version)
@@ -325,13 +282,23 @@ func (h *Target) init() error {
brokers = append(brokers, broker.String())
}
producer, err := sarama.NewSyncProducer(brokers, sconfig)
client, err := sarama.NewClient(brokers, sconfig)
if err != nil {
return err
}
producer, err := sarama.NewSyncProducerFromClient(client)
if err != nil {
return err
}
h.client = client
h.producer = producer
atomic.StoreInt32(&h.status, statusOnline)
if len(h.client.Brokers()) > 0 {
// Refer https://github.com/IBM/sarama/issues/1341
atomic.StoreInt32(&h.status, statusOnline)
}
return nil
}
@@ -409,12 +376,7 @@ func (h *Target) Cancel() {
if h.producer != nil {
h.producer.Close()
}
for _, conn := range h.brokerConns {
if conn != nil {
conn.Close()
}
h.client.Close()
}
// Wait for messages to be sent...
@@ -425,10 +387,9 @@ func (h *Target) Cancel() {
// sends log over http to the specified endpoint
func New(config Config) *Target {
target := &Target{
logCh: make(chan interface{}, config.QueueSize),
kconfig: config,
status: statusOffline,
brokerConns: make(map[string]net.Conn, len(config.Brokers)),
logCh: make(chan interface{}, config.QueueSize),
kconfig: config,
status: statusOffline,
}
return target
}
+1 -1
View File
@@ -307,7 +307,7 @@ func NewReader(readCloser io.ReadCloser, args *ReaderArgs) (*Reader, error) {
ret.Comment = []rune(args.CommentCharacter)[0]
ret.Quote = []rune{}
if len([]rune(args.QuoteCharacter)) > 0 {
// Add the first rune of args.QuoteChracter
// Add the first rune of args.QuoteCharacter
ret.Quote = append(ret.Quote, []rune(args.QuoteCharacter)[0])
}
ret.QuoteEscape = []rune(args.QuoteEscapeCharacter)[0]
+7 -7
View File
@@ -25,11 +25,11 @@ import (
)
var (
errKeyLookup = errors.New("Cannot look up key in non-object value")
errIndexLookup = errors.New("Cannot look up array index in non-array value")
errWildcardObjectLookup = errors.New("Object wildcard used on non-object value")
errWildcardArrayLookup = errors.New("Array wildcard used on non-array value")
errWilcardObjectUsageInvalid = errors.New("Invalid usage of object wildcard")
errKeyLookup = errors.New("Cannot look up key in non-object value")
errIndexLookup = errors.New("Cannot look up array index in non-array value")
errWildcardObjectLookup = errors.New("Object wildcard used on non-object value")
errWildcardArrayLookup = errors.New("Array wildcard used on non-array value")
errWildcardObjectUsageInvalid = errors.New("Invalid usage of object wildcard")
)
// jsonpathEval evaluates a JSON path and returns the value at the path.
@@ -85,13 +85,13 @@ func jsonpathEval(p []*JSONPathElement, v interface{}) (r interface{}, flat bool
switch kvs := v.(type) {
case jstream.KVS:
if len(p[1:]) > 0 {
return nil, false, errWilcardObjectUsageInvalid
return nil, false, errWildcardObjectUsageInvalid
}
return kvs, false, nil
case simdjson.Object:
if len(p[1:]) > 0 {
return nil, false, errWilcardObjectUsageInvalid
return nil, false, errWildcardObjectUsageInvalid
}
return kvs, false, nil
+12 -12
View File
@@ -20,11 +20,11 @@
package s3select
///////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////
//
// Validation errors.
// Validation errors.
//
///////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////
func errExpressionTooLong(err error) *s3Error {
return &s3Error{
code: "ExpressionTooLong",
@@ -151,11 +151,11 @@ func errUnrecognizedFormatException(err error) *s3Error {
}
}
//////////////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////////////
//
// SQL parsing errors.
// SQL parsing errors.
//
//////////////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////////////
func errLexerInvalidChar(err error) *s3Error {
return &s3Error{
code: "LexerInvalidChar",
@@ -498,11 +498,11 @@ func errParseCannotMixSqbAndWildcardInSelectList(err error) *s3Error {
}
}
//////////////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////////////
//
// CAST() related errors.
// CAST() related errors.
//
//////////////////////////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////////////////////////
func errCastFailed(err error) *s3Error {
return &s3Error{
code: "CastFailed",
@@ -593,11 +593,11 @@ func errEvaluatorInvalidTimestampFormatPatternSymbol(err error) *s3Error {
}
}
////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////
//
// Generic S3 HTTP handler errors.
// Generic S3 HTTP handler errors.
//
////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////
func errBusy(err error) *s3Error {
return &s3Error{
code: "Busy",