github.com/duomi520/utils@v0.0.0-20240430123446-e03a4cddd6ec/snowflake_test.go (about) 1 package utils 2 3 import ( 4 "errors" 5 "sync" 6 "testing" 7 "time" 8 ) 9 10 // 11 // 工作组中心分配工作机器id 12 // 13 14 // ErrFailureAllocID 定义错误 15 var ErrFailureAllocID = errors.New("utils.IdWorker.GetId|工作机器id耗尽。") 16 17 // IDWorker 工作组用于分配工作机器id 18 type IDWorker struct { 19 //2018-6-1 00:00:00 UTC ,时间戳启动计算时间零点 20 SystemCenterStartupTime int64 21 queue []int 22 queueMap []int 23 //消费 24 consumption int 25 //生产 26 production int 27 mutex sync.Mutex 28 } 29 30 // NewIDWorker 初始化 31 func NewIDWorker(st int64) *IDWorker { 32 w := &IDWorker{ 33 SystemCenterStartupTime: st, 34 queue: make([]int, MaxWorkNumber), 35 queueMap: make([]int, MaxWorkNumber), 36 production: 0, 37 consumption: 0, 38 } 39 for i := 0; i < MaxWorkNumber; i++ { 40 w.queue[i] = i 41 w.queueMap[i] = i 42 } 43 return w 44 } 45 46 // GetID 取id 47 func (w *IDWorker) GetID() (int, error) { 48 n := 0 49 var err error 50 w.mutex.Lock() 51 if w.queue[w.consumption] == -1 { 52 n = -1 53 err = ErrFailureAllocID 54 } else { 55 n = w.queue[w.consumption] 56 w.queue[w.consumption] = -1 57 w.consumption++ 58 if w.consumption >= MaxWorkNumber { 59 w.consumption = 0 60 } 61 w.queueMap[n] = -1 62 err = nil 63 } 64 w.mutex.Unlock() 65 return n, err 66 } 67 68 // 69 //当工作机器与工作组中心的时间不同步时,释放后再利用的workID与之前释放的workID的snowflake id会重复,逻辑上产生bug。 70 // 71 72 // PutID 还id 73 func (w *IDWorker) PutID(n int) { 74 if n < 0 || n >= MaxWorkNumber { 75 return 76 } 77 w.mutex.Lock() 78 if w.queueMap[n] != -1 || w.queue[w.production] != -1 { 79 w.mutex.Unlock() 80 return 81 } 82 w.queue[w.production] = n 83 w.queueMap[n] = w.production 84 w.production++ 85 if w.production >= MaxWorkNumber { 86 w.production = 0 87 } 88 w.mutex.Unlock() 89 } 90 91 func TestIDWorker(t *testing.T) { 92 // Test table 93 idWorkerTests := []int{2, 3, 8, 10, -1, MaxWorkNumber + 1, -10} 94 // Verify table 95 idWorkerVerify := []int{2, 3, 8, 10} 96 w := NewIDWorker(time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano()) 97 for i := 0; i < MaxWorkNumber; i++ { 98 f, err := w.GetID() 99 if f != i || err != nil { 100 t.Error(f, err, w) 101 } 102 } 103 g0, err := w.GetID() 104 if err == nil { 105 t.Error(g0, err, w) 106 } 107 for _, l := range idWorkerTests { 108 w.PutID(l) 109 } 110 for _, l := range idWorkerVerify { 111 g, err := w.GetID() 112 if l != g || err != nil { 113 t.Error(g, err, w) 114 } 115 116 } 117 } 118 func TestNextID(t *testing.T) { 119 var v [30000]int64 120 s1 := NewSnowFlakeIDPlus(1, time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano()) 121 for i := 0; i < 10000; i++ { 122 v[i] = s1.NextID() 123 } 124 time.Sleep(time.Millisecond) 125 s2 := NewSnowFlakeIDPlus(1, time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano()) 126 for i := 10000; i < 20000; i++ { 127 v[i] = s2.NextID() 128 } 129 s3 := NewSnowFlakeIDPlus(3, time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano()) 130 for i := 20000; i < 30000; i++ { 131 v[i] = s3.NextID() 132 } 133 //验证 134 for i := 0; i < (30000 - 1); i++ { 135 if v[i] >= v[i+1] { 136 t.Error("失败:i:", i, "v[i]:", v[i], "v[i+1]:", v[i+1]) 137 t.FailNow() 138 } 139 } 140 } 141 142 func TestGetWorkID(t *testing.T) { 143 s1 := NewSnowFlakeIDPlus(1, time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano()) 144 s2 := NewSnowFlakeIDPlus(555, time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano()) 145 s3 := NewSnowFlakeIDPlus(1022, time.Date(2017, time.January, 1, 0, 0, 0, 0, time.UTC).UnixNano()) 146 n1 := s1.NextID() 147 n2 := s2.NextID() 148 n3 := s3.NextID() 149 if GetWorkID(n1) != 1 || s1.GetWorkID() != 1 { 150 t.Error("失败:", n1, GetWorkID(n1), s1.GetWorkID()) 151 } 152 if GetWorkID(n2) != 555 || s2.GetWorkID() != 555 { 153 t.Error("失败:", n2, GetWorkID(n2), s2.GetWorkID()) 154 } 155 if GetWorkID(n3) != 1022 || s3.GetWorkID() != 1022 { 156 t.Error("失败:", n3, GetWorkID(n3), s3.GetWorkID()) 157 } 158 }