github.com/pingcap/badger@v1.5.1-0.20230103063557-828f39b09b6d/table/memtable/skl_test.go (about) 1 /* 2 * Copyright 2017 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package memtable 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "math/rand" 24 "sort" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/pingcap/badger/cache/z" 30 "github.com/pingcap/badger/y" 31 "github.com/stretchr/testify/require" 32 ) 33 34 const arenaSize = 1 << 20 35 36 func newValue(v int) []byte { 37 return []byte(fmt.Sprintf("%05d", v)) 38 } 39 40 // length iterates over skiplist to give exact size. 41 func length(s *skiplist) int { 42 x := s.getNext(s.head, 0) 43 count := 0 44 for x != nil { 45 count++ 46 x = s.getNext(x, 0) 47 } 48 return count 49 } 50 51 func TestEmpty(t *testing.T) { 52 key := []byte("aaa") 53 l := newSkiplist(arenaSize) 54 55 v := l.Get(key, 1) 56 require.True(t, v.Value == nil) // Cannot use require.Nil for unsafe.Pointer nil. 57 58 for _, less := range []bool{true, false} { 59 for _, allowEqual := range []bool{true, false} { 60 n, found := l.findNear(key, less, allowEqual) 61 require.Nil(t, n) 62 require.False(t, found) 63 } 64 } 65 66 it := l.NewIterator() 67 require.False(t, it.Valid()) 68 69 it.SeekToFirst() 70 require.False(t, it.Valid()) 71 72 it.SeekToLast() 73 require.False(t, it.Valid()) 74 75 it.Seek(key) 76 require.False(t, it.Valid()) 77 it.Close() 78 } 79 80 // TestBasic tests single-threaded inserts and updates and gets. 81 func TestBasic(t *testing.T) { 82 l := newSkiplist(arenaSize) 83 val1 := newValue(42) 84 val2 := newValue(52) 85 val3 := newValue(62) 86 val4 := newValue(72) 87 88 // Try inserting values. 89 // Somehow require.Nil doesn't work when checking for unsafe.Pointer(nil). 90 l.Put([]byte("key1"), y.ValueStruct{Value: val1, Meta: 55, UserMeta: []byte{0}}) 91 l.Put([]byte("key2"), y.ValueStruct{Value: val2, Meta: 56, UserMeta: []byte{0}, Version: 2}) 92 l.Put([]byte("key3"), y.ValueStruct{Value: val3, Meta: 57, UserMeta: []byte{0}}) 93 94 v := l.Get([]byte("key"), 0) 95 require.True(t, v.Value == nil) 96 97 v = l.Get([]byte("key1"), 0) 98 require.True(t, v.Value != nil) 99 require.EqualValues(t, "00042", string(v.Value)) 100 require.EqualValues(t, 55, v.Meta) 101 102 v = l.Get([]byte("key2"), 0) 103 require.True(t, v.Value == nil) 104 105 v = l.Get([]byte("key3"), 0) 106 require.True(t, v.Value != nil) 107 require.EqualValues(t, "00062", string(v.Value)) 108 require.EqualValues(t, 57, v.Meta) 109 110 l.Put([]byte("key3"), y.ValueStruct{Value: val4, Meta: 12, UserMeta: []byte{0}, Version: 1}) 111 v = l.Get([]byte("key3"), 1) 112 require.True(t, v.Value != nil) 113 require.EqualValues(t, "00072", string(v.Value)) 114 require.EqualValues(t, 12, v.Meta) 115 } 116 117 // TestConcurrentBasic tests concurrent writes followed by concurrent reads. 118 func TestConcurrentBasic(t *testing.T) { 119 const n = 1000 120 l := newSkiplist(arenaSize) 121 var wg sync.WaitGroup 122 key := func(i int) []byte { 123 return []byte(fmt.Sprintf("%05d", i)) 124 } 125 for i := 0; i < n; i++ { 126 wg.Add(1) 127 go func(i int) { 128 defer wg.Done() 129 l.Put(key(i), 130 y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}}) 131 }(i) 132 } 133 wg.Wait() 134 // Check values. Concurrent reads. 135 for i := 0; i < n; i++ { 136 wg.Add(1) 137 go func(i int) { 138 defer wg.Done() 139 v := l.Get(key(i), 0) 140 require.True(t, v.Value != nil) 141 require.EqualValues(t, newValue(i), v.Value) 142 }(i) 143 } 144 wg.Wait() 145 require.EqualValues(t, n, length(l)) 146 } 147 148 func TestFindNear(t *testing.T) { 149 l := newSkiplist(arenaSize) 150 defer l.Delete() 151 for i := 0; i < 1000; i++ { 152 key := fmt.Sprintf("%05d", i*10+5) 153 l.Put([]byte(key), y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}}) 154 } 155 156 n, eq := l.findNear([]byte("00001"), false, false) 157 require.NotNil(t, n) 158 require.EqualValues(t, []byte("00005"), n.key(l.arena)) 159 require.False(t, eq) 160 n, eq = l.findNear([]byte("00001"), false, true) 161 require.NotNil(t, n) 162 require.EqualValues(t, []byte("00005"), n.key(l.arena)) 163 require.False(t, eq) 164 n, eq = l.findNear([]byte("00001"), true, false) 165 require.Nil(t, n) 166 require.False(t, eq) 167 n, eq = l.findNear([]byte("00001"), true, true) 168 require.Nil(t, n) 169 require.False(t, eq) 170 171 n, eq = l.findNear([]byte("00005"), false, false) 172 require.NotNil(t, n) 173 require.EqualValues(t, []byte("00015"), n.key(l.arena)) 174 require.False(t, eq) 175 n, eq = l.findNear([]byte("00005"), false, true) 176 require.NotNil(t, n) 177 require.EqualValues(t, []byte("00005"), n.key(l.arena)) 178 require.True(t, eq) 179 n, eq = l.findNear([]byte("00005"), true, false) 180 require.Nil(t, n) 181 require.False(t, eq) 182 n, eq = l.findNear([]byte("00005"), true, true) 183 require.NotNil(t, n) 184 require.EqualValues(t, []byte("00005"), n.key(l.arena)) 185 require.True(t, eq) 186 187 n, eq = l.findNear([]byte("05555"), false, false) 188 require.NotNil(t, n) 189 require.EqualValues(t, []byte("05565"), n.key(l.arena)) 190 require.False(t, eq) 191 n, eq = l.findNear([]byte("05555"), false, true) 192 require.NotNil(t, n) 193 require.EqualValues(t, []byte("05555"), n.key(l.arena)) 194 require.True(t, eq) 195 n, eq = l.findNear([]byte("05555"), true, false) 196 require.NotNil(t, n) 197 require.EqualValues(t, []byte("05545"), n.key(l.arena)) 198 require.False(t, eq) 199 n, eq = l.findNear([]byte("05555"), true, true) 200 require.NotNil(t, n) 201 require.EqualValues(t, []byte("05555"), n.key(l.arena)) 202 require.True(t, eq) 203 204 n, eq = l.findNear([]byte("05558"), false, false) 205 require.NotNil(t, n) 206 require.EqualValues(t, []byte("05565"), n.key(l.arena)) 207 require.False(t, eq) 208 n, eq = l.findNear([]byte("05558"), false, true) 209 require.NotNil(t, n) 210 require.EqualValues(t, []byte("05565"), n.key(l.arena)) 211 require.False(t, eq) 212 n, eq = l.findNear([]byte("05558"), true, false) 213 require.NotNil(t, n) 214 require.EqualValues(t, []byte("05555"), n.key(l.arena)) 215 require.False(t, eq) 216 n, eq = l.findNear([]byte("05558"), true, true) 217 require.NotNil(t, n) 218 require.EqualValues(t, []byte("05555"), n.key(l.arena)) 219 require.False(t, eq) 220 221 n, eq = l.findNear([]byte("09995"), false, false) 222 require.Nil(t, n) 223 require.False(t, eq) 224 n, eq = l.findNear([]byte("09995"), false, true) 225 require.NotNil(t, n) 226 require.EqualValues(t, []byte("09995"), n.key(l.arena)) 227 require.True(t, eq) 228 n, eq = l.findNear([]byte("09995"), true, false) 229 require.NotNil(t, n) 230 require.EqualValues(t, []byte("09985"), n.key(l.arena)) 231 require.False(t, eq) 232 n, eq = l.findNear([]byte("09995"), true, true) 233 require.NotNil(t, n) 234 require.EqualValues(t, []byte("09995"), n.key(l.arena)) 235 require.True(t, eq) 236 237 n, eq = l.findNear([]byte("59995"), false, false) 238 require.Nil(t, n) 239 require.False(t, eq) 240 n, eq = l.findNear([]byte("59995"), false, true) 241 require.Nil(t, n) 242 require.False(t, eq) 243 n, eq = l.findNear([]byte("59995"), true, false) 244 require.NotNil(t, n) 245 require.EqualValues(t, []byte("09995"), n.key(l.arena)) 246 require.False(t, eq) 247 n, eq = l.findNear([]byte("59995"), true, true) 248 require.NotNil(t, n) 249 require.EqualValues(t, []byte("09995"), n.key(l.arena)) 250 require.False(t, eq) 251 } 252 253 // TestIteratorNext tests a basic iteration over all nodes from the beginning. 254 func TestIteratorNext(t *testing.T) { 255 const n = 100 256 l := newSkiplist(arenaSize) 257 defer l.Delete() 258 it := l.NewIterator() 259 defer it.Close() 260 require.False(t, it.Valid()) 261 it.SeekToFirst() 262 require.False(t, it.Valid()) 263 for i := n - 1; i >= 0; i-- { 264 l.Put([]byte(fmt.Sprintf("%05d", i)), 265 y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}}) 266 } 267 it.SeekToFirst() 268 for i := 0; i < n; i++ { 269 require.True(t, it.Valid()) 270 v := it.Value() 271 require.EqualValues(t, newValue(i), v.Value) 272 it.Next() 273 } 274 require.False(t, it.Valid()) 275 } 276 277 // TestIteratorPrev tests a basic iteration over all nodes from the end. 278 func TestIteratorPrev(t *testing.T) { 279 const n = 100 280 l := newSkiplist(arenaSize) 281 defer l.Delete() 282 it := l.NewIterator() 283 defer it.Close() 284 require.False(t, it.Valid()) 285 it.SeekToFirst() 286 require.False(t, it.Valid()) 287 for i := 0; i < n; i++ { 288 l.Put([]byte(fmt.Sprintf("%05d", i)), 289 y.ValueStruct{Value: newValue(i), Meta: 0, UserMeta: []byte{0}}) 290 } 291 it.SeekToLast() 292 for i := n - 1; i >= 0; i-- { 293 require.True(t, it.Valid()) 294 v := it.Value() 295 require.EqualValues(t, newValue(i), v.Value) 296 it.Prev() 297 } 298 require.False(t, it.Valid()) 299 } 300 301 // TestIteratorSeek tests Seek and SeekForPrev. 302 func TestIteratorSeek(t *testing.T) { 303 const n = 100 304 l := newSkiplist(arenaSize) 305 defer l.Delete() 306 307 it := l.NewIterator() 308 defer it.Close() 309 require.False(t, it.Valid()) 310 it.SeekToFirst() 311 require.False(t, it.Valid()) 312 // 1000, 1010, 1020, ..., 1990. 313 for i := n - 1; i >= 0; i-- { 314 v := i*10 + 1000 315 l.Put([]byte(fmt.Sprintf("%05d", i*10+1000)), 316 y.ValueStruct{Value: newValue(v), Meta: 0, UserMeta: []byte{0}}) 317 } 318 it.SeekToFirst() 319 require.True(t, it.Valid()) 320 v := it.Value() 321 require.EqualValues(t, "01000", v.Value) 322 323 it.Seek([]byte("01000")) 324 require.True(t, it.Valid()) 325 v = it.Value() 326 require.EqualValues(t, "01000", v.Value) 327 328 it.Seek([]byte("01005")) 329 require.True(t, it.Valid()) 330 v = it.Value() 331 require.EqualValues(t, "01010", v.Value) 332 333 it.Seek([]byte("01010")) 334 require.True(t, it.Valid()) 335 v = it.Value() 336 require.EqualValues(t, "01010", v.Value) 337 338 it.Seek([]byte("99999")) 339 require.False(t, it.Valid()) 340 341 // Try SeekForPrev. 342 it.SeekForPrev([]byte("00")) 343 require.False(t, it.Valid()) 344 345 it.SeekForPrev([]byte("01000")) 346 require.True(t, it.Valid()) 347 v = it.Value() 348 require.EqualValues(t, "01000", v.Value) 349 350 it.SeekForPrev([]byte("01005")) 351 require.True(t, it.Valid()) 352 v = it.Value() 353 require.EqualValues(t, "01000", v.Value) 354 355 it.SeekForPrev([]byte("01010")) 356 require.True(t, it.Valid()) 357 v = it.Value() 358 require.EqualValues(t, "01010", v.Value) 359 360 it.SeekForPrev([]byte("99999")) 361 require.True(t, it.Valid()) 362 v = it.Value() 363 require.EqualValues(t, "01990", v.Value) 364 } 365 366 func TestPutWithHint(t *testing.T) { 367 l := newSkiplist(arenaSize) 368 sp := new(hint) 369 cnt := 0 370 for { 371 if l.arena.size() > arenaSize-256 { 372 break 373 } 374 key := randomKey() 375 l.PutWithHint(key, y.ValueStruct{Value: key}, sp) 376 cnt++ 377 } 378 it := l.NewIterator() 379 defer it.Close() 380 var lastKey y.Key 381 cntGot := 0 382 for it.SeekToFirst(); it.Valid(); it.Next() { 383 require.True(t, lastKey.Compare(it.Key()) <= 0) 384 require.True(t, bytes.Compare(it.Key().UserKey, it.Value().Value) == 0) 385 cntGot++ 386 lastKey.Copy(it.Key()) 387 } 388 require.True(t, cntGot == cnt) 389 } 390 391 func TestGetWithHint(t *testing.T) { 392 rand.Seed(time.Now().Unix()) 393 l := newSkiplist(arenaSize) 394 var keys [][]byte 395 sp := new(hint) 396 for { 397 if l.arena.size() > arenaSize-256 { 398 break 399 } 400 key := randomKey() 401 keys = append(keys, key) 402 l.PutWithHint(key, y.ValueStruct{Value: key}, sp) 403 } 404 h := new(hint) 405 for _, key := range keys { 406 bytes.Equal(l.GetWithHint(key, 0, h).Value, key) 407 } 408 sort.Slice(keys, func(i, j int) bool { 409 return bytes.Compare(keys[i], keys[j]) < 0 410 }) 411 for _, key := range keys { 412 bytes.Equal(l.GetWithHint(key, 0, h).Value, key) 413 } 414 } 415 416 func TestPutLargeValue(t *testing.T) { 417 l := newSkiplist(arenaSize) 418 key := randomKey() 419 val := make([]byte, 128*1024) 420 l.Put(key, y.ValueStruct{Value: val}) 421 result := l.Get(key, 0) 422 require.Equal(t, val, result.Value) 423 } 424 425 func key(prefix string, i int) string { 426 return prefix + fmt.Sprintf("%04d", i) 427 } 428 429 func generateKeyValues(prefix string, n int) [][]string { 430 y.Assert(n <= 10000) 431 keyValues := make([][]string, n) 432 for i := 0; i < n; i++ { 433 k := key(prefix, i) 434 v := fmt.Sprintf("%d", i) 435 keyValues[i] = []string{k, v} 436 } 437 return keyValues 438 } 439 440 func buildMultiVersionSkiopList(keyValues [][]string) *skiplist { 441 sort.Slice(keyValues, func(i, j int) bool { 442 return keyValues[i][0] < keyValues[j][0] 443 }) 444 skl := newSkiplist(arenaSize) 445 for _, kv := range keyValues { 446 y.Assert(len(kv) == 2) 447 val := fmt.Sprintf("%s_%d", kv[1], 9) 448 skl.Put([]byte(kv[0]), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}, Version: 9}) 449 for i := uint64(8); i > 0; i-- { 450 if z.FastRand()%4 != 0 { 451 val = fmt.Sprintf("%s_%d", kv[1], i) 452 skl.Put([]byte(kv[0]), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}, Version: i}) 453 } 454 } 455 } 456 return skl 457 } 458 459 func TestIterateMultiVersion(t *testing.T) { 460 keyVals := generateKeyValues("key", 4000) 461 skl := buildMultiVersionSkiopList(keyVals) 462 it := skl.NewIterator() 463 defer it.Close() 464 var lastKey y.Key 465 for it.SeekToFirst(); it.Valid(); it.Next() { 466 if !lastKey.IsEmpty() { 467 require.True(t, bytes.Compare(lastKey.UserKey, it.Key().UserKey) < 0) 468 } 469 lastKey.Copy(it.Key()) 470 } 471 for i := 0; i < 1000; i++ { 472 id := int(z.FastRand() % 4000) 473 k := y.KeyWithTs([]byte(key("key", id)), uint64(5+z.FastRand()%5)) 474 val := skl.Get(k.UserKey, k.Version) 475 if val.Valid() { 476 valStr := fmt.Sprintf("%d_%d", id, k.Version) 477 require.Equal(t, valStr, string(val.Value)) 478 } else { 479 it.Seek(k.UserKey) 480 if it.Valid() { 481 require.True(t, bytes.Compare(it.Key().UserKey, k.UserKey) >= 0) 482 var cpKey y.Key 483 cpKey.Copy(it.Key()) 484 it.Prev() 485 if it.Valid() { 486 require.True(t, bytes.Compare(it.Key().UserKey, k.UserKey) < 0, "%s %s %s", it.Key(), cpKey, k) 487 } 488 } 489 } 490 } 491 revIt := skl.NewUniIterator(true) 492 defer revIt.Close() 493 lastKey.Reset() 494 for revIt.Rewind(); revIt.Valid(); revIt.Next() { 495 if !lastKey.IsEmpty() { 496 require.Truef(t, bytes.Compare(lastKey.UserKey, revIt.Key().UserKey) > 0, "%v %v", lastKey.String(), revIt.Key().String()) 497 } 498 lastKey.Copy(revIt.Key()) 499 } 500 for i := 0; i < 1000; i++ { 501 k := y.KeyWithTs([]byte(key("key", int(z.FastRand()%4000))), uint64(5+z.FastRand()%5)) 502 // reverse iterator never seek to the same key with smaller version. 503 revIt.Seek(k.UserKey) 504 if !revIt.Valid() { 505 continue 506 } 507 require.True(t, bytes.Compare(revIt.Key().UserKey, k.UserKey) <= 0, "%s %s", revIt.Key(), k) 508 } 509 } 510 511 func randomKey() []byte { 512 b := make([]byte, 8) 513 key := rand.Uint32() 514 key2 := rand.Uint32() 515 binary.LittleEndian.PutUint32(b, key) 516 binary.LittleEndian.PutUint32(b[4:], key2) 517 return b 518 } 519 520 // Standard test. Some fraction is read. Some fraction is write. Writes have 521 // to go through mutex lock. 522 func BenchmarkReadWrite(b *testing.B) { 523 value := newValue(123) 524 for i := 0; i <= 10; i++ { 525 readFrac := float32(i) / 10.0 526 b.Run(fmt.Sprintf("frac_%d", i), func(b *testing.B) { 527 l := newSkiplist(int64((b.N + 1) * MaxNodeSize)) 528 defer l.Delete() 529 b.ResetTimer() 530 var count int 531 b.RunParallel(func(pb *testing.PB) { 532 rng := rand.New(rand.NewSource(time.Now().UnixNano())) 533 for pb.Next() { 534 if rng.Float32() < readFrac { 535 v := l.Get(randomKey(), 0) 536 if v.Value != nil { 537 count++ 538 } 539 } else { 540 l.Put(randomKey(), y.ValueStruct{Value: value, Meta: 0, UserMeta: []byte{0}}) 541 } 542 } 543 }) 544 }) 545 } 546 } 547 548 // Standard test. Some fraction is read. Some fraction is write. Writes have 549 // to go through mutex lock. 550 func BenchmarkReadWriteMap(b *testing.B) { 551 value := newValue(123) 552 for i := 0; i <= 10; i++ { 553 readFrac := float32(i) / 10.0 554 b.Run(fmt.Sprintf("frac_%d", i), func(b *testing.B) { 555 m := make(map[string][]byte) 556 var mutex sync.RWMutex 557 b.ResetTimer() 558 var count int 559 b.RunParallel(func(pb *testing.PB) { 560 for pb.Next() { 561 if rand.Float32() < readFrac { 562 mutex.RLock() 563 _, ok := m[string(randomKey())] 564 mutex.RUnlock() 565 if ok { 566 count++ 567 } 568 } else { 569 mutex.Lock() 570 m[string(randomKey())] = value 571 mutex.Unlock() 572 } 573 } 574 }) 575 }) 576 } 577 } 578 579 // Standard test. Some fraction is read. Some fraction is write. Writes have 580 // to go through mutex lock. 581 func BenchmarkGetSequential(b *testing.B) { 582 size := 300000 583 keys, l, _ := buildKeysAndList(size) 584 b.ResetTimer() 585 for i := 0; i < b.N; i++ { 586 key := keys[i%size] 587 l.Get(key, 0) 588 } 589 } 590 591 func BenchmarkGetWithHintSequential(b *testing.B) { 592 size := 300000 593 keys, l, h := buildKeysAndList(size) 594 b.ResetTimer() 595 for i := 0; i < b.N; i++ { 596 key := keys[i%size] 597 l.GetWithHint(key, 0, h) 598 } 599 } 600 601 func buildKeysAndList(size int) ([][]byte, *skiplist, *hint) { 602 l := newSkiplist(32 * 1024 * 1024) 603 keys := make([][]byte, size) 604 h := new(hint) 605 for i := 0; i < size; i++ { 606 keys[i] = []byte(fmt.Sprintf("%05d", i)) 607 } 608 for i := 0; i < size; i++ { 609 key := keys[i] 610 l.PutWithHint(key, y.ValueStruct{Value: []byte{byte(i)}}, h) 611 } 612 return keys, l, h 613 } 614 615 func BenchmarkGetRandom(b *testing.B) { 616 size := 300000 617 keys, l, _ := buildKeysAndList(size) 618 b.ResetTimer() 619 r := rand.New(rand.NewSource(1)) 620 for i := 0; i < b.N; i++ { 621 key := keys[r.Int()%size] 622 l.Get(key, 0) 623 } 624 } 625 626 func BenchmarkGetWithHintRandom(b *testing.B) { 627 size := 300000 628 keys, l, h := buildKeysAndList(size) 629 b.ResetTimer() 630 r := rand.New(rand.NewSource(1)) 631 for i := 0; i < b.N; i++ { 632 key := keys[r.Int()%size] 633 l.GetWithHint(key, 0, h) 634 } 635 } 636 637 func BenchmarkPutWithHint(b *testing.B) { 638 l := newSkiplist(16 * 1024 * 1024) 639 size := 100000 640 keys := make([][]byte, size) 641 for i := 0; i < size; i++ { 642 keys[i] = []byte(fmt.Sprintf("%05d", i)) 643 } 644 b.ResetTimer() 645 for i := 0; i < b.N; i++ { 646 h := new(hint) 647 l = newSkiplist(16 * 1024 * 1024) 648 for j := 0; j < size; j++ { 649 key := keys[j] 650 l.PutWithHint(key, y.ValueStruct{Value: []byte{byte(j)}}, h) 651 } 652 } 653 }