github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/tikv/backoff.go (about)

     1  // Copyright 2016 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package tikv
    15  
    16  import (
    17  	"math"
    18  	"math/rand"
    19  	"time"
    20  
    21  	"github.com/insionng/yougam/libraries/juju/errors"
    22  )
    23  
    24  const (
    25  	// NoJitter makes the backoff sequence strict exponential.
    26  	NoJitter = 1 + iota
    27  	// FullJitter applies random factors to strict exponential.
    28  	FullJitter
    29  	// EqualJitter is also randomized, but prevents very short sleeps.
    30  	EqualJitter
    31  	// DecorrJitter increases the maximum jitter based on the last random value.
    32  	DecorrJitter
    33  )
    34  
    35  // NewBackoff creates a backoff func which implements exponential backoff with
    36  // optional jitters.
    37  // See: http://www.awsarchitectureblog.com/2015/03/backoff.html
    38  func NewBackoff(retry, base, cap, jitter int) func() error {
    39  	attempts := 0
    40  	totalSleep := 0
    41  	lastSleep := base
    42  	return func() error {
    43  		if attempts >= retry {
    44  			return errors.Errorf("still fail after %d retries, total sleep %dms", attempts, totalSleep)
    45  		}
    46  		var sleep int
    47  		switch jitter {
    48  		case NoJitter:
    49  			sleep = expo(base, cap, attempts)
    50  		case FullJitter:
    51  			v := expo(base, cap, attempts)
    52  			sleep = rand.Intn(v)
    53  		case EqualJitter:
    54  			v := expo(base, cap, attempts)
    55  			sleep = v/2 + rand.Intn(v/2)
    56  		case DecorrJitter:
    57  			sleep = int(math.Min(float64(cap), float64(base+rand.Intn(lastSleep*3-base))))
    58  		}
    59  		time.Sleep(time.Duration(sleep) * time.Millisecond)
    60  
    61  		attempts++
    62  		totalSleep += sleep
    63  		lastSleep = sleep
    64  		return nil
    65  	}
    66  }
    67  
    68  func expo(base, cap, n int) int {
    69  	return int(math.Min(float64(cap), float64(base)*math.Pow(2.0, float64(n))))
    70  }