idgen.go 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package util
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "time"
  7. )
  8. type IdWorker struct {
  9. startTime int64
  10. workerIdBits uint
  11. datacenterIdBits uint
  12. maxWorkerId int64
  13. maxDatacenterId int64
  14. sequenceBits uint
  15. workerIdLeftShift uint
  16. datacenterIdLeftShift uint
  17. timestampLeftShift uint
  18. sequenceMask int64
  19. workerId int64
  20. datacenterId int64
  21. sequence int64
  22. lastTimestamp int64
  23. signMask int64
  24. idLock *sync.Mutex
  25. }
  26. func (this *IdWorker) InitIdWorker(workerId, datacenterId int64) error {
  27. var baseValue int64 = -1
  28. this.startTime = 1463834116272
  29. this.workerIdBits = 5
  30. this.datacenterIdBits = 5
  31. this.maxWorkerId = baseValue ^ (baseValue << this.workerIdBits)
  32. this.maxDatacenterId = baseValue ^ (baseValue << this.datacenterIdBits)
  33. this.sequenceBits = 12
  34. this.workerIdLeftShift = this.sequenceBits
  35. this.datacenterIdLeftShift = this.workerIdBits + this.workerIdLeftShift
  36. this.timestampLeftShift = this.datacenterIdBits + this.datacenterIdLeftShift
  37. this.sequenceMask = baseValue ^ (baseValue << this.sequenceBits)
  38. this.sequence = 0
  39. this.lastTimestamp = -1
  40. this.signMask = ^baseValue + 1
  41. this.idLock = &sync.Mutex{}
  42. if this.workerId < 0 || this.workerId > this.maxWorkerId {
  43. return errors.New(fmt.Sprintf("workerId[%v] is less than 0 or greater than maxWorkerId[%v].", workerId, datacenterId))
  44. }
  45. if this.datacenterId < 0 || this.datacenterId > this.maxDatacenterId {
  46. return errors.New(fmt.Sprintf("datacenterId[%d] is less than 0 or greater than maxDatacenterId[%d].", workerId, datacenterId))
  47. }
  48. this.workerId = workerId
  49. this.datacenterId = datacenterId
  50. return nil
  51. }
  52. func (this *IdWorker) NextId() (int64, error) {
  53. this.idLock.Lock()
  54. defer this.idLock.Unlock()
  55. timestamp := time.Now().UnixNano()
  56. if timestamp < this.lastTimestamp {
  57. return -1, errors.New(fmt.Sprintf("Clock moved backwards. Refusing to generate id for %d milliseconds", this.lastTimestamp-timestamp))
  58. }
  59. if timestamp == this.lastTimestamp {
  60. this.sequence = (this.sequence + 1) & this.sequenceMask
  61. if this.sequence == 0 {
  62. timestamp = this.tilNextMillis()
  63. this.sequence = 0
  64. }
  65. } else {
  66. this.sequence = 0
  67. }
  68. this.lastTimestamp = timestamp
  69. id := ((timestamp - this.startTime) << this.timestampLeftShift) |
  70. (this.datacenterId << this.datacenterIdLeftShift) |
  71. (this.workerId << this.workerIdLeftShift) |
  72. this.sequence
  73. if id < 0 {
  74. id = -id
  75. }
  76. return id, nil
  77. }
  78. func (this *IdWorker) tilNextMillis() int64 {
  79. timestamp := time.Now().UnixNano()
  80. if timestamp <= this.lastTimestamp {
  81. timestamp = time.Now().UnixNano() / int64(time.Millisecond)
  82. }
  83. return timestamp
  84. }