github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/storage/mvcc_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 "math" 18 "math/rand" 19 "reflect" 20 "sort" 21 "strconv" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/cockroachdb/cockroach/pkg/keys" 27 "github.com/cockroachdb/cockroach/pkg/roachpb" 28 "github.com/cockroachdb/cockroach/pkg/storage/enginepb" 29 "github.com/cockroachdb/cockroach/pkg/testutils" 30 "github.com/cockroachdb/cockroach/pkg/testutils/zerofields" 31 "github.com/cockroachdb/cockroach/pkg/util/caller" 32 "github.com/cockroachdb/cockroach/pkg/util/encoding" 33 "github.com/cockroachdb/cockroach/pkg/util/hlc" 34 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 35 "github.com/cockroachdb/cockroach/pkg/util/log" 36 "github.com/cockroachdb/cockroach/pkg/util/protoutil" 37 "github.com/cockroachdb/cockroach/pkg/util/randutil" 38 "github.com/cockroachdb/cockroach/pkg/util/shuffle" 39 "github.com/cockroachdb/cockroach/pkg/util/uuid" 40 "github.com/cockroachdb/errors" 41 "github.com/gogo/protobuf/proto" 42 "github.com/kr/pretty" 43 "github.com/stretchr/testify/require" 44 ) 45 46 // Constants for system-reserved keys in the KV map. 47 var ( 48 keyMin = roachpb.KeyMin 49 keyMax = roachpb.KeyMax 50 testKey1 = roachpb.Key("/db1") 51 testKey2 = roachpb.Key("/db2") 52 testKey3 = roachpb.Key("/db3") 53 testKey4 = roachpb.Key("/db4") 54 testKey5 = roachpb.Key("/db5") 55 testKey6 = roachpb.Key("/db6") 56 txn1ID = uuid.MakeV4() 57 txn2ID = uuid.MakeV4() 58 txn1TS = hlc.Timestamp{Logical: 1} 59 txn2TS = hlc.Timestamp{Logical: 2} 60 txn1 = &roachpb.Transaction{TxnMeta: enginepb.TxnMeta{Key: roachpb.Key("a"), ID: txn1ID, Epoch: 1, WriteTimestamp: txn1TS, MinTimestamp: txn1TS}, ReadTimestamp: txn1TS} 61 txn1Commit = &roachpb.Transaction{TxnMeta: enginepb.TxnMeta{Key: roachpb.Key("a"), ID: txn1ID, Epoch: 1, WriteTimestamp: txn1TS, MinTimestamp: txn1TS}, ReadTimestamp: txn1TS, Status: roachpb.COMMITTED} 62 txn1Abort = &roachpb.Transaction{TxnMeta: enginepb.TxnMeta{Key: roachpb.Key("a"), ID: txn1ID, Epoch: 1, WriteTimestamp: txn1TS, MinTimestamp: txn1TS}, Status: roachpb.ABORTED} 63 txn1e2 = &roachpb.Transaction{TxnMeta: enginepb.TxnMeta{Key: roachpb.Key("a"), ID: txn1ID, Epoch: 2, WriteTimestamp: txn1TS, MinTimestamp: txn1TS}, ReadTimestamp: txn1TS} 64 txn1e2Commit = &roachpb.Transaction{TxnMeta: enginepb.TxnMeta{Key: roachpb.Key("a"), ID: txn1ID, Epoch: 2, WriteTimestamp: txn1TS, MinTimestamp: txn1TS}, ReadTimestamp: txn1TS, Status: roachpb.COMMITTED} 65 txn2 = &roachpb.Transaction{TxnMeta: enginepb.TxnMeta{Key: roachpb.Key("a"), ID: txn2ID, WriteTimestamp: txn2TS, MinTimestamp: txn2TS}, ReadTimestamp: txn2TS} 66 txn2Commit = &roachpb.Transaction{TxnMeta: enginepb.TxnMeta{Key: roachpb.Key("a"), ID: txn2ID, WriteTimestamp: txn2TS, MinTimestamp: txn2TS}, ReadTimestamp: txn2TS, Status: roachpb.COMMITTED} 67 value1 = roachpb.MakeValueFromString("testValue1") 68 value2 = roachpb.MakeValueFromString("testValue2") 69 value3 = roachpb.MakeValueFromString("testValue3") 70 value4 = roachpb.MakeValueFromString("testValue4") 71 value5 = roachpb.MakeValueFromString("testValue5") 72 value6 = roachpb.MakeValueFromString("testValue6") 73 tsvalue1 = timeSeriesRowAsValue(testtime, 1000, []tsSample{ 74 {1, 1, 5, 5, 5}, 75 }...) 76 tsvalue2 = timeSeriesRowAsValue(testtime, 1000, []tsSample{ 77 {1, 1, 15, 15, 15}, 78 }...) 79 ) 80 81 // createTestRocksDBEngine returns a new in-memory RocksDB engine with 1MB of 82 // storage capacity. 83 func createTestRocksDBEngine() Engine { 84 return newRocksDBInMem(roachpb.Attributes{}, 1<<20) 85 } 86 87 // createTestPebbleEngine returns a new in-memory Pebble storage engine. 88 func createTestPebbleEngine() Engine { 89 return newPebbleInMem(context.Background(), roachpb.Attributes{}, 1<<20) 90 } 91 92 var mvccEngineImpls = []struct { 93 name string 94 create func() Engine 95 }{ 96 {"rocksdb", createTestRocksDBEngine}, 97 {"pebble", createTestPebbleEngine}, 98 } 99 100 // makeTxn creates a new transaction using the specified base 101 // txn and timestamp. 102 func makeTxn(baseTxn roachpb.Transaction, ts hlc.Timestamp) *roachpb.Transaction { 103 txn := baseTxn.Clone() 104 txn.ReadTimestamp = ts 105 txn.DeprecatedOrigTimestamp = ts 106 txn.WriteTimestamp = ts 107 return txn 108 } 109 110 func mvccVersionKey(key roachpb.Key, ts hlc.Timestamp) MVCCKey { 111 return MVCCKey{Key: key, Timestamp: ts} 112 } 113 114 type mvccKeys []MVCCKey 115 116 func (n mvccKeys) Len() int { return len(n) } 117 func (n mvccKeys) Swap(i, j int) { n[i], n[j] = n[j], n[i] } 118 func (n mvccKeys) Less(i, j int) bool { return n[i].Less(n[j]) } 119 120 // mvccGetGo is identical to MVCCGet except that it uses mvccGetInternal 121 // instead of the C++ Iterator.MVCCGet. It is used to test mvccGetInternal 122 // which is used by mvccPutInternal to avoid Cgo crossings. Simply using the 123 // C++ MVCCGet in mvccPutInternal causes a significant performance hit to 124 // conditional put operations. 125 func mvccGetGo( 126 ctx context.Context, reader Reader, key roachpb.Key, timestamp hlc.Timestamp, opts MVCCGetOptions, 127 ) (*roachpb.Value, *roachpb.Intent, error) { 128 if len(key) == 0 { 129 return nil, nil, emptyKeyError() 130 } 131 132 iter := reader.NewIterator(IterOptions{Prefix: true}) 133 defer iter.Close() 134 135 buf := newGetBuffer() 136 defer buf.release() 137 138 metaKey := MakeMVCCMetadataKey(key) 139 ok, _, _, err := mvccGetMetadata(iter, metaKey, &buf.meta) 140 if !ok || err != nil { 141 return nil, nil, err 142 } 143 144 value, intent, _, err := mvccGetInternal(ctx, iter, metaKey, 145 timestamp, !opts.Inconsistent, safeValue, opts.Txn, buf) 146 if !value.IsPresent() { 147 value = nil 148 } 149 if value == &buf.value { 150 value = &roachpb.Value{} 151 *value = buf.value 152 buf.value.Reset() 153 } 154 return value, intent, err 155 } 156 157 var mvccGetImpls = []struct { 158 name string 159 fn func( 160 ctx context.Context, 161 reader Reader, 162 key roachpb.Key, 163 timestamp hlc.Timestamp, 164 opts MVCCGetOptions, 165 ) (*roachpb.Value, *roachpb.Intent, error) 166 }{ 167 {"cpp", MVCCGet}, 168 {"go", mvccGetGo}, 169 } 170 171 func TestMVCCStatsAddSubForward(t *testing.T) { 172 defer leaktest.AfterTest(t)() 173 goldMS := enginepb.MVCCStats{ 174 ContainsEstimates: 1, 175 KeyBytes: 1, 176 KeyCount: 1, 177 ValBytes: 1, 178 ValCount: 1, 179 IntentBytes: 1, 180 IntentCount: 1, 181 IntentAge: 1, 182 GCBytesAge: 1, 183 LiveBytes: 1, 184 LiveCount: 1, 185 SysBytes: 1, 186 SysCount: 1, 187 LastUpdateNanos: 1, 188 } 189 if err := zerofields.NoZeroField(&goldMS); err != nil { 190 t.Fatal(err) // prevent rot as fields are added 191 } 192 193 cmp := func(act, exp enginepb.MVCCStats) { 194 t.Helper() 195 f, l, _ := caller.Lookup(1) 196 if !reflect.DeepEqual(act, exp) { 197 t.Fatalf("%s:%d: wanted %+v back, got %+v", f, l, exp, act) 198 } 199 } 200 201 ms := goldMS 202 zeroWithLU := enginepb.MVCCStats{ 203 ContainsEstimates: 0, 204 LastUpdateNanos: ms.LastUpdateNanos, 205 } 206 207 ms.Subtract(goldMS) 208 cmp(ms, zeroWithLU) 209 210 ms.Add(goldMS) 211 cmp(ms, goldMS) 212 213 // Double-add double-sub guards against mistaking `+=` for `=`. 214 ms = zeroWithLU 215 ms.Add(goldMS) 216 ms.Add(goldMS) 217 ms.Subtract(goldMS) 218 ms.Subtract(goldMS) 219 cmp(ms, zeroWithLU) 220 221 // Run some checks for Forward. 222 goldDelta := enginepb.MVCCStats{ 223 KeyBytes: 42, 224 IntentCount: 11, 225 LastUpdateNanos: 1e9 - 1000, 226 } 227 delta := goldDelta 228 229 for i, ns := range []int64{1, 1e9 - 1001, 1e9 - 1000, 1e9 - 1, 1e9, 1e9 + 1, 2e9 - 1} { 230 oldDelta := delta 231 delta.AgeTo(ns) 232 if delta.LastUpdateNanos < ns { 233 t.Fatalf("%d: expected LastUpdateNanos < %d, got %d", i, ns, delta.LastUpdateNanos) 234 } 235 shouldAge := ns/1e9-oldDelta.LastUpdateNanos/1e9 > 0 236 didAge := delta.IntentAge != oldDelta.IntentAge && 237 delta.GCBytesAge != oldDelta.GCBytesAge 238 if shouldAge != didAge { 239 t.Fatalf("%d: should age: %t, but had\n%+v\nand now\n%+v", i, shouldAge, oldDelta, delta) 240 } 241 } 242 243 expDelta := goldDelta 244 expDelta.LastUpdateNanos = 2e9 - 1 245 expDelta.GCBytesAge = 42 246 expDelta.IntentAge = 11 247 cmp(delta, expDelta) 248 249 delta.AgeTo(2e9) 250 expDelta.LastUpdateNanos = 2e9 251 expDelta.GCBytesAge += 42 252 expDelta.IntentAge += 11 253 cmp(delta, expDelta) 254 255 { 256 // Verify that AgeTo can go backwards in time. 257 // Works on a copy. 258 tmpDelta := delta 259 expDelta := expDelta 260 261 tmpDelta.AgeTo(2e9 - 1) 262 expDelta.LastUpdateNanos = 2e9 - 1 263 expDelta.GCBytesAge -= 42 264 expDelta.IntentAge -= 11 265 cmp(tmpDelta, expDelta) 266 } 267 268 delta.AgeTo(3e9 - 1) 269 delta.Forward(5) // should be noop 270 expDelta.LastUpdateNanos = 3e9 - 1 271 cmp(delta, expDelta) 272 273 // Check that Add calls Forward appropriately. 274 mss := []enginepb.MVCCStats{goldMS, goldMS} 275 276 mss[0].LastUpdateNanos = 2e9 - 1 277 mss[1].LastUpdateNanos = 10e9 + 1 278 279 expMS := goldMS 280 expMS.Add(goldMS) 281 expMS.LastUpdateNanos = 10e9 + 1 282 expMS.IntentAge += 9 // from aging 9 ticks from 2E9-1 to 10E9+1 283 expMS.GCBytesAge += 9 // ditto 284 285 for i := range mss[:1] { 286 ms := mss[(1+i)%2] 287 ms.Add(mss[i]) 288 cmp(ms, expMS) 289 } 290 291 // Finally, check Forward with negative counts (can happen). 292 neg := zeroWithLU 293 neg.Subtract(goldMS) 294 exp := neg 295 296 neg.AgeTo(2e9) 297 298 exp.LastUpdateNanos = 2e9 299 exp.GCBytesAge = -3 300 exp.IntentAge = -3 301 cmp(neg, exp) 302 } 303 304 // Verify the sort ordering of successive keys with metadata and 305 // versioned values. In particular, the following sequence of keys / 306 // versions: 307 // 308 // a 309 // a<t=max> 310 // a<t=1> 311 // a<t=0> 312 // a\x00 313 // a\x00<t=max> 314 // a\x00<t=1> 315 // a\x00<t=0> 316 func TestMVCCKeys(t *testing.T) { 317 defer leaktest.AfterTest(t)() 318 aKey := roachpb.Key("a") 319 a0Key := roachpb.Key("a\x00") 320 keys := mvccKeys{ 321 mvccKey(aKey), 322 mvccVersionKey(aKey, hlc.Timestamp{WallTime: math.MaxInt64}), 323 mvccVersionKey(aKey, hlc.Timestamp{WallTime: 1}), 324 mvccVersionKey(aKey, hlc.Timestamp{Logical: 1}), 325 mvccKey(a0Key), 326 mvccVersionKey(a0Key, hlc.Timestamp{WallTime: math.MaxInt64}), 327 mvccVersionKey(a0Key, hlc.Timestamp{WallTime: 1}), 328 mvccVersionKey(a0Key, hlc.Timestamp{Logical: 1}), 329 } 330 sortKeys := make(mvccKeys, len(keys)) 331 copy(sortKeys, keys) 332 shuffle.Shuffle(sortKeys) 333 sort.Sort(sortKeys) 334 if !reflect.DeepEqual(sortKeys, keys) { 335 t.Errorf("expected keys to sort in order %s, but got %s", keys, sortKeys) 336 } 337 } 338 339 func TestMVCCGetNotExist(t *testing.T) { 340 defer leaktest.AfterTest(t)() 341 342 for _, engineImpl := range mvccEngineImpls { 343 t.Run(engineImpl.name, func(t *testing.T) { 344 for _, impl := range mvccGetImpls { 345 t.Run(impl.name, func(t *testing.T) { 346 mvccGet := impl.fn 347 348 engine := engineImpl.create() 349 defer engine.Close() 350 351 value, _, err := mvccGet(context.Background(), engine, testKey1, hlc.Timestamp{Logical: 1}, 352 MVCCGetOptions{}) 353 if err != nil { 354 t.Fatal(err) 355 } 356 if value != nil { 357 t.Fatal("the value should be empty") 358 } 359 }) 360 } 361 }) 362 } 363 } 364 365 func TestMVCCGetNoMoreOldVersion(t *testing.T) { 366 defer leaktest.AfterTest(t)() 367 368 ctx := context.Background() 369 370 for _, engineImpl := range mvccEngineImpls { 371 t.Run(engineImpl.name, func(t *testing.T) { 372 for _, impl := range mvccGetImpls { 373 t.Run(impl.name, func(t *testing.T) { 374 mvccGet := impl.fn 375 376 // Need to handle the case here where the scan takes us to the 377 // next key, which may not match the key we're looking for. In 378 // other words, if we're looking for a<T=2>, and we have the 379 // following keys: 380 // 381 // a: MVCCMetadata(a) 382 // a<T=3> 383 // b: MVCCMetadata(b) 384 // b<T=1> 385 // 386 // If we search for a<T=2>, the scan should not return "b". 387 388 engine := engineImpl.create() 389 defer engine.Close() 390 391 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 3}, value1, nil); err != nil { 392 t.Fatal(err) 393 } 394 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 395 t.Fatal(err) 396 } 397 398 value, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 2}, MVCCGetOptions{}) 399 if err != nil { 400 t.Fatal(err) 401 } 402 if value != nil { 403 t.Fatal("the value should be empty") 404 } 405 }) 406 } 407 }) 408 } 409 } 410 411 // TestMVCCGetUncertainty verifies that the appropriate error results when 412 // a transaction reads a key at a timestamp that has versions newer than that 413 // timestamp, but older than the transaction's MaxTimestamp. 414 func TestMVCCGetUncertainty(t *testing.T) { 415 defer leaktest.AfterTest(t)() 416 417 ctx := context.Background() 418 419 for _, engineImpl := range mvccEngineImpls { 420 t.Run(engineImpl.name, func(t *testing.T) { 421 for _, impl := range mvccGetImpls { 422 t.Run(impl.name, func(t *testing.T) { 423 mvccGet := impl.fn 424 engine := engineImpl.create() 425 defer engine.Close() 426 427 // Txn with read timestamp 7 and MaxTimestamp 10. 428 txn := &roachpb.Transaction{ 429 TxnMeta: enginepb.TxnMeta{ 430 ID: uuid.MakeV4(), 431 WriteTimestamp: hlc.Timestamp{WallTime: 7}, 432 }, 433 MaxTimestamp: hlc.Timestamp{WallTime: 10}, 434 } 435 getOptsTxn := MVCCGetOptions{Txn: txn} 436 scanOptsTxn := MVCCScanOptions{Txn: txn} 437 438 // Same txn but with a MaxTimestamp reduced to 9. 439 txnMaxTS9 := txn.Clone() 440 txnMaxTS9.MaxTimestamp = hlc.Timestamp{WallTime: 9} 441 getOptsTxnMaxTS9 := MVCCGetOptions{Txn: txnMaxTS9} 442 scanOptsTxnMaxTS9 := MVCCScanOptions{Txn: txnMaxTS9} 443 444 // Same txn but with a MaxTimestamp reduced to 7. 445 txnMaxTS7 := txn.Clone() 446 txnMaxTS7.MaxTimestamp = hlc.Timestamp{WallTime: 7} 447 getOptsTxnMaxTS7 := MVCCGetOptions{Txn: txnMaxTS7} 448 scanOptsTxnMaxTS7 := MVCCScanOptions{Txn: txnMaxTS7} 449 450 // Case 1: One value in the past, one value in the future of read 451 // and ahead of MaxTimestamp of read. Neither should interfere. 452 // 453 // ----------------- 454 // - 12: val2 455 // | 456 // - 10: max timestamp 457 // | 458 // - 7: read timestamp 459 // | 460 // - 1: val1 461 // ----------------- 462 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 463 t.Fatal(err) 464 } 465 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 12}, value2, nil); err != nil { 466 t.Fatal(err) 467 } 468 // Read with transaction, should get a value back. 469 if val, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 7}, getOptsTxn); err != nil { 470 t.Fatal(err) 471 } else if val == nil || !bytes.Equal(val.RawBytes, value1.RawBytes) { 472 t.Fatalf("wanted %q, got %v", value1.RawBytes, val) 473 } 474 if res, err := MVCCScan( 475 ctx, engine, testKey1, testKey1.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxn, 476 ); err != nil { 477 t.Fatal(err) 478 } else if len(res.KVs) != 1 { 479 t.Fatalf("wanted 1 kv, got %d", len(res.KVs)) 480 } else if val := res.KVs[0].Value; !bytes.Equal(val.RawBytes, value1.RawBytes) { 481 t.Fatalf("wanted %q, got %v", value1.RawBytes, val) 482 } 483 484 // Case 2a: One value in the future of read but below MaxTimestamp 485 // of read. Should result in a ReadWithinUncertaintyIntervalError 486 // when reading. 487 // 488 // ----------------- 489 // - 10: max timestamp 490 // - 9: val2 491 // | 492 // - 7: read timestamp 493 // ----------------- 494 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 9}, value2, nil); err != nil { 495 t.Fatal(err) 496 } 497 // Read with transaction, should get error back. 498 if _, _, err := mvccGet(ctx, engine, testKey2, hlc.Timestamp{WallTime: 7}, getOptsTxn); err == nil { 499 t.Fatal("wanted an error") 500 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 501 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 502 } 503 if _, err := MVCCScan( 504 ctx, engine, testKey2, testKey2.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxn, 505 ); err == nil { 506 t.Fatal("wanted an error") 507 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 508 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 509 } 510 // Case 2b: Reduce MaxTimestamp to exactly that of value in future. 511 // Should result in a ReadWithinUncertaintyIntervalError when 512 // reading. 513 // 514 // ----------------- 515 // - 9: val2 & max timestamp 516 // | 517 // - 7: read timestamp 518 // ----------------- 519 if _, _, err := mvccGet(ctx, engine, testKey2, hlc.Timestamp{WallTime: 7}, getOptsTxnMaxTS9); err == nil { 520 t.Fatal("wanted an error") 521 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 522 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 523 } 524 if _, err := MVCCScan( 525 ctx, engine, testKey2, testKey2.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxnMaxTS9, 526 ); err == nil { 527 t.Fatal("wanted an error") 528 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 529 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 530 } 531 // Case 2c: Reduce MaxTimestamp below value in future. Value should 532 // no longer interfere when reading. 533 // 534 // ----------------- 535 // - 9: val2 536 // | 537 // - 7: read timestamp & max timestamp 538 // ----------------- 539 if _, _, err := mvccGet(ctx, engine, testKey2, hlc.Timestamp{WallTime: 7}, getOptsTxnMaxTS7); err != nil { 540 t.Fatal(err) 541 } 542 if _, err := MVCCScan( 543 ctx, engine, testKey2, testKey2.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxnMaxTS7, 544 ); err != nil { 545 t.Fatal(err) 546 } 547 548 // Case 3a: One intent in the future of read but below MaxTimestamp 549 // of read. Should result in a WriteIntentError when reading. 550 // 551 // ----------------- 552 // - 10: max timestamp 553 // - 9: val2 (intent) 554 // | 555 // - 7: read timestamp 556 // ----------------- 557 intentTxn := &roachpb.Transaction{ 558 TxnMeta: enginepb.TxnMeta{ 559 ID: uuid.MakeV4(), 560 WriteTimestamp: hlc.Timestamp{WallTime: 9}, 561 }, 562 ReadTimestamp: hlc.Timestamp{WallTime: 9}, 563 } 564 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 9}, value2, intentTxn); err != nil { 565 t.Fatal(err) 566 } 567 // Read with transaction, should get error back. 568 if _, _, err := mvccGet(ctx, engine, testKey3, hlc.Timestamp{WallTime: 7}, getOptsTxn); err == nil { 569 t.Fatal("wanted an error") 570 } else if !errors.HasType(err, (*roachpb.WriteIntentError)(nil)) { 571 t.Fatalf("wanted a WriteIntentError, got %+v", err) 572 } 573 if _, err := MVCCScan( 574 ctx, engine, testKey3, testKey3.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxn, 575 ); err == nil { 576 t.Fatal("wanted an error") 577 } else if !errors.HasType(err, (*roachpb.WriteIntentError)(nil)) { 578 t.Fatalf("wanted a WriteIntentError, got %+v", err) 579 } 580 // Case 3b: Reduce MaxTimestamp to exactly that of intent in future. 581 // Should result in a WriteIntentError when reading. 582 // 583 // ----------------- 584 // - 9: val2 (intent) & max timestamp 585 // | 586 // - 7: read timestamp 587 // ----------------- 588 if _, _, err := mvccGet(ctx, engine, testKey3, hlc.Timestamp{WallTime: 7}, getOptsTxnMaxTS9); err == nil { 589 t.Fatal("wanted an error") 590 } else if !errors.HasType(err, (*roachpb.WriteIntentError)(nil)) { 591 t.Fatalf("wanted a WriteIntentError, got %+v", err) 592 } 593 if _, err := MVCCScan( 594 ctx, engine, testKey3, testKey3.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxnMaxTS9, 595 ); err == nil { 596 t.Fatal("wanted an error") 597 } else if !errors.HasType(err, (*roachpb.WriteIntentError)(nil)) { 598 t.Fatalf("wanted a WriteIntentError, got %+v", err) 599 } 600 // Case 3c: Reduce MaxTimestamp below intent in future. Intent should 601 // no longer interfere when reading. 602 // 603 // ----------------- 604 // - 9: val2 (intent) 605 // | 606 // - 7: read timestamp & max timestamp 607 // ----------------- 608 if _, _, err := mvccGet(ctx, engine, testKey3, hlc.Timestamp{WallTime: 7}, getOptsTxnMaxTS7); err != nil { 609 t.Fatal(err) 610 } 611 if _, err := MVCCScan( 612 ctx, engine, testKey3, testKey3.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxnMaxTS7, 613 ); err != nil { 614 t.Fatal(err) 615 } 616 617 // Case 4a: Two values in future of read. One is ahead of 618 // MaxTimestamp of read and one is below MaxTimestamp of read. The 619 // value within the read's uncertainty interval should result in a 620 // ReadWithinUncertaintyIntervalError when reading. 621 // 622 // ----------------- 623 // - 99: val3 624 // | 625 // - 10: max timestamp 626 // - 9: val2 627 // | 628 // - 7: read timestamp 629 // ----------------- 630 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 9}, value2, nil); err != nil { 631 t.Fatal(err) 632 } 633 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 99}, value3, nil); err != nil { 634 t.Fatal(err) 635 } 636 if _, _, err := mvccGet(ctx, engine, testKey4, hlc.Timestamp{WallTime: 7}, getOptsTxn); err == nil { 637 t.Fatalf("wanted an error") 638 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 639 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 640 } 641 if _, err := MVCCScan( 642 ctx, engine, testKey4, testKey4.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxn, 643 ); err == nil { 644 t.Fatal("wanted an error") 645 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 646 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 647 } 648 // Case 4b: Reduce MaxTimestamp to exactly that of second value in 649 // future. The value within the read's uncertainty interval should 650 // result in a ReadWithinUncertaintyIntervalError when reading. 651 // 652 // ----------------- 653 // - 99: val3 654 // | 655 // - 9: val2 & max timestamp 656 // | 657 // - 7: read timestamp 658 // ----------------- 659 if _, _, err := mvccGet(ctx, engine, testKey4, hlc.Timestamp{WallTime: 7}, getOptsTxnMaxTS9); err == nil { 660 t.Fatalf("wanted an error") 661 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 662 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 663 } 664 if _, err := MVCCScan( 665 ctx, engine, testKey4, testKey4.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxnMaxTS9, 666 ); err == nil { 667 t.Fatal("wanted an error") 668 } else if !errors.HasType(err, (*roachpb.ReadWithinUncertaintyIntervalError)(nil)) { 669 t.Fatalf("wanted a ReadWithinUncertaintyIntervalError, got %+v", err) 670 } 671 // Case 4c: Reduce MaxTimestamp below second value in future. Value should 672 // no longer interfere when reading. 673 // 674 // ----------------- 675 // - 99: val3 676 // | 677 // - 9: val2 678 // | 679 // - 7: read timestamp & max timestamp 680 // ----------------- 681 if _, _, err := mvccGet(ctx, engine, testKey4, hlc.Timestamp{WallTime: 7}, getOptsTxnMaxTS7); err != nil { 682 t.Fatal(err) 683 } 684 if _, err := MVCCScan( 685 ctx, engine, testKey4, testKey4.PrefixEnd(), hlc.Timestamp{WallTime: 7}, scanOptsTxnMaxTS7, 686 ); err != nil { 687 t.Fatal(err) 688 } 689 }) 690 } 691 }) 692 } 693 } 694 695 func TestMVCCGetAndDelete(t *testing.T) { 696 defer leaktest.AfterTest(t)() 697 698 ctx := context.Background() 699 700 for _, engineImpl := range mvccEngineImpls { 701 t.Run(engineImpl.name, func(t *testing.T) { 702 for _, impl := range mvccGetImpls { 703 t.Run(impl.name, func(t *testing.T) { 704 mvccGet := impl.fn 705 706 engine := engineImpl.create() 707 defer engine.Close() 708 709 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 710 t.Fatal(err) 711 } 712 value, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 2}, MVCCGetOptions{}) 713 if err != nil { 714 t.Fatal(err) 715 } 716 if value == nil { 717 t.Fatal("the value should not be empty") 718 } 719 720 err = MVCCDelete(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 3}, nil) 721 if err != nil { 722 t.Fatal(err) 723 } 724 725 // Read the latest version which should be deleted. 726 value, _, err = mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 4}, MVCCGetOptions{}) 727 if err != nil { 728 t.Fatal(err) 729 } 730 if value != nil { 731 t.Fatal("the value should be empty") 732 } 733 // Read the latest version with tombstone. 734 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 4}, 735 MVCCGetOptions{Tombstones: true}) 736 if err != nil { 737 t.Fatal(err) 738 } else if value == nil || len(value.RawBytes) != 0 { 739 t.Fatalf("the value should be non-nil with empty RawBytes; got %+v", value) 740 } 741 742 // Read the old version which should still exist. 743 for _, logical := range []int32{0, math.MaxInt32} { 744 value, _, err = mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 2, Logical: logical}, 745 MVCCGetOptions{}) 746 if err != nil { 747 t.Fatal(err) 748 } 749 if value == nil { 750 t.Fatal("the value should not be empty") 751 } 752 } 753 }) 754 } 755 }) 756 } 757 } 758 759 // TestMVCCWriteWithOlderTimestampAfterDeletionOfNonexistentKey tests a write 760 // that comes after a delete on a nonexistent key, with the write holding a 761 // timestamp earlier than the delete timestamp. The delete must write a 762 // tombstone with its timestamp in order to push the write's timestamp. 763 func TestMVCCWriteWithOlderTimestampAfterDeletionOfNonexistentKey(t *testing.T) { 764 defer leaktest.AfterTest(t)() 765 for _, engineImpl := range mvccEngineImpls { 766 t.Run(engineImpl.name, func(t *testing.T) { 767 engine := engineImpl.create() 768 defer engine.Close() 769 770 if err := MVCCDelete( 771 context.Background(), engine, nil, testKey1, hlc.Timestamp{WallTime: 3}, nil, 772 ); err != nil { 773 t.Fatal(err) 774 } 775 776 if err := MVCCPut( 777 context.Background(), engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil, 778 ); !testutils.IsError( 779 err, "write at timestamp 0.000000001,0 too old; wrote at 0.000000003,1", 780 ) { 781 t.Fatal(err) 782 } 783 784 value, _, err := MVCCGet(context.Background(), engine, testKey1, hlc.Timestamp{WallTime: 2}, 785 MVCCGetOptions{}) 786 if err != nil { 787 t.Fatal(err) 788 } 789 // The attempted write at ts(1,0) was performed at ts(3,1), so we should 790 // not see it at ts(2,0). 791 if value != nil { 792 t.Fatalf("value present at TS = %s", value.Timestamp) 793 } 794 795 // Read the latest version which will be the value written with the timestamp pushed. 796 value, _, err = MVCCGet(context.Background(), engine, testKey1, hlc.Timestamp{WallTime: 4}, 797 MVCCGetOptions{}) 798 if err != nil { 799 t.Fatal(err) 800 } 801 if value == nil { 802 t.Fatal("value doesn't exist") 803 } 804 if !bytes.Equal(value.RawBytes, value1.RawBytes) { 805 t.Errorf("expected %q; got %q", value1.RawBytes, value.RawBytes) 806 } 807 if expTS := (hlc.Timestamp{WallTime: 3, Logical: 1}); value.Timestamp != expTS { 808 t.Fatalf("timestamp was not pushed: %s, expected %s", value.Timestamp, expTS) 809 } 810 }) 811 } 812 } 813 814 func TestMVCCInlineWithTxn(t *testing.T) { 815 defer leaktest.AfterTest(t)() 816 817 ctx := context.Background() 818 for _, engineImpl := range mvccEngineImpls { 819 t.Run(engineImpl.name, func(t *testing.T) { 820 engine := engineImpl.create() 821 defer engine.Close() 822 823 // Put an inline value. 824 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{}, value1, nil); err != nil { 825 t.Fatal(err) 826 } 827 828 // Now verify inline get. 829 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{}, MVCCGetOptions{}) 830 if err != nil { 831 t.Fatal(err) 832 } 833 if !reflect.DeepEqual(value1, *value) { 834 t.Errorf("the inline value should be %v; got %v", value1, *value) 835 } 836 837 // Verify inline get with txn does still work (this will happen on a 838 // scan if the distributed sender is forced to wrap it in a txn). 839 if _, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{}, MVCCGetOptions{ 840 Txn: txn1, 841 }); err != nil { 842 t.Error(err) 843 } 844 845 // Verify inline put with txn is an error. 846 err = MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{}, value2, txn2) 847 if !testutils.IsError(err, "writes not allowed within transactions") { 848 t.Errorf("unexpected error: %+v", err) 849 } 850 }) 851 } 852 } 853 854 func TestMVCCDeleteMissingKey(t *testing.T) { 855 defer leaktest.AfterTest(t)() 856 857 ctx := context.Background() 858 for _, engineImpl := range mvccEngineImpls { 859 t.Run(engineImpl.name, func(t *testing.T) { 860 engine := engineImpl.create() 861 defer engine.Close() 862 863 if err := MVCCDelete(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, nil); err != nil { 864 t.Fatal(err) 865 } 866 // Verify nothing is written to the engine. 867 if val, err := engine.Get(mvccKey(testKey1)); err != nil || val != nil { 868 t.Fatalf("expected no mvcc metadata after delete of a missing key; got %q: %+v", val, err) 869 } 870 }) 871 } 872 } 873 874 func TestMVCCGetAndDeleteInTxn(t *testing.T) { 875 defer leaktest.AfterTest(t)() 876 877 ctx := context.Background() 878 879 for _, engineImpl := range mvccEngineImpls { 880 t.Run(engineImpl.name, func(t *testing.T) { 881 for _, impl := range mvccGetImpls { 882 t.Run(impl.name, func(t *testing.T) { 883 mvccGet := impl.fn 884 885 engine := engineImpl.create() 886 defer engine.Close() 887 888 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 889 txn.Sequence++ 890 if err := MVCCPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value1, txn); err != nil { 891 t.Fatal(err) 892 } 893 894 if value, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 2}, MVCCGetOptions{ 895 Txn: txn, 896 }); err != nil { 897 t.Fatal(err) 898 } else if value == nil { 899 t.Fatal("the value should not be empty") 900 } 901 902 txn.Sequence++ 903 txn.WriteTimestamp = hlc.Timestamp{WallTime: 3} 904 if err := MVCCDelete(ctx, engine, nil, testKey1, txn.ReadTimestamp, txn); err != nil { 905 t.Fatal(err) 906 } 907 908 // Read the latest version which should be deleted. 909 if value, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 4}, MVCCGetOptions{ 910 Txn: txn, 911 }); err != nil { 912 t.Fatal(err) 913 } else if value != nil { 914 t.Fatal("the value should be empty") 915 } 916 // Read the latest version with tombstone. 917 if value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 4}, MVCCGetOptions{ 918 Tombstones: true, 919 Txn: txn, 920 }); err != nil { 921 t.Fatal(err) 922 } else if value == nil || len(value.RawBytes) != 0 { 923 t.Fatalf("the value should be non-nil with empty RawBytes; got %+v", value) 924 } 925 926 // Read the old version which shouldn't exist, as within a 927 // transaction, we delete previous values. 928 if value, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 2}, MVCCGetOptions{}); err != nil { 929 t.Fatal(err) 930 } else if value != nil { 931 t.Fatalf("expected value nil, got: %s", value) 932 } 933 }) 934 } 935 }) 936 } 937 } 938 939 func TestMVCCGetWriteIntentError(t *testing.T) { 940 defer leaktest.AfterTest(t)() 941 942 ctx := context.Background() 943 944 for _, engineImpl := range mvccEngineImpls { 945 t.Run(engineImpl.name, func(t *testing.T) { 946 for _, impl := range mvccGetImpls { 947 t.Run(impl.name, func(t *testing.T) { 948 mvccGet := impl.fn 949 950 engine := engineImpl.create() 951 defer engine.Close() 952 953 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 954 t.Fatal(err) 955 } 956 957 if _, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{}); err == nil { 958 t.Fatal("cannot read the value of a write intent without TxnID") 959 } 960 961 if _, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{ 962 Txn: txn2, 963 }); err == nil { 964 t.Fatal("cannot read the value of a write intent from a different TxnID") 965 } 966 }) 967 } 968 }) 969 } 970 } 971 972 func mkVal(s string, ts hlc.Timestamp) roachpb.Value { 973 v := roachpb.MakeValueFromString(s) 974 v.Timestamp = ts 975 return v 976 } 977 978 func TestMVCCScanWriteIntentError(t *testing.T) { 979 defer leaktest.AfterTest(t)() 980 981 ctx := context.Background() 982 for _, engineImpl := range mvccEngineImpls { 983 t.Run(engineImpl.name, func(t *testing.T) { 984 engine := engineImpl.create() 985 defer engine.Close() 986 987 ts := []hlc.Timestamp{{Logical: 1}, {Logical: 2}, {Logical: 3}, {Logical: 4}, {Logical: 5}, {Logical: 6}} 988 989 txn1ts := makeTxn(*txn1, ts[2]) 990 txn2ts := makeTxn(*txn2, ts[5]) 991 992 fixtureKVs := []roachpb.KeyValue{ 993 {Key: testKey1, Value: mkVal("testValue1 pre", ts[0])}, 994 {Key: testKey4, Value: mkVal("testValue4 pre", ts[1])}, 995 {Key: testKey1, Value: mkVal("testValue1", ts[2])}, 996 {Key: testKey2, Value: mkVal("testValue2", ts[3])}, 997 {Key: testKey3, Value: mkVal("testValue3", ts[4])}, 998 {Key: testKey4, Value: mkVal("testValue4", ts[5])}, 999 } 1000 for i, kv := range fixtureKVs { 1001 var txn *roachpb.Transaction 1002 if i == 2 { 1003 txn = txn1ts 1004 } else if i == 5 { 1005 txn = txn2ts 1006 } 1007 v := *protoutil.Clone(&kv.Value).(*roachpb.Value) 1008 v.Timestamp = hlc.Timestamp{} 1009 if err := MVCCPut(ctx, engine, nil, kv.Key, kv.Value.Timestamp, v, txn); err != nil { 1010 t.Fatal(err) 1011 } 1012 } 1013 1014 scanCases := []struct { 1015 consistent bool 1016 txn *roachpb.Transaction 1017 expIntents []roachpb.Intent 1018 expValues []roachpb.KeyValue 1019 }{ 1020 { 1021 consistent: true, 1022 txn: nil, 1023 expIntents: []roachpb.Intent{ 1024 roachpb.MakeIntent(&txn1ts.TxnMeta, testKey1), 1025 roachpb.MakeIntent(&txn2ts.TxnMeta, testKey4), 1026 }, 1027 // would be []roachpb.KeyValue{fixtureKVs[3], fixtureKVs[4]} without WriteIntentError 1028 expValues: nil, 1029 }, 1030 { 1031 consistent: true, 1032 txn: txn1ts, 1033 expIntents: []roachpb.Intent{ 1034 roachpb.MakeIntent(&txn2ts.TxnMeta, testKey4), 1035 }, 1036 expValues: nil, // []roachpb.KeyValue{fixtureKVs[2], fixtureKVs[3], fixtureKVs[4]}, 1037 }, 1038 { 1039 consistent: true, 1040 txn: txn2ts, 1041 expIntents: []roachpb.Intent{ 1042 roachpb.MakeIntent(&txn1ts.TxnMeta, testKey1), 1043 }, 1044 expValues: nil, // []roachpb.KeyValue{fixtureKVs[3], fixtureKVs[4], fixtureKVs[5]}, 1045 }, 1046 { 1047 consistent: false, 1048 txn: nil, 1049 expIntents: []roachpb.Intent{ 1050 roachpb.MakeIntent(&txn1ts.TxnMeta, testKey1), 1051 roachpb.MakeIntent(&txn2ts.TxnMeta, testKey4), 1052 }, 1053 expValues: []roachpb.KeyValue{fixtureKVs[0], fixtureKVs[3], fixtureKVs[4], fixtureKVs[1]}, 1054 }, 1055 } 1056 1057 for i, scan := range scanCases { 1058 cStr := "inconsistent" 1059 if scan.consistent { 1060 cStr = "consistent" 1061 } 1062 res, err := MVCCScan(ctx, engine, testKey1, testKey4.Next(), 1063 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{Inconsistent: !scan.consistent, Txn: scan.txn}) 1064 var wiErr *roachpb.WriteIntentError 1065 _ = errors.As(err, &wiErr) 1066 if (err == nil) != (wiErr == nil) { 1067 t.Errorf("%s(%d): unexpected error: %+v", cStr, i, err) 1068 } 1069 1070 if wiErr == nil != !scan.consistent { 1071 t.Errorf("%s(%d): expected write intent error; got %s", cStr, i, err) 1072 continue 1073 } 1074 1075 intents := res.Intents 1076 kvs := res.KVs 1077 if len(intents) > 0 != !scan.consistent { 1078 t.Errorf("%s(%d): expected different intents slice; got %+v", cStr, i, intents) 1079 continue 1080 } 1081 1082 if scan.consistent { 1083 intents = wiErr.Intents 1084 } 1085 1086 if !reflect.DeepEqual(intents, scan.expIntents) { 1087 t.Fatalf("%s(%d): expected intents:\n%+v;\n got\n%+v", cStr, i, scan.expIntents, intents) 1088 } 1089 1090 if !reflect.DeepEqual(kvs, scan.expValues) { 1091 t.Errorf("%s(%d): expected values %+v; got %+v", cStr, i, scan.expValues, kvs) 1092 } 1093 } 1094 }) 1095 } 1096 } 1097 1098 // TestMVCCGetInconsistent verifies the behavior of get with 1099 // consistent set to false. 1100 func TestMVCCGetInconsistent(t *testing.T) { 1101 defer leaktest.AfterTest(t)() 1102 1103 ctx := context.Background() 1104 1105 for _, engineImpl := range mvccEngineImpls { 1106 t.Run(engineImpl.name, func(t *testing.T) { 1107 for _, impl := range mvccGetImpls { 1108 t.Run(impl.name, func(t *testing.T) { 1109 mvccGet := impl.fn 1110 1111 engine := engineImpl.create() 1112 defer engine.Close() 1113 1114 // Put two values to key 1, the latest with a txn. 1115 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 1116 t.Fatal(err) 1117 } 1118 txn1ts := makeTxn(*txn1, hlc.Timestamp{WallTime: 2}) 1119 if err := MVCCPut(ctx, engine, nil, testKey1, txn1ts.ReadTimestamp, value2, txn1ts); err != nil { 1120 t.Fatal(err) 1121 } 1122 1123 // A get with consistent=false should fail in a txn. 1124 if _, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{ 1125 Inconsistent: true, 1126 Txn: txn1, 1127 }); err == nil { 1128 t.Error("expected an error getting with consistent=false in txn") 1129 } 1130 1131 // Inconsistent get will fetch value1 for any timestamp. 1132 for _, ts := range []hlc.Timestamp{{WallTime: 1}, {WallTime: 2}} { 1133 val, intent, err := mvccGet(ctx, engine, testKey1, ts, MVCCGetOptions{Inconsistent: true}) 1134 if ts.Less(hlc.Timestamp{WallTime: 2}) { 1135 if err != nil { 1136 t.Fatal(err) 1137 } 1138 } else { 1139 if intent == nil || !intent.Key.Equal(testKey1) { 1140 t.Fatalf("expected %v, but got %v", testKey1, intent) 1141 } 1142 } 1143 if !bytes.Equal(val.RawBytes, value1.RawBytes) { 1144 t.Errorf("@%s expected %q; got %q", ts, value1.RawBytes, val.RawBytes) 1145 } 1146 } 1147 1148 // Write a single intent for key 2 and verify get returns empty. 1149 if err := MVCCPut(ctx, engine, nil, testKey2, txn2.ReadTimestamp, value1, txn2); err != nil { 1150 t.Fatal(err) 1151 } 1152 val, intent, err := mvccGet(ctx, engine, testKey2, hlc.Timestamp{WallTime: 2}, 1153 MVCCGetOptions{Inconsistent: true}) 1154 if intent == nil || !intent.Key.Equal(testKey2) { 1155 t.Fatal(err) 1156 } 1157 if val != nil { 1158 t.Errorf("expected empty val; got %+v", val) 1159 } 1160 }) 1161 } 1162 }) 1163 } 1164 } 1165 1166 // TestMVCCGetProtoInconsistent verifies the behavior of GetProto with 1167 // consistent set to false. 1168 func TestMVCCGetProtoInconsistent(t *testing.T) { 1169 defer leaktest.AfterTest(t)() 1170 1171 ctx := context.Background() 1172 for _, engineImpl := range mvccEngineImpls { 1173 t.Run(engineImpl.name, func(t *testing.T) { 1174 engine := engineImpl.create() 1175 defer engine.Close() 1176 1177 bytes1, err := protoutil.Marshal(&value1) 1178 if err != nil { 1179 t.Fatal(err) 1180 } 1181 bytes2, err := protoutil.Marshal(&value2) 1182 if err != nil { 1183 t.Fatal(err) 1184 } 1185 1186 v1 := roachpb.MakeValueFromBytes(bytes1) 1187 v2 := roachpb.MakeValueFromBytes(bytes2) 1188 1189 // Put two values to key 1, the latest with a txn. 1190 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, v1, nil); err != nil { 1191 t.Fatal(err) 1192 } 1193 txn1ts := makeTxn(*txn1, hlc.Timestamp{WallTime: 2}) 1194 if err := MVCCPut(ctx, engine, nil, testKey1, txn1ts.ReadTimestamp, v2, txn1ts); err != nil { 1195 t.Fatal(err) 1196 } 1197 1198 // An inconsistent get should fail in a txn. 1199 if _, err := MVCCGetProto(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, nil, MVCCGetOptions{ 1200 Inconsistent: true, 1201 Txn: txn1, 1202 }); err == nil { 1203 t.Error("expected an error getting inconsistently in txn") 1204 } else if errors.HasType(err, (*roachpb.WriteIntentError)(nil)) { 1205 t.Error("expected non-WriteIntentError with inconsistent read in txn") 1206 } 1207 1208 // Inconsistent get will fetch value1 for any timestamp. 1209 1210 for _, ts := range []hlc.Timestamp{{WallTime: 1}, {WallTime: 2}} { 1211 val := roachpb.Value{} 1212 found, err := MVCCGetProto(ctx, engine, testKey1, ts, &val, MVCCGetOptions{ 1213 Inconsistent: true, 1214 }) 1215 if ts.Less(hlc.Timestamp{WallTime: 2}) { 1216 if err != nil { 1217 t.Fatal(err) 1218 } 1219 } else if err != nil { 1220 t.Fatal(err) 1221 } 1222 if !found { 1223 t.Errorf("expected to find result with inconsistent read") 1224 } 1225 valBytes, err := val.GetBytes() 1226 if err != nil { 1227 t.Fatal(err) 1228 } 1229 if !bytes.Equal(valBytes, []byte("testValue1")) { 1230 t.Errorf("@%s expected %q; got %q", ts, []byte("value1"), valBytes) 1231 } 1232 } 1233 1234 { 1235 // Write a single intent for key 2 and verify get returns empty. 1236 if err := MVCCPut(ctx, engine, nil, testKey2, txn2.ReadTimestamp, v1, txn2); err != nil { 1237 t.Fatal(err) 1238 } 1239 val := roachpb.Value{} 1240 found, err := MVCCGetProto(ctx, engine, testKey2, hlc.Timestamp{WallTime: 2}, &val, MVCCGetOptions{ 1241 Inconsistent: true, 1242 }) 1243 if err != nil { 1244 t.Fatal(err) 1245 } 1246 if found { 1247 t.Errorf("expected no result; got %+v", val) 1248 } 1249 } 1250 1251 { 1252 // Write a malformed value (not an encoded MVCCKeyValue) and a 1253 // write intent to key 3; the parse error is returned instead of the 1254 // write intent. 1255 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 1}, value3, nil); err != nil { 1256 t.Fatal(err) 1257 } 1258 if err := MVCCPut(ctx, engine, nil, testKey3, txn1ts.ReadTimestamp, v2, txn1ts); err != nil { 1259 t.Fatal(err) 1260 } 1261 val := roachpb.Value{} 1262 found, err := MVCCGetProto(ctx, engine, testKey3, hlc.Timestamp{WallTime: 1}, &val, MVCCGetOptions{ 1263 Inconsistent: true, 1264 }) 1265 if err == nil { 1266 t.Errorf("expected error reading malformed data") 1267 } else if !strings.HasPrefix(err.Error(), "proto: ") { 1268 t.Errorf("expected proto error, got %s", err) 1269 } 1270 if !found { 1271 t.Errorf("expected to find result with malformed data") 1272 } 1273 } 1274 }) 1275 } 1276 } 1277 1278 // Regression test for #28205: MVCCGet and MVCCScan, FindSplitKey, and 1279 // ComputeStats need to invalidate the cached iterator data. 1280 func TestMVCCInvalidateIterator(t *testing.T) { 1281 defer leaktest.AfterTest(t)() 1282 1283 for _, which := range []string{"get", "scan", "findSplitKey", "computeStats"} { 1284 t.Run(which, func(t *testing.T) { 1285 for _, engineImpl := range mvccEngineImpls { 1286 t.Run(engineImpl.name, func(t *testing.T) { 1287 engine := engineImpl.create() 1288 defer engine.Close() 1289 1290 ctx := context.Background() 1291 ts1 := hlc.Timestamp{WallTime: 1} 1292 ts2 := hlc.Timestamp{WallTime: 2} 1293 1294 key := roachpb.Key("a") 1295 if err := MVCCPut(ctx, engine, nil, key, ts1, value1, nil); err != nil { 1296 t.Fatal(err) 1297 } 1298 1299 var iterOptions IterOptions 1300 switch which { 1301 case "get": 1302 iterOptions.Prefix = true 1303 case "scan", "findSplitKey", "computeStats": 1304 iterOptions.UpperBound = roachpb.KeyMax 1305 } 1306 1307 // Use a batch which internally caches the iterator. 1308 batch := engine.NewBatch() 1309 defer batch.Close() 1310 1311 { 1312 // Seek the iter to a valid position. 1313 iter := batch.NewIterator(iterOptions) 1314 iter.SeekGE(MakeMVCCMetadataKey(key)) 1315 iter.Close() 1316 } 1317 1318 var err error 1319 switch which { 1320 case "get": 1321 _, _, err = MVCCGet(ctx, batch, key, ts2, MVCCGetOptions{}) 1322 case "scan": 1323 _, err = MVCCScan(ctx, batch, key, roachpb.KeyMax, ts2, MVCCScanOptions{}) 1324 case "findSplitKey": 1325 _, err = MVCCFindSplitKey(ctx, batch, roachpb.RKeyMin, roachpb.RKeyMax, 64<<20) 1326 case "computeStats": 1327 iter := batch.NewIterator(iterOptions) 1328 _, err = iter.ComputeStats(roachpb.KeyMin, roachpb.KeyMax, 0) 1329 iter.Close() 1330 } 1331 if err != nil { 1332 t.Fatal(err) 1333 } 1334 1335 // Verify that the iter is invalid. 1336 iter := batch.NewIterator(iterOptions) 1337 defer iter.Close() 1338 if ok, _ := iter.Valid(); ok { 1339 t.Fatalf("iterator should not be valid") 1340 } 1341 }) 1342 } 1343 }) 1344 } 1345 } 1346 1347 func TestMVCCPutAfterBatchIterCreate(t *testing.T) { 1348 defer leaktest.AfterTest(t)() 1349 1350 for _, engineImpl := range mvccEngineImpls { 1351 t.Run(engineImpl.name, func(t *testing.T) { 1352 engine := engineImpl.create() 1353 defer engine.Close() 1354 1355 err := engine.Put(MVCCKey{testKey1, hlc.Timestamp{WallTime: 5}}, []byte("foobar")) 1356 if err != nil { 1357 t.Fatal(err) 1358 } 1359 err = engine.Put(MVCCKey{testKey2, hlc.Timestamp{WallTime: 5}}, []byte("foobar")) 1360 if err != nil { 1361 t.Fatal(err) 1362 } 1363 err = engine.Put(MVCCKey{testKey2, hlc.Timestamp{WallTime: 3}}, []byte("foobar")) 1364 if err != nil { 1365 t.Fatal(err) 1366 } 1367 err = engine.Put(MVCCKey{testKey3, hlc.Timestamp{WallTime: 5}}, []byte("foobar")) 1368 if err != nil { 1369 t.Fatal(err) 1370 } 1371 err = engine.Put(MVCCKey{testKey4, hlc.Timestamp{WallTime: 5}}, []byte("foobar")) 1372 if err != nil { 1373 t.Fatal(err) 1374 } 1375 1376 batch := engine.NewBatch() 1377 defer batch.Close() 1378 txn := &roachpb.Transaction{ 1379 TxnMeta: enginepb.TxnMeta{ 1380 WriteTimestamp: hlc.Timestamp{WallTime: 10}, 1381 }, 1382 Name: "test", 1383 Status: roachpb.PENDING, 1384 DeprecatedOrigTimestamp: hlc.Timestamp{WallTime: 10}, 1385 ReadTimestamp: hlc.Timestamp{WallTime: 10}, 1386 MaxTimestamp: hlc.Timestamp{WallTime: 10}, 1387 } 1388 iter := batch.NewIterator(IterOptions{ 1389 LowerBound: testKey1, 1390 UpperBound: testKey5, 1391 }) 1392 defer iter.Close() 1393 iter.SeekGE(MVCCKey{testKey1, hlc.Timestamp{WallTime: 5}}) 1394 iter.Next() // key2/5 1395 1396 // Lay down an intent on key3, which will go at key3/0 and sort before key3/5. 1397 err = MVCCDelete(context.Background(), batch, nil, testKey3, txn.WriteTimestamp, txn) 1398 if err != nil { 1399 t.Fatal(err) 1400 } 1401 // Should Next() from key2/5 to key2/3 first, then Seek to key3, and see 1402 // the intent. 1403 iter.NextKey() 1404 1405 if iter.UnsafeKey().IsValue() { 1406 t.Fatalf("expected iterator to land on an intent, got a value: %v", iter.UnsafeKey()) 1407 } 1408 }) 1409 } 1410 } 1411 1412 func mvccScanTest(ctx context.Context, t *testing.T, engine Engine) { 1413 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 1414 t.Fatal(err) 1415 } 1416 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 2}, value4, nil); err != nil { 1417 t.Fatal(err) 1418 } 1419 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 1420 t.Fatal(err) 1421 } 1422 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 3}, value3, nil); err != nil { 1423 t.Fatal(err) 1424 } 1425 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 1}, value3, nil); err != nil { 1426 t.Fatal(err) 1427 } 1428 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 4}, value2, nil); err != nil { 1429 t.Fatal(err) 1430 } 1431 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 1432 t.Fatal(err) 1433 } 1434 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 5}, value1, nil); err != nil { 1435 t.Fatal(err) 1436 } 1437 1438 res, err := MVCCScan(ctx, engine, testKey2, testKey4, 1439 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{}) 1440 if err != nil { 1441 t.Fatal(err) 1442 } 1443 kvs := res.KVs 1444 resumeSpan := res.ResumeSpan 1445 if len(kvs) != 2 || 1446 !bytes.Equal(kvs[0].Key, testKey2) || 1447 !bytes.Equal(kvs[1].Key, testKey3) || 1448 !bytes.Equal(kvs[0].Value.RawBytes, value2.RawBytes) || 1449 !bytes.Equal(kvs[1].Value.RawBytes, value3.RawBytes) { 1450 t.Fatal("the value should not be empty") 1451 } 1452 if resumeSpan != nil { 1453 t.Fatalf("resumeSpan = %+v", resumeSpan) 1454 } 1455 1456 res, err = MVCCScan(ctx, engine, testKey2, testKey4, 1457 hlc.Timestamp{WallTime: 4}, MVCCScanOptions{}) 1458 if err != nil { 1459 t.Fatal(err) 1460 } 1461 kvs = res.KVs 1462 resumeSpan = res.ResumeSpan 1463 if len(kvs) != 2 || 1464 !bytes.Equal(kvs[0].Key, testKey2) || 1465 !bytes.Equal(kvs[1].Key, testKey3) || 1466 !bytes.Equal(kvs[0].Value.RawBytes, value3.RawBytes) || 1467 !bytes.Equal(kvs[1].Value.RawBytes, value2.RawBytes) { 1468 t.Fatal("the value should not be empty") 1469 } 1470 if resumeSpan != nil { 1471 t.Fatalf("resumeSpan = %+v", resumeSpan) 1472 } 1473 1474 res, err = MVCCScan( 1475 ctx, engine, testKey4, keyMax, hlc.Timestamp{WallTime: 1}, MVCCScanOptions{}, 1476 ) 1477 if err != nil { 1478 t.Fatal(err) 1479 } 1480 kvs = res.KVs 1481 resumeSpan = res.ResumeSpan 1482 if len(kvs) != 1 || 1483 !bytes.Equal(kvs[0].Key, testKey4) || 1484 !bytes.Equal(kvs[0].Value.RawBytes, value4.RawBytes) { 1485 t.Fatal("the value should not be empty") 1486 } 1487 if resumeSpan != nil { 1488 t.Fatalf("resumeSpan = %+v", resumeSpan) 1489 } 1490 1491 if _, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{ 1492 Txn: txn2, 1493 }); err != nil { 1494 t.Fatal(err) 1495 } 1496 res, err = MVCCScan(ctx, engine, keyMin, testKey2, 1497 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{}) 1498 if err != nil { 1499 t.Fatal(err) 1500 } 1501 kvs = res.KVs 1502 if len(kvs) != 1 || 1503 !bytes.Equal(kvs[0].Key, testKey1) || 1504 !bytes.Equal(kvs[0].Value.RawBytes, value1.RawBytes) { 1505 t.Fatal("the value should not be empty") 1506 } 1507 } 1508 1509 func TestMVCCScan(t *testing.T) { 1510 defer leaktest.AfterTest(t)() 1511 1512 ctx := context.Background() 1513 for _, engineImpl := range mvccEngineImpls { 1514 t.Run(engineImpl.name, func(t *testing.T) { 1515 engine := engineImpl.create() 1516 defer engine.Close() 1517 1518 mvccScanTest(ctx, t, engine) 1519 }) 1520 } 1521 } 1522 1523 func TestMVCCScanMaxNum(t *testing.T) { 1524 defer leaktest.AfterTest(t)() 1525 1526 ctx := context.Background() 1527 for _, engineImpl := range mvccEngineImpls { 1528 t.Run(engineImpl.name, func(t *testing.T) { 1529 engine := engineImpl.create() 1530 defer engine.Close() 1531 1532 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 1533 t.Fatal(err) 1534 } 1535 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 1536 t.Fatal(err) 1537 } 1538 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 1}, value3, nil); err != nil { 1539 t.Fatal(err) 1540 } 1541 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 1542 t.Fatal(err) 1543 } 1544 if err := MVCCPut(ctx, engine, nil, testKey6, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 1545 t.Fatal(err) 1546 } 1547 1548 res, err := MVCCScan(ctx, engine, testKey2, testKey4, 1549 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{MaxKeys: 1}) 1550 if err != nil { 1551 t.Fatal(err) 1552 } 1553 if len(res.KVs) != 1 || 1554 !bytes.Equal(res.KVs[0].Key, testKey2) || 1555 !bytes.Equal(res.KVs[0].Value.RawBytes, value2.RawBytes) { 1556 t.Fatal("the value should not be empty") 1557 } 1558 if expected := (roachpb.Span{Key: testKey3, EndKey: testKey4}); !res.ResumeSpan.EqualValue(expected) { 1559 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, res.ResumeSpan) 1560 } 1561 1562 res, err = MVCCScan(ctx, engine, testKey2, testKey4, 1563 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{MaxKeys: -1}) 1564 if err != nil { 1565 t.Fatal(err) 1566 } 1567 if len(res.KVs) != 0 { 1568 t.Fatal("the value should be empty") 1569 } 1570 if expected := (roachpb.Span{Key: testKey2, EndKey: testKey4}); !res.ResumeSpan.EqualValue(expected) { 1571 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, res.ResumeSpan) 1572 } 1573 1574 // Note: testKey6, though not scanned directly, is important in testing that 1575 // the computed resume span does not extend beyond the upper bound of a scan. 1576 res, err = MVCCScan(ctx, engine, testKey4, testKey5, 1577 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{MaxKeys: 1}) 1578 if err != nil { 1579 t.Fatal(err) 1580 } 1581 if len(res.KVs) != 1 { 1582 t.Fatalf("expected 1 key but got %d", len(res.KVs)) 1583 } 1584 if res.ResumeSpan != nil { 1585 t.Fatalf("resumeSpan = %+v", res.ResumeSpan) 1586 } 1587 1588 res, err = MVCCScan(ctx, engine, testKey5, testKey6.Next(), 1589 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{Reverse: true, MaxKeys: 1}) 1590 if err != nil { 1591 t.Fatal(err) 1592 } 1593 if len(res.KVs) != 1 { 1594 t.Fatalf("expected 1 key but got %d", len(res.KVs)) 1595 } 1596 if res.ResumeSpan != nil { 1597 t.Fatalf("resumeSpan = %+v", res.ResumeSpan) 1598 } 1599 }) 1600 } 1601 } 1602 1603 func TestMVCCScanWithKeyPrefix(t *testing.T) { 1604 defer leaktest.AfterTest(t)() 1605 1606 ctx := context.Background() 1607 for _, engineImpl := range mvccEngineImpls { 1608 t.Run(engineImpl.name, func(t *testing.T) { 1609 engine := engineImpl.create() 1610 defer engine.Close() 1611 1612 // Let's say you have: 1613 // a 1614 // a<T=2> 1615 // a<T=1> 1616 // aa 1617 // aa<T=3> 1618 // aa<T=2> 1619 // b 1620 // b<T=5> 1621 // In this case, if we scan from "a"-"b", we wish to skip 1622 // a<T=2> and a<T=1> and find "aa'. 1623 if err := MVCCPut(ctx, engine, nil, roachpb.Key("/a"), hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 1624 t.Fatal(err) 1625 } 1626 if err := MVCCPut(ctx, engine, nil, roachpb.Key("/a"), hlc.Timestamp{WallTime: 2}, value2, nil); err != nil { 1627 t.Fatal(err) 1628 } 1629 if err := MVCCPut(ctx, engine, nil, roachpb.Key("/aa"), hlc.Timestamp{WallTime: 2}, value2, nil); err != nil { 1630 t.Fatal(err) 1631 } 1632 if err := MVCCPut(ctx, engine, nil, roachpb.Key("/aa"), hlc.Timestamp{WallTime: 3}, value3, nil); err != nil { 1633 t.Fatal(err) 1634 } 1635 if err := MVCCPut(ctx, engine, nil, roachpb.Key("/b"), hlc.Timestamp{WallTime: 1}, value3, nil); err != nil { 1636 t.Fatal(err) 1637 } 1638 1639 res, err := MVCCScan(ctx, engine, roachpb.Key("/a"), roachpb.Key("/b"), 1640 hlc.Timestamp{WallTime: 2}, MVCCScanOptions{}) 1641 if err != nil { 1642 t.Fatal(err) 1643 } 1644 if len(res.KVs) != 2 || 1645 !bytes.Equal(res.KVs[0].Key, roachpb.Key("/a")) || 1646 !bytes.Equal(res.KVs[1].Key, roachpb.Key("/aa")) || 1647 !bytes.Equal(res.KVs[0].Value.RawBytes, value2.RawBytes) || 1648 !bytes.Equal(res.KVs[1].Value.RawBytes, value2.RawBytes) { 1649 t.Fatal("the value should not be empty") 1650 } 1651 }) 1652 } 1653 } 1654 1655 func TestMVCCScanInTxn(t *testing.T) { 1656 defer leaktest.AfterTest(t)() 1657 1658 ctx := context.Background() 1659 for _, engineImpl := range mvccEngineImpls { 1660 t.Run(engineImpl.name, func(t *testing.T) { 1661 engine := engineImpl.create() 1662 defer engine.Close() 1663 1664 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 1665 t.Fatal(err) 1666 } 1667 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 1668 t.Fatal(err) 1669 } 1670 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 1671 if err := MVCCPut(ctx, engine, nil, testKey3, txn.ReadTimestamp, value3, txn); err != nil { 1672 t.Fatal(err) 1673 } 1674 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 1675 t.Fatal(err) 1676 } 1677 1678 res, err := MVCCScan(ctx, engine, testKey2, testKey4, 1679 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{Txn: txn1}) 1680 if err != nil { 1681 t.Fatal(err) 1682 } 1683 if len(res.KVs) != 2 || 1684 !bytes.Equal(res.KVs[0].Key, testKey2) || 1685 !bytes.Equal(res.KVs[1].Key, testKey3) || 1686 !bytes.Equal(res.KVs[0].Value.RawBytes, value2.RawBytes) || 1687 !bytes.Equal(res.KVs[1].Value.RawBytes, value3.RawBytes) { 1688 t.Fatal("the value should not be empty") 1689 } 1690 1691 if _, err := MVCCScan( 1692 ctx, engine, testKey2, testKey4, hlc.Timestamp{WallTime: 1}, MVCCScanOptions{}, 1693 ); err == nil { 1694 t.Fatal("expected error on uncommitted write intent") 1695 } 1696 }) 1697 } 1698 } 1699 1700 // TestMVCCScanInconsistent writes several values, some as intents and 1701 // verifies that the scan sees only the committed versions. 1702 func TestMVCCScanInconsistent(t *testing.T) { 1703 defer leaktest.AfterTest(t)() 1704 1705 ctx := context.Background() 1706 for _, engineImpl := range mvccEngineImpls { 1707 t.Run(engineImpl.name, func(t *testing.T) { 1708 engine := engineImpl.create() 1709 defer engine.Close() 1710 1711 // A scan with consistent=false should fail in a txn. 1712 if _, err := MVCCScan( 1713 ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 1}, 1714 MVCCScanOptions{Inconsistent: true, Txn: txn1}, 1715 ); err == nil { 1716 t.Error("expected an error scanning with consistent=false in txn") 1717 } 1718 1719 ts1 := hlc.Timestamp{WallTime: 1} 1720 ts2 := hlc.Timestamp{WallTime: 2} 1721 ts3 := hlc.Timestamp{WallTime: 3} 1722 ts4 := hlc.Timestamp{WallTime: 4} 1723 ts5 := hlc.Timestamp{WallTime: 5} 1724 ts6 := hlc.Timestamp{WallTime: 6} 1725 if err := MVCCPut(ctx, engine, nil, testKey1, ts1, value1, nil); err != nil { 1726 t.Fatal(err) 1727 } 1728 txn1ts2 := makeTxn(*txn1, ts2) 1729 if err := MVCCPut(ctx, engine, nil, testKey1, txn1ts2.ReadTimestamp, value2, txn1ts2); err != nil { 1730 t.Fatal(err) 1731 } 1732 if err := MVCCPut(ctx, engine, nil, testKey2, ts3, value1, nil); err != nil { 1733 t.Fatal(err) 1734 } 1735 if err := MVCCPut(ctx, engine, nil, testKey2, ts4, value2, nil); err != nil { 1736 t.Fatal(err) 1737 } 1738 txn2ts5 := makeTxn(*txn2, ts5) 1739 if err := MVCCPut(ctx, engine, nil, testKey3, txn2ts5.ReadTimestamp, value3, txn2ts5); err != nil { 1740 t.Fatal(err) 1741 } 1742 if err := MVCCPut(ctx, engine, nil, testKey4, ts6, value4, nil); err != nil { 1743 t.Fatal(err) 1744 } 1745 1746 expIntents := []roachpb.Intent{ 1747 roachpb.MakeIntent(&txn1ts2.TxnMeta, testKey1), 1748 roachpb.MakeIntent(&txn2ts5.TxnMeta, testKey3), 1749 } 1750 res, err := MVCCScan( 1751 ctx, engine, testKey1, testKey4.Next(), hlc.Timestamp{WallTime: 7}, 1752 MVCCScanOptions{Inconsistent: true}, 1753 ) 1754 if err != nil { 1755 t.Fatal(err) 1756 } 1757 if !reflect.DeepEqual(res.Intents, expIntents) { 1758 t.Fatalf("expected %v, but found %v", expIntents, res.Intents) 1759 } 1760 1761 makeTimestampedValue := func(v roachpb.Value, ts hlc.Timestamp) roachpb.Value { 1762 v.Timestamp = ts 1763 return v 1764 } 1765 1766 expKVs := []roachpb.KeyValue{ 1767 {Key: testKey1, Value: makeTimestampedValue(value1, ts1)}, 1768 {Key: testKey2, Value: makeTimestampedValue(value2, ts4)}, 1769 {Key: testKey4, Value: makeTimestampedValue(value4, ts6)}, 1770 } 1771 if !reflect.DeepEqual(res.KVs, expKVs) { 1772 t.Errorf("expected key values equal %v != %v", res.KVs, expKVs) 1773 } 1774 1775 // Now try a scan at a historical timestamp. 1776 expIntents = expIntents[:1] 1777 res, err = MVCCScan(ctx, engine, testKey1, testKey4.Next(), 1778 hlc.Timestamp{WallTime: 3}, MVCCScanOptions{Inconsistent: true}) 1779 if !reflect.DeepEqual(res.Intents, expIntents) { 1780 t.Fatal(err) 1781 } 1782 expKVs = []roachpb.KeyValue{ 1783 {Key: testKey1, Value: makeTimestampedValue(value1, ts1)}, 1784 {Key: testKey2, Value: makeTimestampedValue(value1, ts3)}, 1785 } 1786 if !reflect.DeepEqual(res.KVs, expKVs) { 1787 t.Errorf("expected key values equal %v != %v", res.Intents, expKVs) 1788 } 1789 }) 1790 } 1791 } 1792 1793 func TestMVCCDeleteRange(t *testing.T) { 1794 defer leaktest.AfterTest(t)() 1795 1796 ctx := context.Background() 1797 for _, engineImpl := range mvccEngineImpls { 1798 t.Run(engineImpl.name, func(t *testing.T) { 1799 engine := engineImpl.create() 1800 defer engine.Close() 1801 1802 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 1803 t.Fatal(err) 1804 } 1805 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 1806 t.Fatal(err) 1807 } 1808 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 1}, value3, nil); err != nil { 1809 t.Fatal(err) 1810 } 1811 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 1812 t.Fatal(err) 1813 } 1814 if err := MVCCPut(ctx, engine, nil, testKey5, hlc.Timestamp{WallTime: 1}, value5, nil); err != nil { 1815 t.Fatal(err) 1816 } 1817 if err := MVCCPut(ctx, engine, nil, testKey6, hlc.Timestamp{WallTime: 1}, value6, nil); err != nil { 1818 t.Fatal(err) 1819 } 1820 1821 // Attempt to delete two keys. 1822 deleted, resumeSpan, num, err := MVCCDeleteRange( 1823 ctx, engine, nil, testKey2, testKey6, 2, hlc.Timestamp{WallTime: 2}, nil, false, 1824 ) 1825 if err != nil { 1826 t.Fatal(err) 1827 } 1828 if deleted != nil { 1829 t.Fatal("the value should be empty") 1830 } 1831 if num != 2 { 1832 t.Fatalf("incorrect number of keys deleted: %d", num) 1833 } 1834 if expected := (roachpb.Span{Key: testKey4, EndKey: testKey6}); !resumeSpan.EqualValue(expected) { 1835 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, resumeSpan) 1836 } 1837 res, _ := MVCCScan(ctx, engine, keyMin, keyMax, 1838 hlc.Timestamp{WallTime: 2}, MVCCScanOptions{}) 1839 if len(res.KVs) != 4 || 1840 !bytes.Equal(res.KVs[0].Key, testKey1) || 1841 !bytes.Equal(res.KVs[1].Key, testKey4) || 1842 !bytes.Equal(res.KVs[2].Key, testKey5) || 1843 !bytes.Equal(res.KVs[3].Key, testKey6) || 1844 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) || 1845 !bytes.Equal(res.KVs[1].Value.RawBytes, value4.RawBytes) || 1846 !bytes.Equal(res.KVs[2].Value.RawBytes, value5.RawBytes) || 1847 !bytes.Equal(res.KVs[3].Value.RawBytes, value6.RawBytes) { 1848 t.Fatal("the value should not be empty") 1849 } 1850 1851 // Try again, but with tombstones set to true to fetch the deleted keys as well. 1852 kvs := []roachpb.KeyValue{} 1853 if _, err = MVCCIterate( 1854 ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, MVCCScanOptions{Tombstones: true}, 1855 func(kv roachpb.KeyValue) (bool, error) { 1856 kvs = append(kvs, kv) 1857 return false, nil 1858 }, 1859 ); err != nil { 1860 t.Fatal(err) 1861 } 1862 if len(kvs) != 6 || 1863 !bytes.Equal(kvs[0].Key, testKey1) || 1864 !bytes.Equal(kvs[1].Key, testKey2) || 1865 !bytes.Equal(kvs[2].Key, testKey3) || 1866 !bytes.Equal(kvs[3].Key, testKey4) || 1867 !bytes.Equal(kvs[4].Key, testKey5) || 1868 !bytes.Equal(kvs[5].Key, testKey6) || 1869 !bytes.Equal(kvs[0].Value.RawBytes, value1.RawBytes) || 1870 !bytes.Equal(kvs[1].Value.RawBytes, nil) || 1871 !bytes.Equal(kvs[2].Value.RawBytes, nil) || 1872 !bytes.Equal(kvs[3].Value.RawBytes, value4.RawBytes) || 1873 !bytes.Equal(kvs[4].Value.RawBytes, value5.RawBytes) || 1874 !bytes.Equal(kvs[5].Value.RawBytes, value6.RawBytes) { 1875 t.Fatal("the value should not be empty") 1876 } 1877 1878 // Attempt to delete no keys. 1879 deleted, resumeSpan, num, err = MVCCDeleteRange( 1880 ctx, engine, nil, testKey2, testKey6, -1, hlc.Timestamp{WallTime: 2}, nil, false) 1881 if err != nil { 1882 t.Fatal(err) 1883 } 1884 if deleted != nil { 1885 t.Fatal("the value should be empty") 1886 } 1887 if num != 0 { 1888 t.Fatalf("incorrect number of keys deleted: %d", num) 1889 } 1890 if expected := (roachpb.Span{Key: testKey2, EndKey: testKey6}); !resumeSpan.EqualValue(expected) { 1891 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, resumeSpan) 1892 } 1893 res, _ = MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 1894 MVCCScanOptions{}) 1895 if len(res.KVs) != 4 || 1896 !bytes.Equal(res.KVs[0].Key, testKey1) || 1897 !bytes.Equal(res.KVs[1].Key, testKey4) || 1898 !bytes.Equal(res.KVs[2].Key, testKey5) || 1899 !bytes.Equal(res.KVs[3].Key, testKey6) || 1900 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) || 1901 !bytes.Equal(res.KVs[1].Value.RawBytes, value4.RawBytes) || 1902 !bytes.Equal(res.KVs[2].Value.RawBytes, value5.RawBytes) || 1903 !bytes.Equal(res.KVs[3].Value.RawBytes, value6.RawBytes) { 1904 t.Fatal("the value should not be empty") 1905 } 1906 1907 deleted, resumeSpan, num, err = MVCCDeleteRange( 1908 ctx, engine, nil, testKey4, keyMax, 0, hlc.Timestamp{WallTime: 2}, nil, false) 1909 if err != nil { 1910 t.Fatal(err) 1911 } 1912 if deleted != nil { 1913 t.Fatal("the value should be empty") 1914 } 1915 if num != 3 { 1916 t.Fatalf("incorrect number of keys deleted: %d", num) 1917 } 1918 if resumeSpan != nil { 1919 t.Fatalf("wrong resume key: expected nil, found %v", resumeSpan) 1920 } 1921 res, err = MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 1922 MVCCScanOptions{}) 1923 if err != nil { 1924 t.Fatal(err) 1925 } 1926 if len(res.KVs) != 1 || 1927 !bytes.Equal(res.KVs[0].Key, testKey1) || 1928 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) { 1929 t.Fatalf("the value should not be empty: %+v", res.KVs) 1930 } 1931 1932 deleted, resumeSpan, num, err = MVCCDeleteRange( 1933 ctx, engine, nil, keyMin, testKey2, 0, hlc.Timestamp{WallTime: 2}, nil, false) 1934 if err != nil { 1935 t.Fatal(err) 1936 } 1937 if deleted != nil { 1938 t.Fatal("the value should not be empty") 1939 } 1940 if num != 1 { 1941 t.Fatalf("incorrect number of keys deleted: %d", num) 1942 } 1943 if resumeSpan != nil { 1944 t.Fatalf("wrong resume key: expected nil, found %v", resumeSpan) 1945 } 1946 res, _ = MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 1947 MVCCScanOptions{}) 1948 if err != nil { 1949 t.Fatal(err) 1950 } 1951 if len(res.KVs) != 0 { 1952 t.Fatal("the value should be empty") 1953 } 1954 }) 1955 } 1956 } 1957 1958 func TestMVCCDeleteRangeReturnKeys(t *testing.T) { 1959 defer leaktest.AfterTest(t)() 1960 1961 ctx := context.Background() 1962 for _, engineImpl := range mvccEngineImpls { 1963 t.Run(engineImpl.name, func(t *testing.T) { 1964 engine := engineImpl.create() 1965 defer engine.Close() 1966 1967 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 1968 t.Fatal(err) 1969 } 1970 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 1971 t.Fatal(err) 1972 } 1973 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 1}, value3, nil); err != nil { 1974 t.Fatal(err) 1975 } 1976 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 1977 t.Fatal(err) 1978 } 1979 if err := MVCCPut(ctx, engine, nil, testKey5, hlc.Timestamp{WallTime: 1}, value5, nil); err != nil { 1980 t.Fatal(err) 1981 } 1982 if err := MVCCPut(ctx, engine, nil, testKey6, hlc.Timestamp{WallTime: 1}, value6, nil); err != nil { 1983 t.Fatal(err) 1984 } 1985 1986 // Attempt to delete two keys. 1987 deleted, resumeSpan, num, err := MVCCDeleteRange( 1988 ctx, engine, nil, testKey2, testKey6, 2, hlc.Timestamp{WallTime: 2}, nil, true) 1989 if err != nil { 1990 t.Fatal(err) 1991 } 1992 if len(deleted) != 2 { 1993 t.Fatal("the value should not be empty") 1994 } 1995 if num != 2 { 1996 t.Fatalf("incorrect number of keys deleted: %d", num) 1997 } 1998 if expected, actual := testKey2, deleted[0]; !expected.Equal(actual) { 1999 t.Fatalf("wrong key deleted: expected %v found %v", expected, actual) 2000 } 2001 if expected, actual := testKey3, deleted[1]; !expected.Equal(actual) { 2002 t.Fatalf("wrong key deleted: expected %v found %v", expected, actual) 2003 } 2004 if expected := (roachpb.Span{Key: testKey4, EndKey: testKey6}); !resumeSpan.EqualValue(expected) { 2005 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, resumeSpan) 2006 } 2007 res, _ := MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 2008 MVCCScanOptions{}) 2009 if len(res.KVs) != 4 || 2010 !bytes.Equal(res.KVs[0].Key, testKey1) || 2011 !bytes.Equal(res.KVs[1].Key, testKey4) || 2012 !bytes.Equal(res.KVs[2].Key, testKey5) || 2013 !bytes.Equal(res.KVs[3].Key, testKey6) || 2014 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) || 2015 !bytes.Equal(res.KVs[1].Value.RawBytes, value4.RawBytes) || 2016 !bytes.Equal(res.KVs[2].Value.RawBytes, value5.RawBytes) || 2017 !bytes.Equal(res.KVs[3].Value.RawBytes, value6.RawBytes) { 2018 t.Fatal("the value should not be empty") 2019 } 2020 2021 // Attempt to delete no keys. 2022 deleted, resumeSpan, num, err = MVCCDeleteRange( 2023 ctx, engine, nil, testKey2, testKey6, -1, hlc.Timestamp{WallTime: 2}, nil, true) 2024 if err != nil { 2025 t.Fatal(err) 2026 } 2027 if deleted != nil { 2028 t.Fatalf("the value should be empty: %s", deleted) 2029 } 2030 if num != 0 { 2031 t.Fatalf("incorrect number of keys deleted: %d", num) 2032 } 2033 if expected := (roachpb.Span{Key: testKey2, EndKey: testKey6}); !resumeSpan.EqualValue(expected) { 2034 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, resumeSpan) 2035 } 2036 res, _ = MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 2037 MVCCScanOptions{}) 2038 if len(res.KVs) != 4 || 2039 !bytes.Equal(res.KVs[0].Key, testKey1) || 2040 !bytes.Equal(res.KVs[1].Key, testKey4) || 2041 !bytes.Equal(res.KVs[2].Key, testKey5) || 2042 !bytes.Equal(res.KVs[3].Key, testKey6) || 2043 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) || 2044 !bytes.Equal(res.KVs[1].Value.RawBytes, value4.RawBytes) || 2045 !bytes.Equal(res.KVs[2].Value.RawBytes, value5.RawBytes) || 2046 !bytes.Equal(res.KVs[3].Value.RawBytes, value6.RawBytes) { 2047 t.Fatal("the value should not be empty") 2048 } 2049 2050 deleted, resumeSpan, num, err = MVCCDeleteRange( 2051 ctx, engine, nil, testKey4, keyMax, math.MaxInt64, hlc.Timestamp{WallTime: 2}, nil, true) 2052 if err != nil { 2053 t.Fatal(err) 2054 } 2055 if len(deleted) != 3 { 2056 t.Fatal("the value should not be empty") 2057 } 2058 if num != 3 { 2059 t.Fatalf("incorrect number of keys deleted: %d", num) 2060 } 2061 if expected, actual := testKey4, deleted[0]; !expected.Equal(actual) { 2062 t.Fatalf("wrong key deleted: expected %v found %v", expected, actual) 2063 } 2064 if expected, actual := testKey5, deleted[1]; !expected.Equal(actual) { 2065 t.Fatalf("wrong key deleted: expected %v found %v", expected, actual) 2066 } 2067 if expected, actual := testKey6, deleted[2]; !expected.Equal(actual) { 2068 t.Fatalf("wrong key deleted: expected %v found %v", expected, actual) 2069 } 2070 if resumeSpan != nil { 2071 t.Fatalf("wrong resume key: expected nil, found %v", resumeSpan) 2072 } 2073 res, _ = MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 2074 MVCCScanOptions{}) 2075 if len(res.KVs) != 1 || 2076 !bytes.Equal(res.KVs[0].Key, testKey1) || 2077 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) { 2078 t.Fatal("the value should not be empty") 2079 } 2080 2081 deleted, resumeSpan, num, err = MVCCDeleteRange( 2082 ctx, engine, nil, keyMin, testKey2, math.MaxInt64, hlc.Timestamp{WallTime: 2}, nil, true) 2083 if err != nil { 2084 t.Fatal(err) 2085 } 2086 if len(deleted) != 1 { 2087 t.Fatal("the value should not be empty") 2088 } 2089 if num != 1 { 2090 t.Fatalf("incorrect number of keys deleted: %d", num) 2091 } 2092 if expected, actual := testKey1, deleted[0]; !expected.Equal(actual) { 2093 t.Fatalf("wrong key deleted: expected %v found %v", expected, actual) 2094 } 2095 if resumeSpan != nil { 2096 t.Fatalf("wrong resume key: %v", resumeSpan) 2097 } 2098 res, _ = MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 2099 MVCCScanOptions{}) 2100 if len(res.KVs) != 0 { 2101 t.Fatal("the value should be empty") 2102 } 2103 }) 2104 } 2105 } 2106 2107 func TestMVCCDeleteRangeFailed(t *testing.T) { 2108 defer leaktest.AfterTest(t)() 2109 2110 ctx := context.Background() 2111 for _, engineImpl := range mvccEngineImpls { 2112 t.Run(engineImpl.name, func(t *testing.T) { 2113 engine := engineImpl.create() 2114 defer engine.Close() 2115 2116 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 2117 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 2118 t.Fatal(err) 2119 } 2120 txn.Sequence++ 2121 if err := MVCCPut(ctx, engine, nil, testKey2, txn.ReadTimestamp, value2, txn); err != nil { 2122 t.Fatal(err) 2123 } 2124 txn.Sequence++ 2125 if err := MVCCPut(ctx, engine, nil, testKey3, txn.ReadTimestamp, value3, txn); err != nil { 2126 t.Fatal(err) 2127 } 2128 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 2129 t.Fatal(err) 2130 } 2131 2132 if _, _, _, err := MVCCDeleteRange( 2133 ctx, engine, nil, testKey2, testKey4, math.MaxInt64, hlc.Timestamp{WallTime: 1}, nil, false, 2134 ); err == nil { 2135 t.Fatal("expected error on uncommitted write intent") 2136 } 2137 2138 txn.Sequence++ 2139 if _, _, _, err := MVCCDeleteRange( 2140 ctx, engine, nil, testKey2, testKey4, math.MaxInt64, txn.ReadTimestamp, txn, false, 2141 ); err != nil { 2142 t.Fatal(err) 2143 } 2144 }) 2145 } 2146 } 2147 2148 func TestMVCCDeleteRangeConcurrentTxn(t *testing.T) { 2149 defer leaktest.AfterTest(t)() 2150 2151 ctx := context.Background() 2152 for _, engineImpl := range mvccEngineImpls { 2153 t.Run(engineImpl.name, func(t *testing.T) { 2154 engine := engineImpl.create() 2155 defer engine.Close() 2156 2157 txn1ts := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 2158 txn2ts := makeTxn(*txn2, hlc.Timestamp{WallTime: 2}) 2159 2160 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 2161 t.Fatal(err) 2162 } 2163 if err := MVCCPut(ctx, engine, nil, testKey2, txn1ts.ReadTimestamp, value2, txn1ts); err != nil { 2164 t.Fatal(err) 2165 } 2166 if err := MVCCPut(ctx, engine, nil, testKey3, txn2ts.ReadTimestamp, value3, txn2ts); err != nil { 2167 t.Fatal(err) 2168 } 2169 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value4, nil); err != nil { 2170 t.Fatal(err) 2171 } 2172 2173 if _, _, _, err := MVCCDeleteRange( 2174 ctx, engine, nil, testKey2, testKey4, math.MaxInt64, txn1ts.ReadTimestamp, txn1ts, false, 2175 ); err == nil { 2176 t.Fatal("expected error on uncommitted write intent") 2177 } 2178 }) 2179 } 2180 } 2181 2182 // TestMVCCUncommittedDeleteRangeVisible tests that the keys in an uncommitted 2183 // DeleteRange are visible to the same transaction at a higher epoch. 2184 func TestMVCCUncommittedDeleteRangeVisible(t *testing.T) { 2185 defer leaktest.AfterTest(t)() 2186 2187 ctx := context.Background() 2188 for _, engineImpl := range mvccEngineImpls { 2189 t.Run(engineImpl.name, func(t *testing.T) { 2190 engine := engineImpl.create() 2191 defer engine.Close() 2192 2193 if err := MVCCPut( 2194 ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil, 2195 ); err != nil { 2196 t.Fatal(err) 2197 } 2198 if err := MVCCPut( 2199 ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil, 2200 ); err != nil { 2201 t.Fatal(err) 2202 } 2203 if err := MVCCPut( 2204 ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 1}, value3, nil, 2205 ); err != nil { 2206 t.Fatal(err) 2207 } 2208 2209 if err := MVCCDelete( 2210 ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 2, Logical: 1}, nil, 2211 ); err != nil { 2212 t.Fatal(err) 2213 } 2214 2215 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 2}) 2216 if _, _, _, err := MVCCDeleteRange( 2217 ctx, engine, nil, testKey1, testKey4, math.MaxInt64, txn.ReadTimestamp, txn, false, 2218 ); err != nil { 2219 t.Fatal(err) 2220 } 2221 2222 txn.Epoch++ 2223 res, _ := MVCCScan(ctx, engine, testKey1, testKey4, 2224 hlc.Timestamp{WallTime: 3}, MVCCScanOptions{Txn: txn}) 2225 if e := 2; len(res.KVs) != e { 2226 t.Fatalf("e = %d, got %d", e, len(res.KVs)) 2227 } 2228 }) 2229 } 2230 } 2231 2232 func TestMVCCDeleteRangeInline(t *testing.T) { 2233 defer leaktest.AfterTest(t)() 2234 2235 ctx := context.Background() 2236 for _, engineImpl := range mvccEngineImpls { 2237 t.Run(engineImpl.name, func(t *testing.T) { 2238 engine := engineImpl.create() 2239 defer engine.Close() 2240 2241 // Make five inline values (zero timestamp). 2242 for i, kv := range []struct { 2243 key roachpb.Key 2244 value roachpb.Value 2245 }{ 2246 {testKey1, value1}, 2247 {testKey2, value2}, 2248 {testKey3, value3}, 2249 {testKey4, value4}, 2250 {testKey5, value5}, 2251 } { 2252 if err := MVCCPut(ctx, engine, nil, kv.key, hlc.Timestamp{Logical: 0}, kv.value, nil); err != nil { 2253 t.Fatalf("%d: %+v", i, err) 2254 } 2255 } 2256 2257 // Create one non-inline value (non-zero timestamp). 2258 if err := MVCCPut(ctx, engine, nil, testKey6, hlc.Timestamp{WallTime: 1}, value6, nil); err != nil { 2259 t.Fatal(err) 2260 } 2261 2262 // Attempt to delete two inline keys, should succeed. 2263 deleted, resumeSpan, num, err := MVCCDeleteRange( 2264 ctx, engine, nil, testKey2, testKey6, 2, hlc.Timestamp{Logical: 0}, nil, true, 2265 ) 2266 if err != nil { 2267 t.Fatal(err) 2268 } 2269 if expected := int64(2); num != expected { 2270 t.Fatalf("got %d deleted keys, expected %d", num, expected) 2271 } 2272 if expected := []roachpb.Key{testKey2, testKey3}; !reflect.DeepEqual(deleted, expected) { 2273 t.Fatalf("got deleted values = %v, expected = %v", deleted, expected) 2274 } 2275 if expected := (roachpb.Span{Key: testKey4, EndKey: testKey6}); !resumeSpan.EqualValue(expected) { 2276 t.Fatalf("got resume span = %s, expected = %s", resumeSpan, expected) 2277 } 2278 2279 const inlineMismatchErrString = "put is inline" 2280 2281 // Attempt to delete inline keys at a timestamp; should fail. 2282 if _, _, _, err := MVCCDeleteRange( 2283 ctx, engine, nil, testKey1, testKey6, 1, hlc.Timestamp{WallTime: 2}, nil, true, 2284 ); !testutils.IsError(err, inlineMismatchErrString) { 2285 t.Fatalf("got error %v, expected error with text '%s'", err, inlineMismatchErrString) 2286 } 2287 2288 // Attempt to delete non-inline key at zero timestamp; should fail. 2289 if _, _, _, err := MVCCDeleteRange( 2290 ctx, engine, nil, testKey6, keyMax, 1, hlc.Timestamp{Logical: 0}, nil, true, 2291 ); !testutils.IsError(err, inlineMismatchErrString) { 2292 t.Fatalf("got error %v, expected error with text '%s'", err, inlineMismatchErrString) 2293 } 2294 2295 // Attempt to delete inline keys in a transaction; should fail. 2296 if _, _, _, err := MVCCDeleteRange( 2297 ctx, engine, nil, testKey2, testKey6, 2, hlc.Timestamp{Logical: 0}, txn1, true, 2298 ); !testutils.IsError(err, "writes not allowed within transactions") { 2299 t.Errorf("unexpected error: %+v", err) 2300 } 2301 2302 // Verify final state of the engine. 2303 expectedKvs := []roachpb.KeyValue{ 2304 { 2305 Key: testKey1, 2306 Value: value1, 2307 }, 2308 { 2309 Key: testKey4, 2310 Value: value4, 2311 }, 2312 { 2313 Key: testKey5, 2314 Value: value5, 2315 }, 2316 { 2317 Key: testKey6, 2318 Value: value6, 2319 }, 2320 } 2321 res, err := MVCCScan(ctx, engine, keyMin, keyMax, hlc.Timestamp{WallTime: 2}, 2322 MVCCScanOptions{}) 2323 if err != nil { 2324 t.Fatal(err) 2325 } 2326 if a, e := len(res.KVs), len(expectedKvs); a != e { 2327 t.Fatalf("engine scan found %d keys; expected %d", a, e) 2328 } 2329 res.KVs[3].Value.Timestamp = hlc.Timestamp{} 2330 if !reflect.DeepEqual(expectedKvs, res.KVs) { 2331 t.Fatalf( 2332 "engine scan found key/values: %v; expected %v. Diff: %s", 2333 res.KVs, 2334 expectedKvs, 2335 pretty.Diff(res.KVs, expectedKvs), 2336 ) 2337 } 2338 }) 2339 } 2340 } 2341 2342 func TestMVCCClearTimeRange(t *testing.T) { 2343 defer leaktest.AfterTest(t)() 2344 2345 ctx := context.Background() 2346 for _, engineImpl := range mvccEngineImpls { 2347 t.Run(engineImpl.name, func(t *testing.T) { 2348 2349 ts0 := hlc.Timestamp{WallTime: 0} 2350 ts0Content := []roachpb.KeyValue{} 2351 ts1 := hlc.Timestamp{WallTime: 10} 2352 v1 := value1 2353 v1.Timestamp = ts1 2354 ts1Content := []roachpb.KeyValue{{Key: testKey2, Value: v1}} 2355 ts2 := hlc.Timestamp{WallTime: 20} 2356 v2 := value2 2357 v2.Timestamp = ts2 2358 ts2Content := []roachpb.KeyValue{{Key: testKey2, Value: v2}, {Key: testKey5, Value: v2}} 2359 ts3 := hlc.Timestamp{WallTime: 30} 2360 v3 := value3 2361 v3.Timestamp = ts3 2362 ts3Content := []roachpb.KeyValue{ 2363 {Key: testKey1, Value: v3}, {Key: testKey2, Value: v2}, {Key: testKey5, Value: v2}, 2364 } 2365 ts4 := hlc.Timestamp{WallTime: 40} 2366 v4 := value4 2367 v4.Timestamp = ts4 2368 ts4Content := []roachpb.KeyValue{ 2369 {Key: testKey1, Value: v3}, {Key: testKey2, Value: v4}, {Key: testKey5, Value: v4}, 2370 } 2371 ts5 := hlc.Timestamp{WallTime: 50} 2372 2373 // setupKVs will generate an engine with the key-time space as follows: 2374 // 50 - 2375 // | 2376 // 40 - v4 v4 2377 // | 2378 // 30 - v3 2379 // time | 2380 // 20 - v2 v2 2381 // | 2382 // 10 - v1 2383 // | 2384 // 0 ----------------------- 2385 // k1 k2 k3 k4 k5 2386 // keys 2387 // This returns a new, populated engine since we can't just setup one and use 2388 // a new batch in each subtest, since batches don't reflect ClearRange results 2389 // when read. 2390 setupKVs := func(t *testing.T) Engine { 2391 engine := engineImpl.create() 2392 require.NoError(t, MVCCPut(ctx, engine, nil, testKey2, ts1, value1, nil)) 2393 require.NoError(t, MVCCPut(ctx, engine, nil, testKey2, ts2, value2, nil)) 2394 require.NoError(t, MVCCPut(ctx, engine, nil, testKey5, ts2, value2, nil)) 2395 require.NoError(t, MVCCPut(ctx, engine, nil, testKey1, ts3, value3, nil)) 2396 require.NoError(t, MVCCPut(ctx, engine, nil, testKey5, ts4, value4, nil)) 2397 require.NoError(t, MVCCPut(ctx, engine, nil, testKey2, ts4, value4, nil)) 2398 return engine 2399 } 2400 2401 assertKVs := func(t *testing.T, reader Reader, at hlc.Timestamp, expected []roachpb.KeyValue) { 2402 t.Helper() 2403 res, err := MVCCScan(ctx, reader, keyMin, keyMax, at, MVCCScanOptions{}) 2404 require.NoError(t, err) 2405 require.Equal(t, expected, res.KVs) 2406 } 2407 2408 t.Run("clear > ts0", func(t *testing.T) { 2409 e := setupKVs(t) 2410 defer e.Close() 2411 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts0, ts5, 10) 2412 require.NoError(t, err) 2413 assertKVs(t, e, ts0, ts0Content) 2414 assertKVs(t, e, ts1, ts0Content) 2415 assertKVs(t, e, ts5, ts0Content) 2416 }) 2417 2418 t.Run("clear > ts1 ", func(t *testing.T) { 2419 e := setupKVs(t) 2420 defer e.Close() 2421 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts1, ts5, 10) 2422 require.NoError(t, err) 2423 assertKVs(t, e, ts1, ts1Content) 2424 assertKVs(t, e, ts2, ts1Content) 2425 assertKVs(t, e, ts5, ts1Content) 2426 }) 2427 2428 t.Run("clear > ts2", func(t *testing.T) { 2429 e := setupKVs(t) 2430 defer e.Close() 2431 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts2, ts5, 10) 2432 require.NoError(t, err) 2433 assertKVs(t, e, ts2, ts2Content) 2434 assertKVs(t, e, ts5, ts2Content) 2435 }) 2436 2437 t.Run("clear > ts3", func(t *testing.T) { 2438 e := setupKVs(t) 2439 defer e.Close() 2440 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts3, ts5, 10) 2441 require.NoError(t, err) 2442 assertKVs(t, e, ts3, ts3Content) 2443 assertKVs(t, e, ts5, ts3Content) 2444 }) 2445 2446 t.Run("clear > ts4 (nothing) ", func(t *testing.T) { 2447 e := setupKVs(t) 2448 defer e.Close() 2449 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts4, ts5, 10) 2450 require.NoError(t, err) 2451 assertKVs(t, e, ts4, ts4Content) 2452 assertKVs(t, e, ts5, ts4Content) 2453 }) 2454 2455 t.Run("clear > ts5 (nothing)", func(t *testing.T) { 2456 e := setupKVs(t) 2457 defer e.Close() 2458 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts5, ts5, 10) 2459 require.NoError(t, err) 2460 assertKVs(t, e, ts4, ts4Content) 2461 assertKVs(t, e, ts5, ts4Content) 2462 }) 2463 2464 t.Run("clear up to k5 to ts0", func(t *testing.T) { 2465 e := setupKVs(t) 2466 defer e.Close() 2467 _, err := MVCCClearTimeRange(ctx, e, nil, testKey1, testKey5, ts0, ts5, 10) 2468 require.NoError(t, err) 2469 assertKVs(t, e, ts2, []roachpb.KeyValue{{Key: testKey5, Value: v2}}) 2470 assertKVs(t, e, ts5, []roachpb.KeyValue{{Key: testKey5, Value: v4}}) 2471 }) 2472 2473 t.Run("clear > ts0 in empty span (nothing)", func(t *testing.T) { 2474 e := setupKVs(t) 2475 defer e.Close() 2476 _, err := MVCCClearTimeRange(ctx, e, nil, testKey3, testKey5, ts0, ts5, 10) 2477 require.NoError(t, err) 2478 assertKVs(t, e, ts2, ts2Content) 2479 assertKVs(t, e, ts5, ts4Content) 2480 }) 2481 2482 t.Run("clear > ts0 in empty span [k3,k5) (nothing)", func(t *testing.T) { 2483 e := setupKVs(t) 2484 defer e.Close() 2485 _, err := MVCCClearTimeRange(ctx, e, nil, testKey3, testKey5, ts0, ts5, 10) 2486 require.NoError(t, err) 2487 assertKVs(t, e, ts2, ts2Content) 2488 assertKVs(t, e, ts5, ts4Content) 2489 }) 2490 2491 t.Run("clear k3 and up in ts0 > x >= ts1 (nothing)", func(t *testing.T) { 2492 e := setupKVs(t) 2493 defer e.Close() 2494 _, err := MVCCClearTimeRange(ctx, e, nil, testKey3, keyMax, ts0, ts1, 10) 2495 require.NoError(t, err) 2496 assertKVs(t, e, ts2, ts2Content) 2497 assertKVs(t, e, ts5, ts4Content) 2498 }) 2499 2500 // Add an intent at k3@ts3. 2501 txn := roachpb.MakeTransaction("test", nil, roachpb.NormalUserPriority, ts3, 1) 2502 setupKVsWithIntent := func(t *testing.T) Engine { 2503 e := setupKVs(t) 2504 require.NoError(t, MVCCPut(ctx, e, nil, testKey3, ts3, value3, &txn)) 2505 return e 2506 } 2507 t.Run("clear everything hitting intent fails", func(t *testing.T) { 2508 e := setupKVsWithIntent(t) 2509 defer e.Close() 2510 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts0, ts5, 10) 2511 require.EqualError(t, err, "conflicting intents on \"/db3\"") 2512 }) 2513 2514 t.Run("clear exactly hitting intent fails", func(t *testing.T) { 2515 e := setupKVsWithIntent(t) 2516 defer e.Close() 2517 _, err := MVCCClearTimeRange(ctx, e, nil, testKey3, testKey4, ts2, ts3, 10) 2518 require.EqualError(t, err, "conflicting intents on \"/db3\"") 2519 }) 2520 2521 t.Run("clear everything above intent", func(t *testing.T) { 2522 e := setupKVsWithIntent(t) 2523 defer e.Close() 2524 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts3, ts5, 10) 2525 require.NoError(t, err) 2526 assertKVs(t, e, ts2, ts2Content) 2527 2528 // Scan (< k3 to avoid intent) to confirm that k2 was indeed reverted to 2529 // value as of ts3 (i.e. v4 was cleared to expose v2). 2530 res, err := MVCCScan(ctx, e, keyMin, testKey3, ts5, MVCCScanOptions{}) 2531 require.NoError(t, err) 2532 require.Equal(t, ts3Content[:2], res.KVs) 2533 2534 // Verify the intent was left alone. 2535 _, err = MVCCScan(ctx, e, testKey3, testKey4, ts5, MVCCScanOptions{}) 2536 require.Error(t, err) 2537 2538 // Scan (> k3 to avoid intent) to confirm that k5 was indeed reverted to 2539 // value as of ts3 (i.e. v4 was cleared to expose v2). 2540 res, err = MVCCScan(ctx, e, testKey4, keyMax, ts5, MVCCScanOptions{}) 2541 require.NoError(t, err) 2542 require.Equal(t, ts3Content[2:], res.KVs) 2543 }) 2544 2545 t.Run("clear below intent", func(t *testing.T) { 2546 e := setupKVsWithIntent(t) 2547 defer e.Close() 2548 assertKVs(t, e, ts2, ts2Content) 2549 _, err := MVCCClearTimeRange(ctx, e, nil, keyMin, keyMax, ts1, ts2, 10) 2550 require.NoError(t, err) 2551 assertKVs(t, e, ts2, ts1Content) 2552 }) 2553 }) 2554 } 2555 } 2556 2557 func computeStats( 2558 t *testing.T, reader Reader, from, to roachpb.Key, nowNanos int64, 2559 ) enginepb.MVCCStats { 2560 t.Helper() 2561 iter := reader.NewIterator(IterOptions{UpperBound: to}) 2562 defer iter.Close() 2563 s, err := ComputeStatsGo(iter, from, to, nowNanos) 2564 if err != nil { 2565 t.Fatalf("%+v", err) 2566 } 2567 return s 2568 } 2569 2570 // TestMVCCClearTimeRangeOnRandomData sets up mostly random KVs and then picks 2571 // some random times to which to revert, ensuring that a MVCC-Scan at each of 2572 // those times before reverting matches the result of an MVCC-Scan done at a 2573 // later time post-revert. 2574 func TestMVCCClearTimeRangeOnRandomData(t *testing.T) { 2575 defer leaktest.AfterTest(t)() 2576 2577 rng, _ := randutil.NewPseudoRand() 2578 2579 ctx := context.Background() 2580 2581 for _, engineImpl := range mvccEngineImpls { 2582 t.Run(engineImpl.name, func(t *testing.T) { 2583 e := engineImpl.create() 2584 defer e.Close() 2585 2586 now := hlc.Timestamp{WallTime: 100000000} 2587 2588 var ms enginepb.MVCCStats 2589 2590 // Setup numKVs random kv by writing to random keys [0, keyRange) except for 2591 // the span [swathStart, swathEnd). Then fill in that swath with kvs all 2592 // having the same ts, to ensure they all revert at the same time, thus 2593 // triggering the ClearRange optimization path. 2594 const numKVs = 10000 2595 const keyRange, swathStart, swathEnd = 5000, 3500, 4000 2596 const swathSize = swathEnd - swathStart 2597 const randTimeRange = 1000 2598 2599 wrote := make(map[int]int64, keyRange) 2600 for i := 0; i < numKVs-swathSize; i++ { 2601 k := rng.Intn(keyRange - swathSize) 2602 if k >= swathStart { 2603 k += swathSize 2604 } 2605 2606 ts := int64(rng.Intn(randTimeRange)) 2607 // Ensure writes to a given key are increasing in time. 2608 if ts <= wrote[k] { 2609 ts = wrote[k] + 1 2610 } 2611 wrote[k] = ts 2612 2613 key := roachpb.Key(fmt.Sprintf("%05d", k)) 2614 if rand.Float64() > 0.8 { 2615 require.NoError(t, MVCCDelete(ctx, e, &ms, key, hlc.Timestamp{WallTime: ts}, nil)) 2616 } else { 2617 v := roachpb.MakeValueFromString(fmt.Sprintf("v-%d", i)) 2618 require.NoError(t, MVCCPut(ctx, e, &ms, key, hlc.Timestamp{WallTime: ts}, v, nil)) 2619 } 2620 } 2621 swathTime := rand.Intn(randTimeRange-100) + 100 2622 for i := swathStart; i < swathEnd; i++ { 2623 key := roachpb.Key(fmt.Sprintf("%05d", i)) 2624 v := roachpb.MakeValueFromString(fmt.Sprintf("v-%d", i)) 2625 require.NoError(t, MVCCPut(ctx, e, &ms, key, hlc.Timestamp{WallTime: int64(swathTime)}, v, nil)) 2626 } 2627 2628 // Add another swath of keys above to exercise an after-iteration range flush. 2629 for i := keyRange; i < keyRange+200; i++ { 2630 key := roachpb.Key(fmt.Sprintf("%05d", i)) 2631 v := roachpb.MakeValueFromString(fmt.Sprintf("v-%d", i)) 2632 require.NoError(t, MVCCPut(ctx, e, &ms, key, hlc.Timestamp{WallTime: int64(randTimeRange + 1)}, v, nil)) 2633 } 2634 2635 ms.AgeTo(2000) 2636 2637 // Sanity check starting stats. 2638 require.Equal(t, computeStats(t, e, keyMin, keyMax, 2000), ms) 2639 2640 // Pick timestamps to which we'll revert, and sort them so we can go back 2641 // though them in order. The largest will still be less than randTimeRange so 2642 // the initial revert will be assured to use ClearRange. 2643 reverts := make([]int, 5) 2644 for i := range reverts { 2645 reverts[i] = rand.Intn(randTimeRange) 2646 } 2647 reverts[0] = swathTime - 1 2648 sort.Ints(reverts) 2649 2650 for i := len(reverts) - 1; i >= 0; i-- { 2651 t.Run(fmt.Sprintf("revert-%d", i), func(t *testing.T) { 2652 revertTo := hlc.Timestamp{WallTime: int64(reverts[i])} 2653 // MVCC-Scan at the revert time. 2654 resBefore, err := MVCCScan(ctx, e, keyMin, keyMax, revertTo, MVCCScanOptions{MaxKeys: numKVs}) 2655 require.NoError(t, err) 2656 2657 // Revert to the revert time. 2658 startKey := keyMin 2659 for { 2660 resume, err := MVCCClearTimeRange(ctx, e, &ms, startKey, keyMax, revertTo, now, 100) 2661 require.NoError(t, err) 2662 if resume == nil { 2663 break 2664 } 2665 startKey = resume.Key 2666 } 2667 2668 require.Equal(t, computeStats(t, e, keyMin, keyMax, 2000), ms) 2669 // Scanning at "now" post-revert should yield the same result as scanning 2670 // at revert-time pre-revert. 2671 resAfter, err := MVCCScan(ctx, e, keyMin, keyMax, now, MVCCScanOptions{MaxKeys: numKVs}) 2672 require.NoError(t, err) 2673 require.Equal(t, resBefore.KVs, resAfter.KVs) 2674 }) 2675 } 2676 }) 2677 } 2678 } 2679 2680 func TestMVCCInitPut(t *testing.T) { 2681 defer leaktest.AfterTest(t)() 2682 2683 ctx := context.Background() 2684 for _, engineImpl := range mvccEngineImpls { 2685 t.Run(engineImpl.name, func(t *testing.T) { 2686 engine := engineImpl.create() 2687 defer engine.Close() 2688 2689 err := MVCCInitPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 1}, value1, false, nil) 2690 if err != nil { 2691 t.Fatal(err) 2692 } 2693 2694 // A repeat of the command will still succeed 2695 err = MVCCInitPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 2}, value1, false, nil) 2696 if err != nil { 2697 t.Fatal(err) 2698 } 2699 2700 // Delete. 2701 err = MVCCDelete(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 3}, nil) 2702 if err != nil { 2703 t.Fatal(err) 2704 } 2705 2706 // Reinserting the value fails if we fail on tombstones. 2707 err = MVCCInitPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 4}, value1, true, nil) 2708 if e := (*roachpb.ConditionFailedError)(nil); errors.As(err, &e) { 2709 if !bytes.Equal(e.ActualValue.RawBytes, nil) { 2710 t.Fatalf("the value %s in get result is not a tombstone", e.ActualValue.RawBytes) 2711 } 2712 } else if err == nil { 2713 t.Fatal("MVCCInitPut with a different value did not fail") 2714 } else { 2715 t.Fatalf("unexpected error %T", e) 2716 } 2717 2718 // But doesn't if we *don't* fail on tombstones. 2719 err = MVCCInitPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 5}, value1, false, nil) 2720 if err != nil { 2721 t.Fatal(err) 2722 } 2723 2724 // A repeat of the command with a different value will fail. 2725 err = MVCCInitPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 6}, value2, false, nil) 2726 if e := (*roachpb.ConditionFailedError)(nil); errors.As(err, &e) { 2727 if !bytes.Equal(e.ActualValue.RawBytes, value1.RawBytes) { 2728 t.Fatalf("the value %s in get result does not match the value %s in request", 2729 e.ActualValue.RawBytes, value1.RawBytes) 2730 } 2731 } else if err == nil { 2732 t.Fatal("MVCCInitPut with a different value did not fail") 2733 } else { 2734 t.Fatalf("unexpected error %T", e) 2735 } 2736 2737 // Ensure that the timestamps were correctly updated. 2738 for _, check := range []struct { 2739 ts, expTS hlc.Timestamp 2740 }{ 2741 {ts: hlc.Timestamp{Logical: 1}, expTS: hlc.Timestamp{Logical: 1}}, 2742 {ts: hlc.Timestamp{Logical: 2}, expTS: hlc.Timestamp{Logical: 2}}, 2743 // If we're checking the future wall time case, the rewrite after delete 2744 // will be present. 2745 {ts: hlc.Timestamp{WallTime: 1}, expTS: hlc.Timestamp{Logical: 5}}, 2746 } { 2747 value, _, err := MVCCGet(ctx, engine, testKey1, check.ts, MVCCGetOptions{}) 2748 if err != nil { 2749 t.Fatal(err) 2750 } 2751 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 2752 t.Fatalf("the value %s in get result does not match the value %s in request", 2753 value1.RawBytes, value.RawBytes) 2754 } 2755 if value.Timestamp != check.expTS { 2756 t.Errorf("value at timestamp %s seen, expected %s", value.Timestamp, check.expTS) 2757 } 2758 } 2759 2760 value, _, pErr := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 0}, MVCCGetOptions{}) 2761 if pErr != nil { 2762 t.Fatal(pErr) 2763 } 2764 if value != nil { 2765 t.Fatalf("%v present at old timestamp", value) 2766 } 2767 }) 2768 } 2769 } 2770 2771 func TestMVCCInitPutWithTxn(t *testing.T) { 2772 defer leaktest.AfterTest(t)() 2773 2774 ctx := context.Background() 2775 for _, engineImpl := range mvccEngineImpls { 2776 t.Run(engineImpl.name, func(t *testing.T) { 2777 engine := engineImpl.create() 2778 defer engine.Close() 2779 2780 clock := hlc.NewClock(hlc.NewManualClock(123).UnixNano, time.Nanosecond) 2781 2782 txn := *txn1 2783 txn.Sequence++ 2784 err := MVCCInitPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value1, false, &txn) 2785 if err != nil { 2786 t.Fatal(err) 2787 } 2788 2789 // A repeat of the command will still succeed. 2790 txn.Sequence++ 2791 err = MVCCInitPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value1, false, &txn) 2792 if err != nil { 2793 t.Fatal(err) 2794 } 2795 2796 // A repeat of the command with a different value at a different epoch 2797 // will still succeed. 2798 txn.Sequence++ 2799 txn.Epoch = 2 2800 err = MVCCInitPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value2, false, &txn) 2801 if err != nil { 2802 t.Fatal(err) 2803 } 2804 2805 // Commit value3. 2806 txnCommit := txn 2807 txnCommit.Status = roachpb.COMMITTED 2808 txnCommit.WriteTimestamp = clock.Now().Add(1, 0) 2809 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 2810 roachpb.MakeLockUpdate(&txnCommit, roachpb.Span{Key: testKey1})); err != nil { 2811 t.Fatal(err) 2812 } 2813 2814 // Write value4 with an old timestamp without txn...should get an error. 2815 err = MVCCInitPut(ctx, engine, nil, testKey1, clock.Now(), value4, false, nil) 2816 if e := (*roachpb.ConditionFailedError)(nil); errors.As(err, &e) { 2817 if !bytes.Equal(e.ActualValue.RawBytes, value2.RawBytes) { 2818 t.Fatalf("the value %s in get result does not match the value %s in request", 2819 e.ActualValue.RawBytes, value2.RawBytes) 2820 } 2821 } else { 2822 t.Fatalf("unexpected error %T", e) 2823 } 2824 }) 2825 } 2826 } 2827 2828 // TestMVCCReverseScan verifies that MVCCReverseScan scans [start, 2829 // end) in descending order of keys. 2830 func TestMVCCReverseScan(t *testing.T) { 2831 defer leaktest.AfterTest(t)() 2832 2833 ctx := context.Background() 2834 for _, engineImpl := range mvccEngineImpls { 2835 t.Run(engineImpl.name, func(t *testing.T) { 2836 engine := engineImpl.create() 2837 defer engine.Close() 2838 2839 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 2840 t.Fatal(err) 2841 } 2842 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 2}, value2, nil); err != nil { 2843 t.Fatal(err) 2844 } 2845 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value3, nil); err != nil { 2846 t.Fatal(err) 2847 } 2848 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 3}, value4, nil); err != nil { 2849 t.Fatal(err) 2850 } 2851 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 2852 t.Fatal(err) 2853 } 2854 if err := MVCCPut(ctx, engine, nil, testKey4, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 2855 t.Fatal(err) 2856 } 2857 if err := MVCCPut(ctx, engine, nil, testKey5, hlc.Timestamp{WallTime: 3}, value5, nil); err != nil { 2858 t.Fatal(err) 2859 } 2860 if err := MVCCPut(ctx, engine, nil, testKey6, hlc.Timestamp{WallTime: 3}, value6, nil); err != nil { 2861 t.Fatal(err) 2862 } 2863 2864 res, err := MVCCScan(ctx, engine, testKey2, testKey4, 2865 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{Reverse: true}) 2866 2867 if err != nil { 2868 t.Fatal(err) 2869 } 2870 if len(res.KVs) != 2 || 2871 !bytes.Equal(res.KVs[0].Key, testKey3) || 2872 !bytes.Equal(res.KVs[1].Key, testKey2) || 2873 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) || 2874 !bytes.Equal(res.KVs[1].Value.RawBytes, value3.RawBytes) { 2875 t.Fatalf("unexpected value: %v", res.KVs) 2876 } 2877 if res.ResumeSpan != nil { 2878 t.Fatalf("resumeSpan = %+v", res.ResumeSpan) 2879 } 2880 2881 res, err = MVCCScan(ctx, engine, testKey2, testKey4, hlc.Timestamp{WallTime: 1}, 2882 MVCCScanOptions{Reverse: true, MaxKeys: 1}) 2883 2884 if err != nil { 2885 t.Fatal(err) 2886 } 2887 if len(res.KVs) != 1 || 2888 !bytes.Equal(res.KVs[0].Key, testKey3) || 2889 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) { 2890 t.Fatalf("unexpected value: %v", res.KVs) 2891 } 2892 if expected := (roachpb.Span{Key: testKey2, EndKey: testKey2.Next()}); !res.ResumeSpan.EqualValue(expected) { 2893 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, res.ResumeSpan) 2894 } 2895 2896 res, err = MVCCScan(ctx, engine, testKey2, testKey4, hlc.Timestamp{WallTime: 1}, 2897 MVCCScanOptions{Reverse: true, MaxKeys: -1}) 2898 2899 if err != nil { 2900 t.Fatal(err) 2901 } 2902 if len(res.KVs) != 0 { 2903 t.Fatalf("unexpected value: %v", res.KVs) 2904 } 2905 if expected := (roachpb.Span{Key: testKey2, EndKey: testKey4}); !res.ResumeSpan.EqualValue(expected) { 2906 t.Fatalf("expected = %+v, resumeSpan = %+v", expected, res.ResumeSpan) 2907 } 2908 2909 // The first key we encounter has multiple versions and we need to read the 2910 // latest. 2911 res, err = MVCCScan(ctx, engine, testKey2, testKey3, hlc.Timestamp{WallTime: 4}, 2912 MVCCScanOptions{Reverse: true, MaxKeys: 1}) 2913 2914 if err != nil { 2915 t.Fatal(err) 2916 } 2917 if len(res.KVs) != 1 || 2918 !bytes.Equal(res.KVs[0].Key, testKey2) || 2919 !bytes.Equal(res.KVs[0].Value.RawBytes, value4.RawBytes) { 2920 t.Errorf("unexpected value: %v", res.KVs) 2921 } 2922 2923 // The first key we encounter is newer than our read timestamp and we need to 2924 // back up to the previous key. 2925 res, err = MVCCScan(ctx, engine, testKey4, testKey6, hlc.Timestamp{WallTime: 1}, 2926 MVCCScanOptions{Reverse: true, MaxKeys: 1}) 2927 2928 if err != nil { 2929 t.Fatal(err) 2930 } 2931 if len(res.KVs) != 1 || 2932 !bytes.Equal(res.KVs[0].Key, testKey4) || 2933 !bytes.Equal(res.KVs[0].Value.RawBytes, value2.RawBytes) { 2934 t.Fatalf("unexpected value: %v", res.KVs) 2935 } 2936 2937 // Scan only the first key in the key space. 2938 res, err = MVCCScan(ctx, engine, testKey1, testKey1.Next(), hlc.Timestamp{WallTime: 1}, 2939 MVCCScanOptions{Reverse: true, MaxKeys: 1}) 2940 2941 if err != nil { 2942 t.Fatal(err) 2943 } 2944 if len(res.KVs) != 1 || 2945 !bytes.Equal(res.KVs[0].Key, testKey1) || 2946 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) { 2947 t.Fatalf("unexpected value: %v", res.KVs) 2948 } 2949 }) 2950 } 2951 } 2952 2953 // TestMVCCReverseScanFirstKeyInFuture verifies that when MVCCReverseScan scans 2954 // encounter a key with only future timestamps first, that it skips the key and 2955 // continues to scan in reverse. #17825 was caused by this not working correctly. 2956 func TestMVCCReverseScanFirstKeyInFuture(t *testing.T) { 2957 defer leaktest.AfterTest(t)() 2958 2959 ctx := context.Background() 2960 for _, engineImpl := range mvccEngineImpls { 2961 t.Run(engineImpl.name, func(t *testing.T) { 2962 engine := engineImpl.create() 2963 defer engine.Close() 2964 2965 // The value at key2 will be at a lower timestamp than the ReverseScan, but 2966 // the value at key3 will be at a larger timetamp. The ReverseScan should 2967 // see key3 and ignore it because none of it versions are at a low enough 2968 // timestamp to read. It should then continue scanning backwards and find a 2969 // value at key2. 2970 // 2971 // Before fixing #17825, the MVCC version scan on key3 would fall out of the 2972 // scan bounds and if it never found another valid key before reaching 2973 // KeyMax, would stop the ReverseScan from continuing. 2974 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 2975 t.Fatal(err) 2976 } 2977 if err := MVCCPut(ctx, engine, nil, testKey3, hlc.Timestamp{WallTime: 3}, value3, nil); err != nil { 2978 t.Fatal(err) 2979 } 2980 2981 res, err := MVCCScan(ctx, engine, testKey1, testKey4, 2982 hlc.Timestamp{WallTime: 2}, MVCCScanOptions{Reverse: true}) 2983 if err != nil { 2984 t.Fatal(err) 2985 } 2986 if len(res.KVs) != 1 || 2987 !bytes.Equal(res.KVs[0].Key, testKey2) || 2988 !bytes.Equal(res.KVs[0].Value.RawBytes, value2.RawBytes) { 2989 t.Errorf("unexpected value: %v", res.KVs) 2990 } 2991 }) 2992 } 2993 } 2994 2995 // Exposes a bug where the reverse MVCC scan can get stuck in an infinite loop 2996 // until we OOM. It happened in the code path optimized to use `SeekForPrev()` 2997 // after N `Prev()`s do not reach another logical key. Further, a write intent 2998 // needed to be present on the logical key to make it conflict with our chosen 2999 // `SeekForPrev()` target (logical key + '\0'). 3000 func TestMVCCReverseScanSeeksOverRepeatedKeys(t *testing.T) { 3001 defer leaktest.AfterTest(t)() 3002 3003 ctx := context.Background() 3004 for _, engineImpl := range mvccEngineImpls { 3005 t.Run(engineImpl.name, func(t *testing.T) { 3006 engine := engineImpl.create() 3007 defer engine.Close() 3008 3009 // 10 is the value of `kMaxItersBeforeSeek` at the time this test case was 3010 // written. Repeat the key enough times to make sure the `SeekForPrev()` 3011 // optimization will be used. 3012 for i := 1; i <= 10; i++ { 3013 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{WallTime: int64(i)}, value2, nil); err != nil { 3014 t.Fatal(err) 3015 } 3016 } 3017 txn1ts := makeTxn(*txn1, hlc.Timestamp{WallTime: 11}) 3018 if err := MVCCPut(ctx, engine, nil, testKey2, txn1ts.ReadTimestamp, value2, txn1ts); err != nil { 3019 t.Fatal(err) 3020 } 3021 3022 res, err := MVCCScan(ctx, engine, testKey1, testKey3, 3023 hlc.Timestamp{WallTime: 1}, MVCCScanOptions{Reverse: true}) 3024 if err != nil { 3025 t.Fatal(err) 3026 } 3027 if len(res.KVs) != 1 || 3028 !bytes.Equal(res.KVs[0].Key, testKey2) || 3029 !bytes.Equal(res.KVs[0].Value.RawBytes, value2.RawBytes) { 3030 t.Fatal("unexpected scan results") 3031 } 3032 }) 3033 } 3034 } 3035 3036 // Exposes a bug where the reverse MVCC scan can get stuck in an infinite loop until we OOM. 3037 // 3038 // The bug happened in this scenario. 3039 // (1) reverse scan is positioned at the range's smallest key and calls `prevKey()` 3040 // (2) `prevKey()` peeks and sees newer versions of the same logical key 3041 // `iters_before_seek_-1` times, moving the iterator backwards each time 3042 // (3) on the `iters_before_seek_`th peek, there are no previous keys found 3043 // 3044 // Then, the problem was `prevKey()` treated finding no previous key as if it had found a 3045 // new logical key with the empty string. It would use `backwardLatestVersion()` to find 3046 // the latest version of this empty string logical key. Due to condition (3), 3047 // `backwardLatestVersion()` would go directly to its seeking optimization rather than 3048 // trying to incrementally move backwards (if it had tried moving incrementally backwards, 3049 // it would've noticed it's out of bounds). The seek optimization would then seek to "\0", 3050 // which is the empty logical key with zero timestamp. Since we set RocksDB iterator lower 3051 // bound to be the lower bound of the range scan, this seek actually lands back at the 3052 // range's smallest key. It thinks it found a new key so it adds it to the result, and then 3053 // this whole process repeats ad infinitum. 3054 func TestMVCCReverseScanStopAtSmallestKey(t *testing.T) { 3055 defer leaktest.AfterTest(t)() 3056 for _, engineImpl := range mvccEngineImpls { 3057 t.Run(engineImpl.name, func(t *testing.T) { 3058 run := func(numPuts int, ts int64) { 3059 ctx := context.Background() 3060 engine := engineImpl.create() 3061 defer engine.Close() 3062 3063 for i := 1; i <= numPuts; i++ { 3064 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: int64(i)}, value1, nil); err != nil { 3065 t.Fatal(err) 3066 } 3067 } 3068 3069 res, err := MVCCScan(ctx, engine, testKey1, testKey3, 3070 hlc.Timestamp{WallTime: ts}, MVCCScanOptions{Reverse: true}) 3071 if err != nil { 3072 t.Fatal(err) 3073 } 3074 if len(res.KVs) != 1 || 3075 !bytes.Equal(res.KVs[0].Key, testKey1) || 3076 !bytes.Equal(res.KVs[0].Value.RawBytes, value1.RawBytes) { 3077 t.Fatal("unexpected scan results") 3078 } 3079 } 3080 // Satisfying (2) and (3) is incredibly intricate because of how `iters_before_seek_` 3081 // is incremented/decremented heuristically. For example, at the time of writing, the 3082 // infinitely looping cases are `numPuts == 6 && ts == 2`, `numPuts == 7 && ts == 3`, 3083 // `numPuts == 8 && ts == 4`, `numPuts == 9 && ts == 5`, and `numPuts == 10 && ts == 6`. 3084 // Tying our test case to the `iters_before_seek_` setting logic seems brittle so let's 3085 // just brute force test a wide range of cases. 3086 for numPuts := 1; numPuts <= 10; numPuts++ { 3087 for ts := 1; ts <= 10; ts++ { 3088 run(numPuts, int64(ts)) 3089 } 3090 } 3091 }) 3092 } 3093 } 3094 3095 func TestMVCCResolveTxn(t *testing.T) { 3096 defer leaktest.AfterTest(t)() 3097 3098 ctx := context.Background() 3099 for _, engineImpl := range mvccEngineImpls { 3100 t.Run(engineImpl.name, func(t *testing.T) { 3101 engine := engineImpl.create() 3102 defer engine.Close() 3103 3104 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 3105 t.Fatal(err) 3106 } 3107 3108 { 3109 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 1}, MVCCGetOptions{ 3110 Txn: txn1, 3111 }) 3112 if err != nil { 3113 t.Fatal(err) 3114 } 3115 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 3116 t.Fatalf("the value %s in get result does not match the value %s in request", 3117 value1.RawBytes, value.RawBytes) 3118 } 3119 } 3120 3121 // Resolve will write with txn1's timestamp which is 0,1. 3122 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 3123 roachpb.MakeLockUpdate(txn1Commit, roachpb.Span{Key: testKey1})); err != nil { 3124 t.Fatal(err) 3125 } 3126 3127 { 3128 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 1}, MVCCGetOptions{}) 3129 if err != nil { 3130 t.Fatal(err) 3131 } 3132 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 3133 t.Fatalf("the value %s in get result does not match the value %s in request", 3134 value1.RawBytes, value.RawBytes) 3135 } 3136 } 3137 }) 3138 } 3139 } 3140 3141 // TestMVCCResolveNewerIntent verifies that resolving a newer intent 3142 // than the committing transaction aborts the intent. 3143 func TestMVCCResolveNewerIntent(t *testing.T) { 3144 defer leaktest.AfterTest(t)() 3145 3146 ctx := context.Background() 3147 for _, engineImpl := range mvccEngineImpls { 3148 t.Run(engineImpl.name, func(t *testing.T) { 3149 engine := engineImpl.create() 3150 defer engine.Close() 3151 3152 // Write first value. 3153 if err := MVCCPut(ctx, engine, nil, testKey1, txn1Commit.WriteTimestamp, value1, nil); err != nil { 3154 t.Fatal(err) 3155 } 3156 // Now, put down an intent which should return a write too old error 3157 // (but will still write the intent at tx1Commit.Timestmap+1. 3158 err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value2, txn1) 3159 if !errors.HasType(err, (*roachpb.WriteTooOldError)(nil)) { 3160 t.Fatalf("expected write too old error; got %s", err) 3161 } 3162 3163 // Resolve will succeed but should remove the intent. 3164 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 3165 roachpb.MakeLockUpdate(txn1Commit, roachpb.Span{Key: testKey1})); err != nil { 3166 t.Fatal(err) 3167 } 3168 3169 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 2}, MVCCGetOptions{}) 3170 if err != nil { 3171 t.Fatal(err) 3172 } 3173 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 3174 t.Fatalf("expected value1 bytes; got %q", value.RawBytes) 3175 } 3176 }) 3177 } 3178 } 3179 3180 func TestMVCCResolveIntentTxnTimestampMismatch(t *testing.T) { 3181 defer leaktest.AfterTest(t)() 3182 3183 ctx := context.Background() 3184 for _, engineImpl := range mvccEngineImpls { 3185 t.Run(engineImpl.name, func(t *testing.T) { 3186 engine := engineImpl.create() 3187 defer engine.Close() 3188 3189 txn := txn1.Clone() 3190 tsEarly := txn.WriteTimestamp 3191 txn.TxnMeta.WriteTimestamp.Forward(tsEarly.Add(10, 0)) 3192 3193 // Write an intent which has txn.Timestamp > meta.timestamp. 3194 if err := MVCCPut(ctx, engine, nil, testKey1, tsEarly, value1, txn); err != nil { 3195 t.Fatal(err) 3196 } 3197 3198 // The Timestamp within is equal to that of txn.Meta even though 3199 // the intent sits at tsEarly. The bug was looking at the former 3200 // instead of the latter (and so we could also tickle it with 3201 // smaller timestamps in Txn). 3202 intent := roachpb.MakeLockUpdate(txn, roachpb.Span{Key: testKey1}) 3203 intent.Status = roachpb.PENDING 3204 3205 // A bug (see #7654) caused intents to just stay where they were instead 3206 // of being moved forward in the situation set up above. 3207 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, intent); err != nil { 3208 t.Fatal(err) 3209 } 3210 3211 for i, test := range []struct { 3212 hlc.Timestamp 3213 found bool 3214 }{ 3215 // Check that the intent has indeed moved to where we pushed it. 3216 {tsEarly, false}, 3217 {intent.Txn.WriteTimestamp.Prev(), false}, 3218 {intent.Txn.WriteTimestamp, true}, 3219 {hlc.MaxTimestamp, true}, 3220 } { 3221 _, _, err := MVCCGet(ctx, engine, testKey1, test.Timestamp, MVCCGetOptions{}) 3222 if errors.HasType(err, (*roachpb.WriteIntentError)(nil)) != test.found { 3223 t.Fatalf("%d: expected write intent error: %t, got %v", i, test.found, err) 3224 } 3225 } 3226 }) 3227 } 3228 } 3229 3230 // TestMVCCConditionalPutOldTimestamp tests a case where a conditional 3231 // put with an older timestamp happens after a put with a newer timestamp. 3232 // 3233 // The conditional put uses the actual value at the timestamp as the 3234 // basis for comparison first, and then may fail later with a 3235 // WriteTooOldError if that timestamp isn't recent. 3236 func TestMVCCConditionalPutOldTimestamp(t *testing.T) { 3237 defer leaktest.AfterTest(t)() 3238 3239 ctx := context.Background() 3240 for _, engineImpl := range mvccEngineImpls { 3241 t.Run(engineImpl.name, func(t *testing.T) { 3242 engine := engineImpl.create() 3243 defer engine.Close() 3244 err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil) 3245 if err != nil { 3246 t.Fatal(err) 3247 } 3248 err = MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 3}, value2, nil) 3249 if err != nil { 3250 t.Fatal(err) 3251 } 3252 3253 // Check nothing is written if the value doesn't match. 3254 err = MVCCConditionalPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 2}, value3, &value1, CPutFailIfMissing, nil) 3255 if err == nil { 3256 t.Errorf("unexpected success on conditional put") 3257 } 3258 if !errors.HasType(err, (*roachpb.ConditionFailedError)(nil)) { 3259 t.Errorf("unexpected error on conditional put: %+v", err) 3260 } 3261 3262 // But if value does match the most recently written version, we'll get 3263 // a write too old error but still write updated value. 3264 err = MVCCConditionalPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 2}, value3, &value2, CPutFailIfMissing, nil) 3265 if err == nil { 3266 t.Errorf("unexpected success on conditional put") 3267 } 3268 if !errors.HasType(err, (*roachpb.WriteTooOldError)(nil)) { 3269 t.Errorf("unexpected error on conditional put: %+v", err) 3270 } 3271 // Verify new value was actually written at (3, 1). 3272 ts := hlc.Timestamp{WallTime: 3, Logical: 1} 3273 value, _, err := MVCCGet(ctx, engine, testKey1, ts, MVCCGetOptions{}) 3274 if err != nil || value.Timestamp != ts || !bytes.Equal(value3.RawBytes, value.RawBytes) { 3275 t.Fatalf("expected err=nil (got %s), timestamp=%s (got %s), value=%q (got %q)", 3276 err, value.Timestamp, ts, value3.RawBytes, value.RawBytes) 3277 } 3278 }) 3279 } 3280 } 3281 3282 // TestMVCCMultiplePutOldTimestamp tests a case where multiple 3283 // transactional Puts occur to the same key, but with older timestamps 3284 // than a pre-existing key. The first should generate a 3285 // WriteTooOldError and write at a higher timestamp. The second should 3286 // avoid the WriteTooOldError but also write at the higher timestamp. 3287 func TestMVCCMultiplePutOldTimestamp(t *testing.T) { 3288 defer leaktest.AfterTest(t)() 3289 3290 ctx := context.Background() 3291 for _, engineImpl := range mvccEngineImpls { 3292 t.Run(engineImpl.name, func(t *testing.T) { 3293 engine := engineImpl.create() 3294 defer engine.Close() 3295 3296 err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 3}, value1, nil) 3297 if err != nil { 3298 t.Fatal(err) 3299 } 3300 3301 // Verify the first txn Put returns a write too old error, but the 3302 // intent is written at the advanced timestamp. 3303 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 3304 txn.Sequence++ 3305 err = MVCCPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value2, txn) 3306 if !errors.HasType(err, (*roachpb.WriteTooOldError)(nil)) { 3307 t.Errorf("expected WriteTooOldError on Put; got %v", err) 3308 } 3309 // Verify new value was actually written at (3, 1). 3310 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.MaxTimestamp, MVCCGetOptions{Txn: txn}) 3311 if err != nil { 3312 t.Fatal(err) 3313 } 3314 expTS := hlc.Timestamp{WallTime: 3, Logical: 1} 3315 if value.Timestamp != expTS || !bytes.Equal(value2.RawBytes, value.RawBytes) { 3316 t.Fatalf("expected timestamp=%s (got %s), value=%q (got %q)", 3317 value.Timestamp, expTS, value2.RawBytes, value.RawBytes) 3318 } 3319 3320 // Put again and verify no WriteTooOldError, but timestamp should continue 3321 // to be set to (3,1). 3322 txn.Sequence++ 3323 err = MVCCPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value3, txn) 3324 if err != nil { 3325 t.Error(err) 3326 } 3327 // Verify new value was actually written at (3, 1). 3328 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.MaxTimestamp, MVCCGetOptions{Txn: txn}) 3329 if err != nil { 3330 t.Fatal(err) 3331 } 3332 if value.Timestamp != expTS || !bytes.Equal(value3.RawBytes, value.RawBytes) { 3333 t.Fatalf("expected timestamp=%s (got %s), value=%q (got %q)", 3334 value.Timestamp, expTS, value3.RawBytes, value.RawBytes) 3335 } 3336 }) 3337 } 3338 } 3339 3340 func TestMVCCPutNegativeTimestampError(t *testing.T) { 3341 defer leaktest.AfterTest(t)() 3342 3343 ctx := context.Background() 3344 for _, engineImpl := range mvccEngineImpls { 3345 t.Run(engineImpl.name, func(t *testing.T) { 3346 engine := engineImpl.create() 3347 defer engine.Close() 3348 3349 timestamp := hlc.Timestamp{WallTime: -1} 3350 expectedErrorString := fmt.Sprintf("cannot write to %q at timestamp %s", testKey1, timestamp) 3351 3352 err := MVCCPut(ctx, engine, nil, testKey1, timestamp, value1, nil) 3353 3354 require.EqualError(t, err, expectedErrorString) 3355 }) 3356 } 3357 } 3358 3359 // TestMVCCPutOldOrigTimestampNewCommitTimestamp tests a case where a 3360 // transactional Put occurs to the same key, but with an older original 3361 // timestamp than a pre-existing key. As always, this should result in a 3362 // WriteTooOld error. However, in this case the transaction has a larger 3363 // provisional commit timestamp than the pre-existing key. It should write 3364 // its intent at this timestamp instead of directly above the existing key. 3365 func TestMVCCPutOldOrigTimestampNewCommitTimestamp(t *testing.T) { 3366 defer leaktest.AfterTest(t)() 3367 3368 ctx := context.Background() 3369 for _, engineImpl := range mvccEngineImpls { 3370 t.Run(engineImpl.name, func(t *testing.T) { 3371 engine := engineImpl.create() 3372 defer engine.Close() 3373 3374 err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 3}, value1, nil) 3375 if err != nil { 3376 t.Fatal(err) 3377 } 3378 3379 // Perform a transactional Put with a transaction whose original timestamp is 3380 // below the existing key's timestamp and whose provisional commit timestamp 3381 // is above the existing key's timestamp. 3382 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 3383 txn.WriteTimestamp = hlc.Timestamp{WallTime: 5} 3384 txn.Sequence++ 3385 err = MVCCPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value2, txn) 3386 3387 // Verify that the Put returned a WriteTooOld with the ActualTime set to the 3388 // transactions provisional commit timestamp. 3389 expTS := txn.WriteTimestamp 3390 if wtoErr := (*roachpb.WriteTooOldError)(nil); !errors.As(err, &wtoErr) || wtoErr.ActualTimestamp != expTS { 3391 t.Fatalf("expected WriteTooOldError with actual time = %s; got %s", expTS, wtoErr) 3392 } 3393 3394 // Verify new value was actually written at the transaction's provisional 3395 // commit timestamp. 3396 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.MaxTimestamp, MVCCGetOptions{Txn: txn}) 3397 if err != nil { 3398 t.Fatal(err) 3399 } 3400 if value.Timestamp != expTS || !bytes.Equal(value2.RawBytes, value.RawBytes) { 3401 t.Fatalf("expected timestamp=%s (got %s), value=%q (got %q)", 3402 value.Timestamp, expTS, value2.RawBytes, value.RawBytes) 3403 } 3404 }) 3405 } 3406 } 3407 3408 func TestMVCCAbortTxn(t *testing.T) { 3409 defer leaktest.AfterTest(t)() 3410 3411 ctx := context.Background() 3412 for _, engineImpl := range mvccEngineImpls { 3413 t.Run(engineImpl.name, func(t *testing.T) { 3414 engine := engineImpl.create() 3415 defer engine.Close() 3416 3417 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 3418 t.Fatal(err) 3419 } 3420 3421 txn1AbortWithTS := txn1Abort.Clone() 3422 txn1AbortWithTS.WriteTimestamp = hlc.Timestamp{Logical: 1} 3423 3424 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 3425 roachpb.MakeLockUpdate(txn1AbortWithTS, roachpb.Span{Key: testKey1}), 3426 ); err != nil { 3427 t.Fatal(err) 3428 } 3429 3430 if value, _, err := MVCCGet( 3431 ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{}, 3432 ); err != nil { 3433 t.Fatal(err) 3434 } else if value != nil { 3435 t.Fatalf("expected the value to be empty: %s", value) 3436 } 3437 if meta, err := engine.Get(mvccKey(testKey1)); err != nil { 3438 t.Fatal(err) 3439 } else if len(meta) != 0 { 3440 t.Fatalf("expected no more MVCCMetadata, got: %s", meta) 3441 } 3442 }) 3443 } 3444 } 3445 3446 func TestMVCCAbortTxnWithPreviousVersion(t *testing.T) { 3447 defer leaktest.AfterTest(t)() 3448 3449 ctx := context.Background() 3450 for _, engineImpl := range mvccEngineImpls { 3451 t.Run(engineImpl.name, func(t *testing.T) { 3452 engine := engineImpl.create() 3453 defer engine.Close() 3454 3455 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 1}, value1, nil); err != nil { 3456 t.Fatal(err) 3457 } 3458 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value2, nil); err != nil { 3459 t.Fatal(err) 3460 } 3461 txn1ts := makeTxn(*txn1, hlc.Timestamp{WallTime: 2}) 3462 if err := MVCCPut(ctx, engine, nil, testKey1, txn1ts.ReadTimestamp, value3, txn1ts); err != nil { 3463 t.Fatal(err) 3464 } 3465 3466 txn1AbortWithTS := txn1Abort.Clone() 3467 txn1AbortWithTS.WriteTimestamp = hlc.Timestamp{WallTime: 2} 3468 3469 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 3470 roachpb.MakeLockUpdate(txn1AbortWithTS, roachpb.Span{Key: testKey1}), 3471 ); err != nil { 3472 t.Fatal(err) 3473 } 3474 3475 if meta, err := engine.Get(mvccKey(testKey1)); err != nil { 3476 t.Fatal(err) 3477 } else if len(meta) != 0 { 3478 t.Fatalf("expected no more MVCCMetadata, got: %s", meta) 3479 } 3480 3481 if value, _, err := MVCCGet( 3482 ctx, engine, testKey1, hlc.Timestamp{WallTime: 3}, MVCCGetOptions{}, 3483 ); err != nil { 3484 t.Fatal(err) 3485 } else if expTS := (hlc.Timestamp{WallTime: 1}); value.Timestamp != expTS { 3486 t.Fatalf("expected timestamp %+v == %+v", value.Timestamp, expTS) 3487 } else if !bytes.Equal(value2.RawBytes, value.RawBytes) { 3488 t.Fatalf("the value %q in get result does not match the value %q in request", 3489 value.RawBytes, value2.RawBytes) 3490 } 3491 }) 3492 } 3493 } 3494 3495 func TestMVCCWriteWithDiffTimestampsAndEpochs(t *testing.T) { 3496 defer leaktest.AfterTest(t)() 3497 3498 ctx := context.Background() 3499 for _, engineImpl := range mvccEngineImpls { 3500 t.Run(engineImpl.name, func(t *testing.T) { 3501 engine := engineImpl.create() 3502 defer engine.Close() 3503 3504 // Start with epoch 1. 3505 txn := *txn1 3506 txn.Sequence++ 3507 if err := MVCCPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value1, &txn); err != nil { 3508 t.Fatal(err) 3509 } 3510 // Now write with greater timestamp and epoch 2. 3511 txne2 := txn 3512 txne2.Sequence++ 3513 txne2.Epoch = 2 3514 txne2.WriteTimestamp = hlc.Timestamp{WallTime: 1} 3515 if err := MVCCPut(ctx, engine, nil, testKey1, txne2.ReadTimestamp, value2, &txne2); err != nil { 3516 t.Fatal(err) 3517 } 3518 // Try a write with an earlier timestamp; this is just ignored. 3519 txne2.Sequence++ 3520 txne2.WriteTimestamp = hlc.Timestamp{WallTime: 1} 3521 if err := MVCCPut(ctx, engine, nil, testKey1, txne2.ReadTimestamp, value1, &txne2); err != nil { 3522 t.Fatal(err) 3523 } 3524 // Try a write with an earlier epoch; again ignored. 3525 if err := MVCCPut(ctx, engine, nil, testKey1, txn.ReadTimestamp, value1, &txn); err == nil { 3526 t.Fatal("unexpected success of a write with an earlier epoch") 3527 } 3528 // Try a write with different value using both later timestamp and epoch. 3529 txne2.Sequence++ 3530 if err := MVCCPut(ctx, engine, nil, testKey1, txne2.ReadTimestamp, value3, &txne2); err != nil { 3531 t.Fatal(err) 3532 } 3533 // Resolve the intent. 3534 txne2Commit := txne2 3535 txne2Commit.Status = roachpb.COMMITTED 3536 txne2Commit.WriteTimestamp = hlc.Timestamp{WallTime: 1} 3537 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 3538 roachpb.MakeLockUpdate(&txne2Commit, roachpb.Span{Key: testKey1})); err != nil { 3539 t.Fatal(err) 3540 } 3541 3542 expTS := txne2Commit.WriteTimestamp.Add(0, 1) 3543 3544 // Now try writing an earlier value without a txn--should get WriteTooOldError. 3545 err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 1}, value4, nil) 3546 if wtoErr := (*roachpb.WriteTooOldError)(nil); !errors.As(err, &wtoErr) { 3547 t.Fatal("unexpected success") 3548 } else if wtoErr.ActualTimestamp != expTS { 3549 t.Fatalf("expected write too old error with actual ts %s; got %s", expTS, wtoErr.ActualTimestamp) 3550 } 3551 // Verify value was actually written at (1, 1). 3552 value, _, err := MVCCGet(ctx, engine, testKey1, expTS, MVCCGetOptions{}) 3553 if err != nil || value.Timestamp != expTS || !bytes.Equal(value4.RawBytes, value.RawBytes) { 3554 t.Fatalf("expected err=nil (got %s), timestamp=%s (got %s), value=%q (got %q)", 3555 err, value.Timestamp, expTS, value4.RawBytes, value.RawBytes) 3556 } 3557 // Now write an intent with exactly the same timestamp--ties also get WriteTooOldError. 3558 err = MVCCPut(ctx, engine, nil, testKey1, txn2.ReadTimestamp, value5, txn2) 3559 intentTS := expTS.Add(0, 1) 3560 if wtoErr := (*roachpb.WriteTooOldError)(nil); !errors.As(err, &wtoErr) { 3561 t.Fatal("unexpected success") 3562 } else if wtoErr.ActualTimestamp != intentTS { 3563 t.Fatalf("expected write too old error with actual ts %s; got %s", intentTS, wtoErr.ActualTimestamp) 3564 } 3565 // Verify intent value was actually written at (1, 2). 3566 value, _, err = MVCCGet(ctx, engine, testKey1, intentTS, MVCCGetOptions{Txn: txn2}) 3567 if err != nil || value.Timestamp != intentTS || !bytes.Equal(value5.RawBytes, value.RawBytes) { 3568 t.Fatalf("expected err=nil (got %s), timestamp=%s (got %s), value=%q (got %q)", 3569 err, value.Timestamp, intentTS, value5.RawBytes, value.RawBytes) 3570 } 3571 // Attempt to read older timestamp; should fail. 3572 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 0}, MVCCGetOptions{}) 3573 if value != nil || err != nil { 3574 t.Fatalf("expected value nil, err nil; got %+v, %v", value, err) 3575 } 3576 // Read at correct timestamp. 3577 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{}) 3578 if err != nil { 3579 t.Fatal(err) 3580 } 3581 if expTS := (hlc.Timestamp{WallTime: 1}); value.Timestamp != expTS { 3582 t.Fatalf("expected timestamp %+v == %+v", value.Timestamp, expTS) 3583 } 3584 if !bytes.Equal(value3.RawBytes, value.RawBytes) { 3585 t.Fatalf("the value %s in get result does not match the value %s in request", 3586 value3.RawBytes, value.RawBytes) 3587 } 3588 }) 3589 } 3590 } 3591 3592 // TestMVCCGetWithDiffEpochs writes a value first using epoch 1, then 3593 // reads using epoch 2 to verify that values written during different 3594 // transaction epochs are not visible. 3595 func TestMVCCGetWithDiffEpochs(t *testing.T) { 3596 defer leaktest.AfterTest(t)() 3597 3598 for _, engineImpl := range mvccEngineImpls { 3599 t.Run(engineImpl.name, func(t *testing.T) { 3600 3601 for _, impl := range mvccGetImpls { 3602 t.Run(impl.name, func(t *testing.T) { 3603 mvccGet := impl.fn 3604 3605 ctx := context.Background() 3606 engine := engineImpl.create() 3607 defer engine.Close() 3608 3609 // Write initial value without a txn. 3610 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 1}, value1, nil); err != nil { 3611 t.Fatal(err) 3612 } 3613 // Now write using txn1, epoch 1. 3614 txn1ts := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 3615 if err := MVCCPut(ctx, engine, nil, testKey1, txn1ts.ReadTimestamp, value2, txn1ts); err != nil { 3616 t.Fatal(err) 3617 } 3618 // Try reading using different txns & epochs. 3619 testCases := []struct { 3620 txn *roachpb.Transaction 3621 expValue *roachpb.Value 3622 expErr bool 3623 }{ 3624 // No transaction; should see error. 3625 {nil, nil, true}, 3626 // Txn1, epoch 1; should see new value2. 3627 {txn1, &value2, false}, 3628 // Txn1, epoch 2; should see original value1. 3629 {txn1e2, &value1, false}, 3630 // Txn2; should see error. 3631 {txn2, nil, true}, 3632 } 3633 for i, test := range testCases { 3634 t.Run(strconv.Itoa(i), func(t *testing.T) { 3635 value, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 2}, MVCCGetOptions{ 3636 Txn: test.txn, 3637 }) 3638 if test.expErr { 3639 if err == nil { 3640 t.Errorf("test %d: unexpected success", i) 3641 } else if !errors.HasType(err, (*roachpb.WriteIntentError)(nil)) { 3642 t.Errorf("test %d: expected write intent error; got %v", i, err) 3643 } 3644 } else if err != nil || value == nil || !bytes.Equal(test.expValue.RawBytes, value.RawBytes) { 3645 t.Errorf("test %d: expected value %q, err nil; got %+v, %v", i, test.expValue.RawBytes, value, err) 3646 } 3647 }) 3648 } 3649 }) 3650 } 3651 }) 3652 } 3653 } 3654 3655 // TestMVCCGetWithDiffEpochsAndTimestamps writes a value first using 3656 // epoch 1, then reads using epoch 2 with different timestamps to verify 3657 // that values written during different transaction epochs are not visible. 3658 // 3659 // The test includes the case where the read at epoch 2 is at a *lower* 3660 // timestamp than the intent write at epoch 1. This is not expected to 3661 // happen commonly, but caused issues in #36089. 3662 func TestMVCCGetWithDiffEpochsAndTimestamps(t *testing.T) { 3663 defer leaktest.AfterTest(t)() 3664 3665 for _, engineImpl := range mvccEngineImpls { 3666 t.Run(engineImpl.name, func(t *testing.T) { 3667 for _, impl := range mvccGetImpls { 3668 t.Run(impl.name, func(t *testing.T) { 3669 mvccGet := impl.fn 3670 3671 ctx := context.Background() 3672 engine := engineImpl.create() 3673 defer engine.Close() 3674 3675 // Write initial value without a txn at timestamp 1. 3676 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 1}, value1, nil); err != nil { 3677 t.Fatal(err) 3678 } 3679 // Write another value without a txn at timestamp 3. 3680 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{WallTime: 3}, value2, nil); err != nil { 3681 t.Fatal(err) 3682 } 3683 // Now write using txn1, epoch 1. 3684 txn1ts := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 3685 // Bump epoch 1's write timestamp to timestamp 4. 3686 txn1ts.WriteTimestamp = hlc.Timestamp{WallTime: 4} 3687 // Expected to hit WriteTooOld error but to still lay down intent. 3688 err := MVCCPut(ctx, engine, nil, testKey1, txn1ts.ReadTimestamp, value3, txn1ts) 3689 if wtoErr := (*roachpb.WriteTooOldError)(nil); !errors.As(err, &wtoErr) { 3690 t.Fatalf("unexpectedly not WriteTooOld: %+v", err) 3691 } else if expTS, actTS := txn1ts.WriteTimestamp, wtoErr.ActualTimestamp; expTS != actTS { 3692 t.Fatalf("expected write too old error with actual ts %s; got %s", expTS, actTS) 3693 } 3694 // Try reading using different epochs & timestamps. 3695 testCases := []struct { 3696 txn *roachpb.Transaction 3697 readTS hlc.Timestamp 3698 expValue *roachpb.Value 3699 }{ 3700 // Epoch 1, read 1; should see new value3. 3701 {txn1, hlc.Timestamp{WallTime: 1}, &value3}, 3702 // Epoch 1, read 2; should see new value3. 3703 {txn1, hlc.Timestamp{WallTime: 2}, &value3}, 3704 // Epoch 1, read 3; should see new value3. 3705 {txn1, hlc.Timestamp{WallTime: 3}, &value3}, 3706 // Epoch 1, read 4; should see new value3. 3707 {txn1, hlc.Timestamp{WallTime: 4}, &value3}, 3708 // Epoch 1, read 5; should see new value3. 3709 {txn1, hlc.Timestamp{WallTime: 5}, &value3}, 3710 // Epoch 2, read 1; should see committed value1. 3711 {txn1e2, hlc.Timestamp{WallTime: 1}, &value1}, 3712 // Epoch 2, read 2; should see committed value1. 3713 {txn1e2, hlc.Timestamp{WallTime: 2}, &value1}, 3714 // Epoch 2, read 3; should see committed value2. 3715 {txn1e2, hlc.Timestamp{WallTime: 3}, &value2}, 3716 // Epoch 2, read 4; should see committed value2. 3717 {txn1e2, hlc.Timestamp{WallTime: 4}, &value2}, 3718 // Epoch 2, read 5; should see committed value2. 3719 {txn1e2, hlc.Timestamp{WallTime: 5}, &value2}, 3720 } 3721 for i, test := range testCases { 3722 t.Run(strconv.Itoa(i), func(t *testing.T) { 3723 value, _, err := mvccGet(ctx, engine, testKey1, test.readTS, MVCCGetOptions{Txn: test.txn}) 3724 if err != nil || value == nil || !bytes.Equal(test.expValue.RawBytes, value.RawBytes) { 3725 t.Errorf("test %d: expected value %q, err nil; got %+v, %v", i, test.expValue.RawBytes, value, err) 3726 } 3727 }) 3728 } 3729 }) 3730 } 3731 }) 3732 } 3733 } 3734 3735 // TestMVCCGetWithOldEpoch writes a value first using epoch 2, then 3736 // reads using epoch 1 to verify that the read will fail. 3737 func TestMVCCGetWithOldEpoch(t *testing.T) { 3738 defer leaktest.AfterTest(t)() 3739 3740 for _, engineImpl := range mvccEngineImpls { 3741 t.Run(engineImpl.name, func(t *testing.T) { 3742 for _, impl := range mvccGetImpls { 3743 t.Run(impl.name, func(t *testing.T) { 3744 mvccGet := impl.fn 3745 3746 ctx := context.Background() 3747 engine := engineImpl.create() 3748 defer engine.Close() 3749 3750 if err := MVCCPut(ctx, engine, nil, testKey1, txn1e2.ReadTimestamp, value2, txn1e2); err != nil { 3751 t.Fatal(err) 3752 } 3753 _, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 2}, MVCCGetOptions{ 3754 Txn: txn1, 3755 }) 3756 if err == nil { 3757 t.Fatalf("unexpected success of get") 3758 } 3759 }) 3760 } 3761 }) 3762 } 3763 } 3764 3765 // TestMVCCDeleteRangeWithSequence verifies that delete range operations at sequence 3766 // numbers equal to or below the sequence of a previous delete range operation 3767 // verify that they agree with the sequence history of each intent left by the 3768 // delete range. If so, they become no-ops because writes are meant to be 3769 // idempotent. If not, they throw errors. 3770 func TestMVCCDeleteRangeWithSequence(t *testing.T) { 3771 defer leaktest.AfterTest(t)() 3772 3773 ctx := context.Background() 3774 for _, engineImpl := range mvccEngineImpls { 3775 t.Run(engineImpl.name, func(t *testing.T) { 3776 engine := engineImpl.create() 3777 defer engine.Close() 3778 3779 testCases := []struct { 3780 name string 3781 sequence enginepb.TxnSeq 3782 expErr string 3783 }{ 3784 {"old seq", 5, "missing an intent"}, 3785 {"same seq", 6, ""}, 3786 {"new seq", 7, ""}, 3787 } 3788 3789 for _, tc := range testCases { 3790 t.Run(tc.name, func(t *testing.T) { 3791 prefix := roachpb.Key(fmt.Sprintf("key-%d", tc.sequence)) 3792 txn := *txn1 3793 for i := enginepb.TxnSeq(0); i < 3; i++ { 3794 key := append(prefix, []byte(strconv.Itoa(int(i)))...) 3795 txn.Sequence = 2 + i 3796 if err := MVCCPut(ctx, engine, nil, key, txn.WriteTimestamp, value1, &txn); err != nil { 3797 t.Fatal(err) 3798 } 3799 } 3800 3801 // Perform the initial DeleteRange. 3802 const origSeq = 6 3803 txn.Sequence = origSeq 3804 origDeleted, _, origNum, err := MVCCDeleteRange( 3805 ctx, engine, nil, prefix, prefix.PrefixEnd(), math.MaxInt64, txn.WriteTimestamp, &txn, true, 3806 ) 3807 if err != nil { 3808 t.Fatal(err) 3809 } 3810 3811 txn.Sequence = tc.sequence 3812 deleted, _, num, err := MVCCDeleteRange( 3813 ctx, engine, nil, prefix, prefix.PrefixEnd(), math.MaxInt64, txn.WriteTimestamp, &txn, true, 3814 ) 3815 if tc.expErr != "" && err != nil { 3816 if !testutils.IsError(err, tc.expErr) { 3817 t.Fatalf("unexpected error: %+v", err) 3818 } 3819 } else if err != nil { 3820 t.Fatalf("unexpected error: %+v", err) 3821 } 3822 3823 // If at the same sequence as the initial DeleteRange. 3824 if tc.sequence == origSeq { 3825 if !reflect.DeepEqual(origDeleted, deleted) { 3826 t.Fatalf("deleted keys did not match original execution: %+v vs. %+v", 3827 origDeleted, deleted) 3828 } 3829 if origNum != num { 3830 t.Fatalf("number of keys deleted did not match original execution: %d vs. %d", 3831 origNum, num) 3832 } 3833 } 3834 }) 3835 } 3836 }) 3837 } 3838 } 3839 3840 // TestMVCCGetWithPushedTimestamp verifies that a read for a value 3841 // written by the transaction, but then subsequently pushed, can still 3842 // be read by the txn at the later timestamp, even if an earlier 3843 // timestamp is specified. This happens when a txn's intents are 3844 // resolved by other actors; the intents shouldn't become invisible 3845 // to pushed txn. 3846 func TestMVCCGetWithPushedTimestamp(t *testing.T) { 3847 defer leaktest.AfterTest(t)() 3848 3849 for _, engineImpl := range mvccEngineImpls { 3850 t.Run(engineImpl.name, func(t *testing.T) { 3851 engine := engineImpl.create() 3852 defer engine.Close() 3853 for _, impl := range mvccGetImpls { 3854 t.Run(impl.name, func(t *testing.T) { 3855 mvccGet := impl.fn 3856 3857 ctx := context.Background() 3858 engine := engineImpl.create() 3859 defer engine.Close() 3860 3861 // Start with epoch 1. 3862 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 3863 t.Fatal(err) 3864 } 3865 // Resolve the intent, pushing its timestamp forward. 3866 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 3867 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 3868 roachpb.MakeLockUpdate(txn, roachpb.Span{Key: testKey1})); err != nil { 3869 t.Fatal(err) 3870 } 3871 // Attempt to read using naive txn's previous timestamp. 3872 value, _, err := mvccGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 1}, MVCCGetOptions{ 3873 Txn: txn1, 3874 }) 3875 if err != nil || value == nil || !bytes.Equal(value.RawBytes, value1.RawBytes) { 3876 t.Errorf("expected value %q, err nil; got %+v, %v", value1.RawBytes, value, err) 3877 } 3878 }) 3879 } 3880 }) 3881 } 3882 } 3883 3884 func TestMVCCResolveWithDiffEpochs(t *testing.T) { 3885 defer leaktest.AfterTest(t)() 3886 3887 ctx := context.Background() 3888 for _, engineImpl := range mvccEngineImpls { 3889 t.Run(engineImpl.name, func(t *testing.T) { 3890 engine := engineImpl.create() 3891 defer engine.Close() 3892 3893 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 3894 t.Fatal(err) 3895 } 3896 if err := MVCCPut(ctx, engine, nil, testKey2, txn1e2.ReadTimestamp, value2, txn1e2); err != nil { 3897 t.Fatal(err) 3898 } 3899 num, _, err := MVCCResolveWriteIntentRange(ctx, engine, nil, 3900 roachpb.MakeLockUpdate(txn1e2Commit, roachpb.Span{Key: testKey1, EndKey: testKey2.Next()}), 2) 3901 if err != nil { 3902 t.Fatal(err) 3903 } 3904 if num != 2 { 3905 t.Errorf("expected 2 rows resolved; got %d", num) 3906 } 3907 3908 // Verify key1 is empty, as resolution with epoch 2 would have 3909 // aborted the epoch 1 intent. 3910 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 1}, MVCCGetOptions{}) 3911 if value != nil || err != nil { 3912 t.Errorf("expected value nil, err nil; got %+v, %v", value, err) 3913 } 3914 3915 // Key2 should be committed. 3916 value, _, err = MVCCGet(ctx, engine, testKey2, hlc.Timestamp{Logical: 1}, MVCCGetOptions{}) 3917 if err != nil { 3918 t.Fatal(err) 3919 } 3920 if !bytes.Equal(value2.RawBytes, value.RawBytes) { 3921 t.Fatalf("the value %s in get result does not match the value %s in request", 3922 value2.RawBytes, value.RawBytes) 3923 } 3924 }) 3925 } 3926 } 3927 3928 func TestMVCCResolveWithUpdatedTimestamp(t *testing.T) { 3929 defer leaktest.AfterTest(t)() 3930 3931 ctx := context.Background() 3932 for _, engineImpl := range mvccEngineImpls { 3933 t.Run(engineImpl.name, func(t *testing.T) { 3934 engine := engineImpl.create() 3935 defer engine.Close() 3936 3937 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 3938 t.Fatal(err) 3939 } 3940 3941 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{ 3942 Txn: txn1, 3943 }) 3944 if err != nil { 3945 t.Fatal(err) 3946 } 3947 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 3948 t.Fatalf("the value %s in get result does not match the value %s in request", 3949 value1.RawBytes, value.RawBytes) 3950 } 3951 3952 // Resolve with a higher commit timestamp -- this should rewrite the 3953 // intent when making it permanent. 3954 txn := makeTxn(*txn1Commit, hlc.Timestamp{WallTime: 1}) 3955 if _, err = MVCCResolveWriteIntent(ctx, engine, nil, 3956 roachpb.MakeLockUpdate(txn, roachpb.Span{Key: testKey1})); err != nil { 3957 t.Fatal(err) 3958 } 3959 3960 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 1}, MVCCGetOptions{}) 3961 if value != nil || err != nil { 3962 t.Fatalf("expected both value and err to be nil: %+v, %v", value, err) 3963 } 3964 3965 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{}) 3966 if err != nil { 3967 t.Error(err) 3968 } 3969 if expTS := (hlc.Timestamp{WallTime: 1}); value.Timestamp != expTS { 3970 t.Fatalf("expected timestamp %+v == %+v", value.Timestamp, expTS) 3971 } 3972 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 3973 t.Fatalf("the value %s in get result does not match the value %s in request", 3974 value1.RawBytes, value.RawBytes) 3975 } 3976 }) 3977 } 3978 } 3979 3980 func TestMVCCResolveWithPushedTimestamp(t *testing.T) { 3981 defer leaktest.AfterTest(t)() 3982 3983 ctx := context.Background() 3984 for _, engineImpl := range mvccEngineImpls { 3985 t.Run(engineImpl.name, func(t *testing.T) { 3986 engine := engineImpl.create() 3987 defer engine.Close() 3988 3989 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 3990 t.Fatal(err) 3991 } 3992 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{ 3993 Txn: txn1, 3994 }) 3995 if err != nil { 3996 t.Fatal(err) 3997 } 3998 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 3999 t.Fatalf("the value %s in get result does not match the value %s in request", 4000 value1.RawBytes, value.RawBytes) 4001 } 4002 4003 // Resolve with a higher commit timestamp, but with still-pending transaction. 4004 // This represents a straightforward push (i.e. from a read/write conflict). 4005 txn := makeTxn(*txn1, hlc.Timestamp{WallTime: 1}) 4006 if _, err = MVCCResolveWriteIntent(ctx, engine, nil, 4007 roachpb.MakeLockUpdate(txn, roachpb.Span{Key: testKey1})); err != nil { 4008 t.Fatal(err) 4009 } 4010 4011 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{}) 4012 if value != nil || err == nil { 4013 t.Fatalf("expected both value nil and err to be a writeIntentError: %+v", value) 4014 } 4015 4016 // Can still fetch the value using txn1. 4017 value, _, err = MVCCGet(ctx, engine, testKey1, hlc.Timestamp{WallTime: 1}, MVCCGetOptions{ 4018 Txn: txn1, 4019 }) 4020 if err != nil { 4021 t.Error(err) 4022 } 4023 if expTS := (hlc.Timestamp{WallTime: 1}); value.Timestamp != expTS { 4024 t.Fatalf("expected timestamp %+v == %+v", value.Timestamp, expTS) 4025 } 4026 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 4027 t.Fatalf("the value %s in get result does not match the value %s in request", 4028 value1.RawBytes, value.RawBytes) 4029 } 4030 }) 4031 } 4032 } 4033 4034 func TestMVCCResolveTxnNoOps(t *testing.T) { 4035 defer leaktest.AfterTest(t)() 4036 4037 ctx := context.Background() 4038 for _, engineImpl := range mvccEngineImpls { 4039 t.Run(engineImpl.name, func(t *testing.T) { 4040 engine := engineImpl.create() 4041 defer engine.Close() 4042 4043 // Resolve a non existent key; noop. 4044 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 4045 roachpb.MakeLockUpdate(txn1Commit, roachpb.Span{Key: testKey1})); err != nil { 4046 t.Fatal(err) 4047 } 4048 4049 // Add key and resolve despite there being no intent. 4050 if err := MVCCPut(ctx, engine, nil, testKey1, hlc.Timestamp{Logical: 1}, value1, nil); err != nil { 4051 t.Fatal(err) 4052 } 4053 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 4054 roachpb.MakeLockUpdate(txn2Commit, roachpb.Span{Key: testKey1})); err != nil { 4055 t.Fatal(err) 4056 } 4057 4058 // Write intent and resolve with different txn. 4059 if err := MVCCPut(ctx, engine, nil, testKey2, txn1.ReadTimestamp, value2, txn1); err != nil { 4060 t.Fatal(err) 4061 } 4062 4063 txn1CommitWithTS := txn2Commit.Clone() 4064 txn1CommitWithTS.WriteTimestamp = hlc.Timestamp{WallTime: 1} 4065 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 4066 roachpb.MakeLockUpdate(txn1CommitWithTS, roachpb.Span{Key: testKey2})); err != nil { 4067 t.Fatal(err) 4068 } 4069 }) 4070 } 4071 } 4072 4073 func TestMVCCResolveTxnRange(t *testing.T) { 4074 defer leaktest.AfterTest(t)() 4075 4076 ctx := context.Background() 4077 for _, engineImpl := range mvccEngineImpls { 4078 t.Run(engineImpl.name, func(t *testing.T) { 4079 engine := engineImpl.create() 4080 defer engine.Close() 4081 4082 if err := MVCCPut(ctx, engine, nil, testKey1, txn1.ReadTimestamp, value1, txn1); err != nil { 4083 t.Fatal(err) 4084 } 4085 if err := MVCCPut(ctx, engine, nil, testKey2, hlc.Timestamp{Logical: 1}, value2, nil); err != nil { 4086 t.Fatal(err) 4087 } 4088 if err := MVCCPut(ctx, engine, nil, testKey3, txn2.ReadTimestamp, value3, txn2); err != nil { 4089 t.Fatal(err) 4090 } 4091 if err := MVCCPut(ctx, engine, nil, testKey4, txn1.ReadTimestamp, value4, txn1); err != nil { 4092 t.Fatal(err) 4093 } 4094 4095 num, resumeSpan, err := MVCCResolveWriteIntentRange(ctx, engine, nil, 4096 roachpb.MakeLockUpdate(txn1Commit, roachpb.Span{Key: testKey1, EndKey: testKey4.Next()}), 4097 math.MaxInt64) 4098 if err != nil { 4099 t.Fatal(err) 4100 } 4101 if num != 2 || resumeSpan != nil { 4102 t.Fatalf("expected all keys to process for resolution, even though 2 are noops; got %d, resume=%s", 4103 num, resumeSpan) 4104 } 4105 4106 { 4107 value, _, err := MVCCGet(ctx, engine, testKey1, hlc.Timestamp{Logical: 1}, MVCCGetOptions{}) 4108 if err != nil { 4109 t.Fatal(err) 4110 } 4111 if !bytes.Equal(value1.RawBytes, value.RawBytes) { 4112 t.Fatalf("the value %s in get result does not match the value %s in request", 4113 value1.RawBytes, value.RawBytes) 4114 } 4115 } 4116 { 4117 value, _, err := MVCCGet(ctx, engine, testKey2, hlc.Timestamp{Logical: 1}, MVCCGetOptions{}) 4118 if err != nil { 4119 t.Fatal(err) 4120 } 4121 if !bytes.Equal(value2.RawBytes, value.RawBytes) { 4122 t.Fatalf("the value %s in get result does not match the value %s in request", 4123 value2.RawBytes, value.RawBytes) 4124 } 4125 } 4126 { 4127 value, _, err := MVCCGet(ctx, engine, testKey3, hlc.Timestamp{Logical: 1}, MVCCGetOptions{ 4128 Txn: txn2, 4129 }) 4130 if err != nil { 4131 t.Fatal(err) 4132 } 4133 if !bytes.Equal(value3.RawBytes, value.RawBytes) { 4134 t.Fatalf("the value %s in get result does not match the value %s in request", 4135 value3.RawBytes, value.RawBytes) 4136 } 4137 } 4138 { 4139 value, _, err := MVCCGet(ctx, engine, testKey4, hlc.Timestamp{Logical: 1}, MVCCGetOptions{}) 4140 if err != nil { 4141 t.Fatal(err) 4142 } 4143 if !bytes.Equal(value4.RawBytes, value.RawBytes) { 4144 t.Fatalf("the value %s in get result does not match the value %s in request", 4145 value1.RawBytes, value.RawBytes) 4146 } 4147 } 4148 }) 4149 } 4150 } 4151 4152 func TestMVCCResolveTxnRangeResume(t *testing.T) { 4153 defer leaktest.AfterTest(t)() 4154 4155 ctx := context.Background() 4156 for _, engineImpl := range mvccEngineImpls { 4157 t.Run(engineImpl.name, func(t *testing.T) { 4158 engine := engineImpl.create() 4159 defer engine.Close() 4160 4161 // Write 10 keys from txn1, 10 from txn2, and 10 with no txn, interleaved. 4162 for i := 0; i < 30; i += 3 { 4163 key0 := roachpb.Key(fmt.Sprintf("%02d", i+0)) 4164 key1 := roachpb.Key(fmt.Sprintf("%02d", i+1)) 4165 key2 := roachpb.Key(fmt.Sprintf("%02d", i+2)) 4166 if err := MVCCPut(ctx, engine, nil, key0, txn1.ReadTimestamp, value1, txn1); err != nil { 4167 t.Fatal(err) 4168 } 4169 txn2ts := makeTxn(*txn2, hlc.Timestamp{Logical: 2}) 4170 if err := MVCCPut(ctx, engine, nil, key1, txn2ts.ReadTimestamp, value2, txn2ts); err != nil { 4171 t.Fatal(err) 4172 } 4173 if err := MVCCPut(ctx, engine, nil, key2, hlc.Timestamp{Logical: 3}, value3, nil); err != nil { 4174 t.Fatal(err) 4175 } 4176 } 4177 4178 // Resolve up to 5 intents. 4179 num, resumeSpan, err := MVCCResolveWriteIntentRange(ctx, engine, nil, 4180 roachpb.MakeLockUpdate(txn1Commit, roachpb.Span{Key: roachpb.Key("00"), EndKey: roachpb.Key("30")}), 4181 5) 4182 if err != nil { 4183 t.Fatal(err) 4184 } 4185 if num != 5 || resumeSpan == nil { 4186 t.Errorf("expected resolution for only 5 keys; got %d, resume=%s", num, resumeSpan) 4187 } 4188 expResumeSpan := &roachpb.Span{Key: roachpb.Key("12").Next(), EndKey: roachpb.Key("30")} 4189 if !resumeSpan.Equal(expResumeSpan) { 4190 t.Errorf("expected resume span %s; got %s", expResumeSpan, resumeSpan) 4191 } 4192 }) 4193 } 4194 } 4195 4196 func TestValidSplitKeys(t *testing.T) { 4197 defer leaktest.AfterTest(t)() 4198 4199 testCases := []struct { 4200 key roachpb.Key 4201 valid bool 4202 }{ 4203 {roachpb.Key("\x02"), false}, 4204 {roachpb.Key("\x02\x00"), false}, 4205 {roachpb.Key("\x02\xff"), false}, 4206 {roachpb.Key("\x03"), true}, 4207 {roachpb.Key("\x03\x00"), true}, 4208 {roachpb.Key("\x03\xff"), true}, 4209 {roachpb.Key("\x03\xff\xff"), false}, 4210 {roachpb.Key("\x03\xff\xff\x88"), false}, 4211 {roachpb.Key("\x04"), true}, 4212 {roachpb.Key("\x05"), true}, 4213 {roachpb.Key("a"), true}, 4214 {roachpb.Key("\xff"), true}, 4215 {roachpb.Key("\xff\x01"), true}, 4216 {keys.SystemSQLCodec.TablePrefix(keys.MaxSystemConfigDescID), false}, 4217 {keys.SystemSQLCodec.TablePrefix(keys.MaxSystemConfigDescID + 1), true}, 4218 } 4219 for i, test := range testCases { 4220 valid := IsValidSplitKey(test.key) 4221 if valid != test.valid { 4222 t.Errorf("%d: expected %q [%x] valid %t; got %t", 4223 i, test.key, []byte(test.key), test.valid, valid) 4224 } 4225 } 4226 } 4227 4228 func TestFindSplitKey(t *testing.T) { 4229 defer leaktest.AfterTest(t)() 4230 4231 ctx := context.Background() 4232 for _, engineImpl := range mvccEngineImpls { 4233 t.Run(engineImpl.name, func(t *testing.T) { 4234 engine := engineImpl.create() 4235 defer engine.Close() 4236 4237 ms := &enginepb.MVCCStats{} 4238 // Generate a series of KeyValues, each containing targetLength 4239 // bytes, writing key #i to (encoded) key #i through the MVCC 4240 // facility. Assuming that this translates roughly into same-length 4241 // values after MVCC encoding, the split key should hence be chosen 4242 // as the middle key of the interval. 4243 splitReservoirSize := 100 4244 for i := 0; i < splitReservoirSize; i++ { 4245 k := fmt.Sprintf("%09d", i) 4246 v := strings.Repeat("X", 10-len(k)) 4247 val := roachpb.MakeValueFromString(v) 4248 // Write the key and value through MVCC 4249 if err := MVCCPut(ctx, engine, ms, []byte(k), hlc.Timestamp{Logical: 1}, val, nil); err != nil { 4250 t.Fatal(err) 4251 } 4252 } 4253 4254 testData := []struct { 4255 targetSize int64 4256 splitInd int 4257 }{ 4258 {(ms.KeyBytes + ms.ValBytes) / 2, splitReservoirSize / 2}, 4259 {0, 0}, 4260 {math.MaxInt64, splitReservoirSize}, 4261 } 4262 4263 for i, td := range testData { 4264 humanSplitKey, err := MVCCFindSplitKey(ctx, engine, roachpb.RKeyMin, roachpb.RKeyMax, td.targetSize) 4265 if err != nil { 4266 t.Fatal(err) 4267 } 4268 ind, err := strconv.Atoi(string(humanSplitKey)) 4269 if err != nil { 4270 t.Fatalf("%d: could not parse key %s as int: %+v", i, humanSplitKey, err) 4271 } 4272 if ind == 0 { 4273 t.Fatalf("%d: should never select first key as split key", i) 4274 } 4275 if diff := td.splitInd - ind; diff > 1 || diff < -1 { 4276 t.Fatalf("%d: wanted key #%d+-1, but got %d (diff %d)", i, td.splitInd, ind, diff) 4277 } 4278 } 4279 }) 4280 } 4281 } 4282 4283 // TestFindValidSplitKeys verifies split keys are located such that 4284 // they avoid splits through invalid key ranges. 4285 func TestFindValidSplitKeys(t *testing.T) { 4286 defer leaktest.AfterTest(t)() 4287 4288 const userID = keys.MinUserDescID 4289 const interleave1 = userID + 1 4290 const interleave2 = userID + 2 4291 const interleave3 = userID + 3 4292 // Manually creates rows corresponding to the schema: 4293 // CREATE TABLE t (id1 STRING, id2 STRING, ... PRIMARY KEY (id1, id2, ...)) 4294 addTablePrefix := func(prefix roachpb.Key, id uint32, rowVals ...string) roachpb.Key { 4295 tableKey := append(prefix, keys.SystemSQLCodec.TablePrefix(id)...) 4296 rowKey := roachpb.Key(encoding.EncodeVarintAscending(tableKey, 1)) 4297 for _, rowVal := range rowVals { 4298 rowKey = encoding.EncodeStringAscending(rowKey, rowVal) 4299 } 4300 return rowKey 4301 } 4302 tablePrefix := func(id uint32, rowVals ...string) roachpb.Key { 4303 return addTablePrefix(nil, id, rowVals...) 4304 } 4305 addColFam := func(rowKey roachpb.Key, colFam uint32) roachpb.Key { 4306 return keys.MakeFamilyKey(append([]byte(nil), rowKey...), colFam) 4307 } 4308 addInterleave := func(rowKey roachpb.Key) roachpb.Key { 4309 return encoding.EncodeInterleavedSentinel(rowKey) 4310 } 4311 4312 testCases := []struct { 4313 keys []roachpb.Key 4314 rangeStart roachpb.Key // optional 4315 expSplit roachpb.Key 4316 expError bool 4317 }{ 4318 // All m1 cannot be split. 4319 { 4320 keys: []roachpb.Key{ 4321 roachpb.Key("\x02"), 4322 roachpb.Key("\x02\x00"), 4323 roachpb.Key("\x02\xff"), 4324 }, 4325 expSplit: nil, 4326 expError: false, 4327 }, 4328 // All system span cannot be split. 4329 { 4330 keys: []roachpb.Key{ 4331 addColFam(tablePrefix(1, "some", "data"), 1), 4332 addColFam(tablePrefix(keys.MaxSystemConfigDescID, "blah"), 1), 4333 }, 4334 rangeStart: keys.SystemSQLCodec.TablePrefix(1), 4335 expSplit: nil, 4336 expError: false, 4337 }, 4338 // Between meta1 and meta2, splits at meta2. 4339 { 4340 keys: []roachpb.Key{ 4341 roachpb.Key("\x02"), 4342 roachpb.Key("\x02\x00"), 4343 roachpb.Key("\x02\xff"), 4344 roachpb.Key("\x03"), 4345 roachpb.Key("\x03\x00"), 4346 roachpb.Key("\x03\xff"), 4347 }, 4348 expSplit: roachpb.Key("\x03"), 4349 expError: false, 4350 }, 4351 // Even lopsided, always split at meta2. 4352 { 4353 keys: []roachpb.Key{ 4354 roachpb.Key("\x02"), 4355 roachpb.Key("\x02\x00"), 4356 roachpb.Key("\x02\xff"), 4357 roachpb.Key("\x03"), 4358 }, 4359 expSplit: roachpb.Key("\x03"), 4360 expError: false, 4361 }, 4362 // Between meta2Max and metaMax, splits at metaMax. 4363 { 4364 keys: []roachpb.Key{ 4365 roachpb.Key("\x03\xff\xff"), 4366 roachpb.Key("\x03\xff\xff\x88"), 4367 roachpb.Key("\x04"), 4368 roachpb.Key("\x04\xff\xff\x88"), 4369 }, 4370 expSplit: roachpb.Key("\x04"), 4371 expError: false, 4372 }, 4373 // Even lopsided, always split at metaMax. 4374 { 4375 keys: []roachpb.Key{ 4376 roachpb.Key("\x03\xff\xff"), 4377 roachpb.Key("\x03\xff\xff\x11"), 4378 roachpb.Key("\x03\xff\xff\x88"), 4379 roachpb.Key("\x03\xff\xff\xee"), 4380 roachpb.Key("\x04"), 4381 }, 4382 expSplit: roachpb.Key("\x04"), 4383 expError: false, 4384 }, 4385 // Lopsided, truncate non-zone prefix. 4386 { 4387 keys: []roachpb.Key{ 4388 roachpb.Key("\x04zond"), 4389 roachpb.Key("\x04zone"), 4390 roachpb.Key("\x04zone\x00"), 4391 roachpb.Key("\x04zone\xff"), 4392 }, 4393 expSplit: roachpb.Key("\x04zone\x00"), 4394 expError: false, 4395 }, 4396 // Lopsided, truncate non-zone suffix. 4397 { 4398 keys: []roachpb.Key{ 4399 roachpb.Key("\x04zone"), 4400 roachpb.Key("\x04zone\x00"), 4401 roachpb.Key("\x04zone\xff"), 4402 roachpb.Key("\x04zonf"), 4403 }, 4404 expSplit: roachpb.Key("\x04zone\xff"), 4405 expError: false, 4406 }, 4407 // A Range for which MVCCSplitKey would return the start key isn't fair 4408 // game, even if the StartKey actually exists. There was once a bug 4409 // here which compared timestamps as well as keys and thus didn't 4410 // realize it was splitting at the initial key (due to getting confused 4411 // by the actual value having a nonzero timestamp). 4412 { 4413 keys: []roachpb.Key{ 4414 roachpb.Key("b"), 4415 }, 4416 rangeStart: roachpb.Key("a"), 4417 expSplit: nil, 4418 expError: false, 4419 }, 4420 // Similar test, but the range starts at first key. 4421 { 4422 keys: []roachpb.Key{ 4423 roachpb.Key("b"), 4424 }, 4425 rangeStart: roachpb.Key("b"), 4426 expSplit: nil, 4427 expError: false, 4428 }, 4429 // Some example table data. Make sure we don't split in the middle of a row 4430 // or return the start key of the range. 4431 { 4432 keys: []roachpb.Key{ 4433 addColFam(tablePrefix(userID, "a"), 1), 4434 addColFam(tablePrefix(userID, "a"), 2), 4435 addColFam(tablePrefix(userID, "a"), 3), 4436 addColFam(tablePrefix(userID, "a"), 4), 4437 addColFam(tablePrefix(userID, "a"), 5), 4438 addColFam(tablePrefix(userID, "b"), 1), 4439 addColFam(tablePrefix(userID, "c"), 1), 4440 }, 4441 rangeStart: tablePrefix(userID, "a"), 4442 expSplit: tablePrefix(userID, "b"), 4443 expError: false, 4444 }, 4445 // More example table data. Make sure ranges at the start of a table can 4446 // be split properly - this checks that the minSplitKey logic doesn't 4447 // break for such ranges. 4448 { 4449 keys: []roachpb.Key{ 4450 addColFam(tablePrefix(userID, "a"), 1), 4451 addColFam(tablePrefix(userID, "b"), 1), 4452 addColFam(tablePrefix(userID, "c"), 1), 4453 addColFam(tablePrefix(userID, "d"), 1), 4454 }, 4455 rangeStart: keys.SystemSQLCodec.TablePrefix(userID), 4456 expSplit: tablePrefix(userID, "c"), 4457 expError: false, 4458 }, 4459 // More example table data. Make sure ranges at the start of a table can 4460 // be split properly even in the presence of a large first row. 4461 { 4462 keys: []roachpb.Key{ 4463 addColFam(tablePrefix(userID, "a"), 1), 4464 addColFam(tablePrefix(userID, "a"), 2), 4465 addColFam(tablePrefix(userID, "a"), 3), 4466 addColFam(tablePrefix(userID, "a"), 4), 4467 addColFam(tablePrefix(userID, "a"), 5), 4468 addColFam(tablePrefix(userID, "b"), 1), 4469 addColFam(tablePrefix(userID, "c"), 1), 4470 }, 4471 rangeStart: keys.SystemSQLCodec.TablePrefix(keys.MinUserDescID), 4472 expSplit: tablePrefix(userID, "b"), 4473 expError: false, 4474 }, 4475 // One partition where partition key is the first column. Checks that 4476 // split logic is not confused by the special partition start key. 4477 { 4478 keys: []roachpb.Key{ 4479 addColFam(tablePrefix(userID, "a", "a"), 1), 4480 addColFam(tablePrefix(userID, "a", "b"), 1), 4481 addColFam(tablePrefix(userID, "a", "c"), 1), 4482 addColFam(tablePrefix(userID, "a", "d"), 1), 4483 }, 4484 rangeStart: tablePrefix(userID, "a"), 4485 expSplit: tablePrefix(userID, "a", "c"), 4486 expError: false, 4487 }, 4488 // One partition with a large first row. Checks that our logic to avoid 4489 // splitting in the middle of a row still applies. 4490 { 4491 keys: []roachpb.Key{ 4492 addColFam(tablePrefix(userID, "a", "a"), 1), 4493 addColFam(tablePrefix(userID, "a", "a"), 2), 4494 addColFam(tablePrefix(userID, "a", "a"), 3), 4495 addColFam(tablePrefix(userID, "a", "a"), 4), 4496 addColFam(tablePrefix(userID, "a", "a"), 5), 4497 addColFam(tablePrefix(userID, "a", "b"), 1), 4498 addColFam(tablePrefix(userID, "a", "c"), 1), 4499 }, 4500 rangeStart: tablePrefix(userID, "a"), 4501 expSplit: tablePrefix(userID, "a", "b"), 4502 expError: false, 4503 }, 4504 // One large first row with interleaved child rows. Check that we can 4505 // split before the first interleaved row. 4506 { 4507 keys: []roachpb.Key{ 4508 addColFam(tablePrefix(userID, "a"), 0), 4509 addColFam(tablePrefix(userID, "a"), 1), 4510 addColFam(tablePrefix(userID, "a"), 2), 4511 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 0), 4512 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 1), 4513 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave2, "c"), 1), 4514 }, 4515 rangeStart: tablePrefix(userID, "a"), 4516 expSplit: addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 4517 expError: false, 4518 }, 4519 // One large first row with a double interleaved child row. Check that 4520 // we can split before the double interleaved row. 4521 { 4522 keys: []roachpb.Key{ 4523 addColFam(tablePrefix(userID, "a"), 0), 4524 addColFam(tablePrefix(userID, "a"), 1), 4525 addColFam(tablePrefix(userID, "a"), 2), 4526 addColFam(addTablePrefix(addInterleave( 4527 addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 4528 ), interleave2, "d"), 3), 4529 }, 4530 rangeStart: tablePrefix(userID, "a"), 4531 expSplit: addTablePrefix(addInterleave( 4532 addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 4533 ), interleave2, "d"), 4534 expError: false, 4535 }, 4536 // Two interleaved rows. Check that we can split between them. 4537 { 4538 keys: []roachpb.Key{ 4539 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 0), 4540 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 1), 4541 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave2, "c"), 3), 4542 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave2, "c"), 4), 4543 }, 4544 rangeStart: addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 4545 expSplit: addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave2, "c"), 4546 expError: false, 4547 }, 4548 // Two small rows with interleaved child rows after the second. Check 4549 // that we can split before the first interleaved row. 4550 { 4551 keys: []roachpb.Key{ 4552 addColFam(tablePrefix(userID, "a"), 0), 4553 addColFam(tablePrefix(userID, "b"), 0), 4554 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "b")), interleave1, "b"), 0), 4555 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "b")), interleave1, "b"), 1), 4556 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "b")), interleave2, "c"), 1), 4557 }, 4558 rangeStart: tablePrefix(userID, "a"), 4559 expSplit: addTablePrefix(addInterleave(tablePrefix(userID, "b")), interleave1, "b"), 4560 expError: false, 4561 }, 4562 // A chain of interleaved rows. Check that we can split them. 4563 { 4564 keys: []roachpb.Key{ 4565 addColFam(tablePrefix(userID, "a"), 0), 4566 addColFam(addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 0), 4567 addColFam(addTablePrefix(addInterleave( 4568 addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 4569 ), interleave2, "c"), 0), 4570 addColFam(addTablePrefix(addInterleave( 4571 addTablePrefix(addInterleave( 4572 addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 4573 ), interleave2, "c"), 4574 ), interleave3, "d"), 0), 4575 }, 4576 rangeStart: tablePrefix(userID, "a"), 4577 expSplit: addTablePrefix(addInterleave( 4578 addTablePrefix(addInterleave(tablePrefix(userID, "a")), interleave1, "b"), 4579 ), interleave2, "c"), 4580 expError: false, 4581 }, 4582 } 4583 4584 for _, engineImpl := range mvccEngineImpls { 4585 t.Run(engineImpl.name, func(t *testing.T) { 4586 for i, test := range testCases { 4587 t.Run("", func(t *testing.T) { 4588 ctx := context.Background() 4589 engine := engineImpl.create() 4590 defer engine.Close() 4591 4592 ms := &enginepb.MVCCStats{} 4593 val := roachpb.MakeValueFromString(strings.Repeat("X", 10)) 4594 for _, k := range test.keys { 4595 // Add three MVCC versions of every key. Splits are not allowed 4596 // between MVCC versions, so this shouldn't have any effect. 4597 for j := 1; j <= 3; j++ { 4598 ts := hlc.Timestamp{Logical: int32(j)} 4599 if err := MVCCPut(ctx, engine, ms, []byte(k), ts, val, nil); err != nil { 4600 t.Fatal(err) 4601 } 4602 } 4603 } 4604 rangeStart := test.keys[0] 4605 if len(test.rangeStart) > 0 { 4606 rangeStart = test.rangeStart 4607 } 4608 rangeEnd := test.keys[len(test.keys)-1].Next() 4609 rangeStartAddr, err := keys.Addr(rangeStart) 4610 if err != nil { 4611 t.Fatal(err) 4612 } 4613 rangeEndAddr, err := keys.Addr(rangeEnd) 4614 if err != nil { 4615 t.Fatal(err) 4616 } 4617 targetSize := (ms.KeyBytes + ms.ValBytes) / 2 4618 splitKey, err := MVCCFindSplitKey(ctx, engine, rangeStartAddr, rangeEndAddr, targetSize) 4619 if test.expError { 4620 if !testutils.IsError(err, "has no valid splits") { 4621 t.Fatalf("%d: unexpected error: %+v", i, err) 4622 } 4623 return 4624 } 4625 if err != nil { 4626 t.Fatalf("%d; unexpected error: %+v", i, err) 4627 } 4628 if !splitKey.Equal(test.expSplit) { 4629 t.Errorf("%d: expected split key %q; got %q", i, test.expSplit, splitKey) 4630 } 4631 }) 4632 } 4633 }) 4634 } 4635 } 4636 4637 // TestFindBalancedSplitKeys verifies split keys are located such that 4638 // the left and right halves are equally balanced. 4639 func TestFindBalancedSplitKeys(t *testing.T) { 4640 defer leaktest.AfterTest(t)() 4641 testCases := []struct { 4642 keySizes []int 4643 valSizes []int 4644 expSplit int 4645 }{ 4646 // Bigger keys on right side. 4647 { 4648 keySizes: []int{10, 100, 10, 10, 500}, 4649 valSizes: []int{1, 1, 1, 1, 1}, 4650 expSplit: 4, 4651 }, 4652 // Bigger keys on left side. 4653 { 4654 keySizes: []int{1000, 500, 500, 10, 10}, 4655 valSizes: []int{1, 1, 1, 1, 1}, 4656 expSplit: 1, 4657 }, 4658 // Bigger values on right side. 4659 { 4660 keySizes: []int{1, 1, 1, 1, 1}, 4661 valSizes: []int{10, 100, 10, 10, 500}, 4662 expSplit: 4, 4663 }, 4664 // Bigger values on left side. 4665 { 4666 keySizes: []int{1, 1, 1, 1, 1}, 4667 valSizes: []int{1000, 100, 500, 10, 10}, 4668 expSplit: 1, 4669 }, 4670 // Bigger key/values on right side. 4671 { 4672 keySizes: []int{10, 100, 10, 10, 250}, 4673 valSizes: []int{10, 100, 10, 10, 250}, 4674 expSplit: 4, 4675 }, 4676 // Bigger key/values on left side. 4677 { 4678 keySizes: []int{500, 50, 250, 10, 10}, 4679 valSizes: []int{500, 50, 250, 10, 10}, 4680 expSplit: 1, 4681 }, 4682 } 4683 4684 for _, engineImpl := range mvccEngineImpls { 4685 t.Run(engineImpl.name, func(t *testing.T) { 4686 for i, test := range testCases { 4687 t.Run("", func(t *testing.T) { 4688 ctx := context.Background() 4689 engine := engineImpl.create() 4690 defer engine.Close() 4691 4692 ms := &enginepb.MVCCStats{} 4693 var expKey roachpb.Key 4694 for j, keySize := range test.keySizes { 4695 key := roachpb.Key(fmt.Sprintf("%d%s", j, strings.Repeat("X", keySize))) 4696 if test.expSplit == j { 4697 expKey = key 4698 } 4699 val := roachpb.MakeValueFromString(strings.Repeat("X", test.valSizes[j])) 4700 if err := MVCCPut(ctx, engine, ms, key, hlc.Timestamp{Logical: 1}, val, nil); err != nil { 4701 t.Fatal(err) 4702 } 4703 } 4704 targetSize := (ms.KeyBytes + ms.ValBytes) / 2 4705 splitKey, err := MVCCFindSplitKey(ctx, engine, roachpb.RKey("\x02"), roachpb.RKeyMax, targetSize) 4706 if err != nil { 4707 t.Fatalf("unexpected error: %+v", err) 4708 } 4709 if !splitKey.Equal(expKey) { 4710 t.Errorf("%d: expected split key %q; got %q", i, expKey, splitKey) 4711 } 4712 }) 4713 } 4714 }) 4715 } 4716 } 4717 4718 // TestMVCCGarbageCollect writes a series of gc'able bytes and then 4719 // sends an MVCC GC request and verifies cleared values and updated 4720 // stats. 4721 func TestMVCCGarbageCollect(t *testing.T) { 4722 defer leaktest.AfterTest(t)() 4723 4724 ctx := context.Background() 4725 for _, engineImpl := range mvccEngineImpls { 4726 t.Run(engineImpl.name, func(t *testing.T) { 4727 engine := engineImpl.create() 4728 defer engine.Close() 4729 4730 ms := &enginepb.MVCCStats{} 4731 4732 bytes := []byte("value") 4733 ts1 := hlc.Timestamp{WallTime: 1e9} 4734 ts2 := hlc.Timestamp{WallTime: 2e9} 4735 ts3 := hlc.Timestamp{WallTime: 3e9} 4736 val1 := roachpb.MakeValueFromBytesAndTimestamp(bytes, ts1) 4737 val2 := roachpb.MakeValueFromBytesAndTimestamp(bytes, ts2) 4738 val3 := roachpb.MakeValueFromBytesAndTimestamp(bytes, ts3) 4739 valInline := roachpb.MakeValueFromBytesAndTimestamp(bytes, hlc.Timestamp{}) 4740 4741 testData := []struct { 4742 key roachpb.Key 4743 vals []roachpb.Value 4744 isDeleted bool // is the most recent value a deletion tombstone? 4745 }{ 4746 {roachpb.Key("a"), []roachpb.Value{val1, val2}, false}, 4747 {roachpb.Key("a-del"), []roachpb.Value{val1, val2}, true}, 4748 {roachpb.Key("b"), []roachpb.Value{val1, val2, val3}, false}, 4749 {roachpb.Key("b-del"), []roachpb.Value{val1, val2, val3}, true}, 4750 {roachpb.Key("inline"), []roachpb.Value{valInline}, false}, 4751 } 4752 4753 for i := 0; i < 3; i++ { 4754 for _, test := range testData { 4755 if i >= len(test.vals) { 4756 continue 4757 } 4758 for _, val := range test.vals[i : i+1] { 4759 if i == len(test.vals)-1 && test.isDeleted { 4760 if err := MVCCDelete(ctx, engine, ms, test.key, val.Timestamp, nil); err != nil { 4761 t.Fatal(err) 4762 } 4763 continue 4764 } 4765 valCpy := *protoutil.Clone(&val).(*roachpb.Value) 4766 valCpy.Timestamp = hlc.Timestamp{} 4767 if err := MVCCPut(ctx, engine, ms, test.key, val.Timestamp, valCpy, nil); err != nil { 4768 t.Fatal(err) 4769 } 4770 } 4771 } 4772 } 4773 if log.V(1) { 4774 kvsn, err := Scan(engine, keyMin, keyMax, 0) 4775 if err != nil { 4776 t.Fatal(err) 4777 } 4778 for i, kv := range kvsn { 4779 log.Infof(context.Background(), "%d: %s", i, kv.Key) 4780 } 4781 } 4782 4783 keys := []roachpb.GCRequest_GCKey{ 4784 {Key: roachpb.Key("a"), Timestamp: ts1}, 4785 {Key: roachpb.Key("a-del"), Timestamp: ts2}, 4786 {Key: roachpb.Key("b"), Timestamp: ts1}, 4787 {Key: roachpb.Key("b-del"), Timestamp: ts2}, 4788 {Key: roachpb.Key("inline"), Timestamp: hlc.Timestamp{}}, 4789 // Keys that don't exist, which should result in a no-op. 4790 {Key: roachpb.Key("a-bad"), Timestamp: ts2}, 4791 {Key: roachpb.Key("inline-bad"), Timestamp: hlc.Timestamp{}}, 4792 } 4793 if err := MVCCGarbageCollect( 4794 context.Background(), engine, ms, keys, ts3, 4795 ); err != nil { 4796 t.Fatal(err) 4797 } 4798 4799 expEncKeys := []MVCCKey{ 4800 mvccVersionKey(roachpb.Key("a"), ts2), 4801 mvccVersionKey(roachpb.Key("b"), ts3), 4802 mvccVersionKey(roachpb.Key("b"), ts2), 4803 mvccVersionKey(roachpb.Key("b-del"), ts3), 4804 } 4805 kvs, err := Scan(engine, keyMin, keyMax, 0) 4806 if err != nil { 4807 t.Fatal(err) 4808 } 4809 if len(kvs) != len(expEncKeys) { 4810 t.Fatalf("number of kvs %d != expected %d", len(kvs), len(expEncKeys)) 4811 } 4812 for i, kv := range kvs { 4813 if !kv.Key.Equal(expEncKeys[i]) { 4814 t.Errorf("%d: expected key %q; got %q", i, expEncKeys[i], kv.Key) 4815 } 4816 } 4817 4818 // Verify aggregated stats match computed stats after GC. 4819 iter := engine.NewIterator(IterOptions{UpperBound: roachpb.KeyMax}) 4820 defer iter.Close() 4821 for _, mvccStatsTest := range mvccStatsTests { 4822 t.Run(mvccStatsTest.name, func(t *testing.T) { 4823 expMS, err := mvccStatsTest.fn(iter, roachpb.KeyMin, roachpb.KeyMax, ts3.WallTime) 4824 if err != nil { 4825 t.Fatal(err) 4826 } 4827 assertEq(t, engine, "verification", ms, &expMS) 4828 }) 4829 } 4830 }) 4831 } 4832 } 4833 4834 // TestMVCCGarbageCollectNonDeleted verifies that the first value for 4835 // a key cannot be GC'd if it's not deleted. 4836 func TestMVCCGarbageCollectNonDeleted(t *testing.T) { 4837 defer leaktest.AfterTest(t)() 4838 4839 ctx := context.Background() 4840 for _, engineImpl := range mvccEngineImpls { 4841 t.Run(engineImpl.name, func(t *testing.T) { 4842 engine := engineImpl.create() 4843 defer engine.Close() 4844 4845 s := "string" 4846 ts1 := hlc.Timestamp{WallTime: 1e9} 4847 ts2 := hlc.Timestamp{WallTime: 2e9} 4848 val1 := mkVal(s, ts1) 4849 val2 := mkVal(s, ts2) 4850 valInline := mkVal(s, hlc.Timestamp{}) 4851 4852 testData := []struct { 4853 key roachpb.Key 4854 vals []roachpb.Value 4855 expError string 4856 }{ 4857 {roachpb.Key("a"), []roachpb.Value{val1, val2}, `request to GC non-deleted, latest value of "a"`}, 4858 {roachpb.Key("inline"), []roachpb.Value{valInline}, ""}, 4859 } 4860 4861 for _, test := range testData { 4862 for _, val := range test.vals { 4863 valCpy := *protoutil.Clone(&val).(*roachpb.Value) 4864 valCpy.Timestamp = hlc.Timestamp{} 4865 if err := MVCCPut(ctx, engine, nil, test.key, val.Timestamp, valCpy, nil); err != nil { 4866 t.Fatal(err) 4867 } 4868 } 4869 keys := []roachpb.GCRequest_GCKey{ 4870 {Key: test.key, Timestamp: ts2}, 4871 } 4872 err := MVCCGarbageCollect(ctx, engine, nil, keys, ts2) 4873 if !testutils.IsError(err, test.expError) { 4874 t.Fatalf("expected error %q when garbage collecting a non-deleted live value, found %v", 4875 test.expError, err) 4876 } 4877 } 4878 }) 4879 } 4880 } 4881 4882 // TestMVCCGarbageCollectIntent verifies that an intent cannot be GC'd. 4883 func TestMVCCGarbageCollectIntent(t *testing.T) { 4884 defer leaktest.AfterTest(t)() 4885 4886 ctx := context.Background() 4887 for _, engineImpl := range mvccEngineImpls { 4888 t.Run(engineImpl.name, func(t *testing.T) { 4889 engine := engineImpl.create() 4890 defer engine.Close() 4891 4892 bytes := []byte("value") 4893 ts1 := hlc.Timestamp{WallTime: 1e9} 4894 ts2 := hlc.Timestamp{WallTime: 2e9} 4895 key := roachpb.Key("a") 4896 { 4897 val1 := roachpb.MakeValueFromBytes(bytes) 4898 if err := MVCCPut(ctx, engine, nil, key, ts1, val1, nil); err != nil { 4899 t.Fatal(err) 4900 } 4901 } 4902 txn := &roachpb.Transaction{ 4903 TxnMeta: enginepb.TxnMeta{ID: uuid.MakeV4(), WriteTimestamp: ts2}, 4904 ReadTimestamp: ts2, 4905 } 4906 if err := MVCCDelete(ctx, engine, nil, key, txn.ReadTimestamp, txn); err != nil { 4907 t.Fatal(err) 4908 } 4909 keys := []roachpb.GCRequest_GCKey{ 4910 {Key: key, Timestamp: ts2}, 4911 } 4912 if err := MVCCGarbageCollect(ctx, engine, nil, keys, ts2); err == nil { 4913 t.Fatal("expected error garbage collecting an intent") 4914 } 4915 }) 4916 } 4917 } 4918 4919 // TestResolveIntentWithLowerEpoch verifies that trying to resolve 4920 // an intent at an epoch that is lower than the epoch of the intent 4921 // leaves the intent untouched. 4922 func TestResolveIntentWithLowerEpoch(t *testing.T) { 4923 defer leaktest.AfterTest(t)() 4924 4925 ctx := context.Background() 4926 for _, engineImpl := range mvccEngineImpls { 4927 t.Run(engineImpl.name, func(t *testing.T) { 4928 engine := engineImpl.create() 4929 defer engine.Close() 4930 4931 // Lay down an intent with a high epoch. 4932 if err := MVCCPut(ctx, engine, nil, testKey1, txn1e2.ReadTimestamp, value1, txn1e2); err != nil { 4933 t.Fatal(err) 4934 } 4935 // Resolve the intent with a low epoch. 4936 if _, err := MVCCResolveWriteIntent(ctx, engine, nil, 4937 roachpb.MakeLockUpdate(txn1, roachpb.Span{Key: testKey1})); err != nil { 4938 t.Fatal(err) 4939 } 4940 4941 // Check that the intent was not cleared. 4942 metaKey := mvccKey(testKey1) 4943 meta := &enginepb.MVCCMetadata{} 4944 ok, _, _, err := engine.GetProto(metaKey, meta) 4945 if err != nil { 4946 t.Fatal(err) 4947 } 4948 if !ok { 4949 t.Fatal("intent should not be cleared by resolve intent request with lower epoch") 4950 } 4951 }) 4952 } 4953 } 4954 4955 // TestMVCCTimeSeriesPartialMerge ensures that "partial merges" of merged time 4956 // series data does not result in a different final result than a "full merge". 4957 func TestMVCCTimeSeriesPartialMerge(t *testing.T) { 4958 defer leaktest.AfterTest(t)() 4959 4960 ctx := context.Background() 4961 for _, engineImpl := range mvccEngineImpls { 4962 t.Run(engineImpl.name, func(t *testing.T) { 4963 engine := engineImpl.create() 4964 defer engine.Close() 4965 4966 // Perform the same sequence of merges on two different keys. For 4967 // one of them, insert some compactions which cause partial merges 4968 // to be run and affect the results. 4969 vals := make([]*roachpb.Value, 2) 4970 4971 for i, k := range []roachpb.Key{testKey1, testKey2} { 4972 if err := MVCCMerge(ctx, engine, nil, k, hlc.Timestamp{Logical: 1}, tsvalue1); err != nil { 4973 t.Fatal(err) 4974 } 4975 if err := MVCCMerge(ctx, engine, nil, k, hlc.Timestamp{Logical: 2}, tsvalue2); err != nil { 4976 t.Fatal(err) 4977 } 4978 4979 if i == 1 { 4980 if err := engine.Compact(); err != nil { 4981 t.Fatal(err) 4982 } 4983 } 4984 4985 if err := MVCCMerge(ctx, engine, nil, k, hlc.Timestamp{Logical: 2}, tsvalue2); err != nil { 4986 t.Fatal(err) 4987 } 4988 if err := MVCCMerge(ctx, engine, nil, k, hlc.Timestamp{Logical: 1}, tsvalue1); err != nil { 4989 t.Fatal(err) 4990 } 4991 4992 if i == 1 { 4993 if err := engine.Compact(); err != nil { 4994 t.Fatal(err) 4995 } 4996 } 4997 4998 if v, _, err := MVCCGet(ctx, engine, k, hlc.Timestamp{}, MVCCGetOptions{}); err != nil { 4999 t.Fatal(err) 5000 } else { 5001 vals[i] = v 5002 } 5003 } 5004 5005 if first, second := vals[0], vals[1]; !proto.Equal(first, second) { 5006 var firstTS, secondTS roachpb.InternalTimeSeriesData 5007 if err := first.GetProto(&firstTS); err != nil { 5008 t.Fatal(err) 5009 } 5010 if err := second.GetProto(&secondTS); err != nil { 5011 t.Fatal(err) 5012 } 5013 t.Fatalf("partially merged value %v differed from expected merged value %v", secondTS, firstTS) 5014 } 5015 }) 5016 } 5017 } 5018 5019 func TestWillOverflow(t *testing.T) { 5020 defer leaktest.AfterTest(t)() 5021 5022 testCases := []struct { 5023 a, b int64 5024 overflow bool // will a+b over- or underflow? 5025 }{ 5026 {0, 0, false}, 5027 {math.MaxInt64, 0, false}, 5028 {math.MaxInt64, 1, true}, 5029 {math.MaxInt64, math.MinInt64, false}, 5030 {math.MinInt64, 0, false}, 5031 {math.MinInt64, -1, true}, 5032 {math.MinInt64, math.MinInt64, true}, 5033 } 5034 5035 for i, c := range testCases { 5036 if willOverflow(c.a, c.b) != c.overflow || 5037 willOverflow(c.b, c.a) != c.overflow { 5038 t.Errorf("%d: overflow recognition error", i) 5039 } 5040 } 5041 }