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