github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/list/x_conc_skl_test.go (about) 1 package list 2 3 import ( 4 "errors" 5 "fmt" 6 randv2 "math/rand/v2" 7 "sort" 8 "sync" 9 "sync/atomic" 10 "testing" 11 "time" 12 13 "github.com/benz9527/xboot/lib/id" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 func TestXConcSkl_SerialProcessing(t *testing.T) { 19 opts := make([]SklOption[uint64, *xSklObject], 0, 2) 20 opts = append(opts, WithXConcSklDataNodeUniqueMode[uint64, *xSklObject](), 21 WithSklKeyCmpDesc[uint64, *xSklObject]()) 22 23 skl, err := NewSkl[uint64, *xSklObject]( 24 XConcSkl, 25 opts..., 26 ) 27 require.NoError(t, err) 28 29 size := 5 30 for i := uint64(0); i < uint64(size); i++ { 31 for j := uint64(0); j < 10; j++ { 32 w := (i+1)*100 + j 33 _ = skl.Insert(w, &xSklObject{id: fmt.Sprintf("%d", w)}) 34 } 35 } 36 t.Logf("nodeLen: %d, indexCount: %d\n", skl.Len(), skl.IndexCount()) 37 38 obj, err := skl.LoadFirst(401) 39 require.NoError(t, err) 40 require.Equal(t, "401", obj.Val().id) 41 42 for i := uint64(0); i < uint64(size); i++ { 43 for j := uint64(0); j < 10; j++ { 44 w := (i+1)*100 + j 45 _, _ = skl.RemoveFirst(w) 46 } 47 } 48 require.Equal(t, int64(0), skl.Len()) 49 require.Equal(t, uint64(0), skl.IndexCount()) 50 } 51 52 func TestXConcSkl_DataRace(t *testing.T) { 53 opts := make([]SklOption[uint64, *xSklObject], 0, 2) 54 opts = append(opts, WithXConcSklDataNodeUniqueMode[uint64, *xSklObject]()) 55 56 skl, err := NewSkl[uint64, *xSklObject]( 57 XConcSkl, 58 opts..., 59 ) 60 require.NoError(t, err) 61 62 ele, err := skl.PopHead() 63 require.Nil(t, ele) 64 require.True(t, errors.Is(err, ErrXSklIsEmpty)) 65 66 size := 5 67 size2 := 10 68 var wg sync.WaitGroup 69 wg.Add(size * size2) 70 for i := uint64(0); i < uint64(size); i++ { 71 for j := uint64(0); j < uint64(size2); j++ { 72 go func(idx uint64) { 73 w := idx 74 time.Sleep(time.Duration(cryptoRandUint32()%5) * time.Millisecond) 75 _ = skl.Insert(w, &xSklObject{id: fmt.Sprintf("%d", w)}) 76 wg.Done() 77 }((i+1)*100 + j) 78 } 79 } 80 wg.Wait() 81 t.Logf("nodeLen: %d, indexCount: %d\n", skl.Len(), skl.IndexCount()) 82 83 obj, err := skl.LoadFirst(401) 84 require.NoError(t, err) 85 require.Equal(t, "401", obj.Val().id) 86 87 wg.Add(size * size2) 88 for i := uint64(0); i < uint64(size); i++ { 89 for j := uint64(0); j < uint64(size2); j++ { 90 go func(idx uint64) { 91 w := idx 92 time.Sleep(time.Duration(cryptoRandUint32()%5) * time.Millisecond) 93 _, _ = skl.RemoveFirst(w) 94 wg.Done() 95 }((i+1)*100 + j) 96 } 97 } 98 wg.Wait() 99 require.Equal(t, int64(0), skl.Len()) 100 require.Equal(t, uint64(0), skl.IndexCount()) 101 } 102 103 func TestXConcSkl_LinkedList_SerialProcessing(t *testing.T) { 104 skl := &xConcSkl[uint64, *xSklObject]{ 105 head: newXConcSklHead[uint64, *xSklObject](), 106 levels: 1, 107 nodeLen: 0, 108 vcmp: func(i, j *xSklObject) int64 { 109 // avoid calculation overflow 110 _i, _j := i.Hash(), j.Hash() 111 if _i == _j { 112 return 0 113 } else if _i > _j { 114 return 1 115 } 116 return -1 117 }, 118 rand: randomLevelV3, 119 flags: 0, 120 } 121 idGen, _ := id.MonotonicNonZeroID() 122 skl.optVer = idGen 123 skl.flags = setBitsAs(skl.flags, xConcSklXNodeModeFlagBits, uint32(linkedList)) 124 125 ele, err := skl.PopHead() 126 require.Nil(t, ele) 127 require.True(t, errors.Is(err, ErrXSklIsEmpty)) 128 129 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 9)}) 130 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 5)}) 131 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 8)}) 132 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 7)}) 133 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 1)}) 134 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 2)}) 135 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 4)}) 136 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 6)}) 137 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 9)}) 138 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 5)}) 139 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 8)}) 140 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 7)}) 141 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 1)}) 142 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 2)}) 143 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 4)}) 144 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 6)}) 145 skl.Insert(3, &xSklObject{id: fmt.Sprintf("%d", 100)}) 146 skl.Insert(3, &xSklObject{id: fmt.Sprintf("%d", 200)}) 147 skl.Insert(3, &xSklObject{id: fmt.Sprintf("%d", 2)}) 148 skl.Insert(1, &xSklObject{id: fmt.Sprintf("%d", 9)}) 149 skl.Insert(1, &xSklObject{id: fmt.Sprintf("%d", 200)}) 150 skl.Insert(1, &xSklObject{id: fmt.Sprintf("%d", 2)}) 151 152 t.Logf("nodeLen: %d, indexCount: %d\n", skl.Len(), skl.IndexCount()) 153 154 skl.Foreach(func(idx int64, item SklIterationItem[uint64, *xSklObject]) bool { 155 t.Logf("idx: %d, key: %v, value: %v, levels: %d, count: %d\n", idx, item.Key(), item.Val(), item.NodeLevel(), item.NodeItemCount()) 156 return true 157 }) 158 159 aux := make(xConcSklAux[uint64, *xSklObject], 2*sklMaxLevel) 160 foundResult := skl.rmTraverse(1, false, aux) 161 assert.LessOrEqual(t, int32(0), foundResult) 162 require.True(t, isSet(aux.loadPred(0).flags, nodeIsHeadFlagBit)) 163 require.Equal(t, uint64(1), aux.loadSucc(0).key) 164 require.Equal(t, "9", (*aux.loadSucc(0).atomicLoadRoot().linkedListNext().vptr).id) 165 166 foundResult = skl.rmTraverse(2, false, aux) 167 assert.LessOrEqual(t, int32(0), foundResult) 168 require.Equal(t, uint64(1), aux.loadPred(0).key) 169 require.Equal(t, "9", (*aux.loadPred(0).atomicLoadRoot().linkedListNext().vptr).id) 170 require.Equal(t, uint64(2), aux.loadSucc(0).key) 171 require.Equal(t, "9", (*aux.loadSucc(0).atomicLoadRoot().linkedListNext().vptr).id) 172 173 foundResult = skl.rmTraverse(3, false, aux) 174 assert.LessOrEqual(t, int32(0), foundResult) 175 require.Equal(t, uint64(2), aux.loadPred(0).key) 176 require.Equal(t, "9", (*aux.loadPred(0).atomicLoadRoot().linkedListNext().vptr).id) 177 require.Equal(t, uint64(3), aux.loadSucc(0).key) 178 require.Equal(t, "2", (*aux.loadSucc(0).atomicLoadRoot().linkedListNext().vptr).id) 179 180 foundResult = skl.rmTraverse(4, false, aux) 181 assert.LessOrEqual(t, int32(0), foundResult) 182 require.Equal(t, uint64(3), aux.loadPred(0).key) 183 require.Equal(t, "2", (*aux.loadPred(0).atomicLoadRoot().linkedListNext().vptr).id) 184 require.Equal(t, uint64(4), aux.loadSucc(0).key) 185 require.Equal(t, "9", (*aux.loadSucc(0).atomicLoadRoot().linkedListNext().vptr).id) 186 187 foundResult = skl.rmTraverse(100, false, aux) 188 assert.Equal(t, int32(-1), foundResult) 189 190 foundResult = skl.rmTraverse(0, false, aux) 191 assert.Equal(t, int32(-1), foundResult) 192 193 removed, err := skl.RemoveAll(3) 194 require.NoError(t, err) 195 require.Equal(t, uint64(3), removed[0].Key()) 196 require.Equal(t, "2", removed[0].Val().id) 197 require.Equal(t, uint64(3), removed[1].Key()) 198 require.Equal(t, "200", removed[1].Val().id) 199 require.Equal(t, uint64(3), removed[2].Key()) 200 require.Equal(t, "100", removed[2].Val().id) 201 skl.Foreach(func(idx int64, item SklIterationItem[uint64, *xSklObject]) bool { 202 if item.Key() == uint64(3) { 203 t.FailNow() 204 return false 205 } 206 return true 207 }) 208 209 removed, err = skl.RemoveIfMatch(2, func(that *xSklObject) bool { 210 return that.id == "8" 211 }) 212 require.NoError(t, err) 213 require.Equal(t, 1, len(removed)) 214 require.Equal(t, uint64(2), removed[0].Key()) 215 require.Equal(t, "8", removed[0].Val().id) 216 skl.Foreach(func(idx int64, item SklIterationItem[uint64, *xSklObject]) bool { 217 if item.Key() == uint64(2) && item.Val().id == "8" { 218 t.FailNow() 219 return false 220 } 221 return true 222 }) 223 224 loaded, err := skl.LoadAll(1) 225 require.NoError(t, err) 226 require.Equal(t, 3, len(loaded)) 227 require.Equal(t, uint64(1), loaded[0].Key()) 228 require.Equal(t, "9", loaded[0].Val().id) 229 require.Equal(t, uint64(1), loaded[1].Key()) 230 require.Equal(t, "2", loaded[1].Val().id) 231 require.Equal(t, uint64(1), loaded[2].Key()) 232 require.Equal(t, "200", loaded[2].Val().id) 233 234 loaded, err = skl.LoadIfMatch(2, func(that *xSklObject) bool { 235 return that.id == "9" 236 }) 237 require.NoError(t, err) 238 require.Equal(t, 1, len(loaded)) 239 require.Equal(t, uint64(2), loaded[0].Key()) 240 require.Equal(t, "9", loaded[0].Val().id) 241 } 242 243 func TestXConcSkl_Rbtree_SerialProcessing(t *testing.T) { 244 skl := &xConcSkl[uint64, *xSklObject]{ 245 head: newXConcSklHead[uint64, *xSklObject](), 246 levels: 1, 247 nodeLen: 0, 248 vcmp: func(i, j *xSklObject) int64 { 249 // avoid calculation overflow 250 _i, _j := i.Hash(), j.Hash() 251 if _i == _j { 252 return 0 253 } else if _i > _j { 254 return 1 255 } 256 return -1 257 }, 258 rand: randomLevelV3, 259 flags: 0, 260 } 261 idGen, _ := id.MonotonicNonZeroID() 262 skl.optVer = idGen 263 skl.flags = setBitsAs(skl.flags, xConcSklXNodeModeFlagBits, uint32(rbtree)) 264 265 ele, err := skl.PopHead() 266 require.Nil(t, ele) 267 require.True(t, errors.Is(err, ErrXSklIsEmpty)) 268 269 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 9)}) 270 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 5)}) 271 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 8)}) 272 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 7)}) 273 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 1)}) 274 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 2)}) 275 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 4)}) 276 skl.Insert(4, &xSklObject{id: fmt.Sprintf("%d", 6)}) 277 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 9)}) 278 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 5)}) 279 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 8)}) 280 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 7)}) 281 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 1)}) 282 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 2)}) 283 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 4)}) 284 skl.Insert(2, &xSklObject{id: fmt.Sprintf("%d", 6)}) 285 skl.Insert(3, &xSklObject{id: fmt.Sprintf("%d", 100)}) 286 skl.Insert(3, &xSklObject{id: fmt.Sprintf("%d", 200)}) 287 skl.Insert(3, &xSklObject{id: fmt.Sprintf("%d", 2)}) 288 skl.Insert(1, &xSklObject{id: fmt.Sprintf("%d", 9)}) 289 skl.Insert(1, &xSklObject{id: fmt.Sprintf("%d", 200)}) 290 skl.Insert(1, &xSklObject{id: fmt.Sprintf("%d", 2)}) 291 292 t.Logf("nodeLen: %d, indexCount: %d\n", skl.Len(), skl.IndexCount()) 293 294 skl.Foreach(func(idx int64, item SklIterationItem[uint64, *xSklObject]) bool { 295 t.Logf("idx: %d, key: %v, value: %v, levels: %d, count: %d\n", idx, item.Key(), item.Val(), item.NodeLevel(), item.NodeItemCount()) 296 return true 297 }) 298 299 removed, err := skl.RemoveAll(3) 300 require.NoError(t, err) 301 require.Equal(t, uint64(3), removed[0].Key()) 302 require.Equal(t, "2", removed[0].Val().id) 303 require.Equal(t, uint64(3), removed[1].Key()) 304 require.Equal(t, "200", removed[1].Val().id) 305 require.Equal(t, uint64(3), removed[2].Key()) 306 require.Equal(t, "100", removed[2].Val().id) 307 skl.Foreach(func(idx int64, item SklIterationItem[uint64, *xSklObject]) bool { 308 if item.Key() == uint64(3) { 309 t.FailNow() 310 return false 311 } 312 return true 313 }) 314 315 removed, err = skl.RemoveIfMatch(2, func(that *xSklObject) bool { 316 return that.id == "8" 317 }) 318 require.NoError(t, err) 319 require.Equal(t, 1, len(removed)) 320 require.Equal(t, uint64(2), removed[0].Key()) 321 require.Equal(t, "8", removed[0].Val().id) 322 skl.Foreach(func(idx int64, item SklIterationItem[uint64, *xSklObject]) bool { 323 if item.Key() == uint64(2) && item.Val().id == "8" { 324 t.FailNow() 325 return false 326 } 327 return true 328 }) 329 330 loaded, err := skl.LoadAll(1) 331 require.NoError(t, err) 332 require.Equal(t, 3, len(loaded)) 333 require.Equal(t, uint64(1), loaded[0].Key()) 334 require.Equal(t, "9", loaded[0].Val().id) 335 require.Equal(t, uint64(1), loaded[1].Key()) 336 require.Equal(t, "2", loaded[1].Val().id) 337 require.Equal(t, uint64(1), loaded[2].Key()) 338 require.Equal(t, "200", loaded[2].Val().id) 339 340 loaded, err = skl.LoadIfMatch(2, func(that *xSklObject) bool { 341 return that.id == "9" 342 }) 343 require.NoError(t, err) 344 require.Equal(t, 1, len(loaded)) 345 require.Equal(t, uint64(2), loaded[0].Key()) 346 require.Equal(t, "9", loaded[0].Val().id) 347 } 348 349 func xConcSklDuplicateDataRaceRunCore(t *testing.T, mode xNodeMode, rmBySucc bool) { 350 opts := []SklOption[uint64, int64]{ 351 WithSklRandLevelGen[uint64, int64](randomLevelV3), 352 } 353 switch mode { 354 case linkedList: 355 opts = append(opts, WithXConcSklDataNodeLinkedListMode[uint64, int64]( 356 func(i, j int64) int64 { 357 // avoid calculation overflow 358 if i == j { 359 return 0 360 } else if i > j { 361 return 1 362 } 363 return -1 364 })) 365 case rbtree: 366 opts = append(opts, WithXConcSklDataNodeRbtreeMode[uint64, int64]( 367 func(i, j int64) int64 { 368 // avoid calculation overflow 369 if i == j { 370 return 0 371 } else if i > j { 372 return 1 373 } 374 return -1 375 }, rmBySucc)) 376 } 377 378 skl, err := NewXSkl[uint64, int64]( 379 XConcSkl, 380 opts..., 381 ) 382 require.NoError(t, err) 383 384 ele, err := skl.PopHead() 385 require.Nil(t, ele) 386 require.True(t, errors.Is(err, ErrXSklIsEmpty)) 387 388 size := 10 389 size2 := 10 390 unorderedWeights := make([]int64, 0, size2) 391 for i := 0; i < size2; i++ { 392 unorderedWeights = append(unorderedWeights, int64(cryptoRandUint64())) 393 } 394 orderedWeights := make([]int64, 0, size2) 395 orderedWeights = append(orderedWeights, unorderedWeights...) 396 sort.Slice(orderedWeights, func(i, j int) bool { 397 return orderedWeights[i] < orderedWeights[j] 398 }) 399 400 var wg sync.WaitGroup 401 wg.Add(size * size2) 402 403 type answer struct { 404 w uint64 405 id int64 406 } 407 expected := make([]*answer, 0, size*size2) 408 409 for i := uint64(0); i < uint64(size); i++ { 410 for j := uint64(0); j < uint64(size2); j++ { 411 go func(_i, _j uint64) { 412 w := (_i + 1) * 100 413 time.Sleep(time.Duration(cryptoRandUint32()%5) * time.Millisecond) 414 _ = skl.Insert(w, unorderedWeights[_j]) 415 wg.Done() 416 }(i, j) 417 expected = append(expected, &answer{w: (i + 1) * 100, id: orderedWeights[j]}) 418 } 419 } 420 wg.Wait() 421 t.Logf("nodeLen: %d, indexCount: %d\n", skl.Len(), skl.IndexCount()) 422 423 skl.Foreach(func(idx int64, item SklIterationItem[uint64, int64]) bool { 424 require.Equalf(t, expected[idx].w, item.Key(), "exp: %d; actual: %d\n", expected[idx].w, item.Key()) 425 require.Equalf(t, expected[idx].id, item.Val(), "exp: %d; actual: %d\n", expected[idx].id, item.Val()) 426 return true 427 }) 428 429 wg.Add(size * size2) 430 for i := uint64(0); i < uint64(size); i++ { 431 for j := uint64(0); j < uint64(size2); j++ { 432 go func(_i, _j uint64) { 433 w := (_i + 1) * 100 434 time.Sleep(time.Duration(cryptoRandUint32()%5) * time.Millisecond) 435 if _, err := skl.RemoveFirst(w); err != nil { 436 t.Logf("remove failed, key: %d, err: %v\n", w, err) 437 } 438 wg.Done() 439 }(i, j) 440 } 441 } 442 wg.Wait() 443 require.Equal(t, int64(0), skl.Len()) 444 require.Equal(t, uint64(0), skl.IndexCount()) 445 } 446 447 func TestXConcSkl_Duplicate_DataRace(t *testing.T) { 448 type testcase struct { 449 name string 450 typ xNodeMode 451 rbRmBySucc bool 452 } 453 testcases := []testcase{ 454 { 455 name: "skl lock free mutex data race - linkedlist", 456 typ: linkedList, 457 }, 458 { 459 name: "skl lock free mutex data race - rbtree", 460 typ: rbtree, 461 }, 462 { 463 name: "skl lock free mutex data race - rbtree (succ)", 464 typ: rbtree, 465 rbRmBySucc: true, 466 }, 467 } 468 t.Parallel() 469 for _, tc := range testcases { 470 t.Run(tc.name, func(tt *testing.T) { 471 xConcSklDuplicateDataRaceRunCore(tt, tc.typ, tc.rbRmBySucc) 472 }) 473 } 474 } 475 476 func xConcSklPeekAndPopHeadRunCore(t *testing.T, mode xNodeMode) { 477 skl := &xConcSkl[uint64, int64]{ 478 head: newXConcSklHead[uint64, int64](), 479 levels: 1, 480 nodeLen: 0, 481 vcmp: func(i, j int64) int64 { 482 // avoid calculation overflow 483 if i == j { 484 return 0 485 } else if i > j { 486 return 1 487 } 488 return -1 489 }, 490 rand: randomLevelV3, 491 flags: 0, 492 } 493 idGen, _ := id.MonotonicNonZeroID() 494 skl.optVer = idGen 495 if mode != unique { 496 skl.flags = setBitsAs(skl.flags, xConcSklXNodeModeFlagBits, uint32(mode)) 497 } 498 499 ele, err := skl.PopHead() 500 require.Nil(t, ele) 501 require.True(t, errors.Is(err, ErrXSklIsEmpty)) 502 503 size := 10 504 size2 := 10 505 unorderedWeights := make([]int64, 0, size2) 506 for i := 0; i < size2; i++ { 507 unorderedWeights = append(unorderedWeights, int64(cryptoRandUint64())) 508 } 509 orderedWeights := make([]int64, 0, size2) 510 orderedWeights = append(orderedWeights, unorderedWeights...) 511 sort.Slice(orderedWeights, func(i, j int) bool { 512 return orderedWeights[i] < orderedWeights[j] 513 }) 514 515 type answer struct { 516 w uint64 517 id int64 518 } 519 expected := make([]*answer, 0, size*size2) 520 521 for i := uint64(0); i < uint64(size); i++ { 522 for j := uint64(0); j < uint64(size2); j++ { 523 w := (i + 1) * 100 524 _ = skl.Insert(w, orderedWeights[j]) 525 expected = append(expected, &answer{w: (i + 1) * 100, id: orderedWeights[j]}) 526 } 527 } 528 t.Logf("nodeLen: %d, indexCount: %d\n", skl.Len(), skl.IndexCount()) 529 530 if mode == unique { 531 skl.Foreach(func(idx int64, item SklIterationItem[uint64, int64]) bool { 532 require.Equalf(t, expected[idx*int64(size2)+9].w, item.Key(), "idx: %d; exp: %d; actual: %d\n", idx, expected[idx*int64(size2)+9].w, item.Key()) 533 require.Equalf(t, expected[idx*int64(size2)+9].id, item.Val(), "idx: %d; exp: %d; actual: %d\n", idx, expected[idx*int64(size2)+9].id, item.Val()) 534 return true 535 }) 536 } else { 537 skl.Foreach(func(idx int64, item SklIterationItem[uint64, int64]) bool { 538 require.Equalf(t, expected[idx].w, item.Key(), "exp: %d; actual: %d\n", expected[idx].w, item.Key()) 539 require.Equalf(t, expected[idx].id, item.Val(), "exp: %d; actual: %d\n", expected[idx].id, item.Val()) 540 return true 541 }) 542 } 543 544 for i := int64(0); skl.Len() > 0; i++ { 545 h1 := skl.PeekHead() 546 require.NotNil(t, h1) 547 h2, err := skl.PopHead() 548 require.NoError(t, err) 549 require.NotNil(t, h2) 550 if mode == unique { 551 require.Equal(t, expected[i*int64(size2)+9].w, h1.Key()) 552 require.Equal(t, expected[i*int64(size2)+9].id, h1.Val()) 553 } else { 554 require.Equal(t, expected[i].w, h1.Key()) 555 require.Equal(t, expected[i].id, h1.Val()) 556 } 557 require.Equal(t, h1.Key(), h2.Key()) 558 require.Equal(t, h1.Val(), h2.Val()) 559 } 560 } 561 562 func TestXConcSklPeekAndPopHead(t *testing.T) { 563 type testcase struct { 564 name string 565 typ xNodeMode 566 } 567 testcases := []testcase{ 568 { 569 name: "skl lock free mutex data race - unique", 570 typ: unique, 571 }, 572 { 573 name: "skl lock free mutex data race - linkedlist", 574 typ: linkedList, 575 }, 576 577 { 578 name: "skl lock free mutex data race - rbtree", 579 typ: rbtree, 580 }, 581 { 582 name: "skl lock free mutex data race - rbtree (succ)", 583 typ: rbtree, 584 }, 585 } 586 t.Parallel() 587 for _, tc := range testcases { 588 t.Run(tc.name, func(tt *testing.T) { 589 xConcSklPeekAndPopHeadRunCore(tt, tc.typ) 590 }) 591 } 592 } 593 594 func BenchmarkXConcSklUnique_Random(b *testing.B) { 595 testByBytes := []byte(`abc`) 596 597 b.StopTimer() 598 opts := make([]SklOption[int, []byte], 0, 2) 599 opts = append(opts, WithXConcSklDataNodeUniqueMode[int, []byte]()) 600 skl, err := NewSkl[int, []byte]( 601 XConcSkl, 602 opts..., 603 ) 604 if err != nil { 605 panic(err) 606 } 607 608 rngArr := make([]int, 0, b.N) 609 for i := 0; i < b.N; i++ { 610 rngArr = append(rngArr, randv2.Int()) 611 } 612 613 b.StartTimer() 614 for i := 0; i < b.N; i++ { 615 err := skl.Insert(rngArr[i], testByBytes) 616 if err != nil { 617 panic(err) 618 } 619 } 620 } 621 622 func BenchmarkXConcSklUnique_Serial(b *testing.B) { 623 testByBytes := []byte(`abc`) 624 625 b.StopTimer() 626 opts := make([]SklOption[int, []byte], 0, 2) 627 opts = append(opts, WithXConcSklDataNodeUniqueMode[int, []byte]()) 628 skl, err := NewSkl[int, []byte]( 629 XConcSkl, 630 opts..., 631 ) 632 if err != nil { 633 panic(err) 634 } 635 636 b.StartTimer() 637 for i := 0; i < b.N; i++ { 638 skl.Insert(i, testByBytes) 639 } 640 } 641 642 func TestXConcSklUnique(t *testing.T) { 643 testByBytes := []byte(`abc`) 644 645 opts := make([]SklOption[int, []byte], 0, 2) 646 opts = append(opts, WithXConcSklDataNodeUniqueMode[int, []byte]()) 647 skl, err := NewSkl[int, []byte]( 648 XConcSkl, 649 opts..., 650 ) 651 if err != nil { 652 panic(err) 653 } 654 655 for i := 0; i < 3000000; i++ { 656 skl.Insert(i, testByBytes) 657 } 658 } 659 660 func BenchmarkXSklReadWrite(b *testing.B) { 661 value := []byte(`abc`) 662 for i := 0; i <= 10; i++ { 663 b.Run(fmt.Sprintf("frac_%d", i), func(b *testing.B) { 664 readFrac := float32(i) / 10.0 665 opts := make([]SklOption[int, []byte], 0, 2) 666 opts = append(opts, WithXConcSklDataNodeUniqueMode[int, []byte]()) 667 skl, err := NewSkl[int, []byte]( 668 XConcSkl, 669 opts..., 670 ) 671 if err != nil { 672 panic(err) 673 } 674 b.ResetTimer() 675 count := atomic.Int64{} 676 b.RunParallel(func(pb *testing.PB) { 677 for pb.Next() { 678 if randv2.Float32() < readFrac { 679 v, err := skl.LoadFirst(randv2.Int()) 680 if err != nil && v != nil { 681 count.Add(1) 682 } 683 } else { 684 skl.Insert(randv2.Int(), value) 685 } 686 } 687 }) 688 }) 689 } 690 }