-
Notifications
You must be signed in to change notification settings - Fork 60
/
token_generator.go
79 lines (64 loc) · 2.13 KB
/
token_generator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package ring
import (
"math/rand"
"sort"
"sync"
"time"
)
type TokenGenerator interface {
// GenerateTokens generates at most requestedTokensCount unique tokens, none of which clashes with
// the given allTakenTokens, representing the set of all tokens currently present in the ring.
// Generated tokens are sorted.
GenerateTokens(requestedTokensCount int, allTakenTokens []uint32) Tokens
// CanJoin checks whether the instance owning this TokenGenerator can join the set of the given instances satisfies,
// and fails if it is not possible.
CanJoin(instances map[string]InstanceDesc) error
// CanJoinEnabled returns true if the instance owning this TokenGenerator should perform the CanJoin check before
// it tries to join the ring.
CanJoinEnabled() bool
}
type RandomTokenGenerator struct {
m sync.Mutex
r *rand.Rand
}
func NewRandomTokenGenerator() *RandomTokenGenerator {
return &RandomTokenGenerator{r: rand.New(rand.NewSource(time.Now().UnixNano()))}
}
func NewRandomTokenGeneratorWithSeed(seed int64) *RandomTokenGenerator {
return &RandomTokenGenerator{r: rand.New(rand.NewSource(seed))}
}
// GenerateTokens generates at most requestedTokensCount unique random tokens, none of which clashes with
// the given allTakenTokens, representing the set of all tokens currently present in the ring.
// Generated tokens are sorted.
func (t *RandomTokenGenerator) GenerateTokens(requestedTokensCount int, allTakenTokens []uint32) Tokens {
if requestedTokensCount <= 0 {
return []uint32{}
}
used := make(map[uint32]bool, len(allTakenTokens))
for _, v := range allTakenTokens {
used[v] = true
}
tokens := make([]uint32, 0, requestedTokensCount)
for i := 0; i < requestedTokensCount; {
t.m.Lock()
candidate := t.r.Uint32()
t.m.Unlock()
if used[candidate] {
continue
}
used[candidate] = true
tokens = append(tokens, candidate)
i++
}
// Ensure returned tokens are sorted.
sort.Slice(tokens, func(i, j int) bool {
return tokens[i] < tokens[j]
})
return tokens
}
func (t *RandomTokenGenerator) CanJoin(_ map[string]InstanceDesc) error {
return nil
}
func (t *RandomTokenGenerator) CanJoinEnabled() bool {
return false
}