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 << 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() } } }