allow more than N number of locks in TopLocks (#9883)

This commit is contained in:
Harshavardhana 2020-06-20 06:33:01 -07:00 committed by GitHub
parent 67062840c1
commit b8cb21c954
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 22 deletions

View file

@ -1,5 +1,5 @@
/* /*
* MinIO Cloud Storage, (C) 2016-2019 MinIO, Inc. * MinIO Cloud Storage, (C) 2016-2020 MinIO, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -328,7 +328,7 @@ func (a adminAPIHandlers) DataUsageInfoHandler(w http.ResponseWriter, r *http.Re
writeSuccessResponseJSON(w, dataUsageInfoJSON) writeSuccessResponseJSON(w, dataUsageInfoJSON)
} }
func newLockEntry(l lockRequesterInfo, resource, server string) *madmin.LockEntry { func lriToLockEntry(l lockRequesterInfo, resource, server string) *madmin.LockEntry {
entry := &madmin.LockEntry{ entry := &madmin.LockEntry{
Timestamp: l.Timestamp, Timestamp: l.Timestamp,
Resource: resource, Resource: resource,
@ -337,14 +337,14 @@ func newLockEntry(l lockRequesterInfo, resource, server string) *madmin.LockEntr
ID: l.UID, ID: l.UID,
} }
if l.Writer { if l.Writer {
entry.Type = "Write" entry.Type = "WRITE"
} else { } else {
entry.Type = "Read" entry.Type = "READ"
} }
return entry return entry
} }
func topLockEntries(peerLocks []*PeerLocks) madmin.LockEntries { func topLockEntries(peerLocks []*PeerLocks, count int) madmin.LockEntries {
entryMap := make(map[string]*madmin.LockEntry) entryMap := make(map[string]*madmin.LockEntry)
for _, peerLock := range peerLocks { for _, peerLock := range peerLocks {
if peerLock == nil { if peerLock == nil {
@ -356,20 +356,19 @@ func topLockEntries(peerLocks []*PeerLocks) madmin.LockEntries {
if val, ok := entryMap[lockReqInfo.UID]; ok { if val, ok := entryMap[lockReqInfo.UID]; ok {
val.ServerList = append(val.ServerList, peerLock.Addr) val.ServerList = append(val.ServerList, peerLock.Addr)
} else { } else {
entryMap[lockReqInfo.UID] = newLockEntry(lockReqInfo, k, peerLock.Addr) entryMap[lockReqInfo.UID] = lriToLockEntry(lockReqInfo, k, peerLock.Addr)
} }
} }
} }
} }
} }
var lockEntries = make(madmin.LockEntries, 0) var lockEntries = make(madmin.LockEntries, 0, len(entryMap))
for _, v := range entryMap { for _, v := range entryMap {
lockEntries = append(lockEntries, *v) lockEntries = append(lockEntries, *v)
} }
sort.Sort(lockEntries) sort.Sort(lockEntries)
const listCount int = 10 if len(lockEntries) > count {
if len(lockEntries) > listCount { lockEntries = lockEntries[:count]
lockEntries = lockEntries[:listCount]
} }
return lockEntries return lockEntries
} }
@ -391,6 +390,16 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request
return return
} }
count := 10 // by default list only top 10 entries
if countStr := r.URL.Query().Get("count"); countStr != "" {
var err error
count, err = strconv.Atoi(countStr)
if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return
}
}
peerLocks := globalNotificationSys.GetLocks(ctx) peerLocks := globalNotificationSys.GetLocks(ctx)
// Once we have received all the locks currently used from peers // Once we have received all the locks currently used from peers
// add the local peer locks list as well. // add the local peer locks list as well.
@ -398,12 +407,13 @@ func (a adminAPIHandlers) TopLocksHandler(w http.ResponseWriter, r *http.Request
for _, llocker := range globalLockServers { for _, llocker := range globalLockServers {
getRespLocks = append(getRespLocks, llocker.DupLockMap()) getRespLocks = append(getRespLocks, llocker.DupLockMap())
} }
peerLocks = append(peerLocks, &PeerLocks{ peerLocks = append(peerLocks, &PeerLocks{
Addr: getHostName(r), Addr: getHostName(r),
Locks: getRespLocks, Locks: getRespLocks,
}) })
topLocks := topLockEntries(peerLocks) topLocks := topLockEntries(peerLocks, count)
// Marshal API response // Marshal API response
jsonBytes, err := json.Marshal(topLocks) jsonBytes, err := json.Marshal(topLocks)

View file

@ -22,6 +22,8 @@ import (
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"strconv"
"time" "time"
) )
@ -29,12 +31,11 @@ import (
// servers holding the lock, source on the client machine, // servers holding the lock, source on the client machine,
// ID, type(read or write) and time stamp. // ID, type(read or write) and time stamp.
type LockEntry struct { type LockEntry struct {
Timestamp time.Time `json:"time"` // Timestamp set at the time of initialization. Timestamp time.Time `json:"time"` // When the lock was first granted
Resource string `json:"resource"` // Resource contains info like bucket, object etc Resource string `json:"resource"` // Resource contains info like bucket+object
Type string `json:"type"` // Bool whether write or read lock. Type string `json:"type"` // Type indicates if 'Write' or 'Read' lock
Source string `json:"source"` // Source which created the lock Source string `json:"source"` // Source at which lock was granted
ServerList []string `json:"serverlist"` // RPC path of servers issuing the lock. ServerList []string `json:"serverlist"` // List of servers participating in the lock.
Owner string `json:"owner"` // RPC path of client claiming lock.
ID string `json:"id"` // UID to uniquely identify request of client. ID string `json:"id"` // UID to uniquely identify request of client.
} }
@ -53,13 +54,19 @@ func (l LockEntries) Swap(i, j int) {
l[i], l[j] = l[j], l[i] l[i], l[j] = l[j], l[i]
} }
// TopLocks - returns the oldest locks in a minio setup. // TopNLocks - returns the count number of oldest locks currently active on the server.
func (adm *AdminClient) TopLocks(ctx context.Context) (LockEntries, error) { func (adm *AdminClient) TopNLocks(ctx context.Context, count int) (LockEntries, error) {
// Execute GET on /minio/admin/v3/top/locks // Execute GET on /minio/admin/v3/top/locks?count=10
// to get the oldest locks in a minio setup. // to get the 'count' number of oldest locks currently
// active on the server.
queryVals := make(url.Values)
queryVals.Set("count", strconv.Itoa(count))
resp, err := adm.executeMethod(ctx, resp, err := adm.executeMethod(ctx,
http.MethodGet, http.MethodGet,
requestData{relPath: adminAPIPrefix + "/top/locks"}, requestData{
relPath: adminAPIPrefix + "/top/locks",
queryValues: queryVals,
},
) )
defer closeResponse(resp) defer closeResponse(resp)
if err != nil { if err != nil {
@ -79,3 +86,8 @@ func (adm *AdminClient) TopLocks(ctx context.Context) (LockEntries, error) {
err = json.Unmarshal(response, &lockEntries) err = json.Unmarshal(response, &lockEntries)
return lockEntries, err return lockEntries, err
} }
// TopLocks - returns top '10' oldest locks currently active on the server.
func (adm *AdminClient) TopLocks(ctx context.Context) (LockEntries, error) {
return adm.TopNLocks(ctx, 10)
}