Use consul/lib's RateScaledInterval

This commit is contained in:
Sean Chittenden 2016-05-03 00:06:59 -07:00
parent 26c9110e82
commit e0e7d94450
No known key found for this signature in database
GPG Key ID: 4EBC9DC16C2E5E16
7 changed files with 125 additions and 35 deletions

View File

@ -4,6 +4,7 @@ import (
"time"
"github.com/armon/go-metrics"
"github.com/hashicorp/consul/lib"
"github.com/hashicorp/nomad/nomad/structs"
)
@ -49,8 +50,7 @@ func (s *Server) resetHeartbeatTimer(id string) (time.Duration, error) {
// Compute the target TTL value
n := len(s.heartbeatTimers)
ttl := rateScaledInterval(s.config.MaxHeartbeatsPerSecond,
s.config.MinHeartbeatTTL, n)
ttl := lib.RateScaledInterval(s.config.MaxHeartbeatsPerSecond, s.config.MinHeartbeatTTL, n)
ttl += randomStagger(ttl)
// Reset the TTL

View File

@ -122,16 +122,6 @@ func maxUint64(a, b uint64) uint64 {
return b
}
// rateScaledInterval is used to choose an interval to perform an action in order
// to target an aggregate number of actions per second across the whole cluster.
func rateScaledInterval(rate float64, min time.Duration, n int) time.Duration {
interval := time.Duration(float64(time.Second) * float64(n) / rate)
if interval < min {
return min
}
return interval
}
// seedRandom seeds the global random variable using a cryptographically random
// seed. It returns an error if determing the random seed fails.
func seedRandom() error {

View File

@ -98,26 +98,3 @@ func TestMaxUint64(t *testing.T) {
t.Fatalf("bad")
}
}
func TestRateScaledInterval(t *testing.T) {
min := 1 * time.Second
rate := 200.0
if v := rateScaledInterval(rate, min, 0); v != min {
t.Fatalf("Bad: %v", v)
}
if v := rateScaledInterval(rate, min, 100); v != min {
t.Fatalf("Bad: %v", v)
}
if v := rateScaledInterval(rate, min, 200); v != 1*time.Second {
t.Fatalf("Bad: %v", v)
}
if v := rateScaledInterval(rate, min, 1000); v != 5*time.Second {
t.Fatalf("Bad: %v", v)
}
if v := rateScaledInterval(rate, min, 5000); v != 25*time.Second {
t.Fatalf("Bad: %v", v)
}
if v := rateScaledInterval(rate, min, 10000); v != 50*time.Second {
t.Fatalf("Bad: %v", v)
}
}

56
vendor/github.com/hashicorp/consul/lib/cluster.go generated vendored Normal file
View File

@ -0,0 +1,56 @@
package lib
import (
"math/rand"
"time"
)
// DurationMinusBuffer returns a duration, minus a buffer and jitter
// subtracted from the duration. This function is used primarily for
// servicing Consul TTL Checks in advance of the TTL.
func DurationMinusBuffer(intv time.Duration, buffer time.Duration, jitter int64) time.Duration {
d := intv - buffer
if jitter == 0 {
d -= RandomStagger(d)
} else {
d -= RandomStagger(time.Duration(int64(d) / jitter))
}
return d
}
// DurationMinusBufferDomain returns the domain of valid durations from a
// call to DurationMinusBuffer. This function is used to check user
// specified input values to DurationMinusBuffer.
func DurationMinusBufferDomain(intv time.Duration, buffer time.Duration, jitter int64) (min time.Duration, max time.Duration) {
max = intv - buffer
if jitter == 0 {
min = max
} else {
min = max - time.Duration(int64(max)/jitter)
}
return min, max
}
// Returns a random stagger interval between 0 and the duration
func RandomStagger(intv time.Duration) time.Duration {
if intv == 0 {
return 0
}
return time.Duration(uint64(rand.Int63()) % uint64(intv))
}
// RateScaledInterval is used to choose an interval to perform an action in
// order to target an aggregate number of actions per second across the whole
// cluster.
func RateScaledInterval(rate float64, min time.Duration, n int) time.Duration {
const minRate = 1 / 86400 // 1/(1 * time.Day)
if rate <= minRate {
return min
}
interval := time.Duration(float64(time.Second) * float64(n) / rate)
if interval < min {
return min
}
return interval
}

22
vendor/github.com/hashicorp/consul/lib/math.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
package lib
func AbsInt(a int) int {
if a > 0 {
return a
}
return a * -1
}
func MaxInt(a, b int) int {
if a > b {
return a
}
return b
}
func MinInt(a, b int) int {
if a > b {
return b
}
return a
}

34
vendor/github.com/hashicorp/consul/lib/rand.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
package lib
import (
crand "crypto/rand"
"math"
"math/big"
"math/rand"
"sync"
"time"
)
var (
once sync.Once
// SeededSecurely is set to true if a cryptographically secure seed
// was used to initialize rand. When false, the start time is used
// as a seed.
SeededSecurely bool
)
// SeedMathRand provides weak, but guaranteed seeding, which is better than
// running with Go's default seed of 1. A call to SeedMathRand() is expected
// to be called via init(), but never a second time.
func SeedMathRand() {
once.Do(func() {
n, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
if err != nil {
rand.Seed(time.Now().UTC().UnixNano())
return
}
rand.Seed(n.Int64())
SeededSecurely = true
})
}

11
vendor/github.com/hashicorp/consul/lib/string.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
package lib
// StrContains checks if a list contains a string
func StrContains(l []string, s string) bool {
for _, v := range l {
if v == s {
return true
}
}
return false
}