mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-06 17:26:52 +08:00
71 lines
1.6 KiB
Go
71 lines
1.6 KiB
Go
package idgenerator
|
|
|
|
import (
|
|
"hash/fnv"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// epoch0 is set to the twitter snowflake epoch of Nov 04 2010 01:42:54 UTC in milliseconds
|
|
// You may customize this to set a different epoch for your application.
|
|
epoch0 int64 = 1288834974657
|
|
maxSequence int64 = -1 ^ (-1 << uint64(nodeLeft))
|
|
timeLeft uint8 = 22
|
|
nodeLeft uint8 = 10
|
|
nodeMask int64 = -1 ^ (-1 << uint64(timeLeft-nodeLeft))
|
|
)
|
|
|
|
// IDGenerator generates unique uint64 ID using snowflake algorithm
|
|
type IDGenerator struct {
|
|
mu *sync.Mutex
|
|
lastStamp int64
|
|
nodeID int64
|
|
sequence int64
|
|
epoch time.Time
|
|
}
|
|
|
|
// MakeGenerator creates a new IDGenerator
|
|
func MakeGenerator(node string) *IDGenerator {
|
|
fnv64 := fnv.New64()
|
|
_, _ = fnv64.Write([]byte(node))
|
|
nodeID := int64(fnv64.Sum64()) & nodeMask
|
|
|
|
var curTime = time.Now()
|
|
epoch := curTime.Add(time.Unix(epoch0/1000, (epoch0%1000)*1000000).Sub(curTime))
|
|
|
|
return &IDGenerator{
|
|
mu: &sync.Mutex{},
|
|
lastStamp: -1,
|
|
nodeID: nodeID,
|
|
sequence: 1,
|
|
epoch: epoch,
|
|
}
|
|
}
|
|
|
|
// NextID returns next unique ID
|
|
func (w *IDGenerator) NextID() int64 {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
timestamp := time.Since(w.epoch).Nanoseconds() / 1000000
|
|
if timestamp < w.lastStamp {
|
|
log.Fatal("can not generate id")
|
|
}
|
|
if w.lastStamp == timestamp {
|
|
w.sequence = (w.sequence + 1) & maxSequence
|
|
if w.sequence == 0 {
|
|
for timestamp <= w.lastStamp {
|
|
timestamp = time.Since(w.epoch).Nanoseconds() / 1000000
|
|
}
|
|
}
|
|
} else {
|
|
w.sequence = 0
|
|
}
|
|
w.lastStamp = timestamp
|
|
id := (timestamp << timeLeft) | (w.nodeID << nodeLeft) | w.sequence
|
|
//fmt.Printf("%d %d %d\n", timestamp, w.sequence, id)
|
|
return id
|
|
}
|