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 }