github.com/minio/madmin-go/v2@v2.2.1/top-commands.go (about)

     1  //
     2  // Copyright (c) 2015-2022 MinIO, Inc.
     3  //
     4  // This file is part of MinIO Object Storage stack
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU Affero General Public License as
     8  // published by the Free Software Foundation, either version 3 of the
     9  // License, or (at your option) any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU Affero General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU Affero General Public License
    17  // along with this program. If not, see <http://www.gnu.org/licenses/>.
    18  //
    19  
    20  package madmin
    21  
    22  import (
    23  	"context"
    24  	"encoding/json"
    25  	"io/ioutil"
    26  	"net/http"
    27  	"net/url"
    28  	"strconv"
    29  	"strings"
    30  	"time"
    31  )
    32  
    33  // LockEntry holds information about client requesting the lock,
    34  // servers holding the lock, source on the client machine,
    35  // ID, type(read or write) and time stamp.
    36  type LockEntry struct {
    37  	Timestamp  time.Time     `json:"time"`       // When the lock was first granted
    38  	Elapsed    time.Duration `json:"elapsed"`    // Duration for which lock has been held
    39  	Resource   string        `json:"resource"`   // Resource contains info like bucket+object
    40  	Type       string        `json:"type"`       // Type indicates if 'Write' or 'Read' lock
    41  	Source     string        `json:"source"`     // Source at which lock was granted
    42  	ServerList []string      `json:"serverlist"` // List of servers participating in the lock.
    43  	Owner      string        `json:"owner"`      // Owner UUID indicates server owns the lock.
    44  	ID         string        `json:"id"`         // UID to uniquely identify request of client.
    45  	// Represents quorum number of servers required to hold this lock, used to look for stale locks.
    46  	Quorum int `json:"quorum"`
    47  }
    48  
    49  // LockEntries - To sort the locks
    50  type LockEntries []LockEntry
    51  
    52  func (l LockEntries) Len() int {
    53  	return len(l)
    54  }
    55  
    56  func (l LockEntries) Less(i, j int) bool {
    57  	return l[i].Timestamp.Before(l[j].Timestamp)
    58  }
    59  
    60  func (l LockEntries) Swap(i, j int) {
    61  	l[i], l[j] = l[j], l[i]
    62  }
    63  
    64  // TopLockOpts top lock options
    65  type TopLockOpts struct {
    66  	Count int
    67  	Stale bool
    68  }
    69  
    70  // ForceUnlock force unlocks input paths...
    71  func (adm *AdminClient) ForceUnlock(ctx context.Context, paths ...string) error {
    72  	// Execute POST on /minio/admin/v3/force-unlock
    73  	queryVals := make(url.Values)
    74  	queryVals.Set("paths", strings.Join(paths, ","))
    75  	resp, err := adm.executeMethod(ctx,
    76  		http.MethodPost,
    77  		requestData{
    78  			relPath:     adminAPIPrefix + "/force-unlock",
    79  			queryValues: queryVals,
    80  		},
    81  	)
    82  	defer closeResponse(resp)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	if resp.StatusCode != http.StatusOK {
    88  		return httpRespToErrorResponse(resp)
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  // TopLocksWithOpts - returns the count number of oldest locks currently active on the server.
    95  // additionally we can also enable `stale` to get stale locks currently present on server.
    96  func (adm *AdminClient) TopLocksWithOpts(ctx context.Context, opts TopLockOpts) (LockEntries, error) {
    97  	// Execute GET on /minio/admin/v3/top/locks?count=10
    98  	// to get the 'count' number of oldest locks currently
    99  	// active on the server.
   100  	queryVals := make(url.Values)
   101  	queryVals.Set("count", strconv.Itoa(opts.Count))
   102  	queryVals.Set("stale", strconv.FormatBool(opts.Stale))
   103  	resp, err := adm.executeMethod(ctx,
   104  		http.MethodGet,
   105  		requestData{
   106  			relPath:     adminAPIPrefix + "/top/locks",
   107  			queryValues: queryVals,
   108  		},
   109  	)
   110  	defer closeResponse(resp)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	if resp.StatusCode != http.StatusOK {
   116  		return nil, httpRespToErrorResponse(resp)
   117  	}
   118  
   119  	response, err := ioutil.ReadAll(resp.Body)
   120  	if err != nil {
   121  		return LockEntries{}, err
   122  	}
   123  
   124  	var lockEntries LockEntries
   125  	err = json.Unmarshal(response, &lockEntries)
   126  	return lockEntries, err
   127  }
   128  
   129  // TopLocks - returns top '10' oldest locks currently active on the server.
   130  func (adm *AdminClient) TopLocks(ctx context.Context) (LockEntries, error) {
   131  	return adm.TopLocksWithOpts(ctx, TopLockOpts{Count: 10})
   132  }