@@ -22,7 +22,7 @@ namespace Yitter.IdGenerator | |||||
public virtual short Method { get; set; } = 1; | public virtual short Method { get; set; } = 1; | ||||
/// <summary> | /// <summary> | ||||
/// 开始时间(UTC格式) | |||||
/// 基础时间(UTC格式) | |||||
/// 不能超过当前系统时间 | /// 不能超过当前系统时间 | ||||
/// </summary> | /// </summary> | ||||
public virtual DateTime BaseTime { get; set; } = new DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc); | public virtual DateTime BaseTime { get; set; } = new DateTime(2020, 2, 20, 2, 20, 2, 20, DateTimeKind.Utc); |
@@ -1,4 +1,22 @@ | |||||
# idgenerator | # idgenerator | ||||
something is going on. | |||||
## Go环境 | |||||
1.go 1.16 | |||||
2. 默认采用GOROOT方式编译,你可修改为Go-Modules | |||||
## Go代码示例 | |||||
``` | |||||
var yid = idgen.YitIdHelper{} | |||||
fmt.Println(yid.NextId()) | |||||
// 方法二:自定义参数 | |||||
var options = contract.NewIdGeneratorOptions(1) | |||||
//options.WorkerIdBitLength = 6 | |||||
//options.SeqBitLength = 6 | |||||
//options.TopOverCostCount = 2000 | |||||
//options.BaseTime = time.Date(2020, 2, 20, 2, 20, 2, 20, time.UTC).UnixNano() / 1e6 | |||||
yid.SetIdGenerator(options) | |||||
``` | |||||
@@ -0,0 +1,36 @@ | |||||
package main | |||||
import ( | |||||
"../yitidgen/contract" | |||||
"../yitidgen/idgen" | |||||
"fmt" | |||||
"time" | |||||
) | |||||
func main() { | |||||
// 方法一:直接采用默认方法生成一个Id | |||||
var yid = idgen.YitIdHelper{} | |||||
fmt.Println(yid.NextId()) | |||||
// 方法二:自定义参数 | |||||
var options = contract.NewIdGeneratorOptions(1) | |||||
//options.WorkerIdBitLength = 6 | |||||
//options.SeqBitLength = 6 | |||||
//options.TopOverCostCount = 2000 | |||||
//options.BaseTime = time.Date(2020, 2, 20, 2, 20, 2, 20, time.UTC).UnixNano() / 1e6 | |||||
yid.SetIdGenerator(options) | |||||
var times = 50000 | |||||
for ; ; { | |||||
var begin = time.Now().UnixNano() / 1e6 | |||||
for i := 0; i < times; i++ { | |||||
yid.NextId() | |||||
} | |||||
var end = time.Now().UnixNano() / 1e6 | |||||
fmt.Println(end - begin) | |||||
time.Sleep(time.Duration(1000) * time.Millisecond) | |||||
} | |||||
} |
@@ -0,0 +1,5 @@ | |||||
package contract | |||||
type IIdGenerator interface { | |||||
NewLong() uint64 | |||||
} |
@@ -0,0 +1,5 @@ | |||||
package contract | |||||
type ISnowWorker interface { | |||||
NextId() uint64 | |||||
} |
@@ -0,0 +1,12 @@ | |||||
package contract | |||||
import "fmt" | |||||
type IdGeneratorException struct { | |||||
message string | |||||
error error | |||||
} | |||||
func (e IdGeneratorException) IdGeneratorException(message ...interface{}) { | |||||
fmt.Println(message) | |||||
} |
@@ -0,0 +1,25 @@ | |||||
package contract | |||||
type IdGeneratorOptions struct { | |||||
Method uint16 // 雪花计算方法,(1-漂移算法|2-传统算法),默认1 | |||||
BaseTime int64 // 基础时间,不能超过当前系统时间 | |||||
WorkerId uint16 // 机器码,与 WorkerIdBitLength 有关系 | |||||
WorkerIdBitLength byte // 机器码位长,范围:1-21(要求:序列数位长+机器码位长不超过22) | |||||
SeqBitLength byte // 序列数位长,范围:2-21(要求:序列数位长+机器码位长不超过22) | |||||
MaxSeqNumber uint32 // 最大序列数(含),(由SeqBitLength计算的最大值) | |||||
MinSeqNumber uint32 // 最小序列数(含),默认5,不小于1,不大于MaxSeqNumber | |||||
TopOverCostCount uint // 最大漂移次数(含),默认2000,推荐范围500-10000(与计算能力有关) | |||||
} | |||||
func NewIdGeneratorOptions(workerId uint16) *IdGeneratorOptions { | |||||
return &IdGeneratorOptions{ | |||||
Method: 1, | |||||
WorkerId: workerId, | |||||
BaseTime: 1582136402000, | |||||
WorkerIdBitLength: 6, | |||||
SeqBitLength: 6, | |||||
MaxSeqNumber: 0, | |||||
MinSeqNumber: 5, | |||||
TopOverCostCount: 2000, | |||||
} | |||||
} |
@@ -0,0 +1,19 @@ | |||||
package contract | |||||
type OverCostActionArg struct { | |||||
ActionType int | |||||
TimeTick int64 | |||||
WorkerId int64 | |||||
OverCostCountInOneTerm int | |||||
GenCountInOneTerm int | |||||
TermIndex int | |||||
} | |||||
func (ocaa OverCostActionArg) OverCostActionArg(workerId int64, timeTick int64, actionType int, overCostCountInOneTerm int, genCountWhenOverCost int, index int) { | |||||
ocaa.ActionType = actionType | |||||
ocaa.TimeTick = timeTick | |||||
ocaa.WorkerId = workerId | |||||
ocaa.OverCostCountInOneTerm = overCostCountInOneTerm | |||||
ocaa.GenCountInOneTerm = genCountWhenOverCost | |||||
ocaa.TermIndex = index | |||||
} |
@@ -0,0 +1,203 @@ | |||||
package core | |||||
import ( | |||||
"../contract" | |||||
"math" | |||||
"sync" | |||||
"time" | |||||
) | |||||
type SnowWorkerM1 struct { | |||||
BaseTime int64 //基础时间 | |||||
WorkerId uint16 //机器码 | |||||
WorkerIdBitLength byte //机器码位长 | |||||
SeqBitLength byte //自增序列数位长 | |||||
MaxSeqNumber uint32 //最大序列数(含) | |||||
MinSeqNumber uint32 //最小序列数(含) | |||||
TopOverCostCount uint //最大漂移次数 | |||||
_TimestampShift byte | |||||
_CurrentSeqNumber uint32 | |||||
_LastTimeTick int64 | |||||
_TurnBackTimeTick int64 | |||||
_TurnBackIndex byte | |||||
_IsOverCost bool | |||||
_OverCostCountInOneTerm uint | |||||
_GenCountInOneTerm uint | |||||
_TermIndex uint | |||||
sync.Mutex | |||||
} | |||||
func NewSnowWorkerM1(options *contract.IdGeneratorOptions) contract.ISnowWorker { | |||||
var WorkerIdBitLength byte | |||||
var SeqBitLength byte | |||||
var MaxSeqNumber uint32 | |||||
var WorkerId = options.WorkerId | |||||
if options.WorkerIdBitLength == 0 { | |||||
WorkerIdBitLength = 6 | |||||
} else { | |||||
WorkerIdBitLength = options.WorkerIdBitLength | |||||
} | |||||
if options.SeqBitLength == 0 { | |||||
SeqBitLength = 6 | |||||
} else { | |||||
SeqBitLength = options.SeqBitLength | |||||
} | |||||
if options.MaxSeqNumber > 0 { | |||||
MaxSeqNumber = options.MaxSeqNumber | |||||
} else { | |||||
MaxSeqNumber = uint32(math.Pow(2, float64(options.SeqBitLength))) - 1 | |||||
} | |||||
var MinSeqNumber = options.MinSeqNumber | |||||
var TopOverCostCount = options.TopOverCostCount | |||||
var BaseTime int64 | |||||
if options.BaseTime != 0 { | |||||
BaseTime = options.BaseTime | |||||
} else { | |||||
BaseTime = 1582136402000 | |||||
} | |||||
timestampShift := (byte)(options.WorkerIdBitLength + options.SeqBitLength) | |||||
currentSeqNumber := options.MinSeqNumber | |||||
return &SnowWorkerM1{ | |||||
BaseTime: BaseTime, | |||||
WorkerId: WorkerId, | |||||
WorkerIdBitLength: WorkerIdBitLength, | |||||
SeqBitLength: SeqBitLength, | |||||
MaxSeqNumber: MaxSeqNumber, | |||||
MinSeqNumber: MinSeqNumber, | |||||
TopOverCostCount: TopOverCostCount, | |||||
_TimestampShift: timestampShift, | |||||
_CurrentSeqNumber: currentSeqNumber} | |||||
} | |||||
func (m1 *SnowWorkerM1) DoGenIdAction(arg *contract.OverCostActionArg) { | |||||
} | |||||
func (m1 *SnowWorkerM1) BeginOverCostAction(useTimeTick int64) { | |||||
} | |||||
func (m1 *SnowWorkerM1) EndOverCostAction(useTimeTick int64) { | |||||
if m1._TermIndex > 10000 { | |||||
m1._TermIndex = 0 | |||||
} | |||||
} | |||||
func (m1 *SnowWorkerM1) BeginTurnBackAction(useTimeTick int64) { | |||||
} | |||||
func (m1 *SnowWorkerM1) EndTurnBackAction(useTimeTick int64) { | |||||
} | |||||
func (m1 *SnowWorkerM1) NextOverCostId() uint64 { | |||||
currentTimeTick := m1.GetCurrentTimeTick() | |||||
if currentTimeTick > m1._LastTimeTick { | |||||
m1.EndOverCostAction(currentTimeTick) | |||||
m1._LastTimeTick = currentTimeTick | |||||
m1._CurrentSeqNumber = m1.MinSeqNumber | |||||
m1._IsOverCost = false | |||||
m1._OverCostCountInOneTerm = 0 | |||||
m1._GenCountInOneTerm = 0 | |||||
return m1.CalcId(m1._LastTimeTick) | |||||
} | |||||
if m1._OverCostCountInOneTerm >= m1.TopOverCostCount { | |||||
m1.EndOverCostAction(currentTimeTick) | |||||
m1._LastTimeTick = m1.GetNextTimeTick() | |||||
m1._CurrentSeqNumber = m1.MinSeqNumber | |||||
m1._IsOverCost = false | |||||
m1._OverCostCountInOneTerm = 0 | |||||
m1._GenCountInOneTerm = 0 | |||||
return m1.CalcId(m1._LastTimeTick) | |||||
} | |||||
if m1._CurrentSeqNumber > m1.MaxSeqNumber { | |||||
m1._LastTimeTick++ | |||||
m1._CurrentSeqNumber = m1.MinSeqNumber | |||||
m1._IsOverCost = true | |||||
m1._OverCostCountInOneTerm++ | |||||
m1._GenCountInOneTerm++ | |||||
return m1.CalcId(m1._LastTimeTick) | |||||
} | |||||
m1._GenCountInOneTerm++ | |||||
return m1.CalcId(m1._LastTimeTick) | |||||
} | |||||
func (m1 *SnowWorkerM1) NextNormalId() uint64 { | |||||
currentTimeTick := m1.GetCurrentTimeTick() | |||||
if currentTimeTick < m1._LastTimeTick { | |||||
if m1._TurnBackTimeTick < 1 { | |||||
m1._TurnBackTimeTick = m1._LastTimeTick - 1 | |||||
m1._TurnBackIndex++ | |||||
// 每毫秒序列数的前5位是预留位,0用于手工新值,1-4是时间回拨次序 | |||||
// 最多4次回拨(防止回拨重叠) | |||||
if m1._TurnBackIndex > 4 { | |||||
m1._TurnBackIndex = 1 | |||||
} | |||||
m1.BeginTurnBackAction(m1._TurnBackTimeTick) | |||||
} | |||||
time.Sleep(time.Duration(10) * time.Millisecond) | |||||
return m1.CalcTurnBackId(m1._TurnBackTimeTick) | |||||
} | |||||
// 时间追平时,_TurnBackTimeTick清零 | |||||
if m1._TurnBackTimeTick > 0 { | |||||
m1.EndTurnBackAction(m1._TurnBackTimeTick) | |||||
m1._TurnBackTimeTick = 0 | |||||
} | |||||
if currentTimeTick > m1._LastTimeTick { | |||||
m1._LastTimeTick = currentTimeTick | |||||
m1._CurrentSeqNumber = m1.MinSeqNumber | |||||
return m1.CalcId(m1._LastTimeTick) | |||||
} | |||||
if m1._CurrentSeqNumber > m1.MaxSeqNumber { | |||||
m1.BeginOverCostAction(currentTimeTick) | |||||
m1._TermIndex++ | |||||
m1._LastTimeTick++ | |||||
m1._CurrentSeqNumber = m1.MinSeqNumber | |||||
m1._IsOverCost = true | |||||
m1._OverCostCountInOneTerm = 1 | |||||
m1._GenCountInOneTerm = 1 | |||||
return m1.CalcId(m1._LastTimeTick) | |||||
} | |||||
return m1.CalcId(m1._LastTimeTick) | |||||
} | |||||
func (m1 *SnowWorkerM1) CalcId(useTimeTick int64) uint64 { | |||||
result := uint64(useTimeTick<<m1._TimestampShift) + uint64(m1.WorkerId<<m1.SeqBitLength) + uint64(m1._CurrentSeqNumber) | |||||
m1._CurrentSeqNumber++ | |||||
return result | |||||
} | |||||
func (m1 *SnowWorkerM1) CalcTurnBackId(useTimeTick int64) uint64 { | |||||
result := uint64(useTimeTick<<m1._TimestampShift) + uint64(m1.WorkerId<<m1.SeqBitLength) + uint64(m1._TurnBackIndex) | |||||
m1._TurnBackTimeTick-- | |||||
return result | |||||
} | |||||
func (m1 *SnowWorkerM1) GetCurrentTimeTick() int64 { | |||||
var millis = time.Now().UnixNano() / 1e6 | |||||
return millis - m1.BaseTime | |||||
} | |||||
func (m1 *SnowWorkerM1) GetNextTimeTick() int64 { | |||||
tempTimeTicker := m1.GetCurrentTimeTick() | |||||
for tempTimeTicker <= m1._LastTimeTick { | |||||
tempTimeTicker = m1.GetCurrentTimeTick() | |||||
} | |||||
return tempTimeTicker | |||||
} | |||||
func (m1 *SnowWorkerM1) NextId() uint64 { | |||||
m1.Lock() | |||||
defer m1.Unlock() | |||||
if m1._IsOverCost { | |||||
return m1.NextOverCostId() | |||||
} else { | |||||
return m1.NextNormalId() | |||||
} | |||||
} |
@@ -0,0 +1,37 @@ | |||||
package core | |||||
import ( | |||||
"../contract" | |||||
"fmt" | |||||
"strconv" | |||||
"sync/atomic" | |||||
) | |||||
type SnowWorkerM2 struct { | |||||
*SnowWorkerM1 | |||||
} | |||||
func NewSnowWorkerM2(options *contract.IdGeneratorOptions) contract.ISnowWorker { | |||||
return &SnowWorkerM2{ | |||||
NewSnowWorkerM1(options).(*SnowWorkerM1), | |||||
} | |||||
} | |||||
func (m2 SnowWorkerM2) NextId() uint64 { | |||||
currentTimeTick := m2.GetCurrentTimeTick() | |||||
if m2._LastTimeTick == currentTimeTick { | |||||
atomic.AddUint32(&m2._CurrentSeqNumber, 1) | |||||
if m2._CurrentSeqNumber > m2.MaxSeqNumber { | |||||
atomic.StoreUint32(&m2._CurrentSeqNumber, uint32(m2.MinSeqNumber)) | |||||
currentTimeTick = m2.GetNextTimeTick() | |||||
} | |||||
} else { | |||||
atomic.StoreUint32(&m2._CurrentSeqNumber, uint32(m2.MinSeqNumber)) | |||||
} | |||||
if currentTimeTick < m2._LastTimeTick { | |||||
fmt.Println("Time error for {0} milliseconds", strconv.FormatInt(m2._LastTimeTick-currentTimeTick, 10)) | |||||
} | |||||
m2._LastTimeTick = currentTimeTick | |||||
result := uint64((currentTimeTick << m2._TimestampShift)) + uint64(m2.WorkerId<<m2.SeqBitLength) + uint64(m2._CurrentSeqNumber) | |||||
return result | |||||
} |
@@ -0,0 +1,70 @@ | |||||
package idgen | |||||
import ( | |||||
"../contract" | |||||
"../core" | |||||
"math" | |||||
"time" | |||||
) | |||||
type DefaultIdGenerator struct { | |||||
Options *contract.IdGeneratorOptions | |||||
SnowWorker contract.ISnowWorker | |||||
IdGeneratorException contract.IdGeneratorException | |||||
} | |||||
func NewDefaultIdGenerator(Options *contract.IdGeneratorOptions) *DefaultIdGenerator { | |||||
if Options == nil { | |||||
panic("dig.Options error.") | |||||
} | |||||
var minTime = time.Now().AddDate(-50, 0, 0).UnixNano() / 1e6 | |||||
if minTime == 0 || Options.BaseTime < minTime || Options.BaseTime > time.Now().UnixNano()/1e6 { | |||||
panic("BaseTime error.") | |||||
} | |||||
if Options.SeqBitLength+Options.WorkerIdBitLength > 22 { | |||||
panic("error:WorkerIdBitLength + SeqBitLength <= 22") | |||||
} | |||||
maxWorkerIdNumber := uint16(math.Pow(float64(2), float64(Options.WorkerIdBitLength))) - 1 | |||||
if Options.WorkerId > maxWorkerIdNumber { | |||||
panic("WorkerId error. (range:[1, "+ string(maxWorkerIdNumber)+ "]") | |||||
} | |||||
if Options.SeqBitLength < 2 || Options.SeqBitLength > 21 { | |||||
panic("SeqBitLength error. (range:[2, 21])") | |||||
} | |||||
maxSeqNumber := uint32(math.Pow(2, float64(Options.SeqBitLength))) - 1 | |||||
if Options.MaxSeqNumber > maxSeqNumber { | |||||
panic("MaxSeqNumber error. (range:[1, "+ string(maxSeqNumber)+ "]") | |||||
} | |||||
if Options.MinSeqNumber > maxSeqNumber { | |||||
panic("MinSeqNumber error. (range:[1, "+ string(maxSeqNumber)+ "]") | |||||
} | |||||
var snowWorker contract.ISnowWorker | |||||
switch Options.Method { | |||||
case 1: | |||||
snowWorker = core.NewSnowWorkerM1(Options) | |||||
case 2: | |||||
snowWorker = core.NewSnowWorkerM2(Options) | |||||
default: | |||||
snowWorker = core.NewSnowWorkerM1(Options) | |||||
} | |||||
if Options.Method == 1 { | |||||
time.Sleep(time.Duration(500) * time.Microsecond) | |||||
} | |||||
return &DefaultIdGenerator{ | |||||
Options: Options, | |||||
SnowWorker: snowWorker, | |||||
} | |||||
} | |||||
func (dig DefaultIdGenerator) NewLong() uint64 { | |||||
return dig.SnowWorker.NextId() | |||||
} |
@@ -0,0 +1,41 @@ | |||||
package idgen | |||||
import ( | |||||
"../contract" | |||||
"sync" | |||||
) | |||||
var ins *YitIdHelper | |||||
var once sync.Once | |||||
type YitIdHelper struct { | |||||
idGenInstance interface { | |||||
NewLong() uint64 | |||||
} | |||||
} | |||||
func GetIns() *YitIdHelper { | |||||
once.Do(func() { | |||||
ins = &YitIdHelper{} | |||||
}) | |||||
return ins | |||||
} | |||||
func (yih *YitIdHelper) GetIdGenInstance() interface{} { | |||||
return yih.idGenInstance | |||||
} | |||||
func (yih *YitIdHelper) SetIdGenerator(options *contract.IdGeneratorOptions) { | |||||
yih.idGenInstance = NewDefaultIdGenerator(options) | |||||
} | |||||
func (yih *YitIdHelper) NextId() uint64 { | |||||
once.Do(func() { | |||||
if yih.idGenInstance == nil { | |||||
options := contract.NewIdGeneratorOptions(1) | |||||
yih.idGenInstance = NewDefaultIdGenerator(options) | |||||
} | |||||
}) | |||||
return yih.idGenInstance.NewLong() | |||||
} |
@@ -17,7 +17,7 @@ public class IdGeneratorOptions { | |||||
public short Method = 1; | public short Method = 1; | ||||
/** | /** | ||||
* 开始时间 | |||||
* 基础时间 | |||||
* 不能超过当前系统时间 | * 不能超过当前系统时间 | ||||
*/ | */ | ||||
public long BaseTime = 1582136402000L; | public long BaseTime = 1582136402000L; | ||||
@@ -34,8 +34,8 @@ public class StartUp { | |||||
options.BaseTime = 1582206693000L; | options.BaseTime = 1582206693000L; | ||||
options.WorkerId = 1; | options.WorkerId = 1; | ||||
IIdGenerator IdGen = new DefaultIdGenerator(options); | |||||
GenTest genTest = new GenTest(IdGen, genIdCount, options.WorkerId); | |||||
IIdGenerator idGen = new DefaultIdGenerator(options); | |||||
GenTest genTest = new GenTest(idGen, genIdCount, options.WorkerId); | |||||
// 首先测试一下 IdHelper 方法,获取单个Id | // 首先测试一下 IdHelper 方法,获取单个Id | ||||
YitIdHelper.setIdGenerator(options); | YitIdHelper.setIdGenerator(options); | ||||