github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/maps/skipmap/skipmap_test.go (about) 1 package skipmap 2 3 import ( 4 "math/rand" 5 "reflect" 6 "runtime" 7 "sync" 8 "sync/atomic" 9 "testing" 10 11 "github.com/songzhibin97/go-baseutils/base/bcomparator" 12 "github.com/songzhibin97/go-baseutils/sys/fastrand" 13 ) 14 15 func TestSkipMap(t *testing.T) { 16 m := New[int64, any](bcomparator.Int64Comparator()) 17 18 // Correctness. 19 m.Store(123, "123") 20 v, ok := m.Load(123) 21 if !ok || v != "123" || m.Len() != 1 { 22 t.Fatal("invalid") 23 } 24 25 m.Store(123, "456") 26 v, ok = m.Load(123) 27 if !ok || v != "456" || m.Len() != 1 { 28 t.Fatal("invalid") 29 } 30 31 m.Store(123, 456) 32 v, ok = m.Load(123) 33 if !ok || v != 456 || m.Len() != 1 { 34 t.Fatal("invalid") 35 } 36 37 m.Delete(123) 38 v, ok = m.Load(123) 39 if ok || m.Len() != 0 || v != nil { 40 t.Fatal("invalid") 41 } 42 43 v, loaded := m.LoadOrStore(123, 456) 44 if loaded || v != 456 || m.Len() != 1 { 45 t.Fatal("invalid") 46 } 47 48 v, loaded = m.LoadOrStore(123, 789) 49 if !loaded || v != 456 || m.Len() != 1 { 50 t.Fatal("invalid") 51 } 52 53 v, ok = m.Load(123) 54 if !ok || v != 456 || m.Len() != 1 { 55 t.Fatal("invalid") 56 } 57 58 v, ok = m.LoadAndDelete(123) 59 if !ok || v != 456 || m.Len() != 0 { 60 t.Fatal("invalid") 61 } 62 63 _, ok = m.LoadOrStore(123, 456) 64 if ok || m.Len() != 1 { 65 t.Fatal("invalid") 66 } 67 68 m.LoadOrStore(456, 123) 69 if ok || m.Len() != 2 { 70 t.Fatal("invalid") 71 } 72 73 m.Range(func(key int64, _ interface{}) bool { 74 if key == 123 { 75 m.Store(123, 123) 76 } else if key == 456 { 77 m.LoadAndDelete(456) 78 } 79 return true 80 }) 81 82 v, ok = m.Load(123) 83 if !ok || v != 123 || m.Len() != 1 { 84 t.Fatal("invalid") 85 } 86 87 // Concurrent. 88 var wg sync.WaitGroup 89 for i := 0; i < 1000; i++ { 90 i := int64(i) 91 wg.Add(1) 92 go func() { 93 m.Store(i, int(i+1000)) 94 wg.Done() 95 }() 96 } 97 wg.Wait() 98 wg.Add(1) 99 go func() { 100 m.Delete(600) 101 wg.Done() 102 }() 103 wg.Wait() 104 wg.Add(1) 105 var count int64 106 go func() { 107 m.Range(func(_ int64, _ interface{}) bool { 108 atomic.AddInt64(&count, 1) 109 return true 110 }) 111 wg.Done() 112 }() 113 wg.Wait() 114 115 val, ok := m.Load(500) 116 if !ok || reflect.TypeOf(val).Kind().String() != "int" || val.(int) != 1500 { 117 t.Fatal("fail") 118 } 119 120 _, ok = m.Load(600) 121 if ok { 122 t.Fatal("fail") 123 } 124 125 if m.Len() != 999 || int(count) != m.Len() { 126 t.Fatal("fail") 127 } 128 // Correctness 2. 129 var m1 sync.Map 130 m2 := New[uint32, any](bcomparator.Uint32Comparator()) 131 var v1, v2 interface{} 132 var ok1, ok2 bool 133 for i := 0; i < 100000; i++ { 134 rd := fastrand.Uint32n(10) 135 r1, r2 := fastrand.Uint32n(100), fastrand.Uint32n(100) 136 if rd == 0 { 137 m1.Store(r1, r2) 138 m2.Store(r1, r2) 139 } else if rd == 1 { 140 v1, ok1 = m1.LoadAndDelete(r1) 141 v2, ok2 = m2.LoadAndDelete(r1) 142 if ok1 != ok2 || v1 != v2 { 143 t.Fatal(rd, v1, ok1, v2, ok2) 144 } 145 } else if rd == 2 { 146 v1, ok1 = m1.LoadOrStore(r1, r2) 147 v2, ok2 = m2.LoadOrStore(r1, r2) 148 if ok1 != ok2 || v1 != v2 { 149 t.Fatal(rd, v1, ok1, v2, ok2, "input -> ", r1, r2) 150 } 151 } else if rd == 3 { 152 m1.Delete(r1) 153 m2.Delete(r1) 154 } else if rd == 4 { 155 m2.Range(func(key uint32, value interface{}) bool { 156 v, ok := m1.Load(key) 157 if !ok || v != value { 158 t.Fatal(v, ok, key, value) 159 } 160 return true 161 }) 162 } else { 163 v1, ok1 = m1.Load(r1) 164 v2, ok2 = m2.Load(r1) 165 if ok1 != ok2 || v1 != v2 { 166 t.Fatal(rd, v1, ok1, v2, ok2) 167 } 168 } 169 } 170 // Correntness 3. (LoadOrStore) 171 // Only one LoadorStore can successfully insert its key and value. 172 // And the returned value is unique. 173 mp := New[int, any](bcomparator.IntComparator()) 174 tmpmap := New[int64, any](bcomparator.Int64Comparator()) 175 samekey := 123 176 var added int64 177 for i := 1; i < 1000; i++ { 178 wg.Add(1) 179 go func() { 180 v := fastrand.Int63() 181 actual, loaded := mp.LoadOrStore(samekey, v) 182 if !loaded { 183 atomic.AddInt64(&added, 1) 184 } 185 tmpmap.Store(actual.(int64), nil) 186 wg.Done() 187 }() 188 } 189 wg.Wait() 190 if added != 1 { 191 t.Fatal("only one LoadOrStore can successfully insert a key and value") 192 } 193 if tmpmap.Len() != 1 { 194 t.Fatal("only one value can be returned from LoadOrStore") 195 } 196 // Correntness 4. (LoadAndDelete) 197 // Only one LoadAndDelete can successfully get a value. 198 mp = New[int, any](bcomparator.IntComparator()) 199 tmpmap = New[int64, any](bcomparator.Int64Comparator()) 200 samekey = 123 201 added = 0 // int64 202 mp.Store(samekey, 555) 203 for i := 1; i < 1000; i++ { 204 wg.Add(1) 205 go func() { 206 value, loaded := mp.LoadAndDelete(samekey) 207 if loaded { 208 atomic.AddInt64(&added, 1) 209 if value != 555 { 210 panic("invalid") 211 } 212 } 213 wg.Done() 214 }() 215 } 216 wg.Wait() 217 if added != 1 { 218 t.Fatal("Only one LoadAndDelete can successfully get a value") 219 } 220 221 // Correntness 5. (LoadOrStoreLazy) 222 mp = New[int, any](bcomparator.IntComparator()) 223 tmpmap = New[int64, any](bcomparator.Int64Comparator()) 224 samekey = 123 225 added = 0 226 var fcalled int64 227 valuef := func() interface{} { 228 atomic.AddInt64(&fcalled, 1) 229 return fastrand.Int63() 230 } 231 for i := 1; i < 1000; i++ { 232 wg.Add(1) 233 go func() { 234 actual, loaded := mp.LoadOrStoreLazy(samekey, valuef) 235 if !loaded { 236 atomic.AddInt64(&added, 1) 237 } 238 tmpmap.Store(actual.(int64), nil) 239 wg.Done() 240 }() 241 } 242 wg.Wait() 243 if added != 1 || fcalled != 1 { 244 t.Fatal("only one LoadOrStoreLazy can successfully insert a key and value") 245 } 246 if tmpmap.Len() != 1 { 247 t.Fatal("only one value can be returned from LoadOrStoreLazy") 248 } 249 } 250 251 func TestSkipMapDesc(t *testing.T) { 252 m := New[int, any](bcomparator.ReverseComparator(bcomparator.IntComparator())) 253 cases := []int{10, 11, 12} 254 for _, v := range cases { 255 m.Store(v, nil) 256 } 257 i := len(cases) - 1 258 m.Range(func(key int, _ interface{}) bool { 259 if key != cases[i] { 260 t.Fail() 261 } 262 i-- 263 return true 264 }) 265 } 266 267 /* Test from sync.Map */ 268 func TestConcurrentRange(t *testing.T) { 269 const mapSize = 1 << 10 270 271 m := New[int64, any](bcomparator.Int64Comparator()) 272 for n := int64(1); n <= mapSize; n++ { 273 m.Store(n, int64(n)) 274 } 275 276 done := make(chan struct{}) 277 var wg sync.WaitGroup 278 defer func() { 279 close(done) 280 wg.Wait() 281 }() 282 for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- { 283 r := rand.New(rand.NewSource(g)) 284 wg.Add(1) 285 go func(g int64) { 286 defer wg.Done() 287 for i := int64(0); ; i++ { 288 select { 289 case <-done: 290 return 291 default: 292 } 293 for n := int64(1); n < mapSize; n++ { 294 if r.Int63n(mapSize) == 0 { 295 m.Store(n, n*i*g) 296 } else { 297 m.Load(n) 298 } 299 } 300 } 301 }(g) 302 } 303 304 iters := 1 << 10 305 if testing.Short() { 306 iters = 16 307 } 308 for n := iters; n > 0; n-- { 309 seen := make(map[int64]bool, mapSize) 310 311 m.Range(func(ki int64, vi interface{}) bool { 312 k, v := ki, vi.(int64) 313 if v%k != 0 { 314 t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v) 315 } 316 if seen[k] { 317 t.Fatalf("Range visited key %v twice", k) 318 } 319 seen[k] = true 320 return true 321 }) 322 323 if len(seen) != mapSize { 324 t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize) 325 } 326 } 327 }