-
Notifications
You must be signed in to change notification settings - Fork 1
/
guid.go
69 lines (61 loc) · 1.34 KB
/
guid.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
package guid
import (
"crypto/rand"
"math/big"
"os"
"strconv"
"sync/atomic"
"time"
)
const logIdLen = 64
const timestampLen = 32
const svrIdLen = 13
const reverseLen = 3
const seqLen = logIdLen - timestampLen - svrIdLen - reverseLen
const seqMask uint64 = (1 << seqLen) - 1
type Uint64GUIDGenerator struct {
seq uint64
_padding0 [56]byte
svrId uint64
_padding1 [56]byte
svrIdMask uint64
_padding2 [56]byte
reverseFlag uint64
_padding3 [56]byte
}
func getReverseFlag() uint64 {
flag := os.Getenv("REVERSE_FLAG")
if len(flag) == 0 {
return 0
}
flagVal, err := strconv.Atoi(flag)
if err == nil {
return 0
}
return uint64(flagVal & ((1 << reverseLen) - 1))
}
func getSvrId() uint64 {
svrId, _ := rand.Int(rand.Reader, big.NewInt(int64(1<<svrIdLen)))
return svrId.Uint64()
}
func NewGuidGenerator() *Uint64GUIDGenerator {
g := &Uint64GUIDGenerator{}
g.svrId = getSvrId()
g.svrIdMask = g.svrId << (reverseLen + seqLen)
g.reverseFlag = getReverseFlag()
return g
}
func (g *Uint64GUIDGenerator) GenGUID() uint64 {
return (uint64(time.Now().Unix()) << (logIdLen - timestampLen)) |
g.svrIdMask |
g.reverseFlag |
g.cycleSeq()
}
func (g *Uint64GUIDGenerator) cycleSeq() uint64 {
for {
cur := atomic.LoadUint64(&g.seq)
if atomic.CompareAndSwapUint64(&g.seq, cur, (cur+1)&seqMask) {
return cur
}
}
}