forked from TrueCloudLab/rclone
Add Attack constant to pacer
This commit is contained in:
parent
874a64e5f6
commit
0166544319
2 changed files with 81 additions and 7 deletions
|
@ -15,6 +15,7 @@ type Pacer struct {
|
||||||
minSleep time.Duration // minimum sleep time
|
minSleep time.Duration // minimum sleep time
|
||||||
maxSleep time.Duration // maximum sleep time
|
maxSleep time.Duration // maximum sleep time
|
||||||
decayConstant uint // decay constant
|
decayConstant uint // decay constant
|
||||||
|
attackConstant uint // attack constant
|
||||||
pacer chan struct{} // To pace the operations
|
pacer chan struct{} // To pace the operations
|
||||||
sleepTime time.Duration // Time to sleep for each transaction
|
sleepTime time.Duration // Time to sleep for each transaction
|
||||||
retries int // Max number of retries
|
retries int // Max number of retries
|
||||||
|
@ -58,11 +59,12 @@ type Paced func() (bool, error)
|
||||||
// New returns a Pacer with sensible defaults
|
// New returns a Pacer with sensible defaults
|
||||||
func New() *Pacer {
|
func New() *Pacer {
|
||||||
p := &Pacer{
|
p := &Pacer{
|
||||||
minSleep: 10 * time.Millisecond,
|
minSleep: 10 * time.Millisecond,
|
||||||
maxSleep: 2 * time.Second,
|
maxSleep: 2 * time.Second,
|
||||||
decayConstant: 2,
|
decayConstant: 2,
|
||||||
retries: fs.Config.LowLevelRetries,
|
attackConstant: 1,
|
||||||
pacer: make(chan struct{}, 1),
|
retries: fs.Config.LowLevelRetries,
|
||||||
|
pacer: make(chan struct{}, 1),
|
||||||
}
|
}
|
||||||
p.sleepTime = p.minSleep
|
p.sleepTime = p.minSleep
|
||||||
p.SetPacer(DefaultPacer)
|
p.SetPacer(DefaultPacer)
|
||||||
|
@ -116,7 +118,7 @@ func (p *Pacer) SetMaxConnections(n int) *Pacer {
|
||||||
// This is the speed the time falls back to the minimum after errors
|
// This is the speed the time falls back to the minimum after errors
|
||||||
// have occurred.
|
// have occurred.
|
||||||
//
|
//
|
||||||
// bigger for slower decay, exponential
|
// bigger for slower decay, exponential. 1 is halve, 0 is go straight to minimum
|
||||||
func (p *Pacer) SetDecayConstant(decay uint) *Pacer {
|
func (p *Pacer) SetDecayConstant(decay uint) *Pacer {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
@ -124,6 +126,19 @@ func (p *Pacer) SetDecayConstant(decay uint) *Pacer {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetAttackConstant sets the attack constant for the pacer
|
||||||
|
//
|
||||||
|
// This is the speed the time grows from the minimum after errors have
|
||||||
|
// occurred.
|
||||||
|
//
|
||||||
|
// bigger for slower attack, 1 is double, 0 is go straight to maximum
|
||||||
|
func (p *Pacer) SetAttackConstant(attack uint) *Pacer {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
p.attackConstant = attack
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// SetRetries sets the max number of tries for Call
|
// SetRetries sets the max number of tries for Call
|
||||||
func (p *Pacer) SetRetries(retries int) *Pacer {
|
func (p *Pacer) SetRetries(retries int) *Pacer {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
|
@ -185,7 +200,11 @@ func (p *Pacer) beginCall() {
|
||||||
func (p *Pacer) defaultPacer(retry bool) {
|
func (p *Pacer) defaultPacer(retry bool) {
|
||||||
oldSleepTime := p.sleepTime
|
oldSleepTime := p.sleepTime
|
||||||
if retry {
|
if retry {
|
||||||
p.sleepTime *= 2
|
if p.attackConstant == 0 {
|
||||||
|
p.sleepTime = p.maxSleep
|
||||||
|
} else {
|
||||||
|
p.sleepTime = (p.sleepTime << p.attackConstant) / ((1 << p.attackConstant) - 1)
|
||||||
|
}
|
||||||
if p.sleepTime > p.maxSleep {
|
if p.sleepTime > p.maxSleep {
|
||||||
p.sleepTime = p.maxSleep
|
p.sleepTime = p.maxSleep
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ func TestNew(t *testing.T) {
|
||||||
if p.decayConstant != 2 {
|
if p.decayConstant != 2 {
|
||||||
t.Errorf("decayConstant")
|
t.Errorf("decayConstant")
|
||||||
}
|
}
|
||||||
|
if p.attackConstant != 1 {
|
||||||
|
t.Errorf("attackConstant")
|
||||||
|
}
|
||||||
if cap(p.pacer) != 1 {
|
if cap(p.pacer) != 1 {
|
||||||
t.Errorf("pacer 1")
|
t.Errorf("pacer 1")
|
||||||
}
|
}
|
||||||
|
@ -85,6 +88,58 @@ func TestSetDecayConstant(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecay(t *testing.T) {
|
||||||
|
p := New().SetMinSleep(time.Microsecond).SetPacer(DefaultPacer).SetMaxSleep(time.Second)
|
||||||
|
for _, test := range []struct {
|
||||||
|
in time.Duration
|
||||||
|
attackConstant uint
|
||||||
|
want time.Duration
|
||||||
|
}{
|
||||||
|
{8 * time.Millisecond, 1, 4 * time.Millisecond},
|
||||||
|
{1 * time.Millisecond, 0, time.Microsecond},
|
||||||
|
{1 * time.Millisecond, 2, (3 * time.Millisecond) / 4},
|
||||||
|
{1 * time.Millisecond, 3, (7 * time.Millisecond) / 8},
|
||||||
|
} {
|
||||||
|
p.sleepTime = test.in
|
||||||
|
p.SetDecayConstant(test.attackConstant)
|
||||||
|
p.defaultPacer(false)
|
||||||
|
got := p.sleepTime
|
||||||
|
if got != test.want {
|
||||||
|
t.Errorf("bad sleep want %v got %v", test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetAttackConstant(t *testing.T) {
|
||||||
|
p := New().SetAttackConstant(19)
|
||||||
|
if p.attackConstant != 19 {
|
||||||
|
t.Errorf("didn't set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttack(t *testing.T) {
|
||||||
|
p := New().SetMinSleep(time.Microsecond).SetPacer(DefaultPacer).SetMaxSleep(time.Second)
|
||||||
|
for _, test := range []struct {
|
||||||
|
in time.Duration
|
||||||
|
attackConstant uint
|
||||||
|
want time.Duration
|
||||||
|
}{
|
||||||
|
{1 * time.Millisecond, 1, 2 * time.Millisecond},
|
||||||
|
{1 * time.Millisecond, 0, time.Second},
|
||||||
|
{1 * time.Millisecond, 2, (4 * time.Millisecond) / 3},
|
||||||
|
{1 * time.Millisecond, 3, (8 * time.Millisecond) / 7},
|
||||||
|
} {
|
||||||
|
p.sleepTime = test.in
|
||||||
|
p.SetAttackConstant(test.attackConstant)
|
||||||
|
p.defaultPacer(true)
|
||||||
|
got := p.sleepTime
|
||||||
|
if got != test.want {
|
||||||
|
t.Errorf("bad sleep want %v got %v", test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestSetRetries(t *testing.T) {
|
func TestSetRetries(t *testing.T) {
|
||||||
p := New().SetRetries(18)
|
p := New().SetRetries(18)
|
||||||
if p.retries != 18 {
|
if p.retries != 18 {
|
||||||
|
|
Loading…
Reference in a new issue