mirror of
https://gitee.com/yitter/idgenerator.git
synced 2026-05-07 23:55:51 +08:00
387 lines
12 KiB
TypeScript
387 lines
12 KiB
TypeScript
import { snowflakeIdv1Option } from "./snowflakeIdv1Option"
|
||
|
||
/**
|
||
*
|
||
*/
|
||
export class snowflakeIdv1 {
|
||
|
||
/**
|
||
* 雪花计算方法,(1-漂移算法|2-传统算法),默认 1
|
||
*/
|
||
private Method
|
||
|
||
/**
|
||
* 基础时间(ms 单位),不能超过当前系统时间
|
||
*/
|
||
private BaseTime
|
||
|
||
/**
|
||
* 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
|
||
*/
|
||
private WorkerId
|
||
|
||
/**
|
||
* 机器码位长,默认值 6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过 22)
|
||
*/
|
||
private WorkerIdBitLength
|
||
|
||
/**
|
||
* 序列数位长,默认值 6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过 22)
|
||
*/
|
||
private SeqBitLength
|
||
|
||
/**
|
||
* 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值 0,表示最大序列数取最大值(2^SeqBitLength-1])
|
||
*/
|
||
private MaxSeqNumber
|
||
|
||
/**
|
||
* 最小序列数(含),默认值 5,取值范围 [5, MaxSeqNumber],每毫秒的前 5 个序列数对应编号 0-4 是保留位,其中 1-4 是时间回拨相应预留位,0 是手工新值预留位
|
||
*/
|
||
private MinSeqNumber
|
||
|
||
/**
|
||
* 最大漂移次数(含),默认 2000,推荐范围 500-10000(与计算能力有关)
|
||
*/
|
||
private TopOverCostCount
|
||
|
||
/**
|
||
*
|
||
*/
|
||
private _TimestampShift
|
||
|
||
/**
|
||
*
|
||
*/
|
||
private _CurrentSeqNumber
|
||
|
||
/**
|
||
*
|
||
*/
|
||
private _LastTimeTick: bigint
|
||
|
||
/**
|
||
* 回拨次序, 支持 4 次回拨次序(避免回拨重叠导致 ID 重复)
|
||
*/
|
||
private _TurnBackTimeTick: bigint
|
||
|
||
/**
|
||
*
|
||
*/
|
||
private _TurnBackIndex
|
||
|
||
/**
|
||
*
|
||
*/
|
||
private _IsOverCost
|
||
|
||
/**
|
||
*
|
||
*/
|
||
private _OverCostCountInOneTerm
|
||
|
||
/**
|
||
*Creates an instance of Genid.
|
||
* @author zhupengfeivip
|
||
* @param {{
|
||
* BaseTime: 1577836800000, // 基础时间(ms 单位),默认2020年1月1日,不能超过当前系统时间,一旦投入使用就不能再更改,更改后产生的ID可能会和以前的重复
|
||
* 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: snowflakeIdv1Option) {
|
||
if (options.workerId === undefined)
|
||
throw new Error("lost WorkerId")
|
||
|
||
// 1.BaseTime 2020年1月1日 Wed, 01 Jan 2020 00:00:00 GMT 0时区的2020年1月1日
|
||
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
|
||
if (options.maxSeqNumber == undefined || options.maxSeqNumber <= 0)
|
||
options.maxSeqNumber = (1 << options.seqBitLength) - 1
|
||
|
||
// 6.MinSeqNumber
|
||
const MinSeqNumber = 5
|
||
if (options.minSeqNumber == undefined || options.minSeqNumber < 0)
|
||
options.minSeqNumber = MinSeqNumber
|
||
|
||
// 7.Others
|
||
const topOverCostCount = 2000
|
||
if (options.topOverCostCount == undefined || 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 = BigInt(0)
|
||
this._TurnBackTimeTick = BigInt(0)
|
||
this._TurnBackIndex = 0
|
||
this._IsOverCost = false
|
||
this._OverCostCountInOneTerm = 0
|
||
}
|
||
|
||
|
||
/**
|
||
* 当前序列号超过最大范围,开始透支使用序号号的通知事件,,本项暂未实现
|
||
* @returns
|
||
*/
|
||
private BeginOverCostAction(useTimeTick: any) {
|
||
|
||
}
|
||
|
||
/**
|
||
* 当前序列号超过最大范围,结束透支使用序号号的通知事件,,本项暂未实现
|
||
* @returns
|
||
*/
|
||
private EndOverCostAction(useTimeTick: any) {
|
||
// if m1._TermIndex > 10000 {
|
||
// m1._TermIndex = 0
|
||
// }
|
||
}
|
||
|
||
/**
|
||
* 开始时间回拨通知,本项暂未实现
|
||
* @returns
|
||
*/
|
||
private BeginTurnBackAction(useTimeTick: any) {
|
||
|
||
}
|
||
|
||
/**
|
||
* 结束时间回拨通知,本项暂未实现
|
||
* @returns
|
||
*/
|
||
private EndTurnBackAction(useTimeTick: any) {
|
||
|
||
}
|
||
|
||
/**
|
||
* 雪花漂移算法
|
||
* @returns
|
||
*/
|
||
private NextOverCostId(): bigint {
|
||
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) {
|
||
//当前漂移次数超过最大限制
|
||
|
||
// TODO: 在漂移终止,等待时间对齐时,如果发生时间回拨较长,则此处可能等待较长时间。可优化为:在漂移终止时增加时间回拨应对逻辑。(该情况发生概率很低)
|
||
|
||
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)
|
||
}
|
||
|
||
/**
|
||
* 常规雪花算法
|
||
* @returns
|
||
*/
|
||
private NextNormalId() {
|
||
const currentTimeTick = this.GetCurrentTimeTick()
|
||
if (currentTimeTick < this._LastTimeTick) {
|
||
if (this._TurnBackTimeTick < 1) {
|
||
this._TurnBackTimeTick = this._LastTimeTick - BigInt(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 = BigInt(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)
|
||
}
|
||
|
||
/**
|
||
* 生成ID
|
||
* @param useTimeTick 时间戳
|
||
* @returns
|
||
*/
|
||
private CalcId(useTimeTick: bigint) {
|
||
//ID组成 1.相对基础时间的时间差 | 2.WorkerId | 3.序列数
|
||
//时间差,是生成ID时的系统时间减去 BaseTime 的总时间差(毫秒单位)
|
||
const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._CurrentSeqNumber)
|
||
this._CurrentSeqNumber++
|
||
return result
|
||
}
|
||
|
||
/**
|
||
* 生成时间回拨ID
|
||
* @returns
|
||
*/
|
||
private CalcTurnBackId(useTimeTick: any) {
|
||
const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._TurnBackIndex)
|
||
this._TurnBackTimeTick--
|
||
return result
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @returns
|
||
*/
|
||
private GetCurrentTimeTick() {
|
||
const millis = BigInt((new Date()).valueOf())
|
||
return millis - this.BaseTime
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @returns
|
||
*/
|
||
private GetNextTimeTick() {
|
||
let tempTimeTicker = this.GetCurrentTimeTick()
|
||
while (tempTimeTicker <= this._LastTimeTick) {
|
||
tempTimeTicker = this.GetCurrentTimeTick()
|
||
}
|
||
return tempTimeTicker
|
||
}
|
||
|
||
/**
|
||
* 生成ID
|
||
* @returns 始终输出number类型,超过时throw error
|
||
*/
|
||
public NextNumber(): number {
|
||
if (this._IsOverCost) {
|
||
//
|
||
let id = this.NextOverCostId()
|
||
if (id >= 9007199254740992n)
|
||
throw Error(`${id.toString()} over max of Number 9007199254740992`)
|
||
|
||
return parseInt(id.toString())
|
||
} else {
|
||
//
|
||
let id = this.NextNormalId()
|
||
if (id >= 9007199254740992n)
|
||
throw Error(`${id.toString()} over max of Number 9007199254740992`)
|
||
|
||
return parseInt(id.toString())
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成ID
|
||
* @returns 根据输出数值判断,小于number最大值时输出number类型,大于时输出bigint
|
||
*/
|
||
public NextId(): number | bigint {
|
||
if (this._IsOverCost) {
|
||
//
|
||
let id = this.NextOverCostId()
|
||
if (id >= 9007199254740992n)
|
||
return id
|
||
else
|
||
return parseInt(id.toString())
|
||
} else {
|
||
//
|
||
let id = this.NextNormalId()
|
||
if (id >= 9007199254740992n)
|
||
return id
|
||
else
|
||
return parseInt(id.toString())
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成ID
|
||
* @returns 始终输出bigint类型
|
||
*/
|
||
public NextBigId(): bigint {
|
||
if (this._IsOverCost) {
|
||
//
|
||
return this.NextOverCostId()
|
||
} else {
|
||
//
|
||
return this.NextNormalId()
|
||
}
|
||
}
|
||
}
|
||
|