storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/bucket/bandwidth/reader.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 18 package bandwidth 19 20 import ( 21 "context" 22 "io" 23 ) 24 25 // MonitoredReader monitors the bandwidth 26 type MonitoredReader struct { 27 opts *MonitorReaderOptions 28 bucketMeasurement *bucketMeasurement // bucket measurement object 29 reader io.Reader // Reader to wrap 30 throttle *throttle // throttle the rate at which replication occur 31 monitor *Monitor // Monitor reference 32 lastErr error // last error reported, if this non-nil all reads will fail. 33 } 34 35 // MonitorReaderOptions provides configurable options for monitor reader implementation. 36 type MonitorReaderOptions struct { 37 Bucket string 38 Object string 39 HeaderSize int 40 BandwidthBytesPerSec int64 41 ClusterBandwidth int64 42 } 43 44 // NewMonitoredReader returns a io.Reader that reports bandwidth details. 45 func NewMonitoredReader(ctx context.Context, monitor *Monitor, reader io.Reader, opts *MonitorReaderOptions) *MonitoredReader { 46 return &MonitoredReader{ 47 opts: opts, 48 bucketMeasurement: monitor.track(opts.Bucket, opts.Object), 49 reader: reader, 50 throttle: monitor.throttleBandwidth(ctx, opts.Bucket, opts.BandwidthBytesPerSec, opts.ClusterBandwidth), 51 monitor: monitor, 52 } 53 } 54 55 // Read wraps the read reader 56 func (m *MonitoredReader) Read(p []byte) (n int, err error) { 57 if m.lastErr != nil { 58 err = m.lastErr 59 return 60 } 61 62 p = p[:m.throttle.GetLimitForBytes(int64(len(p)))] 63 64 n, err = m.reader.Read(p) 65 if err != nil { 66 m.lastErr = err 67 } 68 69 update := n + m.opts.HeaderSize 70 unused := len(p) - update 71 72 m.bucketMeasurement.incrementBytes(uint64(update)) 73 m.opts.HeaderSize = 0 // Set to 0 post first read 74 75 if unused > 0 { 76 m.throttle.ReleaseUnusedBandwidth(int64(unused)) 77 } 78 79 return 80 }