-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsnowflake.go
85 lines (77 loc) · 1.97 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
package snowflake
import (
"errors"
"fmt"
"time"
"sync"
)
const (
offsetTime = int64(1)
serverBit = 7
processBit = 8
sequenceBit = 9
maxServerId = -1 ^ (-1 << serverBit)
maxProcessId = -1 ^ (-1 << processBit)
maxSequenceId = -1 ^ (-1 << sequenceBit)
offsetTimeShift = serverBit + processBit + sequenceBit
serverShift = processBit + sequenceBit
processShift = sequenceBit
sequenceMask = maxSequenceId
)
type ProcessNode struct {
sequence int64
lastTime int64
serverId int64
processId int64
offsetTime int64
mutex sync.Mutex
}
func NewProcessWork(ServerId int64, ProcessId int64) (*ProcessNode, error) {
if ServerId > maxServerId || ServerId < 0 {
fmt.Sprintf("Server Id must be less %d and greater 0", maxServerId)
return nil, errors.New("Server Id error")
}
if ProcessId > maxProcessId || ProcessId < 0 {
fmt.Sprintf("Process Id must be less %d and greater 0", maxProcessId)
return nil, errors.New("Process Id error")
}
processNode := &ProcessNode{}
processNode.sequence = 0
processNode.lastTime = -1
processNode.serverId = ServerId
processNode.processId = ProcessId
processNode.offsetTime = offsetTime
processNode.mutex = sync.Mutex{}
return processNode, nil
}
func genTime() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}
func tilNextMillis(lastTime int64) int64 {
time := genTime()
for time <= lastTime {
time = genTime()
}
return time
}
func (id *ProcessNode) Id() (int64, error) {
id.mutex.Lock()
defer id.mutex.Unlock()
return id.create()
}
func (id *ProcessNode) create() (int64, error) {
time := genTime()
if time < id.lastTime {
return 0, errors.New("local time backwards, please check it")
}
if id.lastTime == time {
id.sequence = (id.sequence + 1) & sequenceMask
if id.sequence == 0 {
time = tilNextMillis(id.lastTime)
}
} else {
id.sequence = 0
}
id.lastTime = time
return ((time - id.offsetTime) << offsetTimeShift) | (id.serverId << serverShift) | (id.processId << processShift) | id.sequence, nil
}