github.com/andy-kimball/arenaskl@v0.0.0-20200617143215-f701008588b9/skl_test.go (about) 1 /* 2 * Copyright 2017 Dgraph Labs, Inc. and Contributors 3 * Modifications copyright (C) 2017 Andy Kimball and Contributors 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package arenaskl 19 20 import ( 21 "encoding/binary" 22 "fmt" 23 "math/rand" 24 "strconv" 25 "sync" 26 "sync/atomic" 27 "testing" 28 "time" 29 30 "github.com/stretchr/testify/require" 31 ) 32 33 const arenaSize = 1 << 20 34 35 func newValue(v int) []byte { 36 return []byte(fmt.Sprintf("%05d", v)) 37 } 38 39 // length iterates over skiplist to give exact size. 40 func length(s *Skiplist) int { 41 count := 0 42 43 var it Iterator 44 it.Init(s) 45 46 for it.SeekToFirst(); it.Valid(); it.Next() { 47 count++ 48 } 49 50 return count 51 } 52 53 // length iterates over skiplist in reverse order to give exact size. 54 func lengthRev(s *Skiplist) int { 55 count := 0 56 57 var it Iterator 58 it.Init(s) 59 60 for it.SeekToLast(); it.Valid(); it.Prev() { 61 count++ 62 } 63 64 return count 65 } 66 67 func TestEmpty(t *testing.T) { 68 key := []byte("aaa") 69 l := NewSkiplist(NewArena(arenaSize)) 70 71 var it Iterator 72 it.Init(l) 73 74 require.False(t, it.Valid()) 75 76 it.SeekToFirst() 77 require.False(t, it.Valid()) 78 79 it.SeekToLast() 80 require.False(t, it.Valid()) 81 82 found := it.Seek(key) 83 require.False(t, found) 84 require.False(t, it.Valid()) 85 } 86 87 func TestFull(t *testing.T) { 88 l := NewSkiplist(NewArena(1000)) 89 90 var it Iterator 91 it.Init(l) 92 93 foundArenaFull := false 94 for i := 0; i < 100; i++ { 95 err := it.Add([]byte(fmt.Sprintf("%05d", i)), newValue(i), 0) 96 if err == ErrArenaFull { 97 foundArenaFull = true 98 } 99 } 100 101 require.True(t, foundArenaFull) 102 103 err := it.Set([]byte("someval"), 0) 104 require.Equal(t, ErrArenaFull, err) 105 106 // Delete does not perform any allocation. 107 err = it.Delete() 108 require.Nil(t, err) 109 } 110 111 // TestBasic tests single-threaded seeks and sets, adds, and deletes. 112 func TestBasic(t *testing.T) { 113 l := NewSkiplist(NewArena(arenaSize)) 114 115 var it Iterator 116 it.Init(l) 117 118 val1 := newValue(42) 119 val2 := newValue(52) 120 val3 := newValue(62) 121 val4 := newValue(72) 122 123 // Try adding values. 124 it.Add([]byte("key1"), val1, 0) 125 it.Add([]byte("key3"), val3, 0xffff) 126 it.Add([]byte("key2"), val2, 100) 127 128 require.False(t, it.Seek([]byte("key"))) 129 130 require.True(t, it.Seek([]byte("key1"))) 131 require.EqualValues(t, "00042", it.Value()) 132 require.EqualValues(t, 0, it.Meta()) 133 134 require.True(t, it.Seek([]byte("key2"))) 135 require.EqualValues(t, "00052", it.Value()) 136 require.EqualValues(t, 100, it.Meta()) 137 138 require.True(t, it.Seek([]byte("key3"))) 139 require.EqualValues(t, "00062", it.Value()) 140 require.EqualValues(t, 0xffff, it.Meta()) 141 142 require.True(t, it.Seek([]byte("key2"))) 143 require.Nil(t, it.Set(val4, 101)) 144 require.EqualValues(t, "00072", it.Value()) 145 require.EqualValues(t, 101, it.Meta()) 146 147 require.True(t, it.Seek([]byte("key3"))) 148 require.Nil(t, it.Delete()) 149 require.True(t, !it.Valid()) 150 } 151 152 // TestConcurrentBasic tests concurrent writes followed by concurrent reads. 153 func TestConcurrentBasic(t *testing.T) { 154 const n = 1000 155 156 // Set testing flag to make it easier to trigger unusual race conditions. 157 l := NewSkiplist(NewArena(arenaSize)) 158 l.testing = true 159 160 var wg sync.WaitGroup 161 for i := 0; i < n; i++ { 162 wg.Add(1) 163 go func(i int) { 164 defer wg.Done() 165 166 var it Iterator 167 it.Init(l) 168 169 it.Add([]byte(fmt.Sprintf("%05d", i)), newValue(i), 0) 170 }(i) 171 } 172 wg.Wait() 173 174 // Check values. Concurrent reads. 175 for i := 0; i < n; i++ { 176 wg.Add(1) 177 go func(i int) { 178 defer wg.Done() 179 180 var it Iterator 181 it.Init(l) 182 183 found := it.Seek([]byte(fmt.Sprintf("%05d", i))) 184 require.True(t, found) 185 require.EqualValues(t, newValue(i), it.Value()) 186 }(i) 187 } 188 wg.Wait() 189 require.Equal(t, n, length(l)) 190 require.Equal(t, n, lengthRev(l)) 191 } 192 193 // TestConcurrentOneKey will read while writing to one single key. 194 func TestConcurrentOneKey(t *testing.T) { 195 const n = 100 196 key := []byte("thekey") 197 198 // Set testing flag to make it easier to trigger unusual race conditions. 199 l := NewSkiplist(NewArena(arenaSize)) 200 l.testing = true 201 202 var wg sync.WaitGroup 203 for i := 0; i < n; i++ { 204 wg.Add(1) 205 go func(i int) { 206 defer wg.Done() 207 208 var it Iterator 209 it.Init(l) 210 it.Add(key, newValue(i), 0) 211 }(i) 212 } 213 // We expect that at least some write made it such that some read returns a value. 214 var sawValue int32 215 for i := 0; i < n; i++ { 216 wg.Add(1) 217 go func() { 218 defer wg.Done() 219 220 var it Iterator 221 it.Init(l) 222 if !it.Seek(key) { 223 return 224 } 225 226 atomic.StoreInt32(&sawValue, 1) 227 v, err := strconv.Atoi(string(it.Value())) 228 require.NoError(t, err) 229 require.True(t, 0 <= v && v < n) 230 }() 231 } 232 wg.Wait() 233 require.True(t, sawValue > 0) 234 require.Equal(t, 1, length(l)) 235 require.Equal(t, 1, lengthRev(l)) 236 } 237 238 func TestIteratorAdd(t *testing.T) { 239 l := NewSkiplist(NewArena(arenaSize)) 240 241 var it Iterator 242 it.Init(l) 243 244 // Add nil key and value (treated same as empty). 245 err := it.Add(nil, nil, 0) 246 require.Nil(t, err) 247 require.EqualValues(t, []byte{}, it.Key()) 248 require.EqualValues(t, []byte{}, it.Value()) 249 require.EqualValues(t, 0, it.Meta()) 250 it.Delete() 251 252 // Add empty key and value (treated same as nil). 253 err = it.Add([]byte{}, []byte{}, 0) 254 require.Nil(t, err) 255 require.EqualValues(t, []byte{}, it.Key()) 256 require.EqualValues(t, []byte{}, it.Value()) 257 require.EqualValues(t, 0, it.Meta()) 258 259 // Add to empty list. 260 err = it.Add([]byte("00002"), []byte("00002"), 50) 261 require.Nil(t, err) 262 require.EqualValues(t, "00002", it.Value()) 263 require.EqualValues(t, 50, it.Meta()) 264 265 // Add first element in non-empty list. 266 err = it.Add([]byte("00001"), []byte("00001"), 100) 267 require.Nil(t, err) 268 require.EqualValues(t, "00001", it.Value()) 269 require.EqualValues(t, 100, it.Meta()) 270 271 // Add last element in non-empty list. 272 err = it.Add([]byte("00004"), []byte("00004"), 150) 273 require.Nil(t, err) 274 require.EqualValues(t, "00004", it.Value()) 275 require.EqualValues(t, 150, it.Meta()) 276 277 // Add element in middle of list. 278 err = it.Add([]byte("00003"), []byte("00003"), 200) 279 require.Nil(t, err) 280 require.EqualValues(t, "00003", it.Value()) 281 require.EqualValues(t, 200, it.Meta()) 282 283 // Try to add element that already exists. 284 err = it.Add([]byte("00002"), []byte("00002*"), 250) 285 require.Equal(t, ErrRecordExists, err) 286 require.EqualValues(t, []byte("00002"), it.Value()) 287 require.EqualValues(t, 50, it.Meta()) 288 289 // Try to add element that was previously deleted. 290 it.Seek([]byte("00004")) 291 it.Delete() 292 err = it.Add([]byte("00004"), []byte("00004*"), 300) 293 require.Nil(t, err) 294 require.EqualValues(t, []byte("00004*"), it.Value()) 295 require.EqualValues(t, 300, it.Meta()) 296 297 require.Equal(t, 5, length(l)) 298 require.Equal(t, 5, lengthRev(l)) 299 } 300 301 func TestIteratorSet(t *testing.T) { 302 l := NewSkiplist(NewArena(arenaSize)) 303 304 var it Iterator 305 it.Init(l) 306 307 var it2 Iterator 308 it2.Init(l) 309 310 // Set when iterator position is invalid. 311 require.Panics(t, func() { it.Set([]byte("00001a"), 0) }) 312 313 // Set new value. 314 it.Add([]byte("00001"), []byte("00001a"), 100) 315 err := it.Set([]byte("00001b"), 200) 316 require.Nil(t, err) 317 require.EqualValues(t, "00001b", it.Value()) 318 require.EqualValues(t, 200, it.Meta()) 319 320 // Try to set value that's been updated by a different iterator. 321 it2.Seek([]byte("00001")) 322 err = it.Set([]byte("00001c"), 300) 323 require.Nil(t, err) 324 err = it2.Set([]byte("00001d"), 400) 325 require.Equal(t, ErrRecordUpdated, err) 326 require.EqualValues(t, []byte("00001c"), it2.Value()) 327 require.EqualValues(t, 300, it2.Meta()) 328 err = it2.Set([]byte("00001d"), 400) 329 require.Nil(t, err) 330 require.EqualValues(t, "00001d", it2.Value()) 331 require.EqualValues(t, 400, it2.Meta()) 332 333 // Try to set value that's been deleted by a different iterator. 334 it.Seek([]byte("00001")) 335 it2.Seek([]byte("00001")) 336 err = it.Delete() 337 require.Nil(t, err) 338 err = it.Add([]byte("00002"), []byte("00002"), 500) 339 require.Nil(t, err) 340 err = it2.Set([]byte("00001e"), 600) 341 require.Equal(t, ErrRecordDeleted, err) 342 require.EqualValues(t, "00001d", it2.Value()) 343 require.EqualValues(t, 400, it2.Meta()) 344 345 require.Equal(t, 1, length(l)) 346 require.Equal(t, 1, lengthRev(l)) 347 } 348 349 func TestIteratorSetMeta(t *testing.T) { 350 l := NewSkiplist(NewArena(arenaSize)) 351 352 var it Iterator 353 it.Init(l) 354 355 var it2 Iterator 356 it2.Init(l) 357 358 // SetMeta when iterator position is invalid. 359 require.Panics(t, func() { it.SetMeta(0) }) 360 361 // SetMeta new value. 362 it.Add([]byte("00001"), []byte("00001a"), 100) 363 val := it.Value() 364 err := it.SetMeta(200) 365 require.Nil(t, err) 366 require.EqualValues(t, "00001a", it.Value()) 367 require.True(t, &val[0] == &it.Value()[0], "Value bytes should not be reused") 368 require.EqualValues(t, 200, it.Meta()) 369 370 // SetMeta new lower value. 371 err = it.SetMeta(50) 372 require.Nil(t, err) 373 require.EqualValues(t, "00001a", it.Value()) 374 require.False(t, &val[0] == &it.Value()[0], "Value bytes should not be reused") 375 require.EqualValues(t, 50, it.Meta()) 376 377 // Try to set meta that's been updated by a different iterator. 378 it2.Seek([]byte("00001")) 379 err = it.SetMeta(300) 380 require.Nil(t, err) 381 err = it2.SetMeta(400) 382 require.Equal(t, ErrRecordUpdated, err) 383 require.EqualValues(t, 300, it2.Meta()) 384 err = it2.SetMeta(400) 385 require.Nil(t, err) 386 require.EqualValues(t, 400, it2.Meta()) 387 388 // Try to set value that's been deleted by a different iterator. 389 it.Seek([]byte("00001")) 390 it2.Seek([]byte("00001")) 391 err = it.Delete() 392 require.Nil(t, err) 393 err = it.Add([]byte("00002"), []byte("00002"), 500) 394 require.Nil(t, err) 395 err = it2.SetMeta(600) 396 require.Equal(t, ErrRecordDeleted, err) 397 require.EqualValues(t, 400, it2.Meta()) 398 399 require.Equal(t, 1, length(l)) 400 require.Equal(t, 1, lengthRev(l)) 401 } 402 403 func TestIteratorDelete(t *testing.T) { 404 l := NewSkiplist(NewArena(arenaSize)) 405 406 var it Iterator 407 it.Init(l) 408 409 var it2 Iterator 410 it2.Init(l) 411 412 // Delete when iterator position is invalid. 413 require.Panics(t, func() { it.Delete() }) 414 415 it.Add([]byte("00001"), []byte("00001"), 100) 416 it.Add([]byte("00002"), []byte("00002"), 200) 417 it.Add([]byte("00003"), []byte("00003"), 300) 418 it.Add([]byte("00004"), []byte("00004"), 400) 419 420 // Delete first node. 421 it.SeekToFirst() 422 err := it.Delete() 423 require.Nil(t, err) 424 require.EqualValues(t, "00002", it.Value()) 425 require.EqualValues(t, 200, it.Meta()) 426 427 // Delete last node. 428 it.Seek([]byte("00004")) 429 err = it.Delete() 430 require.Nil(t, err) 431 require.False(t, it.Valid()) 432 require.Equal(t, 2, length(l)) 433 434 // Try to delete node that's been updated by another iterator. 435 it.SeekToFirst() 436 require.EqualValues(t, "00002", it.Value()) 437 it2.SeekToFirst() 438 require.EqualValues(t, "00002", it2.Value()) 439 it2.Set([]byte("00002a"), 500) 440 err = it.Delete() 441 require.Equal(t, ErrRecordUpdated, err) 442 require.EqualValues(t, "00002a", it.Value()) 443 require.EqualValues(t, 500, it.Meta()) 444 445 // Delete node that's been deleted by another iterator. 446 err = it2.Delete() 447 require.Nil(t, err) 448 err = it.Delete() 449 require.Nil(t, err) 450 require.EqualValues(t, "00003", it.Value()) 451 require.EqualValues(t, 300, it.Meta()) 452 453 // Delete final node so that list is empty. 454 err = it.Delete() 455 require.Nil(t, err) 456 require.False(t, it.Valid()) 457 require.Equal(t, 0, length(l)) 458 require.Equal(t, 0, lengthRev(l)) 459 } 460 461 // TestConcurrentAdd races between adding same nodes. 462 func TestConcurrentAdd(t *testing.T) { 463 const n = 100 464 465 // Set testing flag to make it easier to trigger unusual race conditions. 466 l := NewSkiplist(NewArena(arenaSize)) 467 l.testing = true 468 469 start := make([]sync.WaitGroup, n) 470 end := make([]sync.WaitGroup, n) 471 472 for i := 0; i < n; i++ { 473 start[i].Add(1) 474 end[i].Add(2) 475 } 476 477 for f := 0; f < 2; f++ { 478 go func(id int) { 479 var it Iterator 480 it.Init(l) 481 482 for i := 0; i < n; i++ { 483 start[i].Wait() 484 485 key := newValue(i) 486 val := []byte(fmt.Sprintf("%d: %05d", id, i)) 487 if it.Add(key, val, 0) == nil { 488 it.Seek(key) 489 require.EqualValues(t, val, it.Value()) 490 } 491 492 end[i].Done() 493 } 494 }(f) 495 } 496 497 for i := 0; i < n; i++ { 498 start[i].Done() 499 end[i].Wait() 500 } 501 502 require.Equal(t, n, length(l)) 503 require.Equal(t, n, lengthRev(l)) 504 } 505 506 // TestConcurrentAddDelete races between adding and deleting the same node. 507 func TestConcurrentAddDelete(t *testing.T) { 508 const n = 100 509 510 // Set testing flag to make it easier to trigger unusual race conditions. 511 l := NewSkiplist(NewArena(arenaSize)) 512 l.testing = true 513 514 var wg sync.WaitGroup 515 for i := 0; i < n; i++ { 516 key := []byte("key") 517 val := newValue(i) 518 519 wg.Add(1) 520 go func(i int) { 521 defer wg.Done() 522 523 var it Iterator 524 it.Init(l) 525 526 for { 527 if it.Add(key, val, 0) == nil { 528 require.EqualValues(t, val, it.Value()) 529 break 530 } 531 532 require.NotEqual(t, val, it.Value()) 533 if it.Delete() == nil { 534 require.False(t, it.Valid()) 535 } 536 } 537 }(i) 538 } 539 wg.Wait() 540 541 require.Equal(t, 1, length(l)) 542 require.Equal(t, 1, lengthRev(l)) 543 } 544 545 // TestIteratorNext tests a basic iteration over all nodes from the beginning. 546 func TestIteratorNext(t *testing.T) { 547 const n = 100 548 l := NewSkiplist(NewArena(arenaSize)) 549 550 var it Iterator 551 it.Init(l) 552 553 require.False(t, it.Valid()) 554 555 it.SeekToFirst() 556 require.False(t, it.Valid()) 557 558 for i := n - 1; i >= 0; i-- { 559 it.Add([]byte(fmt.Sprintf("%05d", i)), newValue(i), 0) 560 } 561 562 it.SeekToFirst() 563 for i := 0; i < n; i++ { 564 require.True(t, it.Valid()) 565 require.EqualValues(t, newValue(i), it.Value()) 566 it.Next() 567 } 568 require.False(t, it.Valid()) 569 } 570 571 // TestIteratorPrev tests a basic iteration over all nodes from the end. 572 func TestIteratorPrev(t *testing.T) { 573 const n = 100 574 l := NewSkiplist(NewArena(arenaSize)) 575 576 var it Iterator 577 it.Init(l) 578 579 require.False(t, it.Valid()) 580 581 it.SeekToLast() 582 require.False(t, it.Valid()) 583 584 for i := 0; i < n; i++ { 585 it.Add([]byte(fmt.Sprintf("%05d", i)), newValue(i), 0) 586 } 587 588 it.SeekToLast() 589 for i := n - 1; i >= 0; i-- { 590 require.True(t, it.Valid()) 591 require.EqualValues(t, newValue(i), it.Value()) 592 it.Prev() 593 } 594 require.False(t, it.Valid()) 595 } 596 597 func TestIteratorSeek(t *testing.T) { 598 const n = 100 599 l := NewSkiplist(NewArena(arenaSize)) 600 601 var it Iterator 602 it.Init(l) 603 604 require.False(t, it.Valid()) 605 it.SeekToFirst() 606 require.False(t, it.Valid()) 607 // 1000, 1010, 1020, ..., 1990. 608 for i := n - 1; i >= 0; i-- { 609 v := i*10 + 1000 610 it.Add([]byte(fmt.Sprintf("%05d", i*10+1000)), newValue(v), uint16(v)) 611 } 612 613 found := it.Seek([]byte("")) 614 require.False(t, found) 615 require.True(t, it.Valid()) 616 require.EqualValues(t, "01000", it.Value()) 617 require.EqualValues(t, 1000, it.Meta()) 618 619 found = it.Seek([]byte("01000")) 620 require.True(t, found) 621 require.True(t, it.Valid()) 622 require.EqualValues(t, "01000", it.Value()) 623 require.EqualValues(t, 1000, it.Meta()) 624 625 found = it.Seek([]byte("01005")) 626 require.False(t, found) 627 require.True(t, it.Valid()) 628 require.EqualValues(t, "01010", it.Value()) 629 require.EqualValues(t, 1010, it.Meta()) 630 631 found = it.Seek([]byte("01010")) 632 require.True(t, found) 633 require.True(t, it.Valid()) 634 require.EqualValues(t, "01010", it.Value()) 635 require.EqualValues(t, 1010, it.Meta()) 636 637 found = it.Seek([]byte("99999")) 638 require.False(t, found) 639 require.False(t, it.Valid()) 640 641 // Test seek for deleted key. 642 it.Seek([]byte("01020")) 643 it.Delete() 644 found = it.Seek([]byte("01020")) 645 require.False(t, found) 646 require.True(t, it.Valid()) 647 require.EqualValues(t, "01030", it.Value()) 648 require.EqualValues(t, 1030, it.Meta()) 649 650 // Test seek for empty key. 651 it.Add(nil, nil, 0) 652 found = it.Seek(nil) 653 require.True(t, found) 654 require.True(t, it.Valid()) 655 require.EqualValues(t, "", it.Value()) 656 require.EqualValues(t, 0, it.Meta()) 657 658 found = it.Seek([]byte{}) 659 require.True(t, found) 660 require.True(t, it.Valid()) 661 require.EqualValues(t, "", it.Value()) 662 require.EqualValues(t, 0, it.Meta()) 663 } 664 665 func TestIteratorSeekForPrev(t *testing.T) { 666 const n = 100 667 l := NewSkiplist(NewArena(arenaSize)) 668 669 var it Iterator 670 it.Init(l) 671 672 require.False(t, it.Valid()) 673 it.SeekToFirst() 674 require.False(t, it.Valid()) 675 // 1000, 1010, 1020, ..., 1990. 676 for i := n - 1; i >= 0; i-- { 677 v := i*10 + 1000 678 it.Add([]byte(fmt.Sprintf("%05d", i*10+1000)), newValue(v), uint16(v)) 679 } 680 681 found := it.SeekForPrev([]byte("")) 682 require.False(t, found) 683 require.False(t, it.Valid()) 684 685 found = it.SeekForPrev([]byte("00990")) 686 require.False(t, found) 687 require.False(t, it.Valid()) 688 689 found = it.SeekForPrev([]byte("01000")) 690 require.True(t, found) 691 require.True(t, it.Valid()) 692 require.EqualValues(t, "01000", it.Value()) 693 require.EqualValues(t, 1000, it.Meta()) 694 695 found = it.SeekForPrev([]byte("01005")) 696 require.False(t, found) 697 require.True(t, it.Valid()) 698 require.EqualValues(t, "01000", it.Value()) 699 require.EqualValues(t, 1000, it.Meta()) 700 701 found = it.SeekForPrev([]byte("01990")) 702 require.True(t, found) 703 require.True(t, it.Valid()) 704 require.EqualValues(t, "01990", it.Value()) 705 require.EqualValues(t, 1990, it.Meta()) 706 707 found = it.SeekForPrev([]byte("99999")) 708 require.False(t, found) 709 require.True(t, it.Valid()) 710 require.EqualValues(t, "01990", it.Value()) 711 require.EqualValues(t, 1990, it.Meta()) 712 713 // Test seek for deleted key. 714 it.Seek([]byte("01020")) 715 it.Delete() 716 found = it.SeekForPrev([]byte("01020")) 717 require.False(t, found) 718 require.True(t, it.Valid()) 719 require.EqualValues(t, "01010", it.Value()) 720 require.EqualValues(t, 1010, it.Meta()) 721 722 // Test seek for empty key. 723 it.Add(nil, nil, 0) 724 found = it.SeekForPrev(nil) 725 require.True(t, found) 726 require.True(t, it.Valid()) 727 require.EqualValues(t, "", it.Value()) 728 require.EqualValues(t, 0, it.Meta()) 729 730 found = it.SeekForPrev([]byte{}) 731 require.True(t, found) 732 require.True(t, it.Valid()) 733 require.EqualValues(t, "", it.Value()) 734 require.EqualValues(t, 0, it.Meta()) 735 } 736 737 func randomKey(rng *rand.Rand) []byte { 738 b := make([]byte, 8) 739 key := rng.Uint32() 740 key2 := rng.Uint32() 741 binary.LittleEndian.PutUint32(b, key) 742 binary.LittleEndian.PutUint32(b[4:], key2) 743 return b 744 } 745 746 // Standard test. Some fraction is read. Some fraction is write. 747 func BenchmarkReadWrite(b *testing.B) { 748 value := newValue(123) 749 for i := 0; i <= 10; i++ { 750 readFrac := float32(i) / 10.0 751 b.Run(fmt.Sprintf("frac_%d", i*10), func(b *testing.B) { 752 l := NewSkiplist(NewArena(uint32((b.N + 2) * MaxNodeSize))) 753 b.ResetTimer() 754 var count int 755 b.RunParallel(func(pb *testing.PB) { 756 var iter Iterator 757 iter.Init(l) 758 759 rng := rand.New(rand.NewSource(time.Now().UnixNano())) 760 761 for pb.Next() { 762 if rng.Float32() < readFrac { 763 if iter.Seek(randomKey(rng)) { 764 _ = iter.Value() 765 count++ 766 } 767 } else { 768 iter.Add(randomKey(rng), value, 0) 769 } 770 } 771 }) 772 }) 773 } 774 } 775 776 // Standard test. Some fraction is read. Some fraction is write. Writes have 777 // to go through mutex lock. 778 func BenchmarkReadWriteMap(b *testing.B) { 779 value := newValue(123) 780 for i := 0; i <= 10; i++ { 781 readFrac := float32(i) / 10.0 782 b.Run(fmt.Sprintf("frac_%d", i), func(b *testing.B) { 783 m := make(map[string][]byte) 784 var mutex sync.RWMutex 785 b.ResetTimer() 786 var count int 787 b.RunParallel(func(pb *testing.PB) { 788 rng := rand.New(rand.NewSource(time.Now().UnixNano())) 789 for pb.Next() { 790 if rng.Float32() < readFrac { 791 mutex.RLock() 792 _, ok := m[string(randomKey(rng))] 793 mutex.RUnlock() 794 if ok { 795 count++ 796 } 797 } else { 798 mutex.Lock() 799 m[string(randomKey(rng))] = value 800 mutex.Unlock() 801 } 802 } 803 }) 804 }) 805 } 806 }