storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/bandwidth/monitor.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2020 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 bandwidth 18 19 import ( 20 "context" 21 "sync" 22 "time" 23 24 "storj.io/minio/pkg/bandwidth" 25 ) 26 27 // throttleBandwidth gets the throttle for bucket with the configured value 28 func (m *Monitor) throttleBandwidth(ctx context.Context, bucket string, bandwidthBytesPerSecond int64, clusterBandwidth int64) *throttle { 29 m.lock.Lock() 30 defer m.lock.Unlock() 31 throttle, ok := m.bucketThrottle[bucket] 32 if !ok { 33 throttle = newThrottle(ctx, bandwidthBytesPerSecond, clusterBandwidth) 34 m.bucketThrottle[bucket] = throttle 35 return throttle 36 } 37 throttle.SetBandwidth(bandwidthBytesPerSecond, clusterBandwidth) 38 return throttle 39 } 40 41 // Monitor implements the monitoring for bandwidth measurements. 42 type Monitor struct { 43 lock sync.Mutex // lock for all updates 44 45 activeBuckets map[string]*bucketMeasurement // Buckets with objects in flight 46 47 bucketMovingAvgTicker *time.Ticker // Ticker for calculating moving averages 48 49 bucketThrottle map[string]*throttle 50 51 doneCh <-chan struct{} 52 } 53 54 // NewMonitor returns a monitor with defaults. 55 func NewMonitor(doneCh <-chan struct{}) *Monitor { 56 m := &Monitor{ 57 activeBuckets: make(map[string]*bucketMeasurement), 58 bucketMovingAvgTicker: time.NewTicker(2 * time.Second), 59 bucketThrottle: make(map[string]*throttle), 60 doneCh: doneCh, 61 } 62 go m.trackEWMA() 63 return m 64 } 65 66 // SelectionFunction for buckets 67 type SelectionFunction func(bucket string) bool 68 69 // SelectBuckets will select all the buckets passed in. 70 func SelectBuckets(buckets ...string) SelectionFunction { 71 if len(buckets) == 0 { 72 return func(bucket string) bool { 73 return true 74 } 75 } 76 return func(bucket string) bool { 77 for _, b := range buckets { 78 if b == "" || b == bucket { 79 return true 80 } 81 } 82 return false 83 } 84 } 85 86 // GetReport gets the report for all bucket bandwidth details. 87 func (m *Monitor) GetReport(selectBucket SelectionFunction) *bandwidth.Report { 88 m.lock.Lock() 89 defer m.lock.Unlock() 90 return m.getReport(selectBucket) 91 } 92 93 func (m *Monitor) getReport(selectBucket SelectionFunction) *bandwidth.Report { 94 report := &bandwidth.Report{ 95 BucketStats: make(map[string]bandwidth.Details), 96 } 97 for bucket, bucketMeasurement := range m.activeBuckets { 98 if !selectBucket(bucket) { 99 continue 100 } 101 bucketThrottle, ok := m.bucketThrottle[bucket] 102 if !ok { 103 continue 104 } 105 report.BucketStats[bucket] = bandwidth.Details{ 106 LimitInBytesPerSecond: bucketThrottle.clusterBandwidth, 107 CurrentBandwidthInBytesPerSecond: bucketMeasurement.getExpMovingAvgBytesPerSecond(), 108 } 109 } 110 return report 111 } 112 113 func (m *Monitor) trackEWMA() { 114 for { 115 select { 116 case <-m.bucketMovingAvgTicker.C: 117 m.updateMovingAvg() 118 case <-m.doneCh: 119 return 120 } 121 } 122 } 123 124 func (m *Monitor) getBucketMeasurement(bucket string, initTime time.Time) *bucketMeasurement { 125 bucketTracker, ok := m.activeBuckets[bucket] 126 if !ok { 127 bucketTracker = newBucketMeasurement(initTime) 128 m.activeBuckets[bucket] = bucketTracker 129 } 130 return bucketTracker 131 } 132 133 func (m *Monitor) updateMovingAvg() { 134 m.lock.Lock() 135 defer m.lock.Unlock() 136 for _, bucketMeasurement := range m.activeBuckets { 137 bucketMeasurement.updateExponentialMovingAverage(time.Now()) 138 } 139 } 140 141 // track returns the measurement object for bucket and object 142 func (m *Monitor) track(bucket string, object string) *bucketMeasurement { 143 m.lock.Lock() 144 defer m.lock.Unlock() 145 return m.getBucketMeasurement(bucket, time.Now()) 146 } 147 148 // DeleteBucket deletes monitoring the 'bucket' 149 func (m *Monitor) DeleteBucket(bucket string) { 150 m.lock.Lock() 151 defer m.lock.Unlock() 152 delete(m.activeBuckets, bucket) 153 delete(m.bucketThrottle, bucket) 154 }