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  }