mirror of https://github.com/k3s-io/k3s
90 lines
3.1 KiB
Go
90 lines
3.1 KiB
Go
|
// Package jitter provides methods of transforming durations.
|
||
|
//
|
||
|
// Copyright © 2016 Trevor N. Suarez (Rican7)
|
||
|
package jitter
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
"math/rand"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// Transformation defines a function that calculates a time.Duration based on
|
||
|
// the given duration.
|
||
|
type Transformation func(duration time.Duration) time.Duration
|
||
|
|
||
|
// Full creates a Transformation that transforms a duration into a result
|
||
|
// duration in [0, n) randomly, where n is the given duration.
|
||
|
//
|
||
|
// The given generator is what is used to determine the random transformation.
|
||
|
// If a nil generator is passed, a default one will be provided.
|
||
|
//
|
||
|
// Inspired by https://www.awsarchitectureblog.com/2015/03/backoff.html
|
||
|
func Full(generator *rand.Rand) Transformation {
|
||
|
random := fallbackNewRandom(generator)
|
||
|
|
||
|
return func(duration time.Duration) time.Duration {
|
||
|
return time.Duration(random.Int63n(int64(duration)))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Equal creates a Transformation that transforms a duration into a result
|
||
|
// duration in [n/2, n) randomly, where n is the given duration.
|
||
|
//
|
||
|
// The given generator is what is used to determine the random transformation.
|
||
|
// If a nil generator is passed, a default one will be provided.
|
||
|
//
|
||
|
// Inspired by https://www.awsarchitectureblog.com/2015/03/backoff.html
|
||
|
func Equal(generator *rand.Rand) Transformation {
|
||
|
random := fallbackNewRandom(generator)
|
||
|
|
||
|
return func(duration time.Duration) time.Duration {
|
||
|
return (duration / 2) + time.Duration(random.Int63n(int64(duration))/2)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Deviation creates a Transformation that transforms a duration into a result
|
||
|
// duration that deviates from the input randomly by a given factor.
|
||
|
//
|
||
|
// The given generator is what is used to determine the random transformation.
|
||
|
// If a nil generator is passed, a default one will be provided.
|
||
|
//
|
||
|
// Inspired by https://developers.google.com/api-client-library/java/google-http-java-client/backoff
|
||
|
func Deviation(generator *rand.Rand, factor float64) Transformation {
|
||
|
random := fallbackNewRandom(generator)
|
||
|
|
||
|
return func(duration time.Duration) time.Duration {
|
||
|
min := int64(math.Floor(float64(duration) * (1 - factor)))
|
||
|
max := int64(math.Ceil(float64(duration) * (1 + factor)))
|
||
|
|
||
|
return time.Duration(random.Int63n(max-min) + min)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NormalDistribution creates a Transformation that transforms a duration into a
|
||
|
// result duration based on a normal distribution of the input and the given
|
||
|
// standard deviation.
|
||
|
//
|
||
|
// The given generator is what is used to determine the random transformation.
|
||
|
// If a nil generator is passed, a default one will be provided.
|
||
|
func NormalDistribution(generator *rand.Rand, standardDeviation float64) Transformation {
|
||
|
random := fallbackNewRandom(generator)
|
||
|
|
||
|
return func(duration time.Duration) time.Duration {
|
||
|
return time.Duration(random.NormFloat64()*standardDeviation + float64(duration))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// fallbackNewRandom returns the passed in random instance if it's not nil,
|
||
|
// and otherwise returns a new random instance seeded with the current time.
|
||
|
func fallbackNewRandom(random *rand.Rand) *rand.Rand {
|
||
|
// Return the passed in value if it's already not null
|
||
|
if nil != random {
|
||
|
return random
|
||
|
}
|
||
|
|
||
|
seed := time.Now().UnixNano()
|
||
|
|
||
|
return rand.New(rand.NewSource(seed))
|
||
|
}
|