github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/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 pebble 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "strconv" 12 "strings" 13 "testing" 14 15 "github.com/petermattis/pebble/internal/base" 16 "github.com/petermattis/pebble/internal/datadriven" 17 "github.com/petermattis/pebble/vfs" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestBatch(t *testing.T) { 22 type testCase struct { 23 kind InternalKeyKind 24 key, value string 25 } 26 27 verifyTestCases := func(b *Batch, testCases []testCase) { 28 r := b.Reader() 29 30 for _, tc := range testCases { 31 kind, k, v, ok := r.Next() 32 if !ok { 33 t.Fatalf("next returned !ok: test case = %v", tc) 34 } 35 key, value := string(k), string(v) 36 if kind != tc.kind || key != tc.key || value != tc.value { 37 t.Errorf("got (%d, %q, %q), want (%d, %q, %q)", 38 kind, key, value, tc.kind, tc.key, tc.value) 39 } 40 } 41 if len(r) != 0 { 42 t.Errorf("reader was not exhausted: remaining bytes = %q", r) 43 } 44 } 45 46 testCases := []testCase{ 47 {InternalKeyKindSet, "roses", "red"}, 48 {InternalKeyKindSet, "violets", "blue"}, 49 {InternalKeyKindDelete, "roses", ""}, 50 {InternalKeyKindSet, "", ""}, 51 {InternalKeyKindSet, "", "non-empty"}, 52 {InternalKeyKindDelete, "", ""}, 53 {InternalKeyKindSet, "grass", "green"}, 54 {InternalKeyKindSet, "grass", "greener"}, 55 {InternalKeyKindSet, "eleventy", strings.Repeat("!!11!", 100)}, 56 {InternalKeyKindDelete, "nosuchkey", ""}, 57 {InternalKeyKindSet, "binarydata", "\x00"}, 58 {InternalKeyKindSet, "binarydata", "\xff"}, 59 {InternalKeyKindMerge, "merge", "mergedata"}, 60 {InternalKeyKindMerge, "merge", ""}, 61 {InternalKeyKindMerge, "", ""}, 62 {InternalKeyKindRangeDelete, "a", "b"}, 63 {InternalKeyKindRangeDelete, "", ""}, 64 {InternalKeyKindLogData, "logdata", ""}, 65 {InternalKeyKindLogData, "", ""}, 66 } 67 var b Batch 68 for _, tc := range testCases { 69 switch tc.kind { 70 case InternalKeyKindSet: 71 _ = b.Set([]byte(tc.key), []byte(tc.value), nil) 72 case InternalKeyKindMerge: 73 _ = b.Merge([]byte(tc.key), []byte(tc.value), nil) 74 case InternalKeyKindDelete: 75 _ = b.Delete([]byte(tc.key), nil) 76 case InternalKeyKindRangeDelete: 77 _ = b.DeleteRange([]byte(tc.key), []byte(tc.value), nil) 78 case InternalKeyKindLogData: 79 _ = b.LogData([]byte(tc.key), nil) 80 } 81 } 82 verifyTestCases(&b, testCases) 83 84 b.Reset() 85 // Run the same operations, this time using the Deferred variants of each 86 // operation (eg. SetDeferred). 87 for _, tc := range testCases { 88 key := []byte(tc.key) 89 value := []byte(tc.value) 90 switch tc.kind { 91 case InternalKeyKindSet: 92 d, _ := b.SetDeferred(len(key), len(value), nil) 93 copy(d.Key, key) 94 copy(d.Value, value) 95 d.Finish() 96 case InternalKeyKindMerge: 97 d, _ := b.MergeDeferred(len(key), len(value), nil) 98 copy(d.Key, key) 99 copy(d.Value, value) 100 d.Finish() 101 case InternalKeyKindDelete: 102 d, _ := b.DeleteDeferred(len(key), nil) 103 copy(d.Key, key) 104 copy(d.Value, value) 105 d.Finish() 106 case InternalKeyKindRangeDelete: 107 d, _ := b.DeleteRangeDeferred(len(key), len(value), nil) 108 copy(d.Key, key) 109 copy(d.Value, value) 110 d.Finish() 111 case InternalKeyKindLogData: 112 _ = b.LogData([]byte(tc.key), nil) 113 } 114 } 115 verifyTestCases(&b, testCases) 116 } 117 118 func TestBatchEmpty(t *testing.T) { 119 var b Batch 120 require.True(t, b.Empty()) 121 122 b.Set(nil, nil, nil) 123 require.False(t, b.Empty()) 124 b.Reset() 125 require.True(t, b.Empty()) 126 127 b.Merge(nil, nil, nil) 128 require.False(t, b.Empty()) 129 b.Reset() 130 require.True(t, b.Empty()) 131 132 b.Delete(nil, nil) 133 require.False(t, b.Empty()) 134 b.Reset() 135 require.True(t, b.Empty()) 136 137 b.DeleteRange(nil, nil, nil) 138 require.False(t, b.Empty()) 139 b.Reset() 140 require.True(t, b.Empty()) 141 142 b.LogData(nil, nil) 143 require.False(t, b.Empty()) 144 b.Reset() 145 require.True(t, b.Empty()) 146 } 147 148 func TestBatchIncrement(t *testing.T) { 149 testCases := []uint32{ 150 0x00000000, 151 0x00000001, 152 0x00000002, 153 0x0000007f, 154 0x00000080, 155 0x000000fe, 156 0x000000ff, 157 0x00000100, 158 0x00000101, 159 0x000001ff, 160 0x00000200, 161 0x00000fff, 162 0x00001234, 163 0x0000fffe, 164 0x0000ffff, 165 0x00010000, 166 0x00010001, 167 0x000100fe, 168 0x000100ff, 169 0x00020100, 170 0x03fffffe, 171 0x03ffffff, 172 0x04000000, 173 0x04000001, 174 0x7fffffff, 175 0xfffffffe, 176 0xffffffff, 177 } 178 for _, tc := range testCases { 179 var buf [batchHeaderLen]byte 180 binary.LittleEndian.PutUint32(buf[8:12], tc) 181 var b Batch 182 b.SetRepr(buf[:]) 183 b.increment() 184 got := binary.LittleEndian.Uint32(b.Repr()[8:12]) 185 want := tc + 1 186 if tc == 0xffffffff { 187 want = tc 188 } 189 if got != want { 190 t.Errorf("input=%d: got %d, want %d", tc, got, want) 191 } 192 } 193 } 194 195 func TestBatchOpDoesIncrement(t *testing.T) { 196 var b Batch 197 key := []byte("foo") 198 value := []byte("bar") 199 200 if b.Count() != 0 { 201 t.Fatalf("new batch has a nonzero count: %d", b.Count()) 202 } 203 204 // Should increment count by 1 205 _ = b.Set(key, value, nil) 206 if b.Count() != 1 { 207 t.Fatalf("expected count: %d, got %d", 1, b.Count()) 208 } 209 210 var b2 Batch 211 // Should increment count by 1 each 212 _ = b2.Set(key, value, nil) 213 _ = b2.Delete(key, nil) 214 if b2.Count() != 2 { 215 t.Fatalf("expected count: %d, got %d", 2, b2.Count()) 216 } 217 218 // Should increment count by b2.count() 219 _ = b.Apply(&b2, nil) 220 if b.Count() != 3 { 221 t.Fatalf("expected count: %d, got %d", 3, b.Count()) 222 } 223 224 // Should increment count by 1 225 _ = b.Merge(key, value, nil) 226 if b.Count() != 4 { 227 t.Fatalf("expected count: %d, got %d", 4, b.Count()) 228 } 229 230 // Should NOT increment count. 231 _ = b.LogData([]byte("foobarbaz"), nil) 232 if b.Count() != 4 { 233 t.Fatalf("expected count: %d, got %d", 4, b.Count()) 234 } 235 } 236 237 func TestBatchGet(t *testing.T) { 238 for _, method := range []string{"build", "apply"} { 239 t.Run(method, func(t *testing.T) { 240 d, err := Open("", &Options{ 241 FS: vfs.NewMem(), 242 }) 243 if err != nil { 244 t.Fatalf("Open: %v", err) 245 } 246 defer d.Close() 247 var b *Batch 248 249 datadriven.RunTest(t, "testdata/batch_get", func(td *datadriven.TestData) string { 250 switch td.Cmd { 251 case "define": 252 switch method { 253 case "build": 254 b = d.NewIndexedBatch() 255 case "apply": 256 b = d.NewBatch() 257 } 258 259 if err := runBatchDefineCmd(td, b); err != nil { 260 return err.Error() 261 } 262 263 switch method { 264 case "apply": 265 tmp := d.NewIndexedBatch() 266 tmp.Apply(b, nil) 267 b = tmp 268 } 269 return "" 270 271 case "commit": 272 if err := b.Commit(nil); err != nil { 273 return err.Error() 274 } 275 return "" 276 277 case "get": 278 if len(td.CmdArgs) != 1 { 279 return fmt.Sprintf("%s expects 1 argument", td.Cmd) 280 } 281 v, err := b.Get([]byte(td.CmdArgs[0].String())) 282 if err != nil { 283 return err.Error() 284 } 285 return string(v) 286 287 default: 288 return fmt.Sprintf("unknown command: %s", td.Cmd) 289 } 290 }) 291 }) 292 } 293 } 294 295 func TestBatchIter(t *testing.T) { 296 var b *Batch 297 298 for _, method := range []string{"build", "apply"} { 299 t.Run(method, func(t *testing.T) { 300 datadriven.RunTest(t, "testdata/internal_iter_next", func(d *datadriven.TestData) string { 301 switch d.Cmd { 302 case "define": 303 switch method { 304 case "build": 305 b = newIndexedBatch(nil, DefaultComparer) 306 case "apply": 307 b = newBatch(nil) 308 } 309 310 for _, key := range strings.Split(d.Input, "\n") { 311 j := strings.Index(key, ":") 312 ikey := base.ParseInternalKey(key[:j]) 313 value := []byte(fmt.Sprint(ikey.SeqNum())) 314 b.Set(ikey.UserKey, value, nil) 315 } 316 317 switch method { 318 case "apply": 319 tmp := newIndexedBatch(nil, DefaultComparer) 320 tmp.Apply(b, nil) 321 b = tmp 322 } 323 return "" 324 325 case "iter": 326 iter := b.newInternalIter(nil) 327 defer iter.Close() 328 return runInternalIterCmd(d, iter) 329 330 default: 331 return fmt.Sprintf("unknown command: %s", d.Cmd) 332 } 333 }) 334 }) 335 } 336 } 337 338 func TestBatchDeleteRange(t *testing.T) { 339 var b *Batch 340 341 datadriven.RunTest(t, "testdata/batch_delete_range", func(td *datadriven.TestData) string { 342 switch td.Cmd { 343 case "clear": 344 b = nil 345 return "" 346 347 case "define": 348 if b == nil { 349 b = newIndexedBatch(nil, DefaultComparer) 350 } 351 if err := runBatchDefineCmd(td, b); err != nil { 352 return err.Error() 353 } 354 return "" 355 356 case "scan": 357 var iter internalIterAdapter 358 if len(td.CmdArgs) > 1 { 359 return fmt.Sprintf("%s expects at most 1 argument", td.Cmd) 360 } 361 if len(td.CmdArgs) == 1 { 362 if td.CmdArgs[0].String() != "range-del" { 363 return fmt.Sprintf("%s unknown argument %s", td.Cmd, td.CmdArgs[0]) 364 } 365 iter.internalIterator = b.newRangeDelIter(nil) 366 } else { 367 iter.internalIterator = b.newInternalIter(nil) 368 } 369 defer iter.Close() 370 371 var buf bytes.Buffer 372 for valid := iter.First(); valid; valid = iter.Next() { 373 key := iter.Key() 374 key.SetSeqNum(key.SeqNum() &^ InternalKeySeqNumBatch) 375 fmt.Fprintf(&buf, "%s:%s\n", key, iter.Value()) 376 } 377 return buf.String() 378 379 default: 380 return fmt.Sprintf("unknown command: %s", td.Cmd) 381 } 382 }) 383 } 384 385 func TestFlushableBatchIter(t *testing.T) { 386 var b *flushableBatch 387 datadriven.RunTest(t, "testdata/internal_iter_next", func(d *datadriven.TestData) string { 388 switch d.Cmd { 389 case "define": 390 batch := newBatch(nil) 391 for _, key := range strings.Split(d.Input, "\n") { 392 j := strings.Index(key, ":") 393 ikey := base.ParseInternalKey(key[:j]) 394 value := []byte(fmt.Sprint(ikey.SeqNum())) 395 batch.Set(ikey.UserKey, value, nil) 396 } 397 b = newFlushableBatch(batch, DefaultComparer) 398 return "" 399 400 case "iter": 401 iter := b.newIter(nil) 402 defer iter.Close() 403 return runInternalIterCmd(d, iter) 404 405 default: 406 return fmt.Sprintf("unknown command: %s", d.Cmd) 407 } 408 }) 409 } 410 411 func TestFlushableBatch(t *testing.T) { 412 var b *flushableBatch 413 datadriven.RunTest(t, "testdata/flushable_batch", func(d *datadriven.TestData) string { 414 switch d.Cmd { 415 case "define": 416 batch := newBatch(nil) 417 for _, key := range strings.Split(d.Input, "\n") { 418 j := strings.Index(key, ":") 419 ikey := base.ParseInternalKey(key[:j]) 420 value := []byte(fmt.Sprint(ikey.SeqNum())) 421 switch ikey.Kind() { 422 case InternalKeyKindDelete: 423 batch.Delete(ikey.UserKey, nil) 424 case InternalKeyKindSet: 425 batch.Set(ikey.UserKey, value, nil) 426 case InternalKeyKindMerge: 427 batch.Merge(ikey.UserKey, value, nil) 428 } 429 } 430 b = newFlushableBatch(batch, DefaultComparer) 431 return "" 432 433 case "iter": 434 var opts IterOptions 435 for _, arg := range d.CmdArgs { 436 if len(arg.Vals) != 1 { 437 return fmt.Sprintf("%s: %s=<value>", d.Cmd, arg.Key) 438 } 439 switch arg.Key { 440 case "lower": 441 opts.LowerBound = []byte(arg.Vals[0]) 442 case "upper": 443 opts.UpperBound = []byte(arg.Vals[0]) 444 default: 445 return fmt.Sprintf("%s: unknown arg: %s", d.Cmd, arg.Key) 446 } 447 } 448 449 iter := b.newIter(&opts) 450 defer iter.Close() 451 return runInternalIterCmd(d, iter) 452 453 case "dump": 454 if len(d.CmdArgs) != 1 || len(d.CmdArgs[0].Vals) != 1 || d.CmdArgs[0].Key != "seq" { 455 return fmt.Sprintf("dump seq=<value>\n") 456 } 457 seqNum, err := strconv.Atoi(d.CmdArgs[0].Vals[0]) 458 if err != nil { 459 return err.Error() 460 } 461 b.seqNum = uint64(seqNum) 462 463 iter := internalIterAdapter{b.newIter(nil)} 464 var buf bytes.Buffer 465 for valid := iter.First(); valid; valid = iter.Next() { 466 fmt.Fprintf(&buf, "%s:%s\n", iter.Key(), iter.Value()) 467 } 468 iter.Close() 469 return buf.String() 470 471 default: 472 return fmt.Sprintf("unknown command: %s", d.Cmd) 473 } 474 }) 475 } 476 477 func TestFlushableBatchDeleteRange(t *testing.T) { 478 var fb *flushableBatch 479 var input string 480 481 datadriven.RunTest(t, "testdata/delete_range", func(td *datadriven.TestData) string { 482 switch td.Cmd { 483 case "clear": 484 input = "" 485 return "" 486 487 case "define": 488 b := newBatch(nil) 489 // NB: We can't actually add to the flushable batch as we can to a 490 // memtable (which shares the "testdata/delete_range" data), so we fake 491 // it be concatenating the input and rebuilding the flushable batch from 492 // scratch. 493 input += "\n" + td.Input 494 td.Input = input 495 if err := runBatchDefineCmd(td, b); err != nil { 496 return err.Error() 497 } 498 fb = newFlushableBatch(b, DefaultComparer) 499 return "" 500 501 case "scan": 502 var iter internalIterAdapter 503 if len(td.CmdArgs) > 1 { 504 return fmt.Sprintf("%s expects at most 1 argument", td.Cmd) 505 } 506 if len(td.CmdArgs) == 1 { 507 if td.CmdArgs[0].String() != "range-del" { 508 return fmt.Sprintf("%s unknown argument %s", td.Cmd, td.CmdArgs[0]) 509 } 510 iter.internalIterator = fb.newRangeDelIter(nil) 511 } else { 512 iter.internalIterator = fb.newIter(nil) 513 } 514 defer iter.Close() 515 516 var buf bytes.Buffer 517 for valid := iter.First(); valid; valid = iter.Next() { 518 fmt.Fprintf(&buf, "%s:%s\n", iter.Key(), iter.Value()) 519 } 520 return buf.String() 521 522 default: 523 return fmt.Sprintf("unknown command: %s", td.Cmd) 524 } 525 }) 526 } 527 528 func TestFlushableBatchBytesIterated(t *testing.T) { 529 batch := newBatch(nil) 530 for j := 0; j < 1000; j++ { 531 key := make([]byte, 8+j%3) 532 value := make([]byte, 7+j%5) 533 batch.Set(key, value, nil) 534 535 fb := newFlushableBatch(batch, DefaultComparer) 536 537 var bytesIterated uint64 538 it := fb.newFlushIter(nil, &bytesIterated) 539 540 var prevIterated uint64 541 for it.First(); it.Valid(); it.Next() { 542 if bytesIterated < prevIterated { 543 t.Fatalf("bytesIterated moved backward: %d < %d", bytesIterated, prevIterated) 544 } 545 prevIterated = bytesIterated 546 } 547 548 expected := fb.totalBytes() 549 if bytesIterated != expected { 550 t.Fatalf("bytesIterated: got %d, want %d", bytesIterated, expected) 551 } 552 } 553 } 554 555 func BenchmarkBatchSet(b *testing.B) { 556 value := make([]byte, 10) 557 for i := range value { 558 value[i] = byte(i) 559 } 560 key := make([]byte, 8) 561 batch := newBatch(nil) 562 563 b.ResetTimer() 564 565 const batchSize = 1000 566 for i := 0; i < b.N; i += batchSize { 567 end := i + batchSize 568 if end > b.N { 569 end = b.N 570 } 571 572 for j := i; j < end; j++ { 573 binary.BigEndian.PutUint64(key, uint64(j)) 574 batch.Set(key, value, nil) 575 } 576 batch.Reset() 577 } 578 579 b.StopTimer() 580 } 581 582 func BenchmarkIndexedBatchSet(b *testing.B) { 583 value := make([]byte, 10) 584 for i := range value { 585 value[i] = byte(i) 586 } 587 key := make([]byte, 8) 588 batch := newIndexedBatch(nil, DefaultComparer) 589 590 b.ResetTimer() 591 592 const batchSize = 1000 593 for i := 0; i < b.N; i += batchSize { 594 end := i + batchSize 595 if end > b.N { 596 end = b.N 597 } 598 599 for j := i; j < end; j++ { 600 binary.BigEndian.PutUint64(key, uint64(j)) 601 batch.Set(key, value, nil) 602 } 603 batch.Reset() 604 } 605 606 b.StopTimer() 607 } 608 609 func BenchmarkBatchSetDeferred(b *testing.B) { 610 value := make([]byte, 10) 611 for i := range value { 612 value[i] = byte(i) 613 } 614 key := make([]byte, 8) 615 batch := newBatch(nil) 616 617 b.ResetTimer() 618 619 const batchSize = 1000 620 for i := 0; i < b.N; i += batchSize { 621 end := i + batchSize 622 if end > b.N { 623 end = b.N 624 } 625 626 for j := i; j < end; j++ { 627 binary.BigEndian.PutUint64(key, uint64(j)) 628 deferredOp, err := batch.SetDeferred(len(key), len(value), nil) 629 if err != nil { 630 b.Fatal(err) 631 } 632 633 copy(deferredOp.Key, key) 634 copy(deferredOp.Value, value) 635 636 deferredOp.Finish() 637 } 638 batch.Reset() 639 } 640 641 b.StopTimer() 642 } 643 644 func BenchmarkIndexedBatchSetDeferred(b *testing.B) { 645 value := make([]byte, 10) 646 for i := range value { 647 value[i] = byte(i) 648 } 649 key := make([]byte, 8) 650 batch := newIndexedBatch(nil, DefaultComparer) 651 652 b.ResetTimer() 653 654 const batchSize = 1000 655 for i := 0; i < b.N; i += batchSize { 656 end := i + batchSize 657 if end > b.N { 658 end = b.N 659 } 660 661 for j := i; j < end; j++ { 662 binary.BigEndian.PutUint64(key, uint64(j)) 663 deferredOp, err := batch.SetDeferred(len(key), len(value), nil) 664 if err != nil { 665 b.Fatal(err) 666 } 667 668 copy(deferredOp.Key, key) 669 copy(deferredOp.Value, value) 670 671 deferredOp.Finish() 672 } 673 batch.Reset() 674 } 675 676 b.StopTimer() 677 }