github.com/coocood/badger@v1.5.1-0.20200528065104-c02ac3616d04/table/sstable/table_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 sstable 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 "math" 24 "math/rand" 25 "os" 26 "sort" 27 "testing" 28 "time" 29 30 "github.com/coocood/badger/cache" 31 "github.com/coocood/badger/cache/z" 32 "github.com/coocood/badger/options" 33 "github.com/coocood/badger/table" 34 "github.com/coocood/badger/y" 35 "github.com/dgryski/go-farm" 36 "github.com/stretchr/testify/require" 37 "golang.org/x/time/rate" 38 ) 39 40 func key(prefix string, i int) string { 41 return prefix + fmt.Sprintf("%04d", i) 42 } 43 44 var defaultBuilderOpt = options.TableBuilderOptions{ 45 SuRFStartLevel: 0, 46 SuRFOptions: options.SuRFOptions{ 47 BitsPerKeyHint: 40, 48 RealSuffixLen: 10, 49 }, 50 CompressionPerLevel: []options.CompressionType{options.ZSTD}, 51 BlockSize: 4 * 1024, 52 HashUtilRatio: 0.75, 53 WriteBufferSize: 1024 * 1024, 54 MaxLevels: 1, 55 LevelSizeMultiplier: 10, 56 LogicalBloomFPR: 0.01, 57 } 58 59 func testCache() *cache.Cache { 60 c, err := cache.NewCache(&cache.Config{ 61 NumCounters: 1000000 * 10, 62 MaxCost: 1000000, 63 BufferItems: 64, 64 Metrics: true, 65 }) 66 y.Check(err) 67 return c 68 } 69 70 func generateKeyValues(prefix string, n int) [][]string { 71 y.Assert(n <= 10000) 72 keyValues := make([][]string, n) 73 for i := 0; i < n; i++ { 74 k := key(prefix, i) 75 v := fmt.Sprintf("%d", i) 76 keyValues[i] = []string{k, v} 77 } 78 return keyValues 79 } 80 81 var compressionType = options.ZSTD 82 83 func buildTestTable(t *testing.T, prefix string, n int) *os.File { 84 return buildTable(t, generateKeyValues(prefix, n)) 85 } 86 87 // keyValues is n by 2 where n is number of pairs. 88 func buildTable(t *testing.T, keyValues [][]string) *os.File { 89 // TODO: Add test for file garbage collection here. No files should be left after the tests here. 90 b, f := newTableBuilderForTest() 91 sort.Slice(keyValues, func(i, j int) bool { 92 return keyValues[i][0] < keyValues[j][0] 93 }) 94 for _, kv := range keyValues { 95 y.Assert(len(kv) == 2) 96 err := b.Add(y.KeyWithTs([]byte(kv[0]), 0), y.ValueStruct{Value: []byte(kv[1]), Meta: 'A', UserMeta: []byte{0}}) 97 if t != nil { 98 require.NoError(t, err) 99 } else { 100 y.Check(err) 101 } 102 } 103 y.Check(b.Finish()) 104 y.Check(f.Close()) 105 f, _ = y.OpenSyncedFile(f.Name(), true) 106 return f 107 } 108 109 func newTableBuilderForTest() (*Builder, *os.File) { 110 filename := fmt.Sprintf("%s%s%x.sst", os.TempDir(), string(os.PathSeparator), z.FastRand()) 111 f, err := y.OpenSyncedFile(filename, true) 112 y.Check(err) 113 opt := defaultBuilderOpt 114 if z.FastRand()%2 == 0 { 115 opt.SuRFStartLevel = 8 116 } 117 y.Assert(filename == f.Name()) 118 return NewTableBuilder(f, rate.NewLimiter(rate.Inf, math.MaxInt32), 0, opt), f 119 } 120 121 func buildMultiVersionTable(keyValues [][]string) *os.File { 122 b, f := newTableBuilderForTest() 123 sort.Slice(keyValues, func(i, j int) bool { 124 return keyValues[i][0] < keyValues[j][0] 125 }) 126 for _, kv := range keyValues { 127 y.Assert(len(kv) == 2) 128 val := fmt.Sprintf("%s_%d", kv[1], 9) 129 err := b.Add(y.KeyWithTs([]byte(kv[0]), 9), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}}) 130 y.Check(err) 131 for i := uint64(8); i > 0; i-- { 132 if z.FastRand()%4 != 0 { 133 val = fmt.Sprintf("%s_%d", kv[1], i) 134 err = b.Add(y.KeyWithTs([]byte(kv[0]), i), y.ValueStruct{Value: []byte(val), Meta: 'A', UserMeta: []byte{0}}) 135 y.Check(err) 136 } 137 } 138 } 139 y.Check(b.Finish()) 140 y.Check(f.Close()) 141 f, _ = y.OpenSyncedFile(f.Name(), true) 142 return f 143 } 144 145 func TestTableIterator(t *testing.T) { 146 for _, n := range []int{99, 100, 101} { 147 t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) { 148 f := buildTestTable(t, "key", n) 149 table, err := OpenTable(f.Name(), testCache(), testCache()) 150 require.NoError(t, err) 151 defer table.Delete() 152 it := table.newIterator(false) 153 count := 0 154 for it.Rewind(); it.Valid(); it.Next() { 155 v := it.Value() 156 k := y.KeyWithTs([]byte(key("key", count)), 0) 157 require.EqualValues(t, k, it.Key()) 158 require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value)) 159 count++ 160 } 161 require.Equal(t, count, n) 162 }) 163 } 164 } 165 166 func TestHashIndexTS(t *testing.T) { 167 filename := fmt.Sprintf("%s%s%x.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 168 f, err := y.OpenSyncedFile(filename, true) 169 if t != nil { 170 require.NoError(t, err) 171 } else { 172 y.Check(err) 173 } 174 b := NewTableBuilder(f, nil, 0, defaultBuilderOpt) 175 keys := []y.Key{ 176 y.KeyWithTs([]byte("key"), 9), 177 y.KeyWithTs([]byte("key"), 7), 178 y.KeyWithTs([]byte("key"), 5), 179 y.KeyWithTs([]byte("key"), 3), 180 y.KeyWithTs([]byte("key"), 1), 181 } 182 for _, k := range keys { 183 b.Add(k, y.ValueStruct{Value: k.UserKey, Meta: 'A', UserMeta: []byte{0}}) 184 } 185 y.Check(b.Finish()) 186 f.Close() 187 table, err := OpenTable(filename, testCache(), testCache()) 188 keyHash := farm.Fingerprint64([]byte("key")) 189 190 rk, _, ok, err := table.pointGet(y.KeyWithTs([]byte("key"), 10), keyHash) 191 require.NoError(t, err) 192 require.True(t, ok) 193 require.True(t, rk.Equal(keys[0]), "%s", string(rk.UserKey)) 194 195 rk, _, ok, err = table.pointGet(y.KeyWithTs([]byte("key"), 6), keyHash) 196 require.NoError(t, err) 197 require.True(t, ok) 198 require.True(t, rk.Equal(keys[2])) 199 200 rk, _, ok, err = table.pointGet(y.KeyWithTs([]byte("key"), 2), keyHash) 201 require.NoError(t, err) 202 require.True(t, ok) 203 require.True(t, rk.Equal(keys[4])) 204 } 205 206 func TestPointGet(t *testing.T) { 207 f := buildTestTable(t, "key", 8000) 208 table, err := OpenTable(f.Name(), testCache(), testCache()) 209 require.NoError(t, err) 210 defer table.Delete() 211 212 for i := 0; i < 8000; i++ { 213 k := y.KeyWithTs([]byte(key("key", i)), math.MaxUint64) 214 keyHash := farm.Fingerprint64(k.UserKey) 215 k1, _, ok, err := table.pointGet(k, keyHash) 216 require.NoError(t, err) 217 if !ok { 218 // will fallback to seek 219 continue 220 } 221 require.True(t, k1.SameUserKey(k), "point get not point to correct key") 222 } 223 224 for i := 8000; i < 10000; i++ { 225 k := y.KeyWithTs([]byte(key("key", i)), math.MaxUint64) 226 keyHash := farm.Fingerprint64(k.UserKey) 227 rk, _, ok, err := table.pointGet(k, keyHash) 228 require.NoError(t, err) 229 if !ok { 230 // will fallback to seek 231 continue 232 } 233 if rk.IsEmpty() { 234 // hash table says no entry, fast return 235 continue 236 } 237 require.False(t, k.SameUserKey(rk), "point get not point to correct key") 238 } 239 } 240 241 func TestExternalTable(t *testing.T) { 242 filename := fmt.Sprintf("%s%s%x.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 243 f, err := y.OpenSyncedFile(filename, true) 244 if t != nil { 245 require.NoError(t, err) 246 } else { 247 y.Check(err) 248 } 249 250 n := 200 251 b := NewExternalTableBuilder(f, rate.NewLimiter(rate.Inf, math.MaxInt32), defaultBuilderOpt, compressionType) 252 kvs := generateKeyValues("key", n) 253 for _, kv := range kvs { 254 y.Assert(len(kv) == 2) 255 err := b.Add(y.KeyWithTs([]byte(kv[0]), 0), y.ValueStruct{Value: []byte(kv[1]), Meta: 'A', UserMeta: []byte{0}}) 256 if t != nil { 257 require.NoError(t, err) 258 } else { 259 y.Check(err) 260 } 261 } 262 y.Check(b.Finish()) 263 f.Close() 264 table, err := OpenTable(filename, testCache(), testCache()) 265 require.NoError(t, err) 266 require.NoError(t, table.SetGlobalTs(10)) 267 268 require.NoError(t, table.Close()) 269 table, err = OpenTable(filename, testCache(), testCache()) 270 require.NoError(t, err) 271 defer table.Delete() 272 273 it := table.newIterator(false) 274 count := 0 275 for it.Rewind(); it.Valid(); it.Next() { 276 v := it.Value() 277 k := y.KeyWithTs([]byte(key("key", count)), 10) 278 require.EqualValues(t, k, it.Key()) 279 require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value)) 280 count++ 281 } 282 require.Equal(t, count, n) 283 } 284 285 func TestSeekToFirst(t *testing.T) { 286 for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} { 287 t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) { 288 f := buildTestTable(t, "key", n) 289 table, err := OpenTable(f.Name(), testCache(), testCache()) 290 require.NoError(t, err) 291 defer table.Delete() 292 it := table.newIterator(false) 293 it.seekToFirst() 294 require.True(t, it.Valid()) 295 v := it.Value() 296 require.EqualValues(t, "0", string(v.Value)) 297 require.EqualValues(t, 'A', v.Meta) 298 }) 299 } 300 } 301 302 func TestSeekToLast(t *testing.T) { 303 for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} { 304 t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) { 305 f := buildTestTable(t, "key", n) 306 table, err := OpenTable(f.Name(), testCache(), testCache()) 307 require.NoError(t, err) 308 defer table.Delete() 309 it := table.newIterator(false) 310 it.seekToLast() 311 require.True(t, it.Valid()) 312 v := it.Value() 313 require.EqualValues(t, fmt.Sprintf("%d", n-1), string(v.Value)) 314 require.EqualValues(t, 'A', v.Meta) 315 it.prev() 316 require.True(t, it.Valid()) 317 v = it.Value() 318 require.EqualValues(t, fmt.Sprintf("%d", n-2), string(v.Value)) 319 require.EqualValues(t, 'A', v.Meta) 320 }) 321 } 322 } 323 324 func TestSeekBasic(t *testing.T) { 325 f := buildTestTable(t, "k", 10000) 326 table, err := OpenTable(f.Name(), testCache(), testCache()) 327 require.NoError(t, err) 328 defer table.Delete() 329 330 it := table.newIterator(false) 331 332 var data = []struct { 333 in string 334 valid bool 335 out string 336 }{ 337 {"abc", true, "k0000"}, 338 {"k0100", true, "k0100"}, 339 {"k0100b", true, "k0101"}, // Test case where we jump to next block. 340 {"k1234", true, "k1234"}, 341 {"k1234b", true, "k1235"}, 342 {"k9999", true, "k9999"}, 343 {"z", false, ""}, 344 } 345 346 for _, tt := range data { 347 it.seek([]byte(tt.in)) 348 if !tt.valid { 349 require.False(t, it.Valid()) 350 continue 351 } 352 require.True(t, it.Valid()) 353 k := it.Key() 354 require.EqualValues(t, tt.out, string(k.UserKey)) 355 } 356 } 357 358 func TestSeekForPrev(t *testing.T) { 359 f := buildTestTable(t, "k", 10000) 360 table, err := OpenTable(f.Name(), testCache(), testCache()) 361 require.NoError(t, err) 362 defer table.Delete() 363 364 it := table.newIterator(false) 365 366 var data = []struct { 367 in string 368 valid bool 369 out string 370 }{ 371 {"abc", false, ""}, 372 {"k0100", true, "k0100"}, 373 {"k0100b", true, "k0100"}, // Test case where we jump to next block. 374 {"k1234", true, "k1234"}, 375 {"k1234b", true, "k1234"}, 376 {"k9999", true, "k9999"}, 377 {"z", true, "k9999"}, 378 } 379 380 for _, tt := range data { 381 it.seekForPrev([]byte(tt.in)) 382 if !tt.valid { 383 require.False(t, it.Valid()) 384 continue 385 } 386 require.True(t, it.Valid()) 387 k := it.Key() 388 require.EqualValues(t, tt.out, string(k.UserKey)) 389 } 390 } 391 392 func TestIterateFromStart(t *testing.T) { 393 // Vary the number of elements added. 394 for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} { 395 t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) { 396 f := buildTestTable(t, "key", n) 397 table, err := OpenTable(f.Name(), testCache(), testCache()) 398 require.NoError(t, err) 399 defer table.Delete() 400 ti := table.newIterator(false) 401 ti.reset() 402 ti.seekToFirst() 403 require.True(t, ti.Valid()) 404 // No need to do a Next. 405 // ti.Seek brings us to the first key >= "". Essentially a SeekToFirst. 406 var count int 407 for ; ti.Valid(); ti.next() { 408 v := ti.Value() 409 require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value)) 410 require.EqualValues(t, 'A', v.Meta) 411 count++ 412 } 413 require.EqualValues(t, n, count) 414 }) 415 } 416 } 417 418 func TestIterateFromEnd(t *testing.T) { 419 // Vary the number of elements added. 420 for _, n := range []int{99, 100, 101, 199, 200, 250, 9999, 10000} { 421 t.Run(fmt.Sprintf("n=%d", n), func(t *testing.T) { 422 f := buildTestTable(t, "key", n) 423 table, err := OpenTable(f.Name(), testCache(), testCache()) 424 require.NoError(t, err) 425 defer table.Delete() 426 ti := table.newIterator(false) 427 ti.reset() 428 ti.seek([]byte("zzzzzz")) // Seek to end, an invalid element. 429 require.False(t, ti.Valid()) 430 ti.seekToLast() 431 for i := n - 1; i >= 0; i-- { 432 require.True(t, ti.Valid()) 433 v := ti.Value() 434 require.EqualValues(t, fmt.Sprintf("%d", i), string(v.Value)) 435 require.EqualValues(t, 'A', v.Meta) 436 ti.prev() 437 } 438 ti.prev() 439 require.False(t, ti.Valid()) 440 }) 441 } 442 } 443 444 func TestTable(t *testing.T) { 445 f := buildTestTable(t, "key", 10000) 446 table, err := OpenTable(f.Name(), testCache(), testCache()) 447 require.NoError(t, err) 448 defer table.Delete() 449 ti := table.newIterator(false) 450 kid := 1010 451 seek := y.KeyWithTs([]byte(key("key", kid)), 0) 452 for ti.seek(seek.UserKey); ti.Valid(); ti.next() { 453 k := ti.Key() 454 require.EqualValues(t, string(k.UserKey), key("key", kid)) 455 kid++ 456 } 457 if kid != 10000 { 458 t.Errorf("Expected kid: 10000. Got: %v", kid) 459 } 460 461 ti.seek([]byte(key("key", 99999))) 462 require.False(t, ti.Valid()) 463 464 ti.seek([]byte(key("key", -1))) 465 require.True(t, ti.Valid()) 466 k := ti.Key() 467 require.EqualValues(t, string(k.UserKey), key("key", 0)) 468 } 469 470 func TestIterateBackAndForth(t *testing.T) { 471 f := buildTestTable(t, "key", 10000) 472 table, err := OpenTable(f.Name(), testCache(), testCache()) 473 require.NoError(t, err) 474 defer table.Delete() 475 476 seek := y.KeyWithTs([]byte(key("key", 1010)), 0) 477 it := table.newIterator(false) 478 it.seek(seek.UserKey) 479 require.True(t, it.Valid()) 480 k := it.Key() 481 require.EqualValues(t, seek, k) 482 483 it.prev() 484 it.prev() 485 require.True(t, it.Valid()) 486 k = it.Key() 487 require.EqualValues(t, key("key", 1008), string(k.UserKey)) 488 489 it.next() 490 it.next() 491 require.True(t, it.Valid()) 492 k = it.Key() 493 require.EqualValues(t, key("key", 1010), k.UserKey) 494 495 it.seek([]byte(key("key", 2000))) 496 require.True(t, it.Valid()) 497 k = it.Key() 498 require.EqualValues(t, key("key", 2000), k.UserKey) 499 500 it.prev() 501 require.True(t, it.Valid()) 502 k = it.Key() 503 require.EqualValues(t, key("key", 1999), k.UserKey) 504 505 it.seekToFirst() 506 k = it.Key() 507 require.EqualValues(t, key("key", 0), k.UserKey) 508 } 509 510 func TestIterateMultiVersion(t *testing.T) { 511 f := buildMultiVersionTable(generateKeyValues("key", 4000)) 512 table, err := OpenTable(f.Name(), testCache(), testCache()) 513 require.NoError(t, err) 514 defer table.Delete() 515 it := table.newIterator(false) 516 var lastKey y.Key 517 for it.Rewind(); it.Valid(); it.Next() { 518 if !lastKey.IsEmpty() { 519 require.True(t, lastKey.Compare(it.Key()) < 0) 520 } 521 lastKey.Copy(it.Key()) 522 } 523 for i := 0; i < 1000; i++ { 524 k := y.KeyWithTs([]byte(key("key", int(z.FastRand()%4000))), uint64(5+z.FastRand()%5)) 525 kHash := farm.Fingerprint64(k.UserKey) 526 gotKey, _, ok, _ := table.pointGet(k, kHash) 527 if ok { 528 if !gotKey.IsEmpty() { 529 require.True(t, gotKey.SameUserKey(k)) 530 require.True(t, gotKey.Compare(k) >= 0) 531 } 532 } else { 533 it.Seek(k.UserKey) 534 if it.Valid() { 535 require.True(t, it.Key().Version == 9) 536 require.True(t, bytes.Compare(it.Key().UserKey, k.UserKey) >= 0) 537 if y.SeekToVersion(it, k.Version) { 538 require.True(t, it.Key().Version <= k.Version) 539 } 540 } 541 } 542 } 543 revIt := table.newIterator(true) 544 lastKey.Reset() 545 for revIt.Rewind(); revIt.Valid(); revIt.Next() { 546 if !lastKey.IsEmpty() { 547 require.Truef(t, lastKey.Compare(revIt.Key()) > 0, "%v %v", lastKey.String(), revIt.Key().String()) 548 } 549 lastKey.Copy(revIt.Key()) 550 } 551 for i := 0; i < 1000; i++ { 552 k := y.KeyWithTs([]byte(key("key", int(z.FastRand()%4000))), uint64(5+z.FastRand()%5)) 553 // reverse iterator never seek to the same key with smaller version. 554 revIt.Seek(k.UserKey) 555 if !revIt.Valid() { 556 continue 557 } 558 require.True(t, revIt.Key().Version == 9) 559 require.True(t, revIt.Key().Compare(k) <= 0, "%s %s", revIt.Key(), k) 560 } 561 } 562 563 func TestUniIterator(t *testing.T) { 564 f := buildTestTable(t, "key", 10000) 565 table, err := OpenTable(f.Name(), testCache(), testCache()) 566 require.NoError(t, err) 567 defer table.Delete() 568 { 569 it := table.newIterator(false) 570 var count int 571 for it.Rewind(); it.Valid(); it.Next() { 572 v := it.Value() 573 require.EqualValues(t, fmt.Sprintf("%d", count), string(v.Value)) 574 require.EqualValues(t, 'A', v.Meta) 575 count++ 576 } 577 require.EqualValues(t, 10000, count) 578 } 579 { 580 it := table.newIterator(true) 581 var count int 582 for it.Rewind(); it.Valid(); it.Next() { 583 v := it.Value() 584 require.EqualValues(t, fmt.Sprintf("%d", 10000-1-count), string(v.Value)) 585 require.EqualValues(t, 'A', v.Meta) 586 count++ 587 } 588 require.EqualValues(t, 10000, count) 589 } 590 } 591 592 // Try having only one table. 593 func TestConcatIteratorOneTable(t *testing.T) { 594 f := buildTable(t, [][]string{ 595 {"k1", "a1"}, 596 {"k2", "a2"}, 597 }) 598 599 tbl, err := OpenTable(f.Name(), testCache(), testCache()) 600 require.NoError(t, err) 601 defer tbl.Delete() 602 603 it := table.NewConcatIterator([]table.Table{tbl}, false) 604 605 it.Rewind() 606 require.True(t, it.Valid()) 607 k := it.Key() 608 require.EqualValues(t, "k1", string(k.UserKey)) 609 vs := it.Value() 610 require.EqualValues(t, "a1", string(vs.Value)) 611 require.EqualValues(t, 'A', vs.Meta) 612 } 613 614 func TestConcatIterator(t *testing.T) { 615 f := buildTestTable(t, "keya", 10000) 616 f2 := buildTestTable(t, "keyb", 10000) 617 f3 := buildTestTable(t, "keyc", 10000) 618 blkCache, idxCache := testCache(), testCache() 619 tbl, err := OpenTable(f.Name(), blkCache, idxCache) 620 require.NoError(t, err) 621 defer tbl.Delete() 622 tbl2, err := OpenTable(f2.Name(), blkCache, idxCache) 623 require.NoError(t, err) 624 defer tbl2.Delete() 625 tbl3, err := OpenTable(f3.Name(), blkCache, idxCache) 626 require.NoError(t, err) 627 defer tbl3.Delete() 628 629 { 630 it := table.NewConcatIterator([]table.Table{tbl, tbl2, tbl3}, false) 631 it.Rewind() 632 require.True(t, it.Valid()) 633 var count int 634 for ; it.Valid(); it.Next() { 635 vs := it.Value() 636 require.EqualValues(t, fmt.Sprintf("%d", count%10000), string(vs.Value)) 637 require.EqualValues(t, 'A', vs.Meta) 638 count++ 639 } 640 require.EqualValues(t, 30000, count) 641 642 it.Seek([]byte("a")) 643 require.EqualValues(t, "keya0000", string(it.Key().UserKey)) 644 vs := it.Value() 645 require.EqualValues(t, "0", string(vs.Value)) 646 647 it.Seek([]byte("keyb")) 648 require.EqualValues(t, "keyb0000", string(it.Key().UserKey)) 649 vs = it.Value() 650 require.EqualValues(t, "0", string(vs.Value)) 651 652 it.Seek([]byte("keyb9999b")) 653 require.EqualValues(t, "keyc0000", string(it.Key().UserKey)) 654 vs = it.Value() 655 require.EqualValues(t, "0", string(vs.Value)) 656 657 it.Seek([]byte("keyd")) 658 require.False(t, it.Valid()) 659 } 660 { 661 it := table.NewConcatIterator([]table.Table{tbl, tbl2, tbl3}, true) 662 it.Rewind() 663 require.True(t, it.Valid()) 664 var count int 665 for ; it.Valid(); it.Next() { 666 vs := it.Value() 667 require.EqualValues(t, fmt.Sprintf("%d", 10000-(count%10000)-1), string(vs.Value)) 668 require.EqualValues(t, 'A', vs.Meta) 669 count++ 670 } 671 require.EqualValues(t, 30000, count) 672 673 it.Seek([]byte("a")) 674 require.False(t, it.Valid()) 675 676 it.Seek([]byte("keyb")) 677 require.EqualValues(t, "keya9999", string(it.Key().UserKey)) 678 vs := it.Value() 679 require.EqualValues(t, "9999", string(vs.Value)) 680 681 it.Seek([]byte("keyb9999b")) 682 require.EqualValues(t, "keyb9999", string(it.Key().UserKey)) 683 vs = it.Value() 684 require.EqualValues(t, "9999", string(vs.Value)) 685 686 it.Seek([]byte("keyd")) 687 require.EqualValues(t, "keyc9999", string(it.Key().UserKey)) 688 vs = it.Value() 689 require.EqualValues(t, "9999", string(vs.Value)) 690 } 691 } 692 693 func TestMergingIterator(t *testing.T) { 694 f1 := buildTable(t, [][]string{ 695 {"k1", "a1"}, 696 {"k2", "a2"}, 697 }) 698 f2 := buildTable(t, [][]string{ 699 {"k1", "b1"}, 700 {"k2", "b2"}, 701 }) 702 blkCache, idxCache := testCache(), testCache() 703 tbl1, err := OpenTable(f1.Name(), blkCache, idxCache) 704 require.NoError(t, err) 705 defer tbl1.Delete() 706 tbl2, err := OpenTable(f2.Name(), blkCache, idxCache) 707 require.NoError(t, err) 708 defer tbl2.Delete() 709 it1 := tbl1.newIterator(false) 710 it2 := table.NewConcatIterator([]table.Table{tbl2}, false) 711 it := table.NewMergeIterator([]y.Iterator{it1, it2}, false) 712 713 it.Rewind() 714 require.True(t, it.Valid()) 715 k := it.Key() 716 require.EqualValues(t, "k1", string(k.UserKey)) 717 vs := it.Value() 718 require.EqualValues(t, "a1", string(vs.Value)) 719 require.EqualValues(t, 'A', vs.Meta) 720 it.Next() 721 722 require.True(t, it.Valid()) 723 k = it.Key() 724 require.EqualValues(t, "k2", string(k.UserKey)) 725 vs = it.Value() 726 require.EqualValues(t, "a2", string(vs.Value)) 727 require.EqualValues(t, 'A', vs.Meta) 728 it.Next() 729 730 require.False(t, it.Valid()) 731 } 732 733 func TestMergingIteratorReversed(t *testing.T) { 734 f1 := buildTable(t, [][]string{ 735 {"k1", "a1"}, 736 {"k2", "a2"}, 737 }) 738 f2 := buildTable(t, [][]string{ 739 {"k1", "b1"}, 740 {"k2", "b2"}, 741 }) 742 blkCache, idxCache := testCache(), testCache() 743 tbl1, err := OpenTable(f1.Name(), blkCache, idxCache) 744 require.NoError(t, err) 745 defer tbl1.Delete() 746 tbl2, err := OpenTable(f2.Name(), blkCache, idxCache) 747 require.NoError(t, err) 748 defer tbl2.Delete() 749 it1 := tbl1.newIterator(true) 750 it2 := table.NewConcatIterator([]table.Table{tbl2}, true) 751 it := table.NewMergeIterator([]y.Iterator{it1, it2}, true) 752 753 it.Rewind() 754 require.True(t, it.Valid()) 755 k := it.Key() 756 require.EqualValues(t, "k2", string(k.UserKey)) 757 vs := it.Value() 758 require.EqualValues(t, "a2", string(vs.Value)) 759 require.EqualValues(t, 'A', vs.Meta) 760 it.Next() 761 762 require.True(t, it.Valid()) 763 k = it.Key() 764 require.EqualValues(t, "k1", string(k.UserKey)) 765 vs = it.Value() 766 require.EqualValues(t, "a1", string(vs.Value)) 767 require.EqualValues(t, 'A', vs.Meta) 768 it.Next() 769 770 require.False(t, it.Valid()) 771 } 772 773 // Take only the first iterator. 774 func TestMergingIteratorTakeOne(t *testing.T) { 775 f1 := buildTable(t, [][]string{ 776 {"k1", "a1"}, 777 {"k2", "a2"}, 778 }) 779 f2 := buildTable(t, [][]string{{"l1", "b1"}}) 780 781 blkCache, idxCache := testCache(), testCache() 782 t1, err := OpenTable(f1.Name(), blkCache, idxCache) 783 require.NoError(t, err) 784 defer t1.Delete() 785 t2, err := OpenTable(f2.Name(), blkCache, idxCache) 786 require.NoError(t, err) 787 defer t2.Delete() 788 789 it1 := table.NewConcatIterator([]table.Table{t1}, false) 790 it2 := table.NewConcatIterator([]table.Table{t2}, false) 791 it := table.NewMergeIterator([]y.Iterator{it1, it2}, false) 792 793 it.Rewind() 794 require.True(t, it.Valid()) 795 k := it.Key() 796 require.EqualValues(t, "k1", string(k.UserKey)) 797 vs := it.Value() 798 require.EqualValues(t, "a1", string(vs.Value)) 799 require.EqualValues(t, 'A', vs.Meta) 800 it.Next() 801 802 require.True(t, it.Valid()) 803 k = it.Key() 804 require.EqualValues(t, "k2", string(k.UserKey)) 805 vs = it.Value() 806 require.EqualValues(t, "a2", string(vs.Value)) 807 require.EqualValues(t, 'A', vs.Meta) 808 it.Next() 809 810 k = it.Key() 811 require.EqualValues(t, "l1", string(k.UserKey)) 812 vs = it.Value() 813 require.EqualValues(t, "b1", string(vs.Value)) 814 require.EqualValues(t, 'A', vs.Meta) 815 it.Next() 816 817 require.False(t, it.Valid()) 818 } 819 820 // Take only the second iterator. 821 func TestMergingIteratorTakeTwo(t *testing.T) { 822 f1 := buildTable(t, [][]string{{"l1", "b1"}}) 823 f2 := buildTable(t, [][]string{ 824 {"k1", "a1"}, 825 {"k2", "a2"}, 826 }) 827 blkCache, idxCache := testCache(), testCache() 828 t1, err := OpenTable(f1.Name(), blkCache, idxCache) 829 require.NoError(t, err) 830 defer t1.Delete() 831 t2, err := OpenTable(f2.Name(), blkCache, idxCache) 832 require.NoError(t, err) 833 defer t2.Delete() 834 835 it1 := table.NewConcatIterator([]table.Table{t1}, false) 836 it2 := table.NewConcatIterator([]table.Table{t2}, false) 837 it := table.NewMergeIterator([]y.Iterator{it1, it2}, false) 838 839 it.Rewind() 840 require.True(t, it.Valid()) 841 k := it.Key() 842 require.EqualValues(t, "k1", string(k.UserKey)) 843 vs := it.Value() 844 require.EqualValues(t, "a1", string(vs.Value)) 845 require.EqualValues(t, 'A', vs.Meta) 846 it.Next() 847 848 require.True(t, it.Valid()) 849 k = it.Key() 850 require.EqualValues(t, "k2", string(k.UserKey)) 851 vs = it.Value() 852 require.EqualValues(t, "a2", string(vs.Value)) 853 require.EqualValues(t, 'A', vs.Meta) 854 it.Next() 855 require.True(t, it.Valid()) 856 857 k = it.Key() 858 require.EqualValues(t, "l1", string(k.UserKey)) 859 vs = it.Value() 860 require.EqualValues(t, "b1", string(vs.Value)) 861 require.EqualValues(t, 'A', vs.Meta) 862 it.Next() 863 864 require.False(t, it.Valid()) 865 } 866 867 func BenchmarkRead(b *testing.B) { 868 n := 5 << 20 869 filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 870 f, err := y.OpenSyncedFile(filename, true) 871 y.Check(err) 872 builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt) 873 for i := 0; i < n; i++ { 874 k := fmt.Sprintf("%016x", i) 875 v := fmt.Sprintf("%d", i) 876 y.Check(builder.Add(y.KeyWithTs([]byte(k), 0), y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}})) 877 } 878 879 y.Check(builder.Finish()) 880 tbl, err := OpenTable(f.Name(), testCache(), testCache()) 881 y.Check(err) 882 defer tbl.Delete() 883 884 // y.Printf("Size of table: %d\n", tbl.Size()) 885 b.ResetTimer() 886 // Iterate b.N times over the entire table. 887 for i := 0; i < b.N; i++ { 888 func() { 889 it := tbl.newIterator(false) 890 for it.seekToFirst(); it.Valid(); it.next() { 891 } 892 }() 893 } 894 } 895 896 func BenchmarkBuildTable(b *testing.B) { 897 ns := []int{1000, 10000, 100000, 1000000, 5000000, 10000000, 15000000} 898 for _, n := range ns { 899 kvs := make([]struct { 900 k y.Key 901 v []byte 902 }, n) 903 for i := 0; i < n; i++ { 904 kvs[i].k = y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0) 905 kvs[i].v = []byte(fmt.Sprintf("%d", i)) 906 } 907 b.ResetTimer() 908 909 b.Run(fmt.Sprintf("NoHash_%d", n), func(b *testing.B) { 910 filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 911 f, err := y.OpenSyncedFile(filename, false) 912 y.Check(err) 913 opt := defaultBuilderOpt 914 for bn := 0; bn < b.N; bn++ { 915 builder := NewTableBuilder(f, nil, 0, opt) 916 for i := 0; i < n; i++ { 917 y.Check(builder.Add(kvs[i].k, y.ValueStruct{Value: kvs[i].v, Meta: 123, UserMeta: []byte{0}})) 918 } 919 y.Check(builder.Finish()) 920 _, err := f.Seek(0, io.SeekStart) 921 y.Check(err) 922 } 923 }) 924 925 b.Run(fmt.Sprintf("Hash_%d", n), func(b *testing.B) { 926 filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 927 f, err := y.OpenSyncedFile(filename, false) 928 y.Check(err) 929 for bn := 0; bn < b.N; bn++ { 930 builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt) 931 for i := 0; i < n; i++ { 932 y.Check(builder.Add(kvs[i].k, y.ValueStruct{Value: kvs[i].v, Meta: 123, UserMeta: []byte{0}})) 933 } 934 y.Check(builder.Finish()) 935 _, err := f.Seek(0, io.SeekStart) 936 y.Check(err) 937 } 938 }) 939 } 940 } 941 942 var cacheConfig = cache.Config{ 943 NumCounters: 1000000 * 10, 944 MaxCost: 1000000, 945 BufferItems: 64, 946 Metrics: true, 947 } 948 949 func BenchmarkPointGet(b *testing.B) { 950 ns := []int{1000, 10000, 100000, 1000000, 5000000, 10000000, 15000000} 951 for _, n := range ns { 952 filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 953 f, err := y.OpenSyncedFile(filename, true) 954 builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt) 955 keys := make([]y.Key, n) 956 y.Check(err) 957 for i := 0; i < n; i++ { 958 k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0) 959 v := fmt.Sprintf("%d", i) 960 keys[i] = k 961 y.Check(builder.Add(k, y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}})) 962 } 963 964 y.Check(builder.Finish()) 965 tbl, err := OpenTable(filename, testCache(), testCache()) 966 y.Check(err) 967 b.ResetTimer() 968 969 b.Run(fmt.Sprintf("Seek_%d", n), func(b *testing.B) { 970 var vs y.ValueStruct 971 rand := rand.New(rand.NewSource(0)) 972 for bn := 0; bn < b.N; bn++ { 973 rand.Seed(0) 974 for i := 0; i < n; i++ { 975 k := keys[rand.Intn(n)] 976 it := tbl.newIterator(false) 977 it.Seek(k.UserKey) 978 if !it.Valid() { 979 continue 980 } 981 if !k.SameUserKey(it.Key()) { 982 continue 983 } 984 vs = it.Value() 985 } 986 } 987 _ = vs 988 }) 989 990 b.Run(fmt.Sprintf("Hash_%d", n), func(b *testing.B) { 991 var ( 992 resultKey y.Key 993 resultVs y.ValueStruct 994 ok bool 995 ) 996 rand := rand.New(rand.NewSource(0)) 997 for bn := 0; bn < b.N; bn++ { 998 rand.Seed(0) 999 for i := 0; i < n; i++ { 1000 k := keys[rand.Intn(n)] 1001 keyHash := farm.Fingerprint64(k.UserKey) 1002 resultKey, resultVs, ok, _ = tbl.pointGet(k, keyHash) 1003 if !ok { 1004 it := tbl.newIterator(false) 1005 it.Seek(k.UserKey) 1006 if !it.Valid() { 1007 continue 1008 } 1009 if !k.SameUserKey(it.Key()) { 1010 continue 1011 } 1012 resultKey, resultVs = it.Key(), it.Value() 1013 } 1014 } 1015 } 1016 _, _ = resultKey, resultVs 1017 }) 1018 1019 tbl.Delete() 1020 } 1021 } 1022 1023 func BenchmarkReadAndBuild(b *testing.B) { 1024 n := 5 << 20 1025 filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 1026 f, err := y.OpenSyncedFile(filename, false) 1027 builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt) 1028 y.Check(err) 1029 for i := 0; i < n; i++ { 1030 k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0) 1031 v := fmt.Sprintf("%d", i) 1032 y.Check(builder.Add(k, y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}})) 1033 } 1034 1035 y.Check(builder.Finish()) 1036 tbl, err := OpenTable(f.Name(), testCache(), testCache()) 1037 y.Check(err) 1038 defer tbl.Delete() 1039 1040 // y.Printf("Size of table: %d\n", tbl.Size()) 1041 b.ResetTimer() 1042 // Iterate b.N times over the entire table. 1043 filename = fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 1044 f, err = y.OpenSyncedFile(filename, false) 1045 y.Check(err) 1046 for i := 0; i < b.N; i++ { 1047 func() { 1048 newBuilder := NewTableBuilder(f, nil, 0, options.TableBuilderOptions{}) 1049 it := tbl.newIterator(false) 1050 for it.seekToFirst(); it.Valid(); it.next() { 1051 vs := it.Value() 1052 newBuilder.Add(it.Key(), vs) 1053 } 1054 y.Check(newBuilder.Finish()) 1055 _, err := f.Seek(0, io.SeekStart) 1056 y.Check(err) 1057 }() 1058 } 1059 } 1060 1061 func BenchmarkReadMerged(b *testing.B) { 1062 n := 5 << 20 1063 m := 5 // Number of tables. 1064 y.Assert((n % m) == 0) 1065 tableSize := n / m 1066 var tables []*Table 1067 1068 for i := 0; i < m; i++ { 1069 filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 1070 f, err := y.OpenSyncedFile(filename, true) 1071 y.Check(err) 1072 builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt) 1073 for j := 0; j < tableSize; j++ { 1074 id := j*m + i // Arrays are interleaved. 1075 // id := i*tableSize+j (not interleaved) 1076 k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", id)), 0) 1077 v := fmt.Sprintf("%d", id) 1078 y.Check(builder.Add(k, y.ValueStruct{Value: []byte(v), Meta: 123, UserMeta: []byte{0}})) 1079 } 1080 y.Check(builder.Finish()) 1081 tbl, err := OpenTable(f.Name(), testCache(), testCache()) 1082 y.Check(err) 1083 tables = append(tables, tbl) 1084 defer tbl.Delete() 1085 } 1086 1087 b.ResetTimer() 1088 // Iterate b.N times over the entire table. 1089 for i := 0; i < b.N; i++ { 1090 func() { 1091 var iters []y.Iterator 1092 for _, tbl := range tables { 1093 iters = append(iters, tbl.newIterator(false)) 1094 } 1095 it := table.NewMergeIterator(iters, false) 1096 for it.Rewind(); it.Valid(); it.Next() { 1097 } 1098 }() 1099 } 1100 } 1101 1102 func BenchmarkRandomRead(b *testing.B) { 1103 n := int(5 * 1e6) 1104 tbl := getTableForBenchmarks(b, n, testCache(), testCache()) 1105 1106 r := rand.New(rand.NewSource(time.Now().Unix())) 1107 1108 b.ResetTimer() 1109 for i := 0; i < b.N; i++ { 1110 itr := tbl.newIterator(false) 1111 no := r.Intn(n) 1112 k := []byte(fmt.Sprintf("%016x", no)) 1113 v := []byte(fmt.Sprintf("%d", no)) 1114 itr.Seek(k) 1115 if !itr.Valid() { 1116 b.Fatal("itr should be valid") 1117 } 1118 v1 := itr.Value().Value 1119 1120 if !bytes.Equal(v, v1) { 1121 fmt.Println("value does not match") 1122 b.Fatal() 1123 } 1124 } 1125 } 1126 1127 func getTableForBenchmarks(b *testing.B, count int, blkCache, idxCache *cache.Cache) *Table { 1128 rand.Seed(time.Now().Unix()) 1129 filename := fmt.Sprintf("%s%s%d.sst", os.TempDir(), string(os.PathSeparator), rand.Uint32()) 1130 f, err := y.OpenSyncedFile(filename, false) 1131 builder := NewTableBuilder(f, nil, 0, defaultBuilderOpt) 1132 require.NoError(b, err) 1133 for i := 0; i < count; i++ { 1134 k := y.KeyWithTs([]byte(fmt.Sprintf("%016x", i)), 0) 1135 v := fmt.Sprintf("%d", i) 1136 builder.Add(k, y.ValueStruct{Value: []byte(v)}) 1137 } 1138 1139 err = builder.Finish() 1140 require.NoError(b, err, "unable to write to file") 1141 tbl, err := OpenTable(f.Name(), blkCache, idxCache) 1142 require.NoError(b, err, "unable to open table") 1143 return tbl 1144 } 1145 1146 func TestMain(m *testing.M) { 1147 rand.Seed(time.Now().UTC().UnixNano()) 1148 os.Exit(m.Run()) 1149 }