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