github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/batch_test.go (about) 1 // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package bitalostable 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "io" 12 "math" 13 "math/rand" 14 "strconv" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/cockroachdb/errors" 20 "github.com/stretchr/testify/require" 21 "github.com/zuoyebang/bitalostable/internal/base" 22 "github.com/zuoyebang/bitalostable/internal/batchskl" 23 "github.com/zuoyebang/bitalostable/internal/datadriven" 24 "github.com/zuoyebang/bitalostable/internal/keyspan" 25 "github.com/zuoyebang/bitalostable/internal/testkeys" 26 "github.com/zuoyebang/bitalostable/vfs" 27 ) 28 29 func TestBatch(t *testing.T) { 30 type testCase struct { 31 kind InternalKeyKind 32 key, value string 33 } 34 35 verifyTestCases := func(b *Batch, testCases []testCase) { 36 r := b.Reader() 37 38 for _, tc := range testCases { 39 kind, k, v, ok := r.Next() 40 if !ok { 41 t.Fatalf("next returned !ok: test case = %v", tc) 42 } 43 key, value := string(k), string(v) 44 if kind != tc.kind || key != tc.key || value != tc.value { 45 t.Errorf("got (%d, %q, %q), want (%d, %q, %q)", 46 kind, key, value, tc.kind, tc.key, tc.value) 47 } 48 } 49 if len(r) != 0 { 50 t.Errorf("reader was not exhausted: remaining bytes = %q", r) 51 } 52 } 53 54 // RangeKeySet and RangeKeyUnset are untested here because they don't expose 55 // deferred variants. This is a consequence of these keys' more complex 56 // value encodings. 57 testCases := []testCase{ 58 {InternalKeyKindSet, "roses", "red"}, 59 {InternalKeyKindSet, "violets", "blue"}, 60 {InternalKeyKindDelete, "roses", ""}, 61 {InternalKeyKindSingleDelete, "roses", ""}, 62 {InternalKeyKindSet, "", ""}, 63 {InternalKeyKindSet, "", "non-empty"}, 64 {InternalKeyKindDelete, "", ""}, 65 {InternalKeyKindSingleDelete, "", ""}, 66 {InternalKeyKindSet, "grass", "green"}, 67 {InternalKeyKindSet, "grass", "greener"}, 68 {InternalKeyKindSet, "eleventy", strings.Repeat("!!11!", 100)}, 69 {InternalKeyKindDelete, "nosuchkey", ""}, 70 {InternalKeyKindSingleDelete, "nosuchkey", ""}, 71 {InternalKeyKindSet, "binarydata", "\x00"}, 72 {InternalKeyKindSet, "binarydata", "\xff"}, 73 {InternalKeyKindMerge, "merge", "mergedata"}, 74 {InternalKeyKindMerge, "merge", ""}, 75 {InternalKeyKindMerge, "", ""}, 76 {InternalKeyKindRangeDelete, "a", "b"}, 77 {InternalKeyKindRangeDelete, "", ""}, 78 {InternalKeyKindLogData, "logdata", ""}, 79 {InternalKeyKindLogData, "", ""}, 80 {InternalKeyKindRangeKeyDelete, "grass", "green"}, 81 {InternalKeyKindRangeKeyDelete, "", ""}, 82 } 83 var b Batch 84 for _, tc := range testCases { 85 switch tc.kind { 86 case InternalKeyKindSet: 87 _ = b.Set([]byte(tc.key), []byte(tc.value), nil) 88 case InternalKeyKindMerge: 89 _ = b.Merge([]byte(tc.key), []byte(tc.value), nil) 90 case InternalKeyKindDelete: 91 _ = b.Delete([]byte(tc.key), nil) 92 case InternalKeyKindSingleDelete: 93 _ = b.SingleDelete([]byte(tc.key), nil) 94 case InternalKeyKindRangeDelete: 95 _ = b.DeleteRange([]byte(tc.key), []byte(tc.value), nil) 96 case InternalKeyKindLogData: 97 _ = b.LogData([]byte(tc.key), nil) 98 case InternalKeyKindRangeKeyDelete: 99 _ = b.RangeKeyDelete([]byte(tc.key), []byte(tc.value), nil) 100 } 101 } 102 verifyTestCases(&b, testCases) 103 104 b.Reset() 105 // Run the same operations, this time using the Deferred variants of each 106 // operation (eg. SetDeferred). 107 for _, tc := range testCases { 108 key := []byte(tc.key) 109 value := []byte(tc.value) 110 switch tc.kind { 111 case InternalKeyKindSet: 112 d := b.SetDeferred(len(key), len(value)) 113 copy(d.Key, key) 114 copy(d.Value, value) 115 d.Finish() 116 case InternalKeyKindMerge: 117 d := b.MergeDeferred(len(key), len(value)) 118 copy(d.Key, key) 119 copy(d.Value, value) 120 d.Finish() 121 case InternalKeyKindDelete: 122 d := b.DeleteDeferred(len(key)) 123 copy(d.Key, key) 124 copy(d.Value, value) 125 d.Finish() 126 case InternalKeyKindSingleDelete: 127 d := b.SingleDeleteDeferred(len(key)) 128 copy(d.Key, key) 129 copy(d.Value, value) 130 d.Finish() 131 case InternalKeyKindRangeDelete: 132 d := b.DeleteRangeDeferred(len(key), len(value)) 133 copy(d.Key, key) 134 copy(d.Value, value) 135 d.Finish() 136 case InternalKeyKindLogData: 137 _ = b.LogData([]byte(tc.key), nil) 138 case InternalKeyKindRangeKeyDelete: 139 d := b.RangeKeyDeleteDeferred(len(key), len(value)) 140 copy(d.Key, key) 141 copy(d.Value, value) 142 d.Finish() 143 } 144 } 145 verifyTestCases(&b, testCases) 146 } 147 148 func TestBatchLen(t *testing.T) { 149 var b Batch 150 151 requireLenAndReprEq := func(size int) { 152 require.Equal(t, size, b.Len()) 153 require.Equal(t, size, len(b.Repr())) 154 } 155 156 requireLenAndReprEq(batchHeaderLen) 157 158 key := "test-key" 159 value := "test-value" 160 161 err := b.Set([]byte(key), []byte(value), nil) 162 require.NoError(t, err) 163 164 requireLenAndReprEq(33) 165 166 err = b.Delete([]byte(key), nil) 167 require.NoError(t, err) 168 169 requireLenAndReprEq(43) 170 } 171 172 func TestBatchEmpty(t *testing.T) { 173 var b Batch 174 require.True(t, b.Empty()) 175 176 ops := []func(*Batch) error{ 177 func(b *Batch) error { return b.Set(nil, nil, nil) }, 178 func(b *Batch) error { return b.Merge(nil, nil, nil) }, 179 func(b *Batch) error { return b.Delete(nil, nil) }, 180 func(b *Batch) error { return b.DeleteRange(nil, nil, nil) }, 181 func(b *Batch) error { return b.LogData(nil, nil) }, 182 func(b *Batch) error { return b.RangeKeySet(nil, nil, nil, nil, nil) }, 183 func(b *Batch) error { return b.RangeKeyUnset(nil, nil, nil, nil) }, 184 func(b *Batch) error { return b.RangeKeyDelete(nil, nil, nil) }, 185 } 186 187 for _, op := range ops { 188 require.NoError(t, op(&b)) 189 require.False(t, b.Empty()) 190 b.Reset() 191 require.True(t, b.Empty()) 192 // Reset may choose to reuse b.data, so clear it to the zero value in 193 // order to test the lazy initialization of b.data. 194 b = Batch{} 195 } 196 197 _ = b.Reader() 198 require.True(t, b.Empty()) 199 b.Reset() 200 require.True(t, b.Empty()) 201 b = Batch{} 202 203 require.Equal(t, uint64(0), b.SeqNum()) 204 require.True(t, b.Empty()) 205 b.Reset() 206 require.True(t, b.Empty()) 207 b = Batch{} 208 209 d, err := Open("", &Options{ 210 FS: vfs.NewMem(), 211 }) 212 require.NoError(t, err) 213 defer d.Close() 214 ib := newIndexedBatch(d, DefaultComparer) 215 iter := ib.NewIter(nil) 216 require.False(t, iter.First()) 217 iter2, err := iter.Clone(CloneOptions{}) 218 require.NoError(t, err) 219 require.NoError(t, iter.Close()) 220 _, err = iter.Clone(CloneOptions{}) 221 require.True(t, err != nil) 222 require.False(t, iter2.First()) 223 require.NoError(t, iter2.Close()) 224 } 225 226 func TestBatchReset(t *testing.T) { 227 db, err := Open("", &Options{ 228 FS: vfs.NewMem(), 229 }) 230 require.NoError(t, err) 231 defer db.Close() 232 key := "test-key" 233 value := "test-value" 234 b := db.NewBatch() 235 require.NoError(t, b.Set([]byte(key), []byte(value), nil)) 236 dd := b.DeleteRangeDeferred(len(key), len(value)) 237 copy(dd.Key, key) 238 copy(dd.Value, value) 239 dd.Finish() 240 241 require.NoError(t, b.RangeKeySet([]byte(key), []byte(value), []byte(value), []byte(value), nil)) 242 243 b.setSeqNum(100) 244 b.applied = 1 245 b.commitErr = errors.New("test-error") 246 b.commit.Add(1) 247 require.Equal(t, uint32(3), b.Count()) 248 require.Equal(t, uint64(1), b.countRangeDels) 249 require.Equal(t, uint64(1), b.countRangeKeys) 250 require.True(t, len(b.data) > 0) 251 require.True(t, b.SeqNum() > 0) 252 require.True(t, b.memTableSize > 0) 253 require.NotEqual(t, b.deferredOp, DeferredBatchOp{}) 254 255 b.Reset() 256 require.Equal(t, db, b.db) 257 require.Equal(t, uint32(0), b.applied) 258 require.Nil(t, b.commitErr) 259 require.Equal(t, uint32(0), b.Count()) 260 require.Equal(t, uint64(0), b.countRangeDels) 261 require.Equal(t, uint64(0), b.countRangeKeys) 262 require.Equal(t, batchHeaderLen, len(b.data)) 263 require.Equal(t, uint64(0), b.SeqNum()) 264 require.Equal(t, uint64(0), b.memTableSize) 265 require.Equal(t, b.deferredOp, DeferredBatchOp{}) 266 267 var expected Batch 268 expected.SetRepr(b.data) 269 expected.db = db 270 require.Equal(t, &expected, b) 271 272 // Reset batch can be used to write and commit a new record. 273 b.Set([]byte(key), []byte(value), nil) 274 require.NoError(t, db.Apply(b, nil)) 275 v, closer, err := db.Get([]byte(key)) 276 require.NoError(t, err) 277 defer closer.Close() 278 require.Equal(t, v, []byte(value)) 279 } 280 281 func TestIndexedBatchReset(t *testing.T) { 282 indexCount := func(sl *batchskl.Skiplist) int { 283 count := 0 284 iter := sl.NewIter(nil, nil) 285 defer iter.Close() 286 for iter.First(); iter.Valid(); iter.Next() { 287 count++ 288 } 289 return count 290 } 291 db, err := Open("", &Options{ 292 FS: vfs.NewMem(), 293 }) 294 require.NoError(t, err) 295 defer db.Close() 296 b := newIndexedBatch(db, DefaultComparer) 297 start := "start-key" 298 end := "end-key" 299 key := "test-key" 300 value := "test-value" 301 b.DeleteRange([]byte(start), []byte(end), nil) 302 b.Set([]byte(key), []byte(value), nil) 303 require.NoError(t, b. 304 RangeKeySet([]byte(start), []byte(end), []byte("suffix"), []byte(value), nil)) 305 require.NotNil(t, b.rangeKeyIndex) 306 require.NotNil(t, b.rangeDelIndex) 307 require.NotNil(t, b.index) 308 require.Equal(t, 1, indexCount(b.index)) 309 310 b.Reset() 311 require.NotNil(t, b.cmp) 312 require.NotNil(t, b.formatKey) 313 require.NotNil(t, b.abbreviatedKey) 314 require.NotNil(t, b.index) 315 require.Nil(t, b.rangeDelIndex) 316 require.Nil(t, b.rangeKeyIndex) 317 318 count := func(ib *Batch) int { 319 iter := ib.NewIter(nil) 320 defer iter.Close() 321 iter2, err := iter.Clone(CloneOptions{}) 322 require.NoError(t, err) 323 defer iter2.Close() 324 var count [2]int 325 for i, it := range []*Iterator{iter, iter2} { 326 for it.First(); it.Valid(); it.Next() { 327 count[i]++ 328 } 329 } 330 require.Equal(t, count[0], count[1]) 331 return count[0] 332 } 333 contains := func(ib *Batch, key, value string) bool { 334 iter := ib.NewIter(nil) 335 defer iter.Close() 336 iter2, err := iter.Clone(CloneOptions{}) 337 require.NoError(t, err) 338 defer iter2.Close() 339 var found [2]bool 340 for i, it := range []*Iterator{iter, iter2} { 341 for it.First(); it.Valid(); it.Next() { 342 if string(it.Key()) == key && 343 string(it.Value()) == value { 344 found[i] = true 345 } 346 } 347 } 348 require.Equal(t, found[0], found[1]) 349 return found[0] 350 } 351 // Set a key and check whether the key-value pair is visible. 352 b.Set([]byte(key), []byte(value), nil) 353 require.Equal(t, 1, indexCount(b.index)) 354 require.Equal(t, 1, count(b)) 355 require.True(t, contains(b, key, value)) 356 357 // Use range delete to delete the above inserted key-value pair. 358 b.DeleteRange([]byte(key), []byte(value), nil) 359 require.NotNil(t, b.rangeDelIndex) 360 require.Equal(t, 1, indexCount(b.rangeDelIndex)) 361 require.Equal(t, 0, count(b)) 362 require.False(t, contains(b, key, value)) 363 } 364 365 // TestIndexedBatchMutation tests mutating an indexed batch with an open 366 // iterator. 367 func TestIndexedBatchMutation(t *testing.T) { 368 opts := &Options{ 369 Comparer: testkeys.Comparer, 370 FS: vfs.NewMem(), 371 FormatMajorVersion: FormatNewest, 372 } 373 d, err := Open("", opts) 374 require.NoError(t, err) 375 defer func() { d.Close() }() 376 377 b := newIndexedBatch(d, DefaultComparer) 378 iters := map[string]*Iterator{} 379 defer func() { 380 for _, iter := range iters { 381 require.NoError(t, iter.Close()) 382 } 383 }() 384 385 datadriven.RunTest(t, "testdata/indexed_batch_mutation", func(td *datadriven.TestData) string { 386 switch td.Cmd { 387 case "batch": 388 writeBatch := newBatch(d) 389 if err := runBatchDefineCmd(td, writeBatch); err != nil { 390 return err.Error() 391 } 392 if err := writeBatch.Commit(nil); err != nil { 393 return err.Error() 394 } 395 return "" 396 case "new-batch-iter": 397 name := td.CmdArgs[0].String() 398 iters[name] = b.NewIter(&IterOptions{ 399 KeyTypes: IterKeyTypePointsAndRanges, 400 }) 401 return "" 402 case "new-db-iter": 403 name := td.CmdArgs[0].String() 404 iters[name] = d.NewIter(&IterOptions{ 405 KeyTypes: IterKeyTypePointsAndRanges, 406 }) 407 return "" 408 case "new-batch": 409 if b != nil { 410 require.NoError(t, b.Close()) 411 } 412 b = newIndexedBatch(d, opts.Comparer) 413 if err := runBatchDefineCmd(td, b); err != nil { 414 return err.Error() 415 } 416 return "" 417 case "flush": 418 require.NoError(t, d.Flush()) 419 return "" 420 case "iter": 421 var iter string 422 td.ScanArgs(t, "iter", &iter) 423 return runIterCmd(td, iters[iter], false /* closeIter */) 424 case "mutate": 425 mut := newBatch(d) 426 if err := runBatchDefineCmd(td, mut); err != nil { 427 return err.Error() 428 } 429 if err := b.Apply(mut, nil); err != nil { 430 return err.Error() 431 } 432 return "" 433 case "clone": 434 var from, to string 435 var refreshBatchView bool 436 td.ScanArgs(t, "from", &from) 437 td.ScanArgs(t, "to", &to) 438 td.ScanArgs(t, "refresh-batch", &refreshBatchView) 439 var err error 440 iters[to], err = iters[from].Clone(CloneOptions{RefreshBatchView: refreshBatchView}) 441 if err != nil { 442 return err.Error() 443 } 444 return "" 445 case "reset": 446 for key, iter := range iters { 447 if err := iter.Close(); err != nil { 448 return err.Error() 449 } 450 delete(iters, key) 451 } 452 if d != nil { 453 if err := d.Close(); err != nil { 454 return err.Error() 455 } 456 } 457 opts.FS = vfs.NewMem() 458 d, err = Open("", opts) 459 require.NoError(t, err) 460 return "" 461 default: 462 return fmt.Sprintf("unrecognized command %q", td.Cmd) 463 } 464 }) 465 } 466 467 func TestIndexedBatch_GlobalVisibility(t *testing.T) { 468 opts := &Options{ 469 FS: vfs.NewMem(), 470 FormatMajorVersion: FormatNewest, 471 Comparer: testkeys.Comparer, 472 } 473 d, err := Open("", opts) 474 require.NoError(t, err) 475 defer d.Close() 476 477 require.NoError(t, d.Set([]byte("foo"), []byte("foo"), nil)) 478 479 // Create an iterator over an empty indexed batch. 480 b := newIndexedBatch(d, DefaultComparer) 481 iterOpts := IterOptions{KeyTypes: IterKeyTypePointsAndRanges} 482 iter := b.NewIter(&iterOpts) 483 defer iter.Close() 484 485 // Mutate the database's committed state. 486 mut := newBatch(d) 487 require.NoError(t, mut.Set([]byte("bar"), []byte("bar"), nil)) 488 require.NoError(t, mut.DeleteRange([]byte("e"), []byte("g"), nil)) 489 require.NoError(t, mut.RangeKeySet([]byte("a"), []byte("c"), []byte("@1"), []byte("v"), nil)) 490 require.NoError(t, mut.Commit(nil)) 491 492 scanIter := func() string { 493 var buf bytes.Buffer 494 for valid := iter.First(); valid; valid = iter.Next() { 495 fmt.Fprintf(&buf, "%s: (", iter.Key()) 496 hasPoint, hasRange := iter.HasPointAndRange() 497 if hasPoint { 498 fmt.Fprintf(&buf, "%s,", iter.Value()) 499 } else { 500 fmt.Fprintf(&buf, ".,") 501 } 502 if hasRange { 503 start, end := iter.RangeBounds() 504 fmt.Fprintf(&buf, "[%s-%s)", start, end) 505 writeRangeKeys(&buf, iter) 506 } else { 507 fmt.Fprintf(&buf, ".") 508 } 509 fmt.Fprintln(&buf, ")") 510 } 511 return strings.TrimSpace(buf.String()) 512 } 513 // Scanning the iterator should only see the point key written before the 514 // iterator was constructed. 515 require.Equal(t, `foo: (foo,.)`, scanIter()) 516 517 // After calling SetOptions, the iterator should still only see the point 518 // key written before the iterator was constructed. SetOptions refreshes the 519 // iterator's view of its own indexed batch, but not committed state. 520 iter.SetOptions(&iterOpts) 521 require.Equal(t, `foo: (foo,.)`, scanIter()) 522 } 523 524 func TestFlushableBatchReset(t *testing.T) { 525 var b Batch 526 b.flushable = newFlushableBatch(&b, DefaultComparer) 527 528 b.Reset() 529 require.Nil(t, b.flushable) 530 } 531 532 func TestBatchIncrement(t *testing.T) { 533 testCases := []uint32{ 534 0x00000000, 535 0x00000001, 536 0x00000002, 537 0x0000007f, 538 0x00000080, 539 0x000000fe, 540 0x000000ff, 541 0x00000100, 542 0x00000101, 543 0x000001ff, 544 0x00000200, 545 0x00000fff, 546 0x00001234, 547 0x0000fffe, 548 0x0000ffff, 549 0x00010000, 550 0x00010001, 551 0x000100fe, 552 0x000100ff, 553 0x00020100, 554 0x03fffffe, 555 0x03ffffff, 556 0x04000000, 557 0x04000001, 558 0x7fffffff, 559 0xfffffffe, 560 } 561 for _, tc := range testCases { 562 var buf [batchHeaderLen]byte 563 binary.LittleEndian.PutUint32(buf[8:12], tc) 564 var b Batch 565 b.SetRepr(buf[:]) 566 b.count++ 567 got := binary.LittleEndian.Uint32(b.Repr()[8:12]) 568 want := tc + 1 569 if got != want { 570 t.Errorf("input=%d: got %d, want %d", tc, got, want) 571 } 572 _, count := ReadBatch(b.Repr()) 573 if got != want { 574 t.Errorf("input=%d: got %d, want %d", tc, count, want) 575 } 576 } 577 578 err := func() (err error) { 579 defer func() { 580 if v := recover(); v != nil { 581 if verr, ok := v.(error); ok { 582 err = verr 583 } 584 } 585 }() 586 var buf [batchHeaderLen]byte 587 binary.LittleEndian.PutUint32(buf[8:12], 0xffffffff) 588 var b Batch 589 b.SetRepr(buf[:]) 590 b.count++ 591 b.Repr() 592 return nil 593 }() 594 if err != ErrInvalidBatch { 595 t.Fatalf("expected %v, but found %v", ErrInvalidBatch, err) 596 } 597 } 598 599 func TestBatchOpDoesIncrement(t *testing.T) { 600 var b Batch 601 key := []byte("foo") 602 value := []byte("bar") 603 604 if b.Count() != 0 { 605 t.Fatalf("new batch has a nonzero count: %d", b.Count()) 606 } 607 608 // Should increment count by 1 609 _ = b.Set(key, value, nil) 610 if b.Count() != 1 { 611 t.Fatalf("expected count: %d, got %d", 1, b.Count()) 612 } 613 614 var b2 Batch 615 // Should increment count by 1 each 616 _ = b2.Set(key, value, nil) 617 _ = b2.Delete(key, nil) 618 if b2.Count() != 2 { 619 t.Fatalf("expected count: %d, got %d", 2, b2.Count()) 620 } 621 622 // Should increment count by b2.count() 623 _ = b.Apply(&b2, nil) 624 if b.Count() != 3 { 625 t.Fatalf("expected count: %d, got %d", 3, b.Count()) 626 } 627 628 // Should increment count by 1 629 _ = b.Merge(key, value, nil) 630 if b.Count() != 4 { 631 t.Fatalf("expected count: %d, got %d", 4, b.Count()) 632 } 633 634 // Should NOT increment count. 635 _ = b.LogData([]byte("foobarbaz"), nil) 636 if b.Count() != 4 { 637 t.Fatalf("expected count: %d, got %d", 4, b.Count()) 638 } 639 } 640 641 func TestBatchGet(t *testing.T) { 642 testCases := []struct { 643 method string 644 memTableSize int 645 }{ 646 {"build", 64 << 20}, 647 {"build", 2 << 10}, 648 {"apply", 64 << 20}, 649 } 650 651 for _, c := range testCases { 652 t.Run(fmt.Sprintf("%s,mem=%d", c.method, c.memTableSize), func(t *testing.T) { 653 d, err := Open("", &Options{ 654 FS: vfs.NewMem(), 655 MemTableSize: c.memTableSize, 656 }) 657 if err != nil { 658 t.Fatalf("Open: %v", err) 659 } 660 defer d.Close() 661 var b *Batch 662 663 datadriven.RunTest(t, "testdata/batch_get", func(td *datadriven.TestData) string { 664 switch td.Cmd { 665 case "define": 666 switch c.method { 667 case "build": 668 b = d.NewIndexedBatch() 669 case "apply": 670 b = d.NewBatch() 671 } 672 673 if err := runBatchDefineCmd(td, b); err != nil { 674 return err.Error() 675 } 676 677 switch c.method { 678 case "apply": 679 tmp := d.NewIndexedBatch() 680 tmp.Apply(b, nil) 681 b = tmp 682 } 683 return "" 684 685 case "commit": 686 if err := b.Commit(nil); err != nil { 687 return err.Error() 688 } 689 b = nil 690 return "" 691 692 case "get": 693 if len(td.CmdArgs) != 1 { 694 return fmt.Sprintf("%s expects 1 argument", td.Cmd) 695 } 696 v, closer, err := b.Get([]byte(td.CmdArgs[0].String())) 697 if err != nil { 698 return err.Error() 699 } 700 defer closer.Close() 701 return string(v) 702 703 default: 704 return fmt.Sprintf("unknown command: %s", td.Cmd) 705 } 706 }) 707 }) 708 } 709 } 710 711 func TestBatchIter(t *testing.T) { 712 var b *Batch 713 714 for _, method := range []string{"build", "apply"} { 715 for _, testdata := range []string{ 716 "testdata/internal_iter_next", "testdata/internal_iter_bounds"} { 717 t.Run(method, func(t *testing.T) { 718 datadriven.RunTest(t, testdata, func(d *datadriven.TestData) string { 719 switch d.Cmd { 720 case "define": 721 switch method { 722 case "build": 723 b = newIndexedBatch(nil, DefaultComparer) 724 case "apply": 725 b = newBatch(nil) 726 } 727 728 for _, key := range strings.Split(d.Input, "\n") { 729 j := strings.Index(key, ":") 730 ikey := base.ParseInternalKey(key[:j]) 731 value := []byte(key[j+1:]) 732 b.Set(ikey.UserKey, value, nil) 733 } 734 735 switch method { 736 case "apply": 737 tmp := newIndexedBatch(nil, DefaultComparer) 738 tmp.Apply(b, nil) 739 b = tmp 740 } 741 return "" 742 743 case "iter": 744 var options IterOptions 745 for _, arg := range d.CmdArgs { 746 switch arg.Key { 747 case "lower": 748 if len(arg.Vals) != 1 { 749 return fmt.Sprintf( 750 "%s expects at most 1 value for lower", d.Cmd) 751 } 752 options.LowerBound = []byte(arg.Vals[0]) 753 case "upper": 754 if len(arg.Vals) != 1 { 755 return fmt.Sprintf( 756 "%s expects at most 1 value for upper", d.Cmd) 757 } 758 options.UpperBound = []byte(arg.Vals[0]) 759 default: 760 return fmt.Sprintf("unknown arg: %s", arg.Key) 761 } 762 } 763 iter := b.newInternalIter(&options) 764 defer iter.Close() 765 return runInternalIterCmd(d, iter) 766 767 default: 768 return fmt.Sprintf("unknown command: %s", d.Cmd) 769 } 770 }) 771 }) 772 } 773 } 774 } 775 776 func TestBatchRangeOps(t *testing.T) { 777 var b *Batch 778 779 datadriven.RunTest(t, "testdata/batch_range_ops", func(td *datadriven.TestData) string { 780 switch td.Cmd { 781 case "clear": 782 b = nil 783 return "" 784 785 case "apply": 786 if b == nil { 787 b = newIndexedBatch(nil, DefaultComparer) 788 } 789 t := newBatch(nil) 790 if err := runBatchDefineCmd(td, t); err != nil { 791 return err.Error() 792 } 793 if err := b.Apply(t, nil); err != nil { 794 return err.Error() 795 } 796 return "" 797 798 case "define": 799 if b == nil { 800 b = newIndexedBatch(nil, DefaultComparer) 801 } 802 if err := runBatchDefineCmd(td, b); err != nil { 803 return err.Error() 804 } 805 return "" 806 807 case "scan": 808 if len(td.CmdArgs) > 1 { 809 return fmt.Sprintf("%s expects at most 1 argument", td.Cmd) 810 } 811 var fragmentIter keyspan.FragmentIterator 812 var internalIter base.InternalIterator 813 if len(td.CmdArgs) == 1 { 814 switch td.CmdArgs[0].String() { 815 case "range-del": 816 fragmentIter = b.newRangeDelIter(nil, math.MaxUint64) 817 defer fragmentIter.Close() 818 case "range-key": 819 fragmentIter = b.newRangeKeyIter(nil, math.MaxUint64) 820 defer fragmentIter.Close() 821 default: 822 return fmt.Sprintf("%s unknown argument %s", td.Cmd, td.CmdArgs[0]) 823 } 824 } else { 825 internalIter = b.newInternalIter(nil) 826 defer internalIter.Close() 827 } 828 829 var buf bytes.Buffer 830 if fragmentIter != nil { 831 for s := fragmentIter.First(); s != nil; s = fragmentIter.Next() { 832 for i := range s.Keys { 833 s.Keys[i].Trailer = base.MakeTrailer( 834 s.Keys[i].SeqNum()&^base.InternalKeySeqNumBatch, 835 s.Keys[i].Kind(), 836 ) 837 } 838 fmt.Fprintln(&buf, s) 839 } 840 } else { 841 for k, v := internalIter.First(); k != nil; k, v = internalIter.Next() { 842 k.SetSeqNum(k.SeqNum() &^ InternalKeySeqNumBatch) 843 fmt.Fprintf(&buf, "%s:%s\n", k, v) 844 } 845 } 846 return buf.String() 847 848 default: 849 return fmt.Sprintf("unknown command: %s", td.Cmd) 850 } 851 }) 852 } 853 854 func TestBatchTooLarge(t *testing.T) { 855 var b Batch 856 var result interface{} 857 func() { 858 defer func() { 859 if r := recover(); r != nil { 860 result = r 861 } 862 }() 863 b.grow(maxBatchSize) 864 }() 865 require.EqualValues(t, ErrBatchTooLarge, result) 866 } 867 868 func TestFlushableBatchIter(t *testing.T) { 869 var b *flushableBatch 870 datadriven.RunTest(t, "testdata/internal_iter_next", func(d *datadriven.TestData) string { 871 switch d.Cmd { 872 case "define": 873 batch := newBatch(nil) 874 for _, key := range strings.Split(d.Input, "\n") { 875 j := strings.Index(key, ":") 876 ikey := base.ParseInternalKey(key[:j]) 877 value := []byte(fmt.Sprint(ikey.SeqNum())) 878 batch.Set(ikey.UserKey, value, nil) 879 } 880 b = newFlushableBatch(batch, DefaultComparer) 881 return "" 882 883 case "iter": 884 iter := b.newIter(nil) 885 defer iter.Close() 886 return runInternalIterCmd(d, iter) 887 888 default: 889 return fmt.Sprintf("unknown command: %s", d.Cmd) 890 } 891 }) 892 } 893 894 func TestFlushableBatch(t *testing.T) { 895 var b *flushableBatch 896 datadriven.RunTest(t, "testdata/flushable_batch", func(d *datadriven.TestData) string { 897 switch d.Cmd { 898 case "define": 899 batch := newBatch(nil) 900 for _, key := range strings.Split(d.Input, "\n") { 901 j := strings.Index(key, ":") 902 ikey := base.ParseInternalKey(key[:j]) 903 value := []byte(fmt.Sprint(ikey.SeqNum())) 904 switch ikey.Kind() { 905 case InternalKeyKindDelete: 906 require.NoError(t, batch.Delete(ikey.UserKey, nil)) 907 case InternalKeyKindSet: 908 require.NoError(t, batch.Set(ikey.UserKey, value, nil)) 909 case InternalKeyKindMerge: 910 require.NoError(t, batch.Merge(ikey.UserKey, value, nil)) 911 case InternalKeyKindRangeDelete: 912 require.NoError(t, batch.DeleteRange(ikey.UserKey, value, nil)) 913 case InternalKeyKindRangeKeyDelete: 914 require.NoError(t, batch.RangeKeyDelete(ikey.UserKey, value, nil)) 915 case InternalKeyKindRangeKeySet: 916 require.NoError(t, batch.RangeKeySet(ikey.UserKey, value, value, value, nil)) 917 case InternalKeyKindRangeKeyUnset: 918 require.NoError(t, batch.RangeKeyUnset(ikey.UserKey, value, value, nil)) 919 } 920 } 921 b = newFlushableBatch(batch, DefaultComparer) 922 return "" 923 924 case "iter": 925 var opts IterOptions 926 for _, arg := range d.CmdArgs { 927 if len(arg.Vals) != 1 { 928 return fmt.Sprintf("%s: %s=<value>", d.Cmd, arg.Key) 929 } 930 switch arg.Key { 931 case "lower": 932 opts.LowerBound = []byte(arg.Vals[0]) 933 case "upper": 934 opts.UpperBound = []byte(arg.Vals[0]) 935 default: 936 return fmt.Sprintf("%s: unknown arg: %s", d.Cmd, arg.Key) 937 } 938 } 939 940 iter := b.newIter(&opts) 941 defer iter.Close() 942 return runInternalIterCmd(d, iter) 943 944 case "dump": 945 if len(d.CmdArgs) != 1 || len(d.CmdArgs[0].Vals) != 1 || d.CmdArgs[0].Key != "seq" { 946 return "dump seq=<value>\n" 947 } 948 seqNum, err := strconv.Atoi(d.CmdArgs[0].Vals[0]) 949 if err != nil { 950 return err.Error() 951 } 952 b.setSeqNum(uint64(seqNum)) 953 954 var buf bytes.Buffer 955 956 iter := newInternalIterAdapter(b.newIter(nil)) 957 for valid := iter.First(); valid; valid = iter.Next() { 958 fmt.Fprintf(&buf, "%s:%s\n", iter.Key(), iter.Value()) 959 } 960 iter.Close() 961 962 if rangeDelIter := b.newRangeDelIter(nil); rangeDelIter != nil { 963 scanKeyspanIterator(&buf, rangeDelIter) 964 rangeDelIter.Close() 965 } 966 if rangeKeyIter := b.newRangeKeyIter(nil); rangeKeyIter != nil { 967 scanKeyspanIterator(&buf, rangeKeyIter) 968 rangeKeyIter.Close() 969 } 970 return buf.String() 971 972 default: 973 return fmt.Sprintf("unknown command: %s", d.Cmd) 974 } 975 }) 976 } 977 978 func TestFlushableBatchDeleteRange(t *testing.T) { 979 var fb *flushableBatch 980 var input string 981 982 datadriven.RunTest(t, "testdata/delete_range", func(td *datadriven.TestData) string { 983 switch td.Cmd { 984 case "clear": 985 input = "" 986 return "" 987 988 case "define": 989 b := newBatch(nil) 990 // NB: We can't actually add to the flushable batch as we can to a 991 // memtable (which shares the "testdata/delete_range" data), so we fake 992 // it by concatenating the input and rebuilding the flushable batch from 993 // scratch. 994 input += "\n" + td.Input 995 td.Input = input 996 if err := runBatchDefineCmd(td, b); err != nil { 997 return err.Error() 998 } 999 fb = newFlushableBatch(b, DefaultComparer) 1000 return "" 1001 1002 case "scan": 1003 var buf bytes.Buffer 1004 if len(td.CmdArgs) > 1 { 1005 return fmt.Sprintf("%s expects at most 1 argument", td.Cmd) 1006 } 1007 if len(td.CmdArgs) == 1 { 1008 if td.CmdArgs[0].String() != "range-del" { 1009 return fmt.Sprintf("%s unknown argument %s", td.Cmd, td.CmdArgs[0]) 1010 } 1011 fi := fb.newRangeDelIter(nil) 1012 defer fi.Close() 1013 scanKeyspanIterator(&buf, fi) 1014 } else { 1015 ii := fb.newIter(nil) 1016 defer ii.Close() 1017 scanInternalIterator(&buf, ii) 1018 } 1019 return buf.String() 1020 1021 default: 1022 return fmt.Sprintf("unknown command: %s", td.Cmd) 1023 } 1024 }) 1025 } 1026 1027 func scanInternalIterator(w io.Writer, ii internalIterator) { 1028 for k, v := ii.First(); k != nil; k, v = ii.Next() { 1029 fmt.Fprintf(w, "%s:%s\n", k, v) 1030 } 1031 } 1032 1033 func scanKeyspanIterator(w io.Writer, ki keyspan.FragmentIterator) { 1034 for s := ki.First(); s != nil; s = ki.Next() { 1035 fmt.Fprintln(w, s) 1036 } 1037 } 1038 1039 func TestFlushableBatchBytesIterated(t *testing.T) { 1040 batch := newBatch(nil) 1041 for j := 0; j < 1000; j++ { 1042 key := make([]byte, 8+j%3) 1043 value := make([]byte, 7+j%5) 1044 batch.Set(key, value, nil) 1045 1046 fb := newFlushableBatch(batch, DefaultComparer) 1047 1048 var bytesIterated uint64 1049 it := fb.newFlushIter(nil, &bytesIterated) 1050 1051 var prevIterated uint64 1052 for key, _ := it.First(); key != nil; key, _ = it.Next() { 1053 if bytesIterated < prevIterated { 1054 t.Fatalf("bytesIterated moved backward: %d < %d", bytesIterated, prevIterated) 1055 } 1056 prevIterated = bytesIterated 1057 } 1058 1059 expected := fb.inuseBytes() 1060 if bytesIterated != expected { 1061 t.Fatalf("bytesIterated: got %d, want %d", bytesIterated, expected) 1062 } 1063 } 1064 } 1065 1066 func TestEmptyFlushableBatch(t *testing.T) { 1067 // Verify that we can create a flushable batch on an empty batch. 1068 fb := newFlushableBatch(newBatch(nil), DefaultComparer) 1069 it := newInternalIterAdapter(fb.newIter(nil)) 1070 require.False(t, it.First()) 1071 } 1072 1073 func BenchmarkBatchSet(b *testing.B) { 1074 value := make([]byte, 10) 1075 for i := range value { 1076 value[i] = byte(i) 1077 } 1078 key := make([]byte, 8) 1079 batch := newBatch(nil) 1080 1081 b.ResetTimer() 1082 1083 const batchSize = 1000 1084 for i := 0; i < b.N; i += batchSize { 1085 end := i + batchSize 1086 if end > b.N { 1087 end = b.N 1088 } 1089 1090 for j := i; j < end; j++ { 1091 binary.BigEndian.PutUint64(key, uint64(j)) 1092 batch.Set(key, value, nil) 1093 } 1094 batch.Reset() 1095 } 1096 1097 b.StopTimer() 1098 } 1099 1100 func BenchmarkIndexedBatchSet(b *testing.B) { 1101 value := make([]byte, 10) 1102 for i := range value { 1103 value[i] = byte(i) 1104 } 1105 key := make([]byte, 8) 1106 batch := newIndexedBatch(nil, DefaultComparer) 1107 1108 b.ResetTimer() 1109 1110 const batchSize = 1000 1111 for i := 0; i < b.N; i += batchSize { 1112 end := i + batchSize 1113 if end > b.N { 1114 end = b.N 1115 } 1116 1117 for j := i; j < end; j++ { 1118 binary.BigEndian.PutUint64(key, uint64(j)) 1119 batch.Set(key, value, nil) 1120 } 1121 batch.Reset() 1122 } 1123 1124 b.StopTimer() 1125 } 1126 1127 func BenchmarkBatchSetDeferred(b *testing.B) { 1128 value := make([]byte, 10) 1129 for i := range value { 1130 value[i] = byte(i) 1131 } 1132 key := make([]byte, 8) 1133 batch := newBatch(nil) 1134 1135 b.ResetTimer() 1136 1137 const batchSize = 1000 1138 for i := 0; i < b.N; i += batchSize { 1139 end := i + batchSize 1140 if end > b.N { 1141 end = b.N 1142 } 1143 1144 for j := i; j < end; j++ { 1145 binary.BigEndian.PutUint64(key, uint64(j)) 1146 deferredOp := batch.SetDeferred(len(key), len(value)) 1147 1148 copy(deferredOp.Key, key) 1149 copy(deferredOp.Value, value) 1150 1151 deferredOp.Finish() 1152 } 1153 batch.Reset() 1154 } 1155 1156 b.StopTimer() 1157 } 1158 1159 func BenchmarkIndexedBatchSetDeferred(b *testing.B) { 1160 value := make([]byte, 10) 1161 for i := range value { 1162 value[i] = byte(i) 1163 } 1164 key := make([]byte, 8) 1165 batch := newIndexedBatch(nil, DefaultComparer) 1166 1167 b.ResetTimer() 1168 1169 const batchSize = 1000 1170 for i := 0; i < b.N; i += batchSize { 1171 end := i + batchSize 1172 if end > b.N { 1173 end = b.N 1174 } 1175 1176 for j := i; j < end; j++ { 1177 binary.BigEndian.PutUint64(key, uint64(j)) 1178 deferredOp := batch.SetDeferred(len(key), len(value)) 1179 1180 copy(deferredOp.Key, key) 1181 copy(deferredOp.Value, value) 1182 1183 deferredOp.Finish() 1184 } 1185 batch.Reset() 1186 } 1187 1188 b.StopTimer() 1189 } 1190 1191 func TestBatchMemTableSizeOverflow(t *testing.T) { 1192 opts := &Options{ 1193 FS: vfs.NewMem(), 1194 } 1195 opts.EnsureDefaults() 1196 d, err := Open("", opts) 1197 require.NoError(t, err) 1198 1199 bigValue := make([]byte, 1000) 1200 b := d.NewBatch() 1201 1202 // memTableSize can overflow as a uint32. 1203 b.memTableSize = math.MaxUint32 - 50 1204 for i := 0; i < 10; i++ { 1205 k := fmt.Sprintf("key-%05d", i) 1206 require.NoError(t, b.Set([]byte(k), bigValue, nil)) 1207 } 1208 require.Greater(t, b.memTableSize, uint64(math.MaxUint32)) 1209 require.NoError(t, b.Close()) 1210 require.NoError(t, d.Close()) 1211 } 1212 1213 // TestBatchSpanCaching stress tests the caching of keyspan.Spans for range 1214 // tombstones and range keys. 1215 func TestBatchSpanCaching(t *testing.T) { 1216 opts := &Options{ 1217 Comparer: testkeys.Comparer, 1218 FS: vfs.NewMem(), 1219 FormatMajorVersion: FormatNewest, 1220 } 1221 d, err := Open("", opts) 1222 require.NoError(t, err) 1223 defer d.Close() 1224 1225 ks := testkeys.Alpha(1) 1226 b := d.NewIndexedBatch() 1227 for i := 0; i < ks.Count(); i++ { 1228 k := testkeys.Key(ks, i) 1229 require.NoError(t, b.Set(k, k, nil)) 1230 } 1231 1232 seed := int64(time.Now().UnixNano()) 1233 t.Logf("seed = %d", seed) 1234 rng := rand.New(rand.NewSource(seed)) 1235 iters := make([][]*Iterator, ks.Count()) 1236 defer func() { 1237 for _, keyIters := range iters { 1238 for _, iter := range keyIters { 1239 _ = iter.Close() 1240 } 1241 } 1242 }() 1243 1244 // This test begins with one point key for every letter of the alphabet. 1245 // Over the course of the test, point keys are 'replaced' with range keys 1246 // with narrow bounds from left to right. Iterators are created at random, 1247 // sometimes from the batch and sometimes by cloning existing iterators. 1248 1249 checkIter := func(iter *Iterator, nextKey int) { 1250 var i int 1251 for valid := iter.First(); valid; valid = iter.Next() { 1252 hasPoint, hasRange := iter.HasPointAndRange() 1253 require.Equal(t, testkeys.Key(ks, i), iter.Key()) 1254 if i < nextKey { 1255 // This key should not exist as a point key, just a range key. 1256 require.False(t, hasPoint) 1257 require.True(t, hasRange) 1258 } else { 1259 require.True(t, hasPoint) 1260 require.False(t, hasRange) 1261 } 1262 i++ 1263 } 1264 require.Equal(t, ks.Count(), i) 1265 } 1266 1267 // Each iteration of the below loop either reads or writes. 1268 // 1269 // A write iteration writes a new RANGEDEL and RANGEKEYSET into the batch, 1270 // covering a single point key seeded above. Writing these two span keys 1271 // together 'replaces' the point key with a range key. Each write iteration 1272 // ratchets nextWriteKey so the next write iteration will write the next 1273 // key. 1274 // 1275 // A read iteration creates a new iterator and ensures its state is 1276 // expected: some prefix of only point keys, followed by a suffix of only 1277 // range keys. Iterators created through Clone should observe the point keys 1278 // that existed when the cloned iterator was created. 1279 for nextWriteKey := 0; nextWriteKey < ks.Count(); { 1280 p := rng.Float64() 1281 switch { 1282 case p < .10: /* 10 % */ 1283 // Write a new range deletion and range key. 1284 start := testkeys.Key(ks, nextWriteKey) 1285 end := append(start, 0x00) 1286 require.NoError(t, b.DeleteRange(start, end, nil)) 1287 require.NoError(t, b.RangeKeySet(start, end, nil, []byte("foo"), nil)) 1288 nextWriteKey++ 1289 case p < .55: /* 45 % */ 1290 // Create a new iterator directly from the batch and check that it 1291 // observes the correct state. 1292 iter := b.NewIter(&IterOptions{KeyTypes: IterKeyTypePointsAndRanges}) 1293 checkIter(iter, nextWriteKey) 1294 iters[nextWriteKey] = append(iters[nextWriteKey], iter) 1295 default: /* 45 % */ 1296 // Create a new iterator through cloning a random existing iterator 1297 // and check that it observes the right state. 1298 readKey := rng.Intn(nextWriteKey + 1) 1299 itersForReadKey := iters[readKey] 1300 if len(itersForReadKey) == 0 { 1301 continue 1302 } 1303 iter, err := itersForReadKey[rng.Intn(len(itersForReadKey))].Clone(CloneOptions{}) 1304 require.NoError(t, err) 1305 checkIter(iter, readKey) 1306 iters[readKey] = append(iters[readKey], iter) 1307 } 1308 } 1309 }