github.com/minio/madmin-go@v1.7.5/perf-object.go (about)

     1  //
     2  // MinIO Object Storage (c) 2021 MinIO, Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //      http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package madmin
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"net/http"
    24  	"net/url"
    25  	"strconv"
    26  	"time"
    27  )
    28  
    29  // SpeedTestStatServer - stats of a server
    30  type SpeedTestStatServer struct {
    31  	Endpoint         string `json:"endpoint"`
    32  	ThroughputPerSec uint64 `json:"throughputPerSec"`
    33  	ObjectsPerSec    uint64 `json:"objectsPerSec"`
    34  	Err              string `json:"err"`
    35  }
    36  
    37  // SpeedTestStats - stats of all the servers
    38  type SpeedTestStats struct {
    39  	ThroughputPerSec uint64                `json:"throughputPerSec"`
    40  	ObjectsPerSec    uint64                `json:"objectsPerSec"`
    41  	Response         Timings               `json:"responseTime"`
    42  	TTFB             Timings               `json:"ttfb,omitempty"`
    43  	Servers          []SpeedTestStatServer `json:"servers"`
    44  }
    45  
    46  // SpeedTestResult - result of the speedtest() call
    47  type SpeedTestResult struct {
    48  	Version    string `json:"version"`
    49  	Servers    int    `json:"servers"`
    50  	Disks      int    `json:"disks"`
    51  	Size       int    `json:"size"`
    52  	Concurrent int    `json:"concurrent"`
    53  	PUTStats   SpeedTestStats
    54  	GETStats   SpeedTestStats
    55  }
    56  
    57  // SpeedtestOpts provide configurable options for speedtest
    58  type SpeedtestOpts struct {
    59  	Size         int           // Object size used in speed test
    60  	Concurrency  int           // Concurrency used in speed test
    61  	Duration     time.Duration // Total duration of the speed test
    62  	Autotune     bool          // Enable autotuning
    63  	StorageClass string        // Choose type of storage-class to be used while performing I/O
    64  	Bucket       string        // Choose a custom bucket name while performing I/O
    65  }
    66  
    67  // Speedtest - perform speedtest on the MinIO servers
    68  func (adm *AdminClient) Speedtest(ctx context.Context, opts SpeedtestOpts) (chan SpeedTestResult, error) {
    69  	if !opts.Autotune {
    70  		if opts.Duration <= time.Second {
    71  			return nil, errors.New("duration must be greater a second")
    72  		}
    73  		if opts.Size <= 0 {
    74  			return nil, errors.New("size must be greater than 0 bytes")
    75  		}
    76  		if opts.Concurrency <= 0 {
    77  			return nil, errors.New("concurrency must be greater than 0")
    78  		}
    79  	}
    80  
    81  	queryVals := make(url.Values)
    82  	if opts.Size > 0 {
    83  		queryVals.Set("size", strconv.Itoa(opts.Size))
    84  	}
    85  	if opts.Duration > 0 {
    86  		queryVals.Set("duration", opts.Duration.String())
    87  	}
    88  	if opts.Concurrency > 0 {
    89  		queryVals.Set("concurrent", strconv.Itoa(opts.Concurrency))
    90  	}
    91  	if opts.Bucket != "" {
    92  		queryVals.Set("bucket", opts.Bucket)
    93  	}
    94  	if opts.Autotune {
    95  		queryVals.Set("autotune", "true")
    96  	}
    97  	resp, err := adm.executeMethod(ctx,
    98  		http.MethodPost, requestData{
    99  			relPath:     adminAPIPrefix + "/speedtest",
   100  			queryValues: queryVals,
   101  		})
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	if resp.StatusCode != http.StatusOK {
   106  		return nil, httpRespToErrorResponse(resp)
   107  	}
   108  	ch := make(chan SpeedTestResult)
   109  	go func() {
   110  		defer closeResponse(resp)
   111  		defer close(ch)
   112  		dec := json.NewDecoder(resp.Body)
   113  		for {
   114  			var result SpeedTestResult
   115  			if err := dec.Decode(&result); err != nil {
   116  				return
   117  			}
   118  			select {
   119  			case ch <- result:
   120  			case <-ctx.Done():
   121  				return
   122  			}
   123  		}
   124  	}()
   125  	return ch, nil
   126  }