github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/storage/batch_test.go (about) 1 // Copyright 2014 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package storage 12 13 import ( 14 "bytes" 15 "context" 16 "fmt" 17 "reflect" 18 "sync/atomic" 19 "testing" 20 21 "github.com/cockroachdb/cockroach/pkg/roachpb" 22 "github.com/cockroachdb/cockroach/pkg/storage/enginepb" 23 "github.com/cockroachdb/cockroach/pkg/testutils" 24 "github.com/cockroachdb/cockroach/pkg/util/hlc" 25 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 26 "github.com/cockroachdb/cockroach/pkg/util/protoutil" 27 "github.com/cockroachdb/cockroach/pkg/util/randutil" 28 "github.com/cockroachdb/cockroach/pkg/util/stop" 29 "github.com/cockroachdb/errors" 30 "github.com/gogo/protobuf/proto" 31 "github.com/stretchr/testify/assert" 32 ) 33 34 func mvccKey(k interface{}) MVCCKey { 35 switch k := k.(type) { 36 case string: 37 return MakeMVCCMetadataKey(roachpb.Key(k)) 38 case []byte: 39 return MakeMVCCMetadataKey(roachpb.Key(k)) 40 case roachpb.Key: 41 return MakeMVCCMetadataKey(k) 42 case roachpb.RKey: 43 return MakeMVCCMetadataKey(roachpb.Key(k)) 44 default: 45 panic(fmt.Sprintf("unsupported type: %T", k)) 46 } 47 } 48 49 func testBatchBasics(t *testing.T, writeOnly bool, commit func(e Engine, b Batch) error) { 50 for _, engineImpl := range mvccEngineImpls { 51 t.Run(engineImpl.name, func(t *testing.T) { 52 e := engineImpl.create() 53 defer e.Close() 54 55 var b Batch 56 if writeOnly { 57 b = e.NewWriteOnlyBatch() 58 } else { 59 b = e.NewBatch() 60 } 61 defer b.Close() 62 63 if err := b.Put(mvccKey("a"), []byte("value")); err != nil { 64 t.Fatal(err) 65 } 66 // Write an engine value to be deleted. 67 if err := e.Put(mvccKey("b"), []byte("value")); err != nil { 68 t.Fatal(err) 69 } 70 if err := b.Clear(mvccKey("b")); err != nil { 71 t.Fatal(err) 72 } 73 // Write an engine value to be merged. 74 if err := e.Put(mvccKey("c"), appender("foo")); err != nil { 75 t.Fatal(err) 76 } 77 if err := b.Merge(mvccKey("c"), appender("bar")); err != nil { 78 t.Fatal(err) 79 } 80 // Write a key with an empty value. 81 if err := b.Put(mvccKey("e"), nil); err != nil { 82 t.Fatal(err) 83 } 84 // Write an engine value to be single deleted. 85 if err := e.Put(mvccKey("d"), []byte("before")); err != nil { 86 t.Fatal(err) 87 } 88 if err := b.SingleClear(mvccKey("d")); err != nil { 89 t.Fatal(err) 90 } 91 92 // Check all keys are in initial state (nothing from batch has gone 93 // through to engine until commit). 94 expValues := []MVCCKeyValue{ 95 {Key: mvccKey("b"), Value: []byte("value")}, 96 {Key: mvccKey("c"), Value: appender("foo")}, 97 {Key: mvccKey("d"), Value: []byte("before")}, 98 } 99 kvs, err := Scan(e, roachpb.KeyMin, roachpb.KeyMax, 0) 100 if err != nil { 101 t.Fatal(err) 102 } 103 if !reflect.DeepEqual(expValues, kvs) { 104 t.Fatalf("%v != %v", kvs, expValues) 105 } 106 107 // Now, merged values should be: 108 expValues = []MVCCKeyValue{ 109 {Key: mvccKey("a"), Value: []byte("value")}, 110 {Key: mvccKey("c"), Value: appender("foobar")}, 111 {Key: mvccKey("e"), Value: []byte{}}, 112 } 113 if !writeOnly { 114 // Scan values from batch directly. 115 kvs, err = Scan(b, roachpb.KeyMin, roachpb.KeyMax, 0) 116 if err != nil { 117 t.Fatal(err) 118 } 119 if !reflect.DeepEqual(expValues, kvs) { 120 t.Errorf("%v != %v", kvs, expValues) 121 } 122 } 123 124 // Commit batch and verify direct engine scan yields correct values. 125 if err := commit(e, b); err != nil { 126 t.Fatal(err) 127 } 128 kvs, err = Scan(e, roachpb.KeyMin, roachpb.KeyMax, 0) 129 if err != nil { 130 t.Fatal(err) 131 } 132 if !reflect.DeepEqual(expValues, kvs) { 133 t.Errorf("%v != %v", kvs, expValues) 134 } 135 }) 136 } 137 } 138 139 // TestBatchBasics verifies that all commands work in a batch, aren't 140 // visible until commit, and then are all visible after commit. 141 func TestBatchBasics(t *testing.T) { 142 defer leaktest.AfterTest(t)() 143 testBatchBasics(t, false /* writeOnly */, func(e Engine, b Batch) error { 144 return b.Commit(false /* sync */) 145 }) 146 } 147 148 func shouldPanic(t *testing.T, f func(), funcName string, expectedPanicStr string) { 149 defer func() { 150 if r := recover(); r == nil { 151 t.Fatalf("%v: test did not panic", funcName) 152 } else if r != expectedPanicStr { 153 t.Fatalf("%v: unexpected panic: %v", funcName, r) 154 } 155 }() 156 f() 157 } 158 159 func shouldNotPanic(t *testing.T, f func(), funcName string) { 160 defer func() { 161 if r := recover(); r != nil { 162 t.Fatalf("%v: unexpected panic: %v", funcName, r) 163 } 164 }() 165 f() 166 } 167 168 // TestReadOnlyBasics verifies that for a read-only ReadWriter (obtained via 169 // engine.NewReadOnly()) all Reader methods work, and all Writer methods panic 170 // as "not implemented". Also basic iterating functionality is verified. 171 func TestReadOnlyBasics(t *testing.T) { 172 defer leaktest.AfterTest(t)() 173 174 for _, engineImpl := range mvccEngineImpls { 175 t.Run(engineImpl.name, func(t *testing.T) { 176 e := engineImpl.create() 177 defer e.Close() 178 179 ro := e.NewReadOnly() 180 if ro.Closed() { 181 t.Fatal("read-only is expectedly found to be closed") 182 } 183 a := mvccKey("a") 184 getVal := &roachpb.Value{} 185 successTestCases := []func(){ 186 func() { _, _ = ro.Get(a) }, 187 func() { _, _, _, _ = ro.GetProto(a, getVal) }, 188 func() { _ = ro.Iterate(a.Key, a.Key, func(MVCCKeyValue) (bool, error) { return true, nil }) }, 189 func() { ro.NewIterator(IterOptions{UpperBound: roachpb.KeyMax}).Close() }, 190 func() { 191 ro.NewIterator(IterOptions{ 192 MinTimestampHint: hlc.MinTimestamp, 193 MaxTimestampHint: hlc.MaxTimestamp, 194 UpperBound: roachpb.KeyMax, 195 }).Close() 196 }, 197 } 198 defer func() { 199 ro.Close() 200 if !ro.Closed() { 201 t.Fatal("even after calling Close, a read-only should not be closed") 202 } 203 name := "rocksDBReadOnly" 204 if engineImpl.name == "pebble" { 205 name = "pebbleReadOnly" 206 } 207 shouldPanic(t, func() { ro.Close() }, "Close", "closing an already-closed "+name) 208 for i, f := range successTestCases { 209 shouldPanic(t, f, string(i), "using a closed "+name) 210 } 211 }() 212 213 for i, f := range successTestCases { 214 shouldNotPanic(t, f, string(i)) 215 } 216 217 // For a read-only ReadWriter, all Writer methods should panic. 218 failureTestCases := []func(){ 219 func() { _ = ro.ApplyBatchRepr(nil, false) }, 220 func() { _ = ro.Clear(a) }, 221 func() { _ = ro.SingleClear(a) }, 222 func() { _ = ro.ClearRange(a, a) }, 223 func() { _ = ro.Merge(a, nil) }, 224 func() { _ = ro.Put(a, nil) }, 225 } 226 for i, f := range failureTestCases { 227 shouldPanic(t, f, string(i), "not implemented") 228 } 229 230 if err := e.Put(mvccKey("a"), []byte("value")); err != nil { 231 t.Fatal(err) 232 } 233 if err := e.Put(mvccKey("b"), []byte("value")); err != nil { 234 t.Fatal(err) 235 } 236 if err := e.Clear(mvccKey("b")); err != nil { 237 t.Fatal(err) 238 } 239 if err := e.Put(mvccKey("c"), appender("foo")); err != nil { 240 t.Fatal(err) 241 } 242 if err := e.Merge(mvccKey("c"), appender("bar")); err != nil { 243 t.Fatal(err) 244 } 245 if err := e.Put(mvccKey("d"), []byte("value")); err != nil { 246 t.Fatal(err) 247 } 248 if err := e.SingleClear(mvccKey("d")); err != nil { 249 t.Fatal(err) 250 } 251 252 // Now, merged values should be: 253 expValues := []MVCCKeyValue{ 254 {Key: mvccKey("a"), Value: []byte("value")}, 255 {Key: mvccKey("c"), Value: appender("foobar")}, 256 } 257 258 kvs, err := Scan(e, roachpb.KeyMin, roachpb.KeyMax, 0) 259 if err != nil { 260 t.Fatal(err) 261 } 262 if !reflect.DeepEqual(expValues, kvs) { 263 t.Errorf("%v != %v", kvs, expValues) 264 } 265 }) 266 } 267 } 268 269 func TestBatchRepr(t *testing.T) { 270 defer leaktest.AfterTest(t)() 271 testBatchBasics(t, false /* writeOnly */, func(e Engine, b Batch) error { 272 repr := b.Repr() 273 274 r, err := NewRocksDBBatchReader(repr) 275 if err != nil { 276 t.Fatalf("%+v", err) 277 } 278 const expectedCount = 5 279 if count := r.Count(); count != expectedCount { 280 t.Fatalf("bad count: RocksDBBatchReader.Count expected %d, but found %d", expectedCount, count) 281 } 282 if count, err := RocksDBBatchCount(repr); err != nil { 283 t.Fatal(err) 284 } else if count != expectedCount { 285 t.Fatalf("bad count: RocksDBBatchCount expected %d, but found %d", expectedCount, count) 286 } 287 288 var ops []string 289 for i := 0; i < r.Count(); i++ { 290 if ok := r.Next(); !ok { 291 t.Fatalf("%d: unexpected end of batch", i) 292 } 293 switch r.BatchType() { 294 case BatchTypeDeletion: 295 ops = append(ops, fmt.Sprintf("delete(%s)", string(r.Key()))) 296 case BatchTypeValue: 297 ops = append(ops, fmt.Sprintf("put(%s,%s)", string(r.Key()), string(r.Value()))) 298 case BatchTypeMerge: 299 // The merge value is a protobuf and not easily displayable. 300 ops = append(ops, fmt.Sprintf("merge(%s)", string(r.Key()))) 301 case BatchTypeSingleDeletion: 302 ops = append(ops, fmt.Sprintf("single_delete(%s)", string(r.Key()))) 303 } 304 } 305 if err != nil { 306 t.Fatalf("unexpected err during iteration: %+v", err) 307 } 308 if ok := r.Next(); ok { 309 t.Errorf("expected end of batch") 310 } 311 312 // The keys in the batch have the internal MVCC encoding applied which for 313 // this test implies an appended 0 byte. 314 expOps := []string{ 315 "put(a\x00,value)", 316 "delete(b\x00)", 317 "merge(c\x00)", 318 "put(e\x00,)", 319 "single_delete(d\x00)", 320 } 321 if !reflect.DeepEqual(expOps, ops) { 322 t.Fatalf("expected %v, but found %v", expOps, ops) 323 } 324 325 return e.ApplyBatchRepr(repr, false /* sync */) 326 }) 327 } 328 329 func TestWriteBatchBasics(t *testing.T) { 330 defer leaktest.AfterTest(t)() 331 testBatchBasics(t, true /* writeOnly */, func(e Engine, b Batch) error { 332 return b.Commit(false /* sync */) 333 }) 334 } 335 336 // Regression test for flush issue which caused 337 // b2.ApplyBatchRepr(b1.Repr()).Repr() to not equal a noop. 338 func TestApplyBatchRepr(t *testing.T) { 339 defer leaktest.AfterTest(t)() 340 341 for _, engineImpl := range mvccEngineImpls { 342 t.Run(engineImpl.name, func(t *testing.T) { 343 e := engineImpl.create() 344 defer e.Close() 345 346 // Failure to represent the absorbed Batch again. 347 { 348 b1 := e.NewBatch() 349 defer b1.Close() 350 351 if err := b1.Put(mvccKey("lost"), []byte("update")); err != nil { 352 t.Fatal(err) 353 } 354 355 repr1 := b1.Repr() 356 357 b2 := e.NewBatch() 358 defer b2.Close() 359 if err := b2.ApplyBatchRepr(repr1, false /* sync */); err != nil { 360 t.Fatal(err) 361 } 362 repr2 := b2.Repr() 363 364 if !reflect.DeepEqual(repr1, repr2) { 365 t.Fatalf("old batch represents to:\n%q\nrestored batch to:\n%q", repr1, repr2) 366 } 367 } 368 369 // Failure to commit what was absorbed. 370 { 371 b3 := e.NewBatch() 372 defer b3.Close() 373 374 key := mvccKey("phantom") 375 val := []byte("phantom") 376 377 if err := b3.Put(key, val); err != nil { 378 t.Fatal(err) 379 } 380 381 repr := b3.Repr() 382 383 b4 := e.NewBatch() 384 defer b4.Close() 385 if err := b4.ApplyBatchRepr(repr, false /* sync */); err != nil { 386 t.Fatal(err) 387 } 388 // Intentionally don't call Repr() because the expected user wouldn't. 389 if err := b4.Commit(false /* sync */); err != nil { 390 t.Fatal(err) 391 } 392 393 if b, err := e.Get(key); err != nil { 394 t.Fatal(err) 395 } else if !reflect.DeepEqual(b, val) { 396 t.Fatalf("read %q from engine, expected %q", b, val) 397 } 398 } 399 }) 400 } 401 } 402 403 func TestBatchGet(t *testing.T) { 404 defer leaktest.AfterTest(t)() 405 406 for _, engineImpl := range mvccEngineImpls { 407 t.Run(engineImpl.name, func(t *testing.T) { 408 e := engineImpl.create() 409 defer e.Close() 410 411 b := e.NewBatch() 412 defer b.Close() 413 414 // Write initial values, then write to batch. 415 if err := e.Put(mvccKey("b"), []byte("value")); err != nil { 416 t.Fatal(err) 417 } 418 if err := e.Put(mvccKey("c"), appender("foo")); err != nil { 419 t.Fatal(err) 420 } 421 // Write batch values. 422 if err := b.Put(mvccKey("a"), []byte("value")); err != nil { 423 t.Fatal(err) 424 } 425 if err := b.Clear(mvccKey("b")); err != nil { 426 t.Fatal(err) 427 } 428 if err := b.Merge(mvccKey("c"), appender("bar")); err != nil { 429 t.Fatal(err) 430 } 431 if err := b.Put(mvccKey("d"), []byte("before")); err != nil { 432 t.Fatal(err) 433 } 434 if err := b.SingleClear(mvccKey("d")); err != nil { 435 t.Fatal(err) 436 } 437 if err := b.Put(mvccKey("d"), []byte("after")); err != nil { 438 t.Fatal(err) 439 } 440 441 expValues := []MVCCKeyValue{ 442 {Key: mvccKey("a"), Value: []byte("value")}, 443 {Key: mvccKey("b"), Value: nil}, 444 {Key: mvccKey("c"), Value: appender("foobar")}, 445 {Key: mvccKey("d"), Value: []byte("after")}, 446 } 447 for i, expKV := range expValues { 448 kv, err := b.Get(expKV.Key) 449 if err != nil { 450 t.Fatal(err) 451 } 452 if !bytes.Equal(kv, expKV.Value) { 453 t.Errorf("%d: expected \"value\", got %q", i, kv) 454 } 455 } 456 }) 457 } 458 } 459 460 func compareMergedValues(t *testing.T, result, expected []byte) bool { 461 var resultV, expectedV enginepb.MVCCMetadata 462 if err := protoutil.Unmarshal(result, &resultV); err != nil { 463 t.Fatal(err) 464 } 465 if err := protoutil.Unmarshal(expected, &expectedV); err != nil { 466 t.Fatal(err) 467 } 468 return reflect.DeepEqual(resultV, expectedV) 469 } 470 471 func TestBatchMerge(t *testing.T) { 472 defer leaktest.AfterTest(t)() 473 474 for _, engineImpl := range mvccEngineImpls { 475 t.Run(engineImpl.name, func(t *testing.T) { 476 e := engineImpl.create() 477 defer e.Close() 478 479 b := e.NewBatch() 480 defer b.Close() 481 482 // Write batch put, delete & merge. 483 if err := b.Put(mvccKey("a"), appender("a-value")); err != nil { 484 t.Fatal(err) 485 } 486 if err := b.Clear(mvccKey("b")); err != nil { 487 t.Fatal(err) 488 } 489 if err := b.Merge(mvccKey("c"), appender("c-value")); err != nil { 490 t.Fatal(err) 491 } 492 493 // Now, merge to all three keys. 494 if err := b.Merge(mvccKey("a"), appender("append")); err != nil { 495 t.Fatal(err) 496 } 497 if err := b.Merge(mvccKey("b"), appender("append")); err != nil { 498 t.Fatal(err) 499 } 500 if err := b.Merge(mvccKey("c"), appender("append")); err != nil { 501 t.Fatal(err) 502 } 503 504 // Verify values. 505 val, err := b.Get(mvccKey("a")) 506 if err != nil { 507 t.Fatal(err) 508 } 509 if !compareMergedValues(t, val, appender("a-valueappend")) { 510 t.Error("mismatch of \"a\"") 511 } 512 513 val, err = b.Get(mvccKey("b")) 514 if err != nil { 515 t.Fatal(err) 516 } 517 if !compareMergedValues(t, val, appender("append")) { 518 t.Error("mismatch of \"b\"") 519 } 520 521 val, err = b.Get(mvccKey("c")) 522 if err != nil { 523 t.Fatal(err) 524 } 525 if !compareMergedValues(t, val, appender("c-valueappend")) { 526 t.Error("mismatch of \"c\"") 527 } 528 }) 529 } 530 } 531 532 func TestBatchProto(t *testing.T) { 533 defer leaktest.AfterTest(t)() 534 535 for _, engineImpl := range mvccEngineImpls { 536 t.Run(engineImpl.name, func(t *testing.T) { 537 e := engineImpl.create() 538 defer e.Close() 539 540 b := e.NewBatch() 541 defer b.Close() 542 543 val := roachpb.MakeValueFromString("value") 544 if _, _, err := PutProto(b, mvccKey("proto"), &val); err != nil { 545 t.Fatal(err) 546 } 547 getVal := &roachpb.Value{} 548 ok, keySize, valSize, err := b.GetProto(mvccKey("proto"), getVal) 549 if !ok || err != nil { 550 t.Fatalf("expected GetProto to success ok=%t: %+v", ok, err) 551 } 552 if keySize != 6 { 553 t.Errorf("expected key size 6; got %d", keySize) 554 } 555 data, err := protoutil.Marshal(&val) 556 if err != nil { 557 t.Fatal(err) 558 } 559 if valSize != int64(len(data)) { 560 t.Errorf("expected value size %d; got %d", len(data), valSize) 561 } 562 if !proto.Equal(getVal, &val) { 563 t.Errorf("expected %v; got %v", &val, getVal) 564 } 565 // Before commit, proto will not be available via engine. 566 fmt.Printf("before\n") 567 if ok, _, _, err := e.GetProto(mvccKey("proto"), getVal); ok || err != nil { 568 fmt.Printf("after\n") 569 t.Fatalf("expected GetProto to fail ok=%t: %+v", ok, err) 570 } 571 // Commit and verify the proto can be read directly from the engine. 572 if err := b.Commit(false /* sync */); err != nil { 573 t.Fatal(err) 574 } 575 if ok, _, _, err := e.GetProto(mvccKey("proto"), getVal); !ok || err != nil { 576 t.Fatalf("expected GetProto to success ok=%t: %+v", ok, err) 577 } 578 if !proto.Equal(getVal, &val) { 579 t.Errorf("expected %v; got %v", &val, getVal) 580 } 581 }) 582 } 583 } 584 585 func TestBatchScan(t *testing.T) { 586 defer leaktest.AfterTest(t)() 587 588 for _, engineImpl := range mvccEngineImpls { 589 t.Run(engineImpl.name, func(t *testing.T) { 590 e := engineImpl.create() 591 defer e.Close() 592 593 b := e.NewBatch() 594 defer b.Close() 595 596 existingVals := []MVCCKeyValue{ 597 {Key: mvccKey("a"), Value: []byte("1")}, 598 {Key: mvccKey("b"), Value: []byte("2")}, 599 {Key: mvccKey("c"), Value: []byte("3")}, 600 {Key: mvccKey("d"), Value: []byte("4")}, 601 {Key: mvccKey("e"), Value: []byte("5")}, 602 {Key: mvccKey("f"), Value: []byte("6")}, 603 {Key: mvccKey("g"), Value: []byte("7")}, 604 {Key: mvccKey("h"), Value: []byte("8")}, 605 {Key: mvccKey("i"), Value: []byte("9")}, 606 {Key: mvccKey("j"), Value: []byte("10")}, 607 {Key: mvccKey("k"), Value: []byte("11")}, 608 {Key: mvccKey("l"), Value: []byte("12")}, 609 {Key: mvccKey("m"), Value: []byte("13")}, 610 } 611 for _, kv := range existingVals { 612 if err := e.Put(kv.Key, kv.Value); err != nil { 613 t.Fatal(err) 614 } 615 } 616 617 batchVals := []MVCCKeyValue{ 618 {Key: mvccKey("a"), Value: []byte("b1")}, 619 {Key: mvccKey("bb"), Value: []byte("b2")}, 620 {Key: mvccKey("c"), Value: []byte("b3")}, 621 {Key: mvccKey("dd"), Value: []byte("b4")}, 622 {Key: mvccKey("e"), Value: []byte("b5")}, 623 {Key: mvccKey("ff"), Value: []byte("b6")}, 624 {Key: mvccKey("g"), Value: []byte("b7")}, 625 {Key: mvccKey("hh"), Value: []byte("b8")}, 626 {Key: mvccKey("i"), Value: []byte("b9")}, 627 {Key: mvccKey("jj"), Value: []byte("b10")}, 628 } 629 for _, kv := range batchVals { 630 if err := b.Put(kv.Key, kv.Value); err != nil { 631 t.Fatal(err) 632 } 633 } 634 635 scans := []struct { 636 start, end roachpb.Key 637 max int64 638 }{ 639 // Full monty. 640 {start: roachpb.Key("a"), end: roachpb.Key("z"), max: 0}, 641 // Select ~half. 642 {start: roachpb.Key("a"), end: roachpb.Key("z"), max: 9}, 643 // Select one. 644 {start: roachpb.Key("a"), end: roachpb.Key("z"), max: 1}, 645 // Select half by end key. 646 {start: roachpb.Key("a"), end: roachpb.Key("f0"), max: 0}, 647 // Start at half and select rest. 648 {start: roachpb.Key("f"), end: roachpb.Key("z"), max: 0}, 649 // Start at last and select max=10. 650 {start: roachpb.Key("m"), end: roachpb.Key("z"), max: 10}, 651 } 652 653 // Scan each case using the batch and store the results. 654 results := map[int][]MVCCKeyValue{} 655 for i, scan := range scans { 656 kvs, err := Scan(b, scan.start, scan.end, scan.max) 657 if err != nil { 658 t.Fatal(err) 659 } 660 results[i] = kvs 661 } 662 663 // Now, commit batch and re-scan using engine direct to compare results. 664 if err := b.Commit(false /* sync */); err != nil { 665 t.Fatal(err) 666 } 667 for i, scan := range scans { 668 kvs, err := Scan(e, scan.start, scan.end, scan.max) 669 if err != nil { 670 t.Fatal(err) 671 } 672 if !reflect.DeepEqual(kvs, results[i]) { 673 t.Errorf("%d: expected %v; got %v", i, results[i], kvs) 674 } 675 } 676 }) 677 } 678 } 679 680 // TestBatchScanWithDelete verifies that a scan containing 681 // a single deleted value returns nothing. 682 func TestBatchScanWithDelete(t *testing.T) { 683 defer leaktest.AfterTest(t)() 684 685 for _, engineImpl := range mvccEngineImpls { 686 t.Run(engineImpl.name, func(t *testing.T) { 687 e := engineImpl.create() 688 defer e.Close() 689 690 b := e.NewBatch() 691 defer b.Close() 692 693 // Write initial value, then delete via batch. 694 if err := e.Put(mvccKey("a"), []byte("value")); err != nil { 695 t.Fatal(err) 696 } 697 if err := b.Clear(mvccKey("a")); err != nil { 698 t.Fatal(err) 699 } 700 kvs, err := Scan(b, roachpb.KeyMin, roachpb.KeyMax, 0) 701 if err != nil { 702 t.Fatal(err) 703 } 704 if len(kvs) != 0 { 705 t.Errorf("expected empty scan with batch-deleted value; got %v", kvs) 706 } 707 }) 708 } 709 } 710 711 // TestBatchScanMaxWithDeleted verifies that if a deletion 712 // in the updates map shadows an entry from the engine, the 713 // max on a scan is still reached. 714 func TestBatchScanMaxWithDeleted(t *testing.T) { 715 defer leaktest.AfterTest(t)() 716 717 for _, engineImpl := range mvccEngineImpls { 718 t.Run(engineImpl.name, func(t *testing.T) { 719 e := engineImpl.create() 720 defer e.Close() 721 722 b := e.NewBatch() 723 defer b.Close() 724 725 // Write two values. 726 if err := e.Put(mvccKey("a"), []byte("value1")); err != nil { 727 t.Fatal(err) 728 } 729 if err := e.Put(mvccKey("b"), []byte("value2")); err != nil { 730 t.Fatal(err) 731 } 732 // Now, delete "a" in batch. 733 if err := b.Clear(mvccKey("a")); err != nil { 734 t.Fatal(err) 735 } 736 // A scan with max=1 should scan "b". 737 kvs, err := Scan(b, roachpb.KeyMin, roachpb.KeyMax, 1) 738 if err != nil { 739 t.Fatal(err) 740 } 741 if len(kvs) != 1 || !bytes.Equal(kvs[0].Key.Key, []byte("b")) { 742 t.Errorf("expected scan of \"b\"; got %v", kvs) 743 } 744 }) 745 } 746 } 747 748 // TestBatchConcurrency verifies operation of batch when the 749 // underlying engine has concurrent modifications to overlapping 750 // keys. This should never happen with the way Cockroach uses 751 // batches, but worth verifying. 752 func TestBatchConcurrency(t *testing.T) { 753 defer leaktest.AfterTest(t)() 754 755 for _, engineImpl := range mvccEngineImpls { 756 t.Run(engineImpl.name, func(t *testing.T) { 757 e := engineImpl.create() 758 defer e.Close() 759 760 b := e.NewBatch() 761 defer b.Close() 762 763 // Write a merge to the batch. 764 if err := b.Merge(mvccKey("a"), appender("bar")); err != nil { 765 t.Fatal(err) 766 } 767 val, err := b.Get(mvccKey("a")) 768 if err != nil { 769 t.Fatal(err) 770 } 771 if !compareMergedValues(t, val, appender("bar")) { 772 t.Error("mismatch of \"a\"") 773 } 774 // Write an engine value. 775 if err := e.Put(mvccKey("a"), appender("foo")); err != nil { 776 t.Fatal(err) 777 } 778 // Now, read again and verify that the merge happens on top of the mod. 779 val, err = b.Get(mvccKey("a")) 780 if err != nil { 781 t.Fatal(err) 782 } 783 if !bytes.Equal(val, appender("foobar")) { 784 t.Error("mismatch of \"a\"") 785 } 786 }) 787 } 788 } 789 790 func TestBatchBuilder(t *testing.T) { 791 defer leaktest.AfterTest(t)() 792 793 stopper := stop.NewStopper() 794 defer stopper.Stop(context.Background()) 795 e := newRocksDBInMem(roachpb.Attributes{}, 1<<20) 796 stopper.AddCloser(e) 797 798 batch := e.NewBatch().(*rocksDBBatch) 799 batch.ensureBatch() 800 // Ensure that, even though we reach into the batch's internals with 801 // dbPut etc, asking for the batch's Repr will get data from C++ and 802 // not its unused builder. 803 batch.flushes++ 804 defer batch.Close() 805 806 builder := &RocksDBBatchBuilder{} 807 808 testData := []struct { 809 key string 810 ts hlc.Timestamp 811 }{ 812 {"a", hlc.Timestamp{}}, 813 {"b", hlc.Timestamp{WallTime: 1}}, 814 {"c", hlc.Timestamp{WallTime: 1, Logical: 1}}, 815 } 816 for _, data := range testData { 817 key := MVCCKey{roachpb.Key(data.key), data.ts} 818 if err := dbPut(batch.batch, key, []byte("value")); err != nil { 819 t.Fatal(err) 820 } 821 if err := dbClear(batch.batch, key); err != nil { 822 t.Fatal(err) 823 } 824 // TODO(itsbilal): Uncomment this when pebble.Batch supports SingleDeletion. 825 //if err := dbSingleClear(batch.batch, key); err != nil { 826 // t.Fatal(err) 827 //} 828 if err := dbMerge(batch.batch, key, appender("bar")); err != nil { 829 t.Fatal(err) 830 } 831 832 builder.Put(key, []byte("value")) 833 builder.Clear(key) 834 // TODO(itsbilal): Uncomment this when pebble.Batch supports SingleDeletion. 835 //builder.SingleClear(key) 836 builder.Merge(key, appender("bar")) 837 } 838 839 batchRepr := batch.Repr() 840 builderRepr := builder.Finish() 841 if !bytes.Equal(batchRepr, builderRepr) { 842 t.Fatalf("expected [% x], but got [% x]", batchRepr, builderRepr) 843 } 844 } 845 846 func TestBatchBuilderStress(t *testing.T) { 847 defer leaktest.AfterTest(t)() 848 849 stopper := stop.NewStopper() 850 defer stopper.Stop(context.Background()) 851 e := newRocksDBInMem(roachpb.Attributes{}, 1<<20) 852 stopper.AddCloser(e) 853 854 rng, _ := randutil.NewPseudoRand() 855 856 for i := 0; i < 1000; i++ { 857 count := 1 + rng.Intn(1000) 858 859 func() { 860 batch := e.NewBatch().(*rocksDBBatch) 861 batch.ensureBatch() 862 // Ensure that, even though we reach into the batch's internals with 863 // dbPut etc, asking for the batch's Repr will get data from C++ and 864 // not its unused builder. 865 batch.flushes++ 866 defer batch.Close() 867 868 builder := &RocksDBBatchBuilder{} 869 870 for j := 0; j < count; j++ { 871 var ts hlc.Timestamp 872 if rng.Float32() <= 0.9 { 873 // Give 90% of keys timestamps. 874 ts.WallTime = rng.Int63() 875 if rng.Float32() <= 0.1 { 876 // Give 10% of timestamps a non-zero logical component. 877 ts.Logical = rng.Int31() 878 } 879 } 880 key := MVCCKey{ 881 Key: []byte(fmt.Sprintf("%d", rng.Intn(10000))), 882 Timestamp: ts, 883 } 884 // Generate a random mixture of puts, deletes, single deletes, and merges. 885 switch rng.Intn(3) { 886 case 0: 887 if err := dbPut(batch.batch, key, []byte("value")); err != nil { 888 t.Fatal(err) 889 } 890 builder.Put(key, []byte("value")) 891 case 1: 892 if err := dbClear(batch.batch, key); err != nil { 893 t.Fatal(err) 894 } 895 builder.Clear(key) 896 case 2: 897 // TODO(itsbilal): Don't test SingleClears matching up until 898 // pebble.Batch supports them. 899 //if err := dbSingleClear(batch.batch, key); err != nil { 900 // t.Fatal(err) 901 //} 902 //builder.SingleClear(key) 903 case 3: 904 if err := dbMerge(batch.batch, key, appender("bar")); err != nil { 905 t.Fatal(err) 906 } 907 builder.Merge(key, appender("bar")) 908 } 909 } 910 911 batchRepr := batch.Repr() 912 builderRepr := builder.Finish() 913 if !bytes.Equal(batchRepr, builderRepr) { 914 t.Fatalf("expected [% x], but got [% x]", batchRepr, builderRepr) 915 } 916 }() 917 } 918 } 919 920 func TestBatchDistinctAfterApplyBatchRepr(t *testing.T) { 921 defer leaktest.AfterTest(t)() 922 923 for _, engineImpl := range mvccEngineImpls { 924 t.Run(engineImpl.name, func(t *testing.T) { 925 e := engineImpl.create() 926 defer e.Close() 927 928 wb := func() []byte { 929 batch := e.NewBatch() 930 defer batch.Close() 931 932 if err := batch.Put(mvccKey("batchkey"), []byte("b")); err != nil { 933 t.Fatal(err) 934 } 935 936 return batch.Repr() 937 }() 938 939 batch := e.NewBatch() 940 defer batch.Close() 941 942 assert.NoError(t, batch.ApplyBatchRepr(wb, false /* sync */)) 943 944 distinct := batch.Distinct() 945 defer distinct.Close() 946 947 // The distinct batch can see the earlier write to the batch. 948 v, err := distinct.Get(mvccKey("batchkey")) 949 if err != nil { 950 t.Fatal(err) 951 } 952 assert.Equal(t, []byte("b"), v) 953 }) 954 } 955 } 956 957 func TestBatchDistinct(t *testing.T) { 958 defer leaktest.AfterTest(t)() 959 960 for _, engineImpl := range mvccEngineImpls { 961 t.Run(engineImpl.name, func(t *testing.T) { 962 e := engineImpl.create() 963 defer e.Close() 964 965 if err := e.Put(mvccKey("b"), []byte("b")); err != nil { 966 t.Fatal(err) 967 } 968 969 batch := e.NewBatch() 970 defer batch.Close() 971 972 if err := batch.Put(mvccKey("a"), []byte("a")); err != nil { 973 t.Fatal(err) 974 } 975 if err := batch.Clear(mvccKey("b")); err != nil { 976 t.Fatal(err) 977 } 978 979 // The original batch can see the writes to the batch. 980 if v, err := batch.Get(mvccKey("a")); err != nil { 981 t.Fatal(err) 982 } else if string(v) != "a" { 983 t.Fatalf("expected a, but got %s", v) 984 } 985 986 // The distinct batch will see previous writes to the batch. 987 distinct := batch.Distinct() 988 if v, err := distinct.Get(mvccKey("a")); err != nil { 989 t.Fatal(err) 990 } else if string(v) != "a" { 991 t.Fatalf("expected a, but got %s", v) 992 } 993 if v, err := distinct.Get(mvccKey("b")); err != nil { 994 t.Fatal(err) 995 } else if v != nil { 996 t.Fatalf("expected nothing, but got %s", v) 997 } 998 999 // Similarly, for distinct batch iterators we will see previous writes to the 1000 // batch. 1001 iter := distinct.NewIterator(IterOptions{UpperBound: roachpb.KeyMax}) 1002 iter.SeekGE(mvccKey("a")) 1003 if ok, err := iter.Valid(); !ok { 1004 t.Fatalf("expected iterator to be valid; err=%v", err) 1005 } 1006 if string(iter.Key().Key) != "a" { 1007 t.Fatalf("expected a, but got %s", iter.Key()) 1008 } 1009 iter.Close() 1010 1011 if err := distinct.Put(mvccKey("c"), []byte("c")); err != nil { 1012 t.Fatal(err) 1013 } 1014 if v, err := distinct.Get(mvccKey("c")); err != nil { 1015 t.Fatal(err) 1016 } else { 1017 switch engineImpl.name { 1018 case "pebble": 1019 // With Pebble, writes to the distinct batch are readable by the 1020 // distinct batch. This semantic difference is due to not buffering 1021 // writes in a builder. 1022 if v == nil { 1023 t.Fatalf("expected success, but got %s", v) 1024 } 1025 default: 1026 // Writes to the distinct batch are not readable by the distinct 1027 // batch. 1028 if v != nil { 1029 t.Fatalf("expected nothing, but got %s", v) 1030 } 1031 } 1032 } 1033 distinct.Close() 1034 1035 // Writes to the distinct batch are reflected in the original batch. 1036 if v, err := batch.Get(mvccKey("c")); err != nil { 1037 t.Fatal(err) 1038 } else if string(v) != "c" { 1039 t.Fatalf("expected c, but got %s", v) 1040 } 1041 }) 1042 } 1043 } 1044 1045 func TestWriteOnlyBatchDistinct(t *testing.T) { 1046 defer leaktest.AfterTest(t)() 1047 1048 for _, engineImpl := range mvccEngineImpls { 1049 t.Run(engineImpl.name, func(t *testing.T) { 1050 e := engineImpl.create() 1051 defer e.Close() 1052 1053 if err := e.Put(mvccKey("b"), []byte("b")); err != nil { 1054 t.Fatal(err) 1055 } 1056 if _, _, err := PutProto(e, mvccKey("c"), &roachpb.Value{}); err != nil { 1057 t.Fatal(err) 1058 } 1059 1060 b := e.NewWriteOnlyBatch() 1061 defer b.Close() 1062 1063 distinct := b.Distinct() 1064 defer distinct.Close() 1065 1066 // Verify that reads on the distinct batch go to the underlying engine, not 1067 // to the write-only batch. 1068 iter := distinct.NewIterator(IterOptions{UpperBound: roachpb.KeyMax}) 1069 iter.SeekGE(mvccKey("a")) 1070 if ok, err := iter.Valid(); !ok { 1071 t.Fatalf("expected iterator to be valid, err=%v", err) 1072 } 1073 if string(iter.Key().Key) != "b" { 1074 t.Fatalf("expected b, but got %s", iter.Key()) 1075 } 1076 iter.Close() 1077 1078 if v, err := distinct.Get(mvccKey("b")); err != nil { 1079 t.Fatal(err) 1080 } else if string(v) != "b" { 1081 t.Fatalf("expected b, but got %s", v) 1082 } 1083 1084 val := &roachpb.Value{} 1085 if _, _, _, err := distinct.GetProto(mvccKey("c"), val); err != nil { 1086 t.Fatal(err) 1087 } 1088 }) 1089 } 1090 } 1091 1092 func TestBatchDistinctPanics(t *testing.T) { 1093 defer leaktest.AfterTest(t)() 1094 1095 for _, engineImpl := range mvccEngineImpls { 1096 t.Run(engineImpl.name, func(t *testing.T) { 1097 e := engineImpl.create() 1098 defer e.Close() 1099 1100 batch := e.NewBatch() 1101 defer batch.Close() 1102 1103 distinct := batch.Distinct() 1104 defer distinct.Close() 1105 1106 // The various Reader and Writer methods on the original batch should panic 1107 // while the distinct batch is open. 1108 a := mvccKey("a") 1109 testCases := []func(){ 1110 func() { _ = batch.Put(a, nil) }, 1111 func() { _ = batch.Merge(a, nil) }, 1112 func() { _ = batch.Clear(a) }, 1113 func() { _ = batch.SingleClear(a) }, 1114 func() { _ = batch.ApplyBatchRepr(nil, false) }, 1115 func() { _, _ = batch.Get(a) }, 1116 func() { _, _, _, _ = batch.GetProto(a, nil) }, 1117 func() { _ = batch.Iterate(a.Key, a.Key, nil) }, 1118 func() { _ = batch.NewIterator(IterOptions{UpperBound: roachpb.KeyMax}) }, 1119 } 1120 for i, f := range testCases { 1121 func() { 1122 defer func() { 1123 if r := recover(); r == nil { 1124 t.Fatalf("%d: test did not panic", i) 1125 } else if r != "distinct batch open" { 1126 t.Fatalf("%d: unexpected panic: %v", i, r) 1127 } 1128 }() 1129 f() 1130 }() 1131 } 1132 }) 1133 } 1134 } 1135 1136 func TestBatchIteration(t *testing.T) { 1137 defer leaktest.AfterTest(t)() 1138 1139 for _, engineImpl := range mvccEngineImpls { 1140 t.Run(engineImpl.name, func(t *testing.T) { 1141 e := engineImpl.create() 1142 defer e.Close() 1143 1144 b := e.NewBatch() 1145 defer b.Close() 1146 1147 k1 := MakeMVCCMetadataKey(roachpb.Key("c")) 1148 k2 := MakeMVCCMetadataKey(roachpb.Key("d")) 1149 k3 := MakeMVCCMetadataKey(roachpb.Key("e")) 1150 v1 := []byte("value1") 1151 v2 := []byte("value2") 1152 1153 if err := b.Put(k1, v1); err != nil { 1154 t.Fatal(err) 1155 } 1156 if err := b.Put(k2, v2); err != nil { 1157 t.Fatal(err) 1158 } 1159 if err := b.Put(k3, []byte("doesn't matter")); err != nil { 1160 t.Fatal(err) 1161 } 1162 1163 iterOpts := IterOptions{UpperBound: k3.Key} 1164 iter := b.NewIterator(iterOpts) 1165 defer iter.Close() 1166 1167 // Forward iteration, 1168 iter.SeekGE(k1) 1169 if ok, err := iter.Valid(); !ok { 1170 t.Fatal(err) 1171 } 1172 if !reflect.DeepEqual(iter.Key(), k1) { 1173 t.Fatalf("expected %s, got %s", k1, iter.Key()) 1174 } 1175 if !reflect.DeepEqual(iter.Value(), v1) { 1176 t.Fatalf("expected %s, got %s", v1, iter.Value()) 1177 } 1178 iter.Next() 1179 if ok, err := iter.Valid(); !ok { 1180 t.Fatal(err) 1181 } 1182 if !reflect.DeepEqual(iter.Key(), k2) { 1183 t.Fatalf("expected %s, got %s", k2, iter.Key()) 1184 } 1185 if !reflect.DeepEqual(iter.Value(), v2) { 1186 t.Fatalf("expected %s, got %s", v2, iter.Value()) 1187 } 1188 iter.Next() 1189 if ok, err := iter.Valid(); err != nil { 1190 t.Fatal(err) 1191 } else if ok { 1192 t.Fatalf("expected invalid, got valid at key %s", iter.Key()) 1193 } 1194 1195 // Reverse iteration. 1196 switch engineImpl.name { 1197 case "pebble": 1198 // Reverse iteration in batches works on Pebble. 1199 iter.SeekLT(k3) 1200 if ok, err := iter.Valid(); !ok { 1201 t.Fatal(err) 1202 } 1203 if !reflect.DeepEqual(iter.Key(), k2) { 1204 t.Fatalf("expected %s, got %s", k2, iter.Key()) 1205 } 1206 if !reflect.DeepEqual(iter.Value(), v2) { 1207 t.Fatalf("expected %s, got %s", v2, iter.Value()) 1208 } 1209 1210 iter.Prev() 1211 if ok, err := iter.Valid(); !ok || err != nil { 1212 t.Fatalf("expected success, but got invalid: %v", err) 1213 } 1214 if !reflect.DeepEqual(iter.Key(), k1) { 1215 t.Fatalf("expected %s, got %s", k1, iter.Key()) 1216 } 1217 if !reflect.DeepEqual(iter.Value(), v1) { 1218 t.Fatalf("expected %s, got %s", v1, iter.Value()) 1219 } 1220 default: 1221 // Reverse iteration in batches is not supported with RocksDB. 1222 iter.SeekLT(k3) 1223 if ok, err := iter.Valid(); ok { 1224 t.Fatalf("expected invalid, got valid at key %s", iter.Key()) 1225 } else if !testutils.IsError(err, "SeekForPrev\\(\\) not supported") { 1226 t.Fatalf("expected 'SeekForPrev() not supported', got %s", err) 1227 } 1228 1229 iter.Prev() 1230 if ok, err := iter.Valid(); ok { 1231 t.Fatalf("expected invalid, got valid at key %s", iter.Key()) 1232 } else if !testutils.IsError(err, "Prev\\(\\) not supported") { 1233 t.Fatalf("expected 'Prev() not supported', got %s", err) 1234 } 1235 } 1236 }) 1237 } 1238 } 1239 1240 // Test combining of concurrent commits of write-only batches, verifying that 1241 // all of the keys written by the individual batches are subsequently readable. 1242 func TestBatchCombine(t *testing.T) { 1243 defer leaktest.AfterTest(t)() 1244 1245 for _, engineImpl := range mvccEngineImpls { 1246 t.Run(engineImpl.name, func(t *testing.T) { 1247 e := engineImpl.create() 1248 defer e.Close() 1249 1250 var n uint32 1251 const count = 10000 1252 1253 errs := make(chan error, 10) 1254 for i := 0; i < cap(errs); i++ { 1255 go func() { 1256 for { 1257 v := atomic.AddUint32(&n, 1) - 1 1258 if v >= count { 1259 break 1260 } 1261 k := fmt.Sprint(v) 1262 1263 b := e.NewWriteOnlyBatch() 1264 if err := b.Put(mvccKey(k), []byte(k)); err != nil { 1265 errs <- errors.Wrap(err, "put failed") 1266 return 1267 } 1268 if err := b.Commit(false); err != nil { 1269 errs <- errors.Wrap(err, "commit failed") 1270 return 1271 } 1272 1273 // Verify we can read the key we just wrote immediately. 1274 if v, err := e.Get(mvccKey(k)); err != nil { 1275 errs <- errors.Wrap(err, "get failed") 1276 return 1277 } else if string(v) != k { 1278 errs <- errors.Errorf("read %q from engine, expected %q", v, k) 1279 return 1280 } 1281 } 1282 errs <- nil 1283 }() 1284 } 1285 1286 for i := 0; i < cap(errs); i++ { 1287 if err := <-errs; err != nil { 1288 t.Error(err) 1289 } 1290 } 1291 }) 1292 } 1293 } 1294 1295 func TestDecodeKey(t *testing.T) { 1296 defer leaktest.AfterTest(t)() 1297 1298 e := newRocksDBInMem(roachpb.Attributes{}, 1<<20) 1299 defer e.Close() 1300 1301 tests := []MVCCKey{ 1302 {Key: []byte{}}, 1303 {Key: []byte("foo")}, 1304 {Key: []byte("foo"), Timestamp: hlc.Timestamp{WallTime: 1}}, 1305 {Key: []byte("foo"), Timestamp: hlc.Timestamp{WallTime: 1, Logical: 1}}, 1306 } 1307 for _, test := range tests { 1308 t.Run(test.String(), func(t *testing.T) { 1309 b := e.NewBatch() 1310 defer b.Close() 1311 if err := b.Put(test, nil); err != nil { 1312 t.Fatalf("%+v", err) 1313 } 1314 repr := b.Repr() 1315 1316 r, err := NewRocksDBBatchReader(repr) 1317 if err != nil { 1318 t.Fatalf("%+v", err) 1319 } 1320 if !r.Next() { 1321 t.Fatalf("could not get the first entry: %+v", r.Error()) 1322 } 1323 decodedKey, err := DecodeMVCCKey(r.Key()) 1324 if err != nil { 1325 t.Fatalf("unexpected err: %+v", err) 1326 } 1327 if !reflect.DeepEqual(test, decodedKey) { 1328 t.Errorf("expected %+v got %+v", test, decodedKey) 1329 } 1330 }) 1331 } 1332 }