-
Notifications
You must be signed in to change notification settings - Fork 25
/
idgen.go
123 lines (105 loc) · 3.15 KB
/
idgen.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
122
123
package sharding
import (
"math"
"sync/atomic"
"time"
)
var (
_epoch = time.Date(2010, time.January, 01, 00, 0, 0, 0, time.UTC)
DefaultIDGen = NewIDGen(41, 11, 12, _epoch)
)
type IDGen struct {
shardBits uint
seqBits uint
epoch int64 // in milliseconds
minTime time.Time
shardMask int64
seqMask int64
}
func NewIDGen(timeBits, shardBits, seqBits uint, epoch time.Time) *IDGen {
if timeBits+shardBits+seqBits != 64 {
panic("timeBits + shardBits + seqBits != 64")
}
dur := time.Duration(1) << (timeBits - 1) * time.Millisecond
return &IDGen{
shardBits: shardBits,
seqBits: seqBits,
epoch: epoch.UnixNano() / int64(time.Millisecond),
minTime: epoch.Add(-dur),
shardMask: int64(1)<<shardBits - 1,
seqMask: int64(1)<<seqBits - 1,
}
}
func (g *IDGen) NumShards() int {
return int(g.shardMask) + 1
}
// MakeId returns an id for the time. Note that you can only
// generate 4096 unique numbers per millisecond.
func (g *IDGen) MakeID(tm time.Time, shard, seq int64) int64 {
if tm.Before(g.minTime) {
return int64(math.MinInt64)
}
id := tm.UnixNano()/int64(time.Millisecond) - g.epoch
id <<= g.shardBits + g.seqBits
id |= shard << g.seqBits
id |= seq % (g.seqMask + 1)
return id
}
// MinID returns min id for the time.
func (g *IDGen) MinID(tm time.Time) int64 {
return g.MakeID(tm, 0, 0)
}
// MaxID returns max id for the time.
func (g *IDGen) MaxID(tm time.Time) int64 {
return g.MakeID(tm, g.shardMask, g.seqMask)
}
// SplitID splits id into time, shard id, and sequence id.
func (g *IDGen) SplitID(id int64) (tm time.Time, shardID int64, seqID int64) {
ms := id>>(g.shardBits+g.seqBits) + g.epoch
sec := ms / 1000
tm = time.Unix(sec, (ms-sec*1000)*int64(time.Millisecond))
shardID = (id >> g.seqBits) & g.shardMask
seqID = id & g.seqMask
return
}
//------------------------------------------------------------------------------
// IDGen generates sortable unique int64 numbers that consist of:
// - 41 bits for time in milliseconds.
// - 11 bits for shard id.
// - 12 bits for auto-incrementing sequence.
//
// As a result we can generate 4096 ids per millisecond for each of 2048 shards.
// Minimum supported time is 1975-02-28, maximum is 2044-12-31.
type ShardIDGen struct {
shard int64
seq int64
gen *IDGen
}
// NewShardIDGen returns id generator for the shard.
func NewShardIDGen(shard int64, gen *IDGen) *ShardIDGen {
if gen == nil {
gen = DefaultIDGen
}
return &ShardIDGen{
shard: shard % int64(gen.NumShards()),
gen: gen,
}
}
// NextID returns incremental id for the time. Note that you can only
// generate 4096 unique numbers per millisecond.
func (g *ShardIDGen) NextID(tm time.Time) int64 {
seq := atomic.AddInt64(&g.seq, 1) - 1
return g.gen.MakeID(tm, g.shard, seq)
}
// MinId returns min id for the time.
func (g *ShardIDGen) MinID(tm time.Time) int64 {
return g.gen.MakeID(tm, g.shard, 0)
}
// MaxId returns max id for the time.
func (g *ShardIDGen) MaxID(tm time.Time) int64 {
return g.gen.MakeID(tm, g.shard, g.gen.seqMask)
}
// SplitID splits id into time, shard id, and sequence id.
func (g *ShardIDGen) SplitID(id int64) (tm time.Time, shardID int64, seqID int64) {
return g.gen.SplitID(id)
}