github.com/minio/madmin-go/v2@v2.2.1/perf-object.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  	"errors"
    26  	"net/http"
    27  	"net/url"
    28  	"strconv"
    29  	"time"
    30  )
    31  
    32  // SpeedTestStatServer - stats of a server
    33  type SpeedTestStatServer struct {
    34  	Endpoint         string `json:"endpoint"`
    35  	ThroughputPerSec uint64 `json:"throughputPerSec"`
    36  	ObjectsPerSec    uint64 `json:"objectsPerSec"`
    37  	Err              string `json:"err"`
    38  }
    39  
    40  // SpeedTestStats - stats of all the servers
    41  type SpeedTestStats struct {
    42  	ThroughputPerSec uint64                `json:"throughputPerSec"`
    43  	ObjectsPerSec    uint64                `json:"objectsPerSec"`
    44  	Response         Timings               `json:"responseTime"`
    45  	TTFB             Timings               `json:"ttfb,omitempty"`
    46  	Servers          []SpeedTestStatServer `json:"servers"`
    47  }
    48  
    49  // SpeedTestResult - result of the speedtest() call
    50  type SpeedTestResult struct {
    51  	Version    string `json:"version"`
    52  	Servers    int    `json:"servers"`
    53  	Disks      int    `json:"disks"`
    54  	Size       int    `json:"size"`
    55  	Concurrent int    `json:"concurrent"`
    56  	PUTStats   SpeedTestStats
    57  	GETStats   SpeedTestStats
    58  }
    59  
    60  // SpeedtestOpts provide configurable options for speedtest
    61  type SpeedtestOpts struct {
    62  	Size         int           // Object size used in speed test
    63  	Concurrency  int           // Concurrency used in speed test
    64  	Duration     time.Duration // Total duration of the speed test
    65  	Autotune     bool          // Enable autotuning
    66  	StorageClass string        // Choose type of storage-class to be used while performing I/O
    67  	Bucket       string        // Choose a custom bucket name while performing I/O
    68  	NoClear      bool          // Avoid cleanup after running an object speed test
    69  }
    70  
    71  // Speedtest - perform speedtest on the MinIO servers
    72  func (adm *AdminClient) Speedtest(ctx context.Context, opts SpeedtestOpts) (chan SpeedTestResult, error) {
    73  	if !opts.Autotune {
    74  		if opts.Duration <= time.Second {
    75  			return nil, errors.New("duration must be greater a second")
    76  		}
    77  		if opts.Size <= 0 {
    78  			return nil, errors.New("size must be greater than 0 bytes")
    79  		}
    80  		if opts.Concurrency <= 0 {
    81  			return nil, errors.New("concurrency must be greater than 0")
    82  		}
    83  	}
    84  
    85  	queryVals := make(url.Values)
    86  	if opts.Size > 0 {
    87  		queryVals.Set("size", strconv.Itoa(opts.Size))
    88  	}
    89  	if opts.Duration > 0 {
    90  		queryVals.Set("duration", opts.Duration.String())
    91  	}
    92  	if opts.Concurrency > 0 {
    93  		queryVals.Set("concurrent", strconv.Itoa(opts.Concurrency))
    94  	}
    95  	if opts.Bucket != "" {
    96  		queryVals.Set("bucket", opts.Bucket)
    97  	}
    98  	if opts.Autotune {
    99  		queryVals.Set("autotune", "true")
   100  	}
   101  	if opts.NoClear {
   102  		queryVals.Set("noclear", "true")
   103  	}
   104  	resp, err := adm.executeMethod(ctx,
   105  		http.MethodPost, requestData{
   106  			relPath:     adminAPIPrefix + "/speedtest",
   107  			queryValues: queryVals,
   108  		})
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	if resp.StatusCode != http.StatusOK {
   113  		return nil, httpRespToErrorResponse(resp)
   114  	}
   115  	ch := make(chan SpeedTestResult)
   116  	go func() {
   117  		defer closeResponse(resp)
   118  		defer close(ch)
   119  		dec := json.NewDecoder(resp.Body)
   120  		for {
   121  			var result SpeedTestResult
   122  			if err := dec.Decode(&result); err != nil {
   123  				return
   124  			}
   125  			select {
   126  			case ch <- result:
   127  			case <-ctx.Done():
   128  				return
   129  			}
   130  		}
   131  	}()
   132  	return ch, nil
   133  }