-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchannel_worker.go
84 lines (68 loc) · 1.38 KB
/
channel_worker.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
package snowflake
import ()
// ChannelWorker snowflake worker implemented using golang channel
type ChannelWorker struct {
workerID int64
chanIn chan struct{}
chanOut chan struct {
id int64
err error
}
}
// NewChannelWorker create a new ChannelWorker object
func NewChannelWorker(workerID int64) (Worker, error) {
if err := checkWorkerID(workerID); err != nil {
return nil, err
}
var cw = &ChannelWorker{
workerID: workerID,
}
cw.chanIn = make(chan struct{}, 10)
cw.chanOut = make(chan struct {
id int64
err error
}, 1)
go cw.startBackground()
return cw, nil
}
// Next get next ID
func (cw *ChannelWorker) Next() (int64, error) {
cw.chanIn <- struct{}{}
var out = struct {
id int64
err error
}{}
out = <-cw.chanOut
return out.id, out.err
}
func (cw *ChannelWorker) startBackground() {
var lastSeq, lastTime = int64(-1), int64(-1)
var seq, now int64
for {
_, ok := <-cw.chanIn
if !ok {
return
}
seq, now = int64(0), nowMillis()
if lastTime > now {
cw.chanOut <- struct {
id int64
err error
}{-1, ErrTimeGoesBack}
} else if now == lastTime {
seq = sequenceMask & (lastSeq + 1)
if seq == 0 {
// reach to max sequence, wait
now = waitUntilNextMillis(now)
}
}
cw.chanOut <- struct {
id int64
err error
}{
id: combine(now, cw.workerID, seq),
err: nil,
}
lastSeq, lastTime = seq, now
}
}