github.com/minio/madmin-go/v3@v3.0.51/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  	EnableSha256 bool          // Enable calculating sha256 for uploads
    70  }
    71  
    72  // Speedtest - perform speedtest on the MinIO servers
    73  func (adm *AdminClient) Speedtest(ctx context.Context, opts SpeedtestOpts) (chan SpeedTestResult, error) {
    74  	if !opts.Autotune {
    75  		if opts.Duration <= time.Second {
    76  			return nil, errors.New("duration must be greater a second")
    77  		}
    78  		if opts.Size <= 0 {
    79  			return nil, errors.New("size must be greater than 0 bytes")
    80  		}
    81  		if opts.Concurrency <= 0 {
    82  			return nil, errors.New("concurrency must be greater than 0")
    83  		}
    84  	}
    85  
    86  	queryVals := make(url.Values)
    87  	if opts.Size > 0 {
    88  		queryVals.Set("size", strconv.Itoa(opts.Size))
    89  	}
    90  	if opts.Duration > 0 {
    91  		queryVals.Set("duration", opts.Duration.String())
    92  	}
    93  	if opts.Concurrency > 0 {
    94  		queryVals.Set("concurrent", strconv.Itoa(opts.Concurrency))
    95  	}
    96  	if opts.Bucket != "" {
    97  		queryVals.Set("bucket", opts.Bucket)
    98  	}
    99  	if opts.Autotune {
   100  		queryVals.Set("autotune", "true")
   101  	}
   102  	if opts.NoClear {
   103  		queryVals.Set("noclear", "true")
   104  	}
   105  	if opts.EnableSha256 {
   106  		queryVals.Set("enableSha256", "true")
   107  	}
   108  	resp, err := adm.executeMethod(ctx,
   109  		http.MethodPost, requestData{
   110  			relPath:     adminAPIPrefix + "/speedtest",
   111  			queryValues: queryVals,
   112  		})
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	if resp.StatusCode != http.StatusOK {
   117  		return nil, httpRespToErrorResponse(resp)
   118  	}
   119  	ch := make(chan SpeedTestResult)
   120  	go func() {
   121  		defer closeResponse(resp)
   122  		defer close(ch)
   123  		dec := json.NewDecoder(resp.Body)
   124  		for {
   125  			var result SpeedTestResult
   126  			if err := dec.Decode(&result); err != nil {
   127  				return
   128  			}
   129  			select {
   130  			case ch <- result:
   131  			case <-ctx.Done():
   132  				return
   133  			}
   134  		}
   135  	}()
   136  	return ch, nil
   137  }