|
|
@@ -0,0 +1,214 @@ |
|
|
|
/** |
|
|
|
* @description: |
|
|
|
* @author: bubao |
|
|
|
* @date: 2021-04-27 17:19:51 |
|
|
|
* @last author: bubao |
|
|
|
* @last edit time: 2021-04-27 23:17:06 |
|
|
|
*/ |
|
|
|
class Genid { |
|
|
|
/** |
|
|
|
*Creates an instance of Genid. |
|
|
|
* @author bubao |
|
|
|
* @date 2021-04-27 |
|
|
|
* @param {{ |
|
|
|
* Method: 1, // 雪花计算方法,(1-漂移算法|2-传统算法),默认 1 |
|
|
|
* BaseTime: 1577836800000, // 基础时间(ms 单位),不能超过当前系统时间 |
|
|
|
* WorkerId: Number, // 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1 |
|
|
|
* WorkerIdBitLength: 6, // 机器码位长,默认值 6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过 22) |
|
|
|
* SeqBitLength: 6, // 序列数位长,默认值 6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过 22) |
|
|
|
* MaxSeqNumber: 5, // 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值 0,表示最大序列数取最大值(2^SeqBitLength-1]) |
|
|
|
* MinSeqNumber: 5, // 最小序列数(含),默认值 5,取值范围 [5, MaxSeqNumber],每毫秒的前 5 个序列数对应编号 0-4 是保留位,其中 1-4 是时间回拨相应预留位,0 是手工新值预留位 |
|
|
|
* TopOverCostCount: 2000// 最大漂移次数(含),默认 2000,推荐范围 500-10000(与计算能力有关) |
|
|
|
* }} options |
|
|
|
* @memberof Genid |
|
|
|
*/ |
|
|
|
constructor(options) { |
|
|
|
if (options.WorkerId === undefined) { |
|
|
|
throw new Error("lost WorkerId"); |
|
|
|
} |
|
|
|
// 1.BaseTime |
|
|
|
const BaseTime = 1577836800000; |
|
|
|
if (!options.BaseTime || options.BaseTime < 0) { |
|
|
|
options.BaseTime = BaseTime; |
|
|
|
} |
|
|
|
// 2.WorkerIdBitLength |
|
|
|
const WorkerIdBitLength = 6; |
|
|
|
if (!options.WorkerIdBitLength || options.WorkerIdBitLength < 0) { |
|
|
|
options.WorkerIdBitLength = WorkerIdBitLength; |
|
|
|
} |
|
|
|
|
|
|
|
// 4.SeqBitLength |
|
|
|
const SeqBitLength = 6; |
|
|
|
if (!options.SeqBitLength || options.SeqBitLength < 0) { |
|
|
|
options.SeqBitLength = SeqBitLength; |
|
|
|
} |
|
|
|
// 5.MaxSeqNumber |
|
|
|
const MaxSeqNumber = (1 << SeqBitLength) - 1; |
|
|
|
if (options.MaxSeqNumber <= 0 || options.MaxSeqNumber === undefined) { |
|
|
|
options.MaxSeqNumber = MaxSeqNumber; |
|
|
|
} |
|
|
|
// 6.MinSeqNumber |
|
|
|
const MinSeqNumber = 5; |
|
|
|
if (!options.MinSeqNumber || options.MinSeqNumber < 0) { |
|
|
|
options.MinSeqNumber = MinSeqNumber; |
|
|
|
} |
|
|
|
// 7.Others |
|
|
|
const topOverCostCount = 2000; |
|
|
|
if (!options.TopOverCostCount || options.TopOverCostCount < 0) { |
|
|
|
options.TopOverCostCount = topOverCostCount; |
|
|
|
} |
|
|
|
|
|
|
|
if (options.Method !== 2) { |
|
|
|
options.Method = 1; |
|
|
|
} else { |
|
|
|
options.Method = 2; |
|
|
|
} |
|
|
|
|
|
|
|
this.Method = BigInt(options.Method); |
|
|
|
this.BaseTime = BigInt(options.BaseTime); |
|
|
|
this.WorkerId = BigInt(options.WorkerId); |
|
|
|
this.WorkerIdBitLength = BigInt(options.WorkerIdBitLength); |
|
|
|
this.SeqBitLength = BigInt(options.SeqBitLength); |
|
|
|
this.MaxSeqNumber = BigInt(options.MaxSeqNumber); |
|
|
|
this.MinSeqNumber = BigInt(options.MinSeqNumber); |
|
|
|
this.TopOverCostCount = BigInt(options.TopOverCostCount); |
|
|
|
|
|
|
|
const timestampShift = this.WorkerIdBitLength + this.SeqBitLength; |
|
|
|
const currentSeqNumber = this.MinSeqNumber; |
|
|
|
|
|
|
|
this._TimestampShift = timestampShift; |
|
|
|
this._CurrentSeqNumber = currentSeqNumber; |
|
|
|
|
|
|
|
this._LastTimeTick = 0; |
|
|
|
this._TurnBackTimeTick = 0; |
|
|
|
this._TurnBackIndex = 0; |
|
|
|
this._IsOverCost = false; |
|
|
|
this._OverCostCountInOneTerm = 0; |
|
|
|
} |
|
|
|
|
|
|
|
// DoGenIDAction . |
|
|
|
DoGenIdAction(OverCostActionArg) { } |
|
|
|
|
|
|
|
BeginOverCostAction(useTimeTick) { } |
|
|
|
|
|
|
|
EndOverCostAction(useTimeTick) { |
|
|
|
// if m1._TermIndex > 10000 { |
|
|
|
// m1._TermIndex = 0 |
|
|
|
// } |
|
|
|
} |
|
|
|
|
|
|
|
BeginTurnBackAction(useTimeTick) { } |
|
|
|
|
|
|
|
EndTurnBackAction(useTimeTick) { } |
|
|
|
|
|
|
|
NextOverCostId() { |
|
|
|
const currentTimeTick = this.GetCurrentTimeTick(); |
|
|
|
if (currentTimeTick > this._LastTimeTick) { |
|
|
|
// this.EndOverCostAction(currentTimeTick) |
|
|
|
this._LastTimeTick = currentTimeTick; |
|
|
|
this._CurrentSeqNumber = this.MinSeqNumber; |
|
|
|
this._IsOverCost = false; |
|
|
|
this._OverCostCountInOneTerm = 0; |
|
|
|
// this._GenCountInOneTerm = 0 |
|
|
|
return this.CalcId(this._LastTimeTick); |
|
|
|
} |
|
|
|
if (this._OverCostCountInOneTerm >= this.TopOverCostCount) { |
|
|
|
// this.EndOverCostAction(currentTimeTick) |
|
|
|
this._LastTimeTick = this.GetNextTimeTick(); |
|
|
|
this._CurrentSeqNumber = this.MinSeqNumber; |
|
|
|
this._IsOverCost = false; |
|
|
|
this._OverCostCountInOneTerm = 0; |
|
|
|
// this._GenCountInOneTerm = 0 |
|
|
|
return this.CalcId(this._LastTimeTick); |
|
|
|
} |
|
|
|
if (this._CurrentSeqNumber > this.MaxSeqNumber) { |
|
|
|
this._LastTimeTick++; |
|
|
|
this._CurrentSeqNumber = this.MinSeqNumber; |
|
|
|
this._IsOverCost = true; |
|
|
|
this._OverCostCountInOneTerm++; |
|
|
|
// this._GenCountInOneTerm++ |
|
|
|
|
|
|
|
return this.CalcId(this._LastTimeTick); |
|
|
|
} |
|
|
|
|
|
|
|
// this._GenCountInOneTerm++ |
|
|
|
return this.CalcId(this._LastTimeTick); |
|
|
|
} |
|
|
|
|
|
|
|
NextNormalId() { |
|
|
|
const currentTimeTick = this.GetCurrentTimeTick(); |
|
|
|
if (currentTimeTick < this._LastTimeTick) { |
|
|
|
if (this._TurnBackTimeTick < 1) { |
|
|
|
this._TurnBackTimeTick = this._LastTimeTick - 1; |
|
|
|
this._TurnBackIndex++; |
|
|
|
// 每毫秒序列数的前 5 位是预留位,0 用于手工新值,1-4 是时间回拨次序 |
|
|
|
// 支持 4 次回拨次序(避免回拨重叠导致 ID 重复),可无限次回拨(次序循环使用)。 |
|
|
|
if (this._TurnBackIndex > 4) { |
|
|
|
this._TurnBackIndex = 1; |
|
|
|
} |
|
|
|
this.BeginTurnBackAction(this._TurnBackTimeTick); |
|
|
|
} |
|
|
|
return this.CalcTurnBackId(this._TurnBackTimeTick); |
|
|
|
} |
|
|
|
// 时间追平时,_TurnBackTimeTick 清零 |
|
|
|
if (this._TurnBackTimeTick > 0) { |
|
|
|
this.EndTurnBackAction(this._TurnBackTimeTick); |
|
|
|
this._TurnBackTimeTick = 0; |
|
|
|
} |
|
|
|
|
|
|
|
if (currentTimeTick > this._LastTimeTick) { |
|
|
|
this._LastTimeTick = currentTimeTick; |
|
|
|
this._CurrentSeqNumber = this.MinSeqNumber; |
|
|
|
return this.CalcId(this._LastTimeTick); |
|
|
|
} |
|
|
|
|
|
|
|
if (this._CurrentSeqNumber > this.MaxSeqNumber) { |
|
|
|
this.BeginOverCostAction(currentTimeTick); |
|
|
|
// this._TermIndex++ |
|
|
|
this._LastTimeTick++; |
|
|
|
this._CurrentSeqNumber = this.MinSeqNumber; |
|
|
|
this._IsOverCost = true; |
|
|
|
this._OverCostCountInOneTerm = 1; |
|
|
|
// this._GenCountInOneTerm = 1 |
|
|
|
|
|
|
|
return this.CalcId(this._LastTimeTick); |
|
|
|
} |
|
|
|
|
|
|
|
return this.CalcId(this._LastTimeTick); |
|
|
|
} |
|
|
|
|
|
|
|
CalcId(useTimeTick) { |
|
|
|
const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._CurrentSeqNumber); |
|
|
|
this._CurrentSeqNumber++; |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
CalcTurnBackId(useTimeTick) { |
|
|
|
const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._TurnBackIndex); |
|
|
|
this._TurnBackTimeTick--; |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
GetCurrentTimeTick() { |
|
|
|
const millis = BigInt((new Date()).valueOf()); |
|
|
|
return millis - this.BaseTime; |
|
|
|
} |
|
|
|
|
|
|
|
GetNextTimeTick() { |
|
|
|
let tempTimeTicker = this.GetCurrentTimeTick(); |
|
|
|
while (tempTimeTicker <= this._LastTimeTick) { |
|
|
|
tempTimeTicker = this.GetCurrentTimeTick(); |
|
|
|
} |
|
|
|
return tempTimeTicker; |
|
|
|
} |
|
|
|
|
|
|
|
NextId() { |
|
|
|
if (this._IsOverCost) { |
|
|
|
return parseInt(this.NextOverCostId()); |
|
|
|
} else { |
|
|
|
return parseInt(this.NextNormalId()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
module.exports = Genid; |