Initial Golang version
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var EPOCH_TIME time.Time = time.Unix(0, 1609459200000*int64(time.Millisecond))
|
||||
var TIME_MASK uint64 = 0x1FFFFFFFFFF
|
||||
|
||||
var tooManyRequests = errors.New("Too many requests in the current ms")
|
||||
var incorrectSystemTime = errors.New("The current time is less than the last generated time! Check the system time.")
|
||||
|
||||
type Generator struct {
|
||||
LastGeneratedTime time.Duration
|
||||
Counter uint64
|
||||
LastCounterRollover time.Duration
|
||||
WorkerID uint64
|
||||
}
|
||||
|
||||
func (g *Generator) GenerateSnowflake() (uint64, error) {
|
||||
time := time.Since(EPOCH_TIME)
|
||||
if time < g.LastGeneratedTime {
|
||||
return 0, incorrectSystemTime
|
||||
}
|
||||
if g.Counter == 4095 {
|
||||
if g.LastCounterRollover >= time {
|
||||
return 0, tooManyRequests
|
||||
}
|
||||
g.LastCounterRollover = time
|
||||
g.Counter = 0
|
||||
} else {
|
||||
g.Counter += 1
|
||||
}
|
||||
g.LastGeneratedTime = time
|
||||
return (((uint64(time.Milliseconds()) & TIME_MASK) << 22) + g.WorkerID + g.Counter), nil
|
||||
}
|
||||
|
||||
func CreateGenerator(workerID uint64) (*Generator, error) {
|
||||
if workerID <= 0 {
|
||||
return nil, errors.New("Worker ID must be greater than 0")
|
||||
}
|
||||
return &Generator{
|
||||
LastGeneratedTime: time.Since(EPOCH_TIME),
|
||||
Counter: 0,
|
||||
LastCounterRollover: time.Since(EPOCH_TIME),
|
||||
WorkerID: workerID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *Generator) Run(request chan chan uint64) {
|
||||
for output := range request {
|
||||
id, err := g.GenerateSnowflake()
|
||||
if err != nil {
|
||||
if err == tooManyRequests {
|
||||
time.Sleep(time.Millisecond)
|
||||
continue
|
||||
} else if err == incorrectSystemTime {
|
||||
panic("System time is incorrect")
|
||||
}
|
||||
}
|
||||
output <- id
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user