-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathfactory.go
121 lines (99 loc) · 2.59 KB
/
factory.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package snowflake
import (
"sync"
"time"
)
var (
nanosInMilli int64 = time.Millisecond.Nanoseconds()
epoch int64 = time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano() / nanosInMilli
)
const (
defaultServerBits = 10
defaultSequenceBits = 12
)
// Default represents a default Factory suitable for unit testing; this is NOT suitable for production
// use as the ServerId is fixed at 0
var Mock = NewFactory(FactoryOptions{
ServerBits: 10,
SequenceBits: 12,
})
// Options contains the configurable options for Factory
type FactoryOptions struct {
// ServerId represents a unique value that identifies this generator instance
ServerID int64
// ServerBits represents the number of bits used to represents the server
ServerBits uint
// SequenceBits represents the number of bits in the sequence; defaults to 12
SequenceBits uint
}
func (o FactoryOptions) build() FactoryOptions {
opts := FactoryOptions{
ServerID: o.ServerID,
ServerBits: o.ServerBits,
SequenceBits: o.SequenceBits,
}
if o.ServerBits == 0 {
opts.ServerBits = defaultServerBits
}
if o.SequenceBits == 0 {
opts.SequenceBits = defaultSequenceBits
}
return opts
}
// Factory is a generator of ids using Twitter's snowflake pattern
type Factory struct {
serverID int64
serverBits uint
serverMask int64
sequence int64
sequenceBits uint
sequenceMax int64
lastTime int64
mux *sync.Mutex
}
func maxValue(bits uint) int64 {
var value int64 = 1
for i := 0; i < int(bits); i++ {
value = value * 2
}
return value
}
func mask(bits uint) int64 {
return maxValue(bits) - 1
}
// New constructs a new snowflake Factory
func NewFactory(opts FactoryOptions) *Factory {
opts = opts.build()
serverMask := mask(opts.ServerBits)
return &Factory{
serverID: opts.ServerID & serverMask,
serverBits: opts.ServerBits,
serverMask: serverMask,
sequenceBits: opts.SequenceBits,
sequenceMax: maxValue(opts.SequenceBits),
mux: &sync.Mutex{},
}
}
// IdN requests the next n ids
func (s *Factory) IdN(n int) []int64 {
s.mux.Lock()
defer s.mux.Unlock()
t := time.Now().UnixNano()/nanosInMilli - epoch
ids := make([]int64, 0, n)
for i := 0; i < n; i++ {
if t <= s.lastTime {
s.sequence = s.sequence + 1
if s.sequence == s.sequenceMax {
// sequence has reached it's maximum value, it's time to move to the next time slow
s.sequence = 0
s.lastTime++
}
} else {
s.sequence = 0
s.lastTime = t
}
id := (s.lastTime << (s.serverBits + s.sequenceBits)) | (s.sequence << s.serverBits) | s.serverID
ids = append(ids, id)
}
return ids
}