You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ntool/nrandom/snowflake/snowflake_offset.go

183 lines
5.3 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package snowflake
import (
"sync"
"time"
)
// SnowWorkerOffset 雪花漂移算法
type SnowWorkerOffset struct {
baseTime int64 // 基础时间ms单位
workerId uint16 // 机器码
workerIdBitLength byte // 机器码位长
seqBitLength byte // 序列数位长
maxSeqNumber uint32 // 最大序列数(含)
minSeqNumber uint32 // 最小序列数(含)
topOverCostCount uint32 // 最大漂移次数(含)
timestampShift byte
currentSeqNumber uint32
lastTimeTick int64
turnBackTimeTick int64
turnBackIndex byte
isOverCost bool
overCostCountInOneTerm uint32
sync.Mutex
}
func NewSnowWorkerOffset(options *Options) *SnowWorkerOffset {
if options == nil {
options = defaultOptions
}
baseTime := options.BaseTime
if baseTime <= 0 {
baseTime = defaultOptions.BaseTime
}
workerIdBitLength := options.WorkerIdBitLength
if workerIdBitLength == 0 {
workerIdBitLength = defaultOptions.WorkerIdBitLength
}
seqBitLength := options.SeqBitLength
if seqBitLength == 0 {
seqBitLength = defaultOptions.SeqBitLength
}
// 序列数位长+机器码位长不超过22
if workerIdBitLength+seqBitLength > 22 {
workerIdBitLength = defaultOptions.WorkerIdBitLength
if workerIdBitLength+seqBitLength > 22 {
seqBitLength = defaultOptions.SeqBitLength
}
}
minSeqNumber := options.MinSeqNumber
if minSeqNumber < 5 {
minSeqNumber = defaultOptions.MinSeqNumber
}
maxSeqNumber := options.MaxSeqNumber
if maxSeqNumber <= 0 {
maxSeqNumber = (1 << seqBitLength) - 1
}
topOverCostCount := options.TopOverCostCount
if topOverCostCount == 0 {
topOverCostCount = defaultOptions.TopOverCostCount
}
return &SnowWorkerOffset{
baseTime: baseTime,
workerId: options.WorkerId,
workerIdBitLength: workerIdBitLength,
seqBitLength: seqBitLength,
maxSeqNumber: maxSeqNumber,
minSeqNumber: minSeqNumber,
topOverCostCount: topOverCostCount,
timestampShift: workerIdBitLength + seqBitLength,
currentSeqNumber: minSeqNumber,
lastTimeTick: 0,
turnBackTimeTick: 0,
turnBackIndex: 0,
isOverCost: false,
overCostCountInOneTerm: 0,
}
}
func (s *SnowWorkerOffset) NextID() int64 {
s.Lock()
defer s.Unlock()
if s.isOverCost {
return s.nextOverCost()
} else {
return s.nextNormal()
}
}
func (s *SnowWorkerOffset) nextOverCost() int64 {
currentTimeTick := s.currentTimeTick()
if currentTimeTick > s.lastTimeTick {
s.lastTimeTick = currentTimeTick
s.currentSeqNumber = s.minSeqNumber
s.isOverCost = false
s.overCostCountInOneTerm = 0
return s.calcId(s.lastTimeTick)
}
if s.overCostCountInOneTerm >= s.topOverCostCount {
s.lastTimeTick = s.nextTimeTick()
s.currentSeqNumber = s.minSeqNumber
s.isOverCost = false
s.overCostCountInOneTerm = 0
return s.calcId(s.lastTimeTick)
}
if s.currentSeqNumber > s.maxSeqNumber {
s.lastTimeTick++
s.currentSeqNumber = s.minSeqNumber
s.isOverCost = true
s.overCostCountInOneTerm++
return s.calcId(s.lastTimeTick)
}
return s.calcId(s.lastTimeTick)
}
func (s *SnowWorkerOffset) nextNormal() int64 {
currentTimeTick := s.currentTimeTick()
if currentTimeTick < s.lastTimeTick {
if s.turnBackTimeTick < 1 {
s.turnBackTimeTick = s.lastTimeTick - 1
s.turnBackIndex++
// 每毫秒序列数的前5位是预留位0用于手工新值1-4是时间回拨次序
// 支持4次回拨次序避免回拨重叠导致ID重复可无限次回拨次序循环使用
if s.turnBackIndex > 4 {
s.turnBackIndex = 1
}
}
return s.calcTurnBackId(s.turnBackTimeTick)
}
// 时间追平时turnBackTimeTick 清零
if s.turnBackTimeTick > 0 {
s.turnBackTimeTick = 0
}
if currentTimeTick > s.lastTimeTick {
s.lastTimeTick = currentTimeTick
s.currentSeqNumber = s.minSeqNumber
return s.calcId(s.lastTimeTick)
}
if s.currentSeqNumber > s.maxSeqNumber {
s.lastTimeTick++
s.currentSeqNumber = s.minSeqNumber
s.isOverCost = true
s.overCostCountInOneTerm = 1
return s.calcId(s.lastTimeTick)
}
return s.calcId(s.lastTimeTick)
}
func (s *SnowWorkerOffset) calcId(timeTick int64) int64 {
id := timeTick<<s.timestampShift + int64(s.workerId<<s.seqBitLength) + int64(s.currentSeqNumber)
s.currentSeqNumber++
return id
}
func (s *SnowWorkerOffset) calcTurnBackId(timeTick int64) int64 {
id := timeTick<<s.timestampShift + int64(s.workerId<<s.seqBitLength) + int64(s.turnBackIndex)
s.turnBackIndex++
return id
}
func (s *SnowWorkerOffset) currentTimeTick() int64 {
return (time.Now().UnixNano() / 1e6) - s.baseTime
}
func (s *SnowWorkerOffset) nextTimeTick() int64 {
tmp := s.currentTimeTick()
for tmp <= s.lastTimeTick {
tmp = s.currentTimeTick()
}
return tmp
}