-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnowflake.go
100 lines (86 loc) · 2.21 KB
/
snowflake.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
package snowflake
import (
"fmt"
"sync"
"time"
"github.com/js179/logf"
)
const (
timestampBits = uint(41) // 时间戳占用位数
workerBits = uint(4) // 工作节点占用位数
datacenterBits = uint(6) // 数据节点占用位数
seqBits = uint(12) //序列号占用位数
timestampMax = int64(-1 ^ (-1 << timestampBits))
workerMax = int64(-1 ^ (-1 << workerBits))
datacenterMax = int64(-1 ^ (-1 << datacenterBits))
seqMax = int64(-1 ^ (-1 << seqBits))
workerShift = seqBits // 偏移量
datacenterShift = seqBits + workerBits
timestampShift = seqBits + workerBits + datacenterBits
)
type Snowflake struct {
sync.Mutex
epoch int64 // 开始日期时间戳
timestamp int64 // 时间戳
worker int64 // 工作节点id
datacenter int64 // 数据节点id
seq int64 // 序列号
}
func (s *Snowflake) SetWorker(worker int64) {
if worker > workerMax {
logf.Errorf("worker must be between 0 and %d", workerMax-1)
s.worker = 0
} else {
s.worker = worker
}
}
func (s *Snowflake) SetDatacenter(d int64) {
if d > datacenterMax {
logf.Errorf("datacenter must be between 0 and %d", workerMax-1)
s.worker = 0
} else {
s.datacenter = d
}
}
func (s *Snowflake) SetEpoch(epoch int64) {
if epoch > time.Now().UnixMilli() || epoch < 0 {
epoch = time.Now().UnixMilli()
}
s.epoch = epoch
}
func (s *Snowflake) CreateID() (int64, error) {
s.Lock()
defer s.Unlock()
now := time.Now().UnixMilli()
if now == s.timestamp {
s.seq = (s.seq + 1) & seqMax
// 当前毫秒内的seq已经全部占用,等待下一毫秒内再生成
if s.seq == 0 {
for now < s.timestamp {
now = time.Now().UnixMilli()
}
}
} else {
s.seq = 0
}
t := now - s.epoch
if t > timestampMax {
return -1, fmt.Errorf("epoch must be between 0 and %d", timestampMax-1)
}
s.timestamp = now
return (t << timestampShift) | (s.datacenter << datacenterShift) | (s.worker << workerShift) | s.seq, nil
}
var snowflake *Snowflake
func New(work, d, epoch int64) {
snowflake = &Snowflake{}
snowflake.SetWorker(work)
snowflake.SetDatacenter(d)
snowflake.SetEpoch(epoch)
}
func init() {
New(4, 6, 1687752676742)
}
func ID() int64 {
id, _ := snowflake.CreateID()
return id
}