func (d *nullDelayer) delay() time.Duration {
	return time.Duration(0)
}
delay applies no delay.
package swim
import (
	"math"
	"math/rand"
	"time"
	"github.com/uber-common/bark"
	"github.com/uber/ringpop-go/logging"
	"github.com/uber/ringpop-go/util"
)
const (
	defaultInitial = 100 * time.Millisecond
	defaultMax     = 60 * time.Second
)
var delayerRand = rand.New(rand.NewSource(time.Now().UnixNano()))
var defaultRandomizer = delayerRand.Intn
var defaultSleeper = time.Sleep
var noDelay = time.Duration(0)
type joinDelayer interface {
	delay() time.Duration
}
type delayRandomizer func(int) int
type delaySleeper func(time.Duration)
type delayOpts struct {
	initial    time.Duration
	max        time.Duration
	randomizer delayRandomizer
	sleeper    delaySleeper
}
func newDelayOpts() *delayOpts {
	return &delayOpts{
		initial:    defaultInitial,
		max:        defaultMax,
		randomizer: defaultRandomizer,
		sleeper:    defaultSleeper,
	}
}
type exponentialDelayer struct {
	logger bark.Logger
	initialDelay time.Duration
	maxDelay time.Duration
	maxDelayReached bool
	nextDelayMin float64
	randomizer delayRandomizer
	sleeper delaySleeper
	numDelays uint
}
func newExponentialDelayer(joiner string, opts *delayOpts) (*exponentialDelayer, error) {
	if opts == nil {
		opts = newDelayOpts()
	}
	randomizer := opts.randomizer
	if randomizer == nil {
		randomizer = defaultRandomizer
	}
	sleeper := opts.sleeper
	if sleeper == nil {
		sleeper = defaultSleeper
	}
	return &exponentialDelayer{
		logger:          logging.Logger("join").WithField("local", joiner),
		initialDelay:    opts.initial,
		nextDelayMin:    0,
		maxDelayReached: false,
		maxDelay:        opts.max,
		randomizer:      randomizer,
		sleeper:         sleeper,
		numDelays:       0,
	}, nil
}
func (d *exponentialDelayer) delay() time.Duration {
	initialDelayMs := float64(util.MS(d.initialDelay))
	maxDelayMs := float64(util.MS(d.maxDelay))
	uncappedDelay := initialDelayMs * math.Pow(2, float64(d.numDelays))
	cappedDelay := math.Min(maxDelayMs, uncappedDelay)
	var jitteredDelay int
	if cappedDelay == d.nextDelayMin {
		jitteredDelay = int(cappedDelay)
	} else {
		jitteredDelay = d.randomizer(int(cappedDelay-d.nextDelayMin)) + int(d.nextDelayMin)
	}
	if uncappedDelay >= maxDelayMs && d.maxDelayReached == false {
		d.logger.WithFields(bark.Fields{
			"numDelays":     d.numDelays,
			"initialDelay":  d.initialDelay,
			"minDelay":      d.nextDelayMin,
			"maxDelay":      d.maxDelay,
			"uncappedDelay": uncappedDelay,
			"cappedDelay":   cappedDelay,
			"jitteredDelay": jitteredDelay,
		}).Warn("ringpop join attempt delay reached max")
		d.maxDelayReached = true
	}
	d.nextDelayMin = cappedDelay
	sleepDuration := time.Duration(jitteredDelay) * time.Millisecond
	d.sleeper(sleepDuration)
	d.numDelays++
	return sleepDuration
}
type nullDelayer struct{}