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.

snowflake.go 3.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package sequence
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. "github.com/seata/seata-go/pkg/util/log"
  7. )
  8. // SnowflakeSeqGenerator snowflake gen ids
  9. // ref: https://en.wikipedia.org/wiki/Snowflake_ID
  10. var (
  11. // set the beginning time
  12. epoch = time.Date(2024, time.January, 01, 00, 00, 00, 00, time.UTC).UnixMilli()
  13. )
  14. const (
  15. // timestamp occupancy bits
  16. timestampBits = 41
  17. // dataCenterId occupancy bits
  18. dataCenterIdBits = 5
  19. // workerId occupancy bits
  20. workerIdBits = 5
  21. // sequence occupancy bits
  22. seqBits = 12
  23. // timestamp max value, just like 2^41-1 = 2199023255551
  24. timestampMaxValue = -1 ^ (-1 << timestampBits)
  25. // dataCenterId max value, just like 2^5-1 = 31
  26. dataCenterIdMaxValue = -1 ^ (-1 << dataCenterIdBits)
  27. // workId max value, just like 2^5-1 = 31
  28. workerIdMaxValue = -1 ^ (-1 << workerIdBits)
  29. // sequence max value, just like 2^12-1 = 4095
  30. seqMaxValue = -1 ^ (-1 << seqBits)
  31. // number of workId offsets (seqBits)
  32. workIdShift = 12
  33. // number of dataCenterId offsets (seqBits + workerIdBits)
  34. dataCenterIdShift = 17
  35. // number of timestamp offsets (seqBits + workerIdBits + dataCenterIdBits)
  36. timestampShift = 22
  37. defaultInitValue = 0
  38. )
  39. type SnowflakeSeqGenerator struct {
  40. mu *sync.Mutex
  41. timestamp int64
  42. dataCenterId int64
  43. workerId int64
  44. sequence int64
  45. }
  46. // NewSnowflakeSeqGenerator initiates the snowflake generator
  47. func NewSnowflakeSeqGenerator(dataCenterId, workId int64) (r *SnowflakeSeqGenerator, err error) {
  48. if dataCenterId < 0 || dataCenterId > dataCenterIdMaxValue {
  49. err = fmt.Errorf("dataCenterId should between 0 and %d", dataCenterIdMaxValue-1)
  50. return
  51. }
  52. if workId < 0 || workId > workerIdMaxValue {
  53. err = fmt.Errorf("workId should between 0 and %d", dataCenterIdMaxValue-1)
  54. return
  55. }
  56. return &SnowflakeSeqGenerator{
  57. mu: new(sync.Mutex),
  58. timestamp: defaultInitValue - 1,
  59. dataCenterId: dataCenterId,
  60. workerId: workId,
  61. sequence: defaultInitValue,
  62. }, nil
  63. }
  64. // GenerateId timestamp + dataCenterId + workId + sequence
  65. func (S *SnowflakeSeqGenerator) GenerateId(entity string, ruleName string) string {
  66. S.mu.Lock()
  67. defer S.mu.Unlock()
  68. now := time.Now().UnixMilli()
  69. if S.timestamp > now { // Clock callback
  70. log.Errorf("Clock moved backwards. Refusing to generate ID, last timestamp is %d, now is %d", S.timestamp, now)
  71. return ""
  72. }
  73. if S.timestamp == now {
  74. // generate multiple IDs in the same millisecond, incrementing the sequence number to prevent conflicts
  75. S.sequence = (S.sequence + 1) & seqMaxValue
  76. if S.sequence == 0 {
  77. // sequence overflow, waiting for next millisecond
  78. for now <= S.timestamp {
  79. now = time.Now().UnixMilli()
  80. }
  81. }
  82. } else {
  83. // initialized sequences are used directly at different millisecond timestamps
  84. S.sequence = defaultInitValue
  85. }
  86. tmp := now - epoch
  87. if tmp > timestampMaxValue {
  88. log.Errorf("epoch should between 0 and %d", timestampMaxValue-1)
  89. return ""
  90. }
  91. S.timestamp = now
  92. // combine the parts to generate the final ID and convert the 64-bit binary to decimal digits.
  93. r := (tmp)<<timestampShift |
  94. (S.dataCenterId << dataCenterIdShift) |
  95. (S.workerId << workIdShift) |
  96. (S.sequence)
  97. return fmt.Sprintf("%d", r)
  98. }