-
Notifications
You must be signed in to change notification settings - Fork 0
/
fastid.go
115 lines (100 loc) · 2.89 KB
/
fastid.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
package fastid
import (
"fmt"
"sync/atomic"
"time"
)
// 日期格式
const dateLayout = "20060102"
const (
seqBits uint8 = 11 // 1毫秒内可生成的seq序号的二进制位数
userBits uint8 = 8 // user_id 二进制位数
opBits uint8 = 8 // operator_id 二进制位数
machineBits uint8 = 8 // machine_id 二进制位数
timeBits uint8 = 28 // 时间毫秒
// bit shift
userShift = seqBits
opShift = userShift + userBits
machineShift = opShift + opBits
timeShift = machineShift + machineBits
// mask
seqMask = ^(int64(-1) << seqBits)
timeMask = ^(int64(-1) << timeBits)
)
/**
+-+------------------------+---------------+---------------+---------------+---+---------------+
|0| timestamps(28 bits) | machine_id (8)| operator (8) | user_id (8) | seq (11) |
+-+------------------------+---------------+---------------+---------------+---+---------------+
*/
// FastID 分布式唯一ID
type FastID struct {
lastID int64
}
// NewFastID new
func NewFastID() *FastID {
return &FastID{}
}
// StdFastID 默认的fastID
var StdFastID = NewFastID()
// LSB last byte
func LSB(v uint) byte {
return byte(v)
}
// GetSeqFromID 从ID中获取seq
func GetSeqFromID(id int64) int64 {
return id & seqMask
}
// GetTimeFromID 从ID中获取time
func GetTimeFromID(id int64) int64 {
return (id >> timeShift) & timeMask
}
// GetMachineFromID 从ID中获取machineID
func GetMachineFromID(id int64) byte {
if id > 0 {
return byte(id >> machineShift)
}
return GetMachineByIP("127.0.0.1")
}
// GenID 生成唯一ID (格式:YYYYMMDD+ID,27位数字)
func (f *FastID) GenID(operatorID, userID uint) string {
for {
var preLastID = atomic.LoadInt64(&f.lastID)
var seq = GetSeqFromID(preLastID)
var preLastTime = GetTimeFromID(preLastID)
var machineID = GetMachineFromID(preLastID)
var tm = time.Now()
var now = todayMills(&tm)
if int64(now) != preLastTime {
seq = 1
} else if seq >= seqMask {
// wait until the next millisecond
var sleepNs = int(time.Millisecond) - tm.Nanosecond()%int(time.Millisecond)
time.Sleep(time.Duration(sleepNs))
continue
} else {
seq++
}
newID := generate(now, machineID, operatorID, userID, seq)
if atomic.CompareAndSwapInt64(&f.lastID, preLastID, newID) {
return datePrefix(&tm, newID)
}
}
}
// today millisecond
func todayMills(t *time.Time) int {
return (t.Hour()*3600+t.Minute()*60+t.Second())*1000 + t.Nanosecond()/int(time.Millisecond)
}
// 使用位运算,生成int64 id
func generate(now int, machineID byte, operatorID, userID uint, seq int64) int64 {
var p1 = seq
var p2 = int64(LSB(userID)) << userShift
var p3 = int64(LSB(operatorID)) << opShift
var p4 = int64(machineID) << machineShift
var p5 = int64(now) << timeShift
var newID = p1 | p2 | p3 | p4 | p5
return newID
}
// add date prefix
func datePrefix(t *time.Time, id int64) string {
return t.Format(dateLayout) + fmt.Sprintf("%019d", id)
}