-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerator.go
128 lines (107 loc) · 2.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
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
124
125
126
127
128
package flakeidgenerator
import (
"errors"
"sync"
"time"
)
const (
TIMESTAMP_LEN = 48
SEQUENCE_LEN = 7
MACHINE_ID_LEN = 8
NANOSEC = 1e-9
MILISEC = 1e-3
)
type IdPayload struct {
Timestamp uint64
MachineId uint8
Sequence uint8
}
type IdFlakeGeneratorSetting struct {
StartTime time.Time
MachineIdGetter func() uint8
}
type IdFlakeGenerator struct {
mutex *sync.Mutex
startTime uint64
elapsedTime uint64
sequence uint8
machineId uint8
}
func NewIdFlakeGenerator(st IdFlakeGeneratorSetting) *IdFlakeGenerator {
sf := new(IdFlakeGenerator)
sf.mutex = new(sync.Mutex)
sf.sequence = 0
sf.elapsedTime = 0
if st.StartTime.After(time.Now()) {
return nil
} else if st.StartTime.IsZero() {
sf.startTime = toFlaketimestamp(time.Date(2022, 6, 23, 0, 0, 0, 0, time.UTC))
} else {
sf.startTime = toFlaketimestamp(st.StartTime)
}
if st.MachineIdGetter == nil {
sf.machineId = 1
} else {
sf.machineId = st.MachineIdGetter()
}
return sf
}
func (gen *IdFlakeGenerator) NextId() (uint64, error) {
gen.mutex.Lock()
defer gen.mutex.Unlock()
current := getElapsedTime(gen.startTime)
if gen.elapsedTime < current {
gen.elapsedTime = current
gen.sequence = 0
} else {
seqMask := uint8((1 << SEQUENCE_LEN) - 1)
gen.sequence = (gen.sequence + 1) & seqMask
if gen.sequence == 0 {
gen.elapsedTime++
overtime := gen.elapsedTime - current
time.Sleep(getSleepTime(overtime))
}
}
payload := IdPayload{
Timestamp: gen.elapsedTime,
MachineId: gen.machineId,
Sequence: gen.sequence,
}
return idFromPayload(payload)
}
func getElapsedTime(startTime uint64) uint64 {
return toFlaketimestamp(time.Now()) - startTime
}
func toFlaketimestamp(time time.Time) uint64 {
return uint64(time.UTC().UnixMilli())
}
func getSleepTime(overtime uint64) time.Duration {
return time.Duration(overtime*(MILISEC/NANOSEC)) - time.Duration(time.Now().UTC().UnixNano()%(MILISEC/NANOSEC))
}
func idFromPayload(payload IdPayload) (uint64, error) {
if payload.Timestamp > (1<<(TIMESTAMP_LEN+SEQUENCE_LEN+MACHINE_ID_LEN+1))-1 {
return 0, errors.New("OUT OF MEMORY")
}
return (0 << (TIMESTAMP_LEN + SEQUENCE_LEN + MACHINE_ID_LEN)) |
(payload.Timestamp << (SEQUENCE_LEN + MACHINE_ID_LEN)) |
uint64(payload.MachineId)<<SEQUENCE_LEN |
uint64(payload.Sequence), nil
}
func idToPayload(id uint64) IdPayload {
return IdPayload{
Timestamp: getTimestamp(id),
MachineId: getMachineId(id),
Sequence: getSequence(id),
}
}
func getTimestamp(id uint64) uint64 {
return id >> (SEQUENCE_LEN + MACHINE_ID_LEN)
}
func getMachineId(id uint64) uint8 {
mask := ((1 << MACHINE_ID_LEN) - 1) << SEQUENCE_LEN
return uint8((id & uint64(mask)) >> SEQUENCE_LEN)
}
func getSequence(id uint64) uint8 {
mask := (1 << SEQUENCE_LEN) - 1
return uint8((id & uint64(mask)))
}