github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/pacer.go (about) 1 // Pacer with logging and calculator 2 3 package fs 4 5 import ( 6 "context" 7 "time" 8 9 "github.com/rclone/rclone/fs/fserrors" 10 "github.com/rclone/rclone/lib/pacer" 11 ) 12 13 // Pacer is a simple wrapper around a pacer.Pacer with logging. 14 type Pacer struct { 15 *pacer.Pacer 16 } 17 18 type logCalculator struct { 19 pacer.Calculator 20 } 21 22 // NewPacer creates a Pacer for the given Fs and Calculator. 23 func NewPacer(ctx context.Context, c pacer.Calculator) *Pacer { 24 ci := GetConfig(ctx) 25 retries := ci.LowLevelRetries 26 if retries <= 0 { 27 retries = 1 28 } 29 p := &Pacer{ 30 Pacer: pacer.New( 31 pacer.InvokerOption(pacerInvoker), 32 // pacer.MaxConnectionsOption(ci.Checkers+ci.Transfers), 33 pacer.RetriesOption(retries), 34 pacer.CalculatorOption(c), 35 ), 36 } 37 p.SetCalculator(c) 38 return p 39 } 40 41 func (d *logCalculator) Calculate(state pacer.State) time.Duration { 42 oldSleepTime := state.SleepTime 43 newSleepTime := d.Calculator.Calculate(state) 44 if state.ConsecutiveRetries > 0 { 45 if newSleepTime != oldSleepTime { 46 Debugf("pacer", "Rate limited, increasing sleep to %v", newSleepTime) 47 } 48 } else { 49 if newSleepTime != oldSleepTime { 50 Debugf("pacer", "Reducing sleep to %v", newSleepTime) 51 } 52 } 53 return newSleepTime 54 } 55 56 // SetCalculator sets the pacing algorithm. Don't modify the Calculator object 57 // afterwards, use the ModifyCalculator method when needed. 58 // 59 // It will choose the default algorithm if nil is passed in. 60 func (p *Pacer) SetCalculator(c pacer.Calculator) { 61 switch c.(type) { 62 case *logCalculator: 63 Logf("pacer", "Invalid Calculator in fs.Pacer.SetCalculator") 64 case nil: 65 c = &logCalculator{pacer.NewDefault()} 66 default: 67 c = &logCalculator{c} 68 } 69 70 p.Pacer.SetCalculator(c) 71 } 72 73 // ModifyCalculator calls the given function with the currently configured 74 // Calculator and the Pacer lock held. 75 func (p *Pacer) ModifyCalculator(f func(pacer.Calculator)) { 76 p.Pacer.ModifyCalculator(func(c pacer.Calculator) { 77 switch _c := c.(type) { 78 case *logCalculator: 79 f(_c.Calculator) 80 default: 81 Logf("pacer", "Invalid Calculator in fs.Pacer: %t", c) 82 f(c) 83 } 84 }) 85 } 86 87 func pacerInvoker(try, retries int, f pacer.Paced) (retry bool, err error) { 88 retry, err = f() 89 if retry { 90 Debugf("pacer", "low level retry %d/%d (error %v)", try, retries, err) 91 err = fserrors.RetryError(err) 92 } 93 return 94 }