-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgenerator.go
92 lines (74 loc) · 1.77 KB
/
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
80
81
82
83
84
85
86
87
88
89
90
91
92
package ksuid
import (
"time"
"sync/atomic"
)
// A Generator rep
type Generator interface {
Next() KSUID
}
// AsyncGenerator optimizes for reduced allocations and comparisons by a background timer to
// Reset the sequence and change the timestamp each second.
// Note: This generator must be started with Run()
type AsyncGenerator struct {
// The function used to partition KSUIDs
Partitioner PartitionFunc
clk *time.Ticker
ts time.Time
seq uint32
}
// StandardGenerator runs without goroutines or background tickers.
type StandardGenerator struct {
Partitioner PartitionFunc
ts time.Time
seq uint32
}
var defaultGenerator = StandardGenerator{
Partitioner: NilPartitioner,
}
// Next will get the next KSUID from the package-wide default generator.
func Next() KSUID {
return defaultGenerator.Next()
}
// SetPartitioner sets the PartitionFunc for the package-wide default generator.
func SetPartitioner(p PartitionFunc) {
defaultGenerator.Partitioner = p
}
func (g *StandardGenerator) Next() KSUID {
t := time.Now().Truncate(time.Second)
if t.After(g.ts) {
atomic.StoreUint32(&g.seq, 0)
g.ts = t
}
seq := atomic.LoadUint32(&g.seq)
atomic.AddUint32(&g.seq, 1)
return KSUID{
T: t,
Seq: seq,
Partition: g.Partitioner(),
}
}
func NewAsyncGenerator() *AsyncGenerator {
return &AsyncGenerator{
clk: time.NewTicker(time.Second),
Partitioner: NilPartitioner,
}
}
// Run will start the generator's background sequence.
func (g *AsyncGenerator) Run() {
for {
t := <-g.clk.C
g.ts = t.Truncate(time.Second)
atomic.StoreUint32(&g.seq, 0)
}
}
// Next gets the next KSUID from the generator
func (g *AsyncGenerator) Next() KSUID {
s := atomic.LoadUint32(&g.seq)
atomic.AddUint32(&g.seq, 1)
return KSUID{
Partition: g.Partitioner(),
Seq: s,
T: g.ts,
}
}