You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

snowflakeIdv1.ts 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /**
  2. *
  3. */
  4. export class snowflakeIdv1 {
  5. /**
  6. * 雪花计算方法,(1-漂移算法|2-传统算法),默认 1
  7. */
  8. private Method
  9. /**
  10. * 基础时间(ms 单位),不能超过当前系统时间
  11. */
  12. private BaseTime
  13. /**
  14. * 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
  15. */
  16. private WorkerId
  17. /**
  18. * 机器码位长,默认值 6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过 22)
  19. */
  20. private WorkerIdBitLength
  21. /**
  22. * 序列数位长,默认值 6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过 22)
  23. */
  24. private SeqBitLength
  25. /**
  26. * 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值 0,表示最大序列数取最大值(2^SeqBitLength-1])
  27. */
  28. private MaxSeqNumber
  29. /**
  30. * 最小序列数(含),默认值 5,取值范围 [5, MaxSeqNumber],每毫秒的前 5 个序列数对应编号 0-4 是保留位,其中 1-4 是时间回拨相应预留位,0 是手工新值预留位
  31. */
  32. private MinSeqNumber
  33. /**
  34. * 最大漂移次数(含),默认 2000,推荐范围 500-10000(与计算能力有关)
  35. */
  36. private TopOverCostCount
  37. /**
  38. *
  39. */
  40. private _TimestampShift
  41. /**
  42. *
  43. */
  44. private _CurrentSeqNumber
  45. /**
  46. *
  47. */
  48. private _LastTimeTick: bigint
  49. /**
  50. * 回拨次序, 支持 4 次回拨次序(避免回拨重叠导致 ID 重复)
  51. */
  52. private _TurnBackTimeTick: bigint
  53. /**
  54. *
  55. */
  56. private _TurnBackIndex
  57. /**
  58. *
  59. */
  60. private _IsOverCost
  61. /**
  62. *
  63. */
  64. private _OverCostCountInOneTerm
  65. /**
  66. *Creates an instance of Genid.
  67. * @author bubao
  68. * @param {{
  69. * Method: 1, // 雪花计算方法,(1-漂移算法|2-传统算法),默认 1
  70. * BaseTime: 1577836800000, // 基础时间(ms 单位),不能超过当前系统时间
  71. * WorkerId: Number, // 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
  72. * WorkerIdBitLength: 6, // 机器码位长,默认值 6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过 22)
  73. * SeqBitLength: 6, // 序列数位长,默认值 6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过 22)
  74. * MaxSeqNumber: 5, // 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值 0,表示最大序列数取最大值(2^SeqBitLength-1])
  75. * MinSeqNumber: 5, // 最小序列数(含),默认值 5,取值范围 [5, MaxSeqNumber],每毫秒的前 5 个序列数对应编号 0-4 是保留位,其中 1-4 是时间回拨相应预留位,0 是手工新值预留位
  76. * TopOverCostCount: 2000// 最大漂移次数(含),默认 2000,推荐范围 500-10000(与计算能力有关)
  77. * }} options
  78. * @memberof Genid
  79. */
  80. constructor(options: any) {
  81. if (options.WorkerId === undefined)
  82. throw new Error("lost WorkerId")
  83. // 1.BaseTime 2020年1月1日
  84. const BaseTime = 1577836800000
  85. if (!options.BaseTime || options.BaseTime < 0)
  86. options.BaseTime = BaseTime
  87. // 2.WorkerIdBitLength
  88. const WorkerIdBitLength = 6
  89. if (!options.WorkerIdBitLength || options.WorkerIdBitLength < 0)
  90. options.WorkerIdBitLength = WorkerIdBitLength
  91. // 4.SeqBitLength
  92. const SeqBitLength = 6
  93. if (!options.SeqBitLength || options.SeqBitLength < 0)
  94. options.SeqBitLength = SeqBitLength
  95. // 5.MaxSeqNumber
  96. const MaxSeqNumber = (1 << SeqBitLength) - 1
  97. if (options.MaxSeqNumber <= 0 || options.MaxSeqNumber === undefined) {
  98. options.MaxSeqNumber = MaxSeqNumber
  99. }
  100. // 6.MinSeqNumber
  101. const MinSeqNumber = 5
  102. if (!options.MinSeqNumber || options.MinSeqNumber < 0)
  103. options.MinSeqNumber = MinSeqNumber
  104. // 7.Others
  105. const topOverCostCount = 2000
  106. if (!options.TopOverCostCount || options.TopOverCostCount < 0)
  107. options.TopOverCostCount = topOverCostCount
  108. if (options.Method !== 2)
  109. options.Method = 1
  110. else
  111. options.Method = 2
  112. this.Method = BigInt(options.Method)
  113. this.BaseTime = BigInt(options.BaseTime)
  114. this.WorkerId = BigInt(options.WorkerId)
  115. this.WorkerIdBitLength = BigInt(options.WorkerIdBitLength)
  116. this.SeqBitLength = BigInt(options.SeqBitLength)
  117. this.MaxSeqNumber = BigInt(options.MaxSeqNumber)
  118. this.MinSeqNumber = BigInt(options.MinSeqNumber)
  119. this.TopOverCostCount = BigInt(options.TopOverCostCount)
  120. const timestampShift = this.WorkerIdBitLength + this.SeqBitLength
  121. const currentSeqNumber = this.MinSeqNumber
  122. this._TimestampShift = timestampShift
  123. this._CurrentSeqNumber = currentSeqNumber
  124. this._LastTimeTick = BigInt(0)
  125. this._TurnBackTimeTick = BigInt(0)
  126. this._TurnBackIndex = 0
  127. this._IsOverCost = false
  128. this._OverCostCountInOneTerm = 0
  129. }
  130. /**
  131. * 当前序列号超过最大范围,开始透支使用序号号的通知事件,,本项暂未实现
  132. * @returns
  133. */
  134. private BeginOverCostAction(useTimeTick: any) {
  135. }
  136. /**
  137. * 当前序列号超过最大范围,结束透支使用序号号的通知事件,,本项暂未实现
  138. * @returns
  139. */
  140. private EndOverCostAction(useTimeTick: any) {
  141. // if m1._TermIndex > 10000 {
  142. // m1._TermIndex = 0
  143. // }
  144. }
  145. /**
  146. * 开始时间回拨通知,本项暂未实现
  147. * @returns
  148. */
  149. private BeginTurnBackAction(useTimeTick: any) {
  150. }
  151. /**
  152. * 结束时间回拨通知,本项暂未实现
  153. * @returns
  154. */
  155. private EndTurnBackAction(useTimeTick: any) {
  156. }
  157. /**
  158. * 雪花漂移算法
  159. * @returns
  160. */
  161. private NextOverCostId(): bigint {
  162. const currentTimeTick = this.GetCurrentTimeTick()
  163. if (currentTimeTick > this._LastTimeTick) {
  164. this.EndOverCostAction(currentTimeTick)
  165. //当前时间大于上次时间,说明是时间是递增的,这是正常情况
  166. this._LastTimeTick = currentTimeTick
  167. this._CurrentSeqNumber = this.MinSeqNumber
  168. this._IsOverCost = false
  169. this._OverCostCountInOneTerm = 0
  170. // this._GenCountInOneTerm = 0
  171. return this.CalcId(this._LastTimeTick)
  172. }
  173. if (this._OverCostCountInOneTerm >= this.TopOverCostCount) {
  174. //当前漂移次数超过最大限制
  175. // TODO: 在漂移终止,等待时间对齐时,如果发生时间回拨较长,则此处可能等待较长时间。可优化为:在漂移终止时增加时间回拨应对逻辑。(该情况发生概率很低)
  176. this.EndOverCostAction(currentTimeTick)
  177. this._LastTimeTick = this.GetNextTimeTick()
  178. this._CurrentSeqNumber = this.MinSeqNumber
  179. this._IsOverCost = false
  180. this._OverCostCountInOneTerm = 0
  181. // this._GenCountInOneTerm = 0
  182. return this.CalcId(this._LastTimeTick)
  183. }
  184. if (this._CurrentSeqNumber > this.MaxSeqNumber) {
  185. //当前序列数超过最大限制,则要提前透支
  186. this._LastTimeTick++
  187. this._CurrentSeqNumber = this.MinSeqNumber
  188. this._IsOverCost = true
  189. this._OverCostCountInOneTerm++
  190. // this._GenCountInOneTerm++
  191. return this.CalcId(this._LastTimeTick)
  192. }
  193. // this._GenCountInOneTerm++
  194. return this.CalcId(this._LastTimeTick)
  195. }
  196. /**
  197. * 常规雪花算法
  198. * @returns
  199. */
  200. private NextNormalId() {
  201. const currentTimeTick = this.GetCurrentTimeTick()
  202. if (currentTimeTick < this._LastTimeTick) {
  203. if (this._TurnBackTimeTick < 1) {
  204. this._TurnBackTimeTick = this._LastTimeTick - BigInt(1)
  205. this._TurnBackIndex++
  206. // 每毫秒序列数的前 5 位是预留位,0 用于手工新值,1-4 是时间回拨次序
  207. // 支持 4 次回拨次序(避免回拨重叠导致 ID 重复),可无限次回拨(次序循环使用)。
  208. if (this._TurnBackIndex > 4)
  209. this._TurnBackIndex = 1
  210. this.BeginTurnBackAction(this._TurnBackTimeTick)
  211. }
  212. return this.CalcTurnBackId(this._TurnBackTimeTick)
  213. }
  214. // 时间追平时,_TurnBackTimeTick 清零
  215. if (this._TurnBackTimeTick > 0) {
  216. this.EndTurnBackAction(this._TurnBackTimeTick)
  217. this._TurnBackTimeTick = BigInt(0)
  218. }
  219. if (currentTimeTick > this._LastTimeTick) {
  220. this._LastTimeTick = currentTimeTick
  221. this._CurrentSeqNumber = this.MinSeqNumber
  222. return this.CalcId(this._LastTimeTick)
  223. }
  224. if (this._CurrentSeqNumber > this.MaxSeqNumber) {
  225. this.BeginOverCostAction(currentTimeTick)
  226. // this._TermIndex++
  227. this._LastTimeTick++
  228. this._CurrentSeqNumber = this.MinSeqNumber
  229. this._IsOverCost = true
  230. this._OverCostCountInOneTerm = 1
  231. // this._GenCountInOneTerm = 1
  232. return this.CalcId(this._LastTimeTick)
  233. }
  234. return this.CalcId(this._LastTimeTick)
  235. }
  236. /**
  237. * 生成ID
  238. * @param useTimeTick 时间戳
  239. * @returns
  240. */
  241. private CalcId(useTimeTick: bigint) {
  242. //ID组成 1.相对基础时间的时间差 | 2.WorkerId | 3.序列数
  243. //时间差,是生成ID时的系统时间减去 BaseTime 的总时间差(毫秒单位)
  244. const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._CurrentSeqNumber)
  245. this._CurrentSeqNumber++
  246. return result
  247. }
  248. /**
  249. * 生成时间回拨ID
  250. * @returns
  251. */
  252. private CalcTurnBackId(useTimeTick: any) {
  253. const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._TurnBackIndex)
  254. this._TurnBackTimeTick--
  255. return result
  256. }
  257. /**
  258. *
  259. * @returns
  260. */
  261. private GetCurrentTimeTick() {
  262. const millis = BigInt((new Date()).valueOf())
  263. return millis - this.BaseTime
  264. }
  265. /**
  266. *
  267. * @returns
  268. */
  269. private GetNextTimeTick() {
  270. let tempTimeTicker = this.GetCurrentTimeTick()
  271. while (tempTimeTicker <= this._LastTimeTick) {
  272. tempTimeTicker = this.GetCurrentTimeTick()
  273. }
  274. return tempTimeTicker
  275. }
  276. /**
  277. * 生成ID
  278. * @returns
  279. */
  280. public NextId(): number {
  281. if (this.Method == BigInt(1)) {
  282. //雪花漂移算法
  283. return parseInt(this.NextOverCostId().toString())
  284. } else {
  285. //常规雪花算法
  286. return parseInt(this.NextNormalId().toString())
  287. }
  288. }
  289. }