zhangqian
2023-10-13 13194e787d51e4ce07dfc35341d536fb5db7aaa3
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
package snowflake
 
import (
    "errors"
    "sync"
    "time"
)
 
const (
    CEpoch         = 1474802888000
    CWorkerIdBits  = 10 // Num of WorkerId Bits
    CSenquenceBits = 12 // Num of Sequence Bits
 
    CWorkerIdShift  = 12
    CTimeStampShift = 22
 
    CSequenceMask = 0xfff // equal as getSequenceMask()
    CMaxWorker    = 0x3ff // equal as getMaxWorkerId()
)
 
type IdWorker struct {
    workerId      int64
    lastTimeStamp int64
    sequence      int64
    maxWorkerId   int64
    lock          *sync.Mutex
}
 
func NewIdWorker(workerId int64) (iw *IdWorker, err error) {
    iw = new(IdWorker)
 
    iw.maxWorkerId = getMaxWorkerId()
 
    if workerId > iw.maxWorkerId || workerId < 0 {
        return nil, errors.New("worker not fit")
    }
    iw.workerId = workerId
    iw.lastTimeStamp = -1
    iw.sequence = 0
    iw.lock = new(sync.Mutex)
    return iw, nil
}
 
func getMaxWorkerId() int64 {
    return -1 ^ -1<<CWorkerIdBits
}
 
func getSequenceMask() int64 {
    return -1 ^ -1<<CSenquenceBits
}
 
// return in ms
func (iw *IdWorker) timeGen() int64 {
    return time.Now().UnixNano() / 1000 / 1000
}
 
func (iw *IdWorker) timeReGen(last int64) int64 {
    ts := time.Now().UnixNano() / 1000 / 1000
    for {
        if ts <= last {
            ts = iw.timeGen()
        } else {
            break
        }
    }
    return ts
}
 
func (iw *IdWorker) NextId() (ts int64, err error) {
    iw.lock.Lock()
    defer iw.lock.Unlock()
    ts = iw.timeGen()
    if ts == iw.lastTimeStamp {
        iw.sequence = (iw.sequence + 1) & CSequenceMask
        if iw.sequence == 0 {
            ts = iw.timeReGen(ts)
        }
    } else {
        iw.sequence = 0
    }
 
    if ts < iw.lastTimeStamp {
        err = errors.New("Clock moved backwards, Refuse gen id")
        return 0, err
    }
    iw.lastTimeStamp = ts
    ts = (ts-CEpoch)<<CTimeStampShift | iw.workerId<<CWorkerIdShift | iw.sequence
    return ts, nil
}
 
func ParseId(id int64) (t time.Time, ts int64, workerId int64, seq int64) {
    seq = id & CSequenceMask
    workerId = (id >> CWorkerIdShift) & CMaxWorker
    ts = (id >> CTimeStampShift) + CEpoch
    t = time.Unix(ts/1000, (ts%1000)*1000000)
    return
}
 
var idGenerater, _ = NewIdWorker(0)
 
func GenerateId() int64 {
start:
    id, err := idGenerater.NextId()
    if err != nil {
        goto start
    }
    return id
}