func TestMakeKey(t *testing.T) { if !bytes.Equal(makeKey(roachpb.Key("A"), roachpb.Key("B")), roachpb.Key("AB")) || !bytes.Equal(makeKey(roachpb.Key("A")), roachpb.Key("A")) || !bytes.Equal(makeKey(roachpb.Key("A"), roachpb.Key("B"), roachpb.Key("C")), roachpb.Key("ABC")) { t.Fatalf("MakeKey is broken") } }
func TestBatchPrevNextWithNoop(t *testing.T) { defer leaktest.AfterTest(t)() leftKey := roachpb.Key("a") middleKey := roachpb.RKey("b") rightKey := roachpb.Key("c") var ba roachpb.BatchRequest ba.Add(&roachpb.GetRequest{Span: roachpb.Span{Key: leftKey}}) ba.Add(&roachpb.NoopRequest{}) ba.Add(&roachpb.GetRequest{Span: roachpb.Span{Key: rightKey}}) t.Run("prev", func(t *testing.T) { rk, err := prev(ba, middleKey) if err != nil { t.Fatal(err) } if !rk.Equal(leftKey) { t.Errorf("got %s, expected %s", rk, leftKey) } }) t.Run("next", func(t *testing.T) { rk, err := next(ba, middleKey) if err != nil { t.Fatal(err) } if !rk.Equal(rightKey) { t.Errorf("got %s, expected %s", rk, rightKey) } }) }
func runMVCCConditionalPut(emk engineMaker, valueSize int, createFirst bool, b *testing.B) { rng, _ := randutil.NewPseudoRand() value := roachpb.MakeValueFromBytes(randutil.RandBytes(rng, valueSize)) keyBuf := append(make([]byte, 0, 64), []byte("key-")...) eng := emk(b, fmt.Sprintf("cput_%d", valueSize)) defer eng.Close() b.SetBytes(int64(valueSize)) var expected *roachpb.Value if createFirst { for i := 0; i < b.N; i++ { key := roachpb.Key(encoding.EncodeUvarintAscending(keyBuf[:4], uint64(i))) ts := makeTS(timeutil.Now().UnixNano(), 0) if err := MVCCPut(context.Background(), eng, nil, key, ts, value, nil); err != nil { b.Fatalf("failed put: %s", err) } } expected = &value } b.ResetTimer() for i := 0; i < b.N; i++ { key := roachpb.Key(encoding.EncodeUvarintAscending(keyBuf[:4], uint64(i))) ts := makeTS(timeutil.Now().UnixNano(), 0) if err := MVCCConditionalPut(context.Background(), eng, nil, key, ts, value, expected, nil); err != nil { b.Fatalf("failed put: %s", err) } } b.StopTimer() }
// TestBatchError verifies that Range returns an error if a request has an invalid range. func TestBatchError(t *testing.T) { testCases := []struct { req [2]string errMsg string }{ { req: [2]string{"\xff\xff\xff\xff", "a"}, errMsg: "must be less than KeyMax", }, { req: [2]string{"a", "\xff\xff\xff\xff"}, errMsg: "must be less than or equal to KeyMax", }, } for i, c := range testCases { var ba roachpb.BatchRequest ba.Add(&roachpb.ScanRequest{Span: roachpb.Span{Key: roachpb.Key(c.req[0]), EndKey: roachpb.Key(c.req[1])}}) if _, err := Range(ba); !testutils.IsError(err, c.errMsg) { t.Errorf("%d: unexpected error %v", i, err) } } // Test a case where a non-range request has an end key. var ba roachpb.BatchRequest ba.Add(&roachpb.GetRequest{Span: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}}) if _, err := Range(ba); !testutils.IsError(err, "end key specified for non-range operation") { t.Errorf("unexpected error %v", err) } }
// TestTimestampCacheEqualTimestamp verifies that in the event of two // non-overlapping transactions with equal timestamps, the returned // timestamp is not owned by either one. func TestTimestampCacheEqualTimestamps(t *testing.T) { defer leaktest.AfterTest(t)() manual := hlc.NewManualClock(123) clock := hlc.NewClock(manual.UnixNano, time.Nanosecond) tc := newTimestampCache(clock) txn1 := uuid.MakeV4() txn2 := uuid.MakeV4() // Add two non-overlapping transactions at the same timestamp. ts1 := clock.Now() tc.add(roachpb.Key("a"), roachpb.Key("b"), ts1, &txn1, true) tc.add(roachpb.Key("b"), roachpb.Key("c"), ts1, &txn2, true) // When querying either side separately, the transaction ID is returned. if ts, txn, _ := tc.GetMaxRead(roachpb.Key("a"), roachpb.Key("b")); !ts.Equal(ts1) { t.Errorf("expected 'a'-'b' to have timestamp %s, but found %s", ts1, ts) } else if *txn != txn1 { t.Errorf("expected 'a'-'b' to have txn id %s, but found %s", txn1, txn) } if ts, txn, _ := tc.GetMaxRead(roachpb.Key("b"), roachpb.Key("c")); !ts.Equal(ts1) { t.Errorf("expected 'b'-'c' to have timestamp %s, but found %s", ts1, ts) } else if *txn != txn2 { t.Errorf("expected 'b'-'c' to have txn id %s, but found %s", txn2, txn) } // Querying a span that overlaps both returns a nil txn ID; neither // can proceed here. if ts, txn, _ := tc.GetMaxRead(roachpb.Key("a"), roachpb.Key("c")); !ts.Equal(ts1) { t.Errorf("expected 'a'-'c' to have timestamp %s, but found %s", ts1, ts) } else if txn != nil { t.Errorf("expected 'a'-'c' to have nil txn id, but found %s", txn) } }
// TestTimestampCacheNoEviction verifies that even after // the MinTSCacheWindow interval, if the cache has not hit // its size threshold, it will not evict entries. func TestTimestampCacheNoEviction(t *testing.T) { defer leaktest.AfterTest(t)() manual := hlc.NewManualClock(123) clock := hlc.NewClock(manual.UnixNano, time.Nanosecond) tc := newTimestampCache(clock) // Increment time to the low water mark + 1. manual.Increment(1) aTS := clock.Now() tc.add(roachpb.Key("a"), nil, aTS, nil, true) tc.AddRequest(cacheRequest{ reads: []roachpb.Span{{Key: roachpb.Key("c")}}, timestamp: aTS, }) // Increment time by the MinTSCacheWindow and add another key. manual.Increment(MinTSCacheWindow.Nanoseconds()) tc.add(roachpb.Key("b"), nil, clock.Now(), nil, true) tc.AddRequest(cacheRequest{ reads: []roachpb.Span{{Key: roachpb.Key("d")}}, timestamp: clock.Now(), }) // Verify that the cache still has 4 entries in it if l, want := tc.len(), 4; l != want { t.Errorf("expected %d entries to remain, got %d", want, l) } }
// deleteRow adds to the batch the kv operations necessary to delete a table row // with the given values. func (rd *rowDeleter) deleteRow(ctx context.Context, b *client.Batch, values []parser.Datum) error { if err := rd.fks.checkAll(values); err != nil { return err } primaryIndexKey, secondaryIndexEntries, err := rd.helper.encodeIndexes(rd.fetchColIDtoRowIndex, values) if err != nil { return err } for _, secondaryIndexEntry := range secondaryIndexEntries { if log.V(2) { log.Infof(ctx, "Del %s", secondaryIndexEntry.Key) } b.Del(secondaryIndexEntry.Key) } // Delete the row. rd.startKey = roachpb.Key(primaryIndexKey) rd.endKey = roachpb.Key(encoding.EncodeNotNullDescending(primaryIndexKey)) if log.V(2) { log.Infof(ctx, "DelRange %s - %s", rd.startKey, rd.endKey) } b.DelRange(&rd.startKey, &rd.endKey, false) rd.startKey, rd.endKey = nil, nil return nil }
func TestCommandQueueCoveringOptimization(t *testing.T) { defer leaktest.AfterTest(t)() cq := NewCommandQueue(true) a := roachpb.Span{Key: roachpb.Key("a")} b := roachpb.Span{Key: roachpb.Key("b")} c := roachpb.Span{Key: roachpb.Key("c")} { // Test adding a covering entry and then not expanding it. wk := cq.add(false, a, b) if n := cq.tree.Len(); n != 1 { t.Fatalf("expected a single covering span, but got %d", n) } waitCmdDone(cq.getWait(false, c)) cq.remove(wk) } { // Test adding a covering entry and expanding it. wk := cq.add(false, a, b) chans := cq.getWait(false, a) cq.remove(wk) waitCmdDone(chans) } }
func initScanArgs(args []string) (startKey, endKey roachpb.Key, _ error) { if len(args) >= 1 { unquoted, err := unquoteArg(args[0], false) if err != nil { return nil, nil, errors.Wrap(err, "invalid start key") } startKey = roachpb.Key(unquoted) } else { // Start with the first key after the system key range. startKey = keys.UserDataSpan.Key } if len(args) >= 2 { unquoted, err := unquoteArg(args[1], false) if err != nil { return nil, nil, errors.Wrap(err, "invalid end key") } endKey = roachpb.Key(unquoted) } else { // Exclude table data keys by default. The user can explicitly request them // by passing \xff\xff for the end key. endKey = keys.UserDataSpan.EndKey } if bytes.Compare(startKey, endKey) >= 0 { return nil, nil, errors.New("start key must be smaller than end key") } return startKey, endKey, nil }
// TestCommandQueueExclusiveEnd verifies that an end key is treated as // an exclusive end when GetWait calculates overlapping commands. Test // it by calling GetWait with a command whose start key is equal to // the end key of a previous command. func TestCommandQueueExclusiveEnd(t *testing.T) { defer leaktest.AfterTest(t)() cq := NewCommandQueue(true) add(cq, roachpb.Key("a"), roachpb.Key("b"), false) // Verify no wait on the second writer command on "b" since // it does not overlap with the first command on ["a", "b"). waitCmdDone(getWait(cq, roachpb.Key("b"), nil, false)) }
// TestCommandQueueSelfOverlap makes sure that GetWait adds all of the // key ranges simultaneously. If that weren't the case, all but the first // span would wind up waiting on overlapping previous spans, resulting // in deadlock. func TestCommandQueueSelfOverlap(t *testing.T) { defer leaktest.AfterTest(t)() cq := NewCommandQueue(true) a := roachpb.Key("a") k := add(cq, a, roachpb.Key("b"), false) chans := cq.getWait(false, []roachpb.Span{{Key: a}, {Key: a}, {Key: a}}...) cq.remove(k) waitCmdDone(chans) }
// TestBatchPrevNext tests batch.{Prev,Next}. func TestBatchPrevNext(t *testing.T) { defer leaktest.AfterTest(t)() loc := func(s string) string { return string(keys.RangeDescriptorKey(roachpb.RKey(s))) } span := func(strs ...string) []roachpb.Span { var r []roachpb.Span for i, str := range strs { if i%2 == 0 { r = append(r, roachpb.Span{Key: roachpb.Key(str)}) } else { r[len(r)-1].EndKey = roachpb.Key(str) } } return r } max, min := string(roachpb.RKeyMax), string(roachpb.RKeyMin) abc := span("a", "", "b", "", "c", "") testCases := []struct { spans []roachpb.Span key, expFW, expBW string }{ {spans: span("a", "c", "b", ""), key: "b", expFW: "b", expBW: "b"}, {spans: span("a", "c", "b", ""), key: "a", expFW: "a", expBW: "a"}, {spans: span("a", "c", "d", ""), key: "c", expFW: "d", expBW: "c"}, {spans: span("a", "c\x00", "d", ""), key: "c", expFW: "c", expBW: "c"}, {spans: abc, key: "b", expFW: "b", expBW: "b"}, {spans: abc, key: "b\x00", expFW: "c", expBW: "b\x00"}, {spans: abc, key: "bb", expFW: "c", expBW: "b"}, {spans: span(), key: "whatevs", expFW: max, expBW: min}, {spans: span(loc("a"), loc("c")), key: "c", expFW: "c", expBW: "c"}, {spans: span(loc("a"), loc("c")), key: "c\x00", expFW: max, expBW: "c\x00"}, } for i, test := range testCases { var ba roachpb.BatchRequest for _, span := range test.spans { args := &roachpb.ScanRequest{} args.Key, args.EndKey = span.Key, span.EndKey ba.Add(args) } if next, err := next(ba, roachpb.RKey(test.key)); err != nil { t.Errorf("%d: %v", i, err) } else if !bytes.Equal(next, roachpb.Key(test.expFW)) { t.Errorf("%d: next: expected %q, got %q", i, test.expFW, next) } if prev, err := prev(ba, roachpb.RKey(test.key)); err != nil { t.Errorf("%d: %v", i, err) } else if !bytes.Equal(prev, roachpb.Key(test.expBW)) { t.Errorf("%d: prev: expected %q, got %q", i, test.expBW, prev) } } }
// TestInconsistentReads tests that the methods that generate inconsistent reads // generate outgoing requests with an INCONSISTENT read consistency. func TestInconsistentReads(t *testing.T) { defer leaktest.AfterTest(t)() // Mock out DistSender's sender function to check the read consistency for // outgoing BatchRequests and return an empty reply. var senderFn client.SenderFunc senderFn = func(_ context.Context, ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) { if ba.ReadConsistency != roachpb.INCONSISTENT { return nil, roachpb.NewErrorf("BatchRequest has unexpected ReadConsistency %s", ba.ReadConsistency) } return ba.CreateReply(), nil } db := client.NewDB(senderFn) ctx := context.TODO() prepInconsistent := func() *client.Batch { b := &client.Batch{} b.Header.ReadConsistency = roachpb.INCONSISTENT return b } // Perform inconsistent reads through the mocked sender function. { key := roachpb.Key([]byte("key")) b := prepInconsistent() b.Get(key) if err := db.Run(ctx, b); err != nil { t.Fatal(err) } } { b := prepInconsistent() key1 := roachpb.Key([]byte("key1")) key2 := roachpb.Key([]byte("key2")) b.Scan(key1, key2) if err := db.Run(ctx, b); err != nil { t.Fatal(err) } } { key := roachpb.Key([]byte("key")) b := &client.Batch{} b.Header.ReadConsistency = roachpb.INCONSISTENT b.Get(key) if err := db.Run(ctx, b); err != nil { t.Fatal(err) } } }
func marshalKey(k interface{}) (roachpb.Key, error) { switch t := k.(type) { case *roachpb.Key: return *t, nil case roachpb.Key: return t, nil case string: return roachpb.Key(t), nil case []byte: return roachpb.Key(t), nil } return nil, fmt.Errorf("unable to marshal key: %T %q", k, k) }
// TestLocalKeySorting is a sanity check to make sure that // the non-replicated part of a store sorts before the meta. func TestKeySorting(t *testing.T) { // Reminder: Increasing the last byte by one < adding a null byte. if !(roachpb.RKey("").Less(roachpb.RKey("\x00")) && roachpb.RKey("\x00").Less(roachpb.RKey("\x01")) && roachpb.RKey("\x01").Less(roachpb.RKey("\x01\x00"))) { t.Fatalf("something is seriously wrong with this machine") } if bytes.Compare(localPrefix, Meta1Prefix) >= 0 { t.Fatalf("local key spilling into replicated ranges") } if !bytes.Equal(roachpb.Key(""), roachpb.Key(nil)) { t.Fatalf("equality between keys failed") } }
// TestTxnMultipleCoord checks that a coordinator uses the Writing flag to // enforce that only one coordinator can be used for transactional writes. func TestTxnMultipleCoord(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() testCases := []struct { args roachpb.Request writing bool ok bool }{ {roachpb.NewGet(roachpb.Key("a")), true, false}, {roachpb.NewGet(roachpb.Key("a")), false, true}, {roachpb.NewPut(roachpb.Key("a"), roachpb.Value{}), false, false}, // transactional write before begin {roachpb.NewPut(roachpb.Key("a"), roachpb.Value{}), true, false}, // must have switched coordinators } for i, tc := range testCases { txn := roachpb.NewTransaction("test", roachpb.Key("a"), 1, enginepb.SERIALIZABLE, s.Clock.Now(), s.Clock.MaxOffset().Nanoseconds()) txn.Writing = tc.writing reply, pErr := client.SendWrappedWith(context.Background(), sender, roachpb.Header{ Txn: txn, }, tc.args) if pErr == nil != tc.ok { t.Errorf("%d: %T (writing=%t): success_expected=%t, but got: %v", i, tc.args, tc.writing, tc.ok, pErr) } if pErr != nil { continue } txn = reply.Header().Txn // The transaction should come back rw if it started rw or if we just // wrote. isWrite := roachpb.IsTransactionWrite(tc.args) if (tc.writing || isWrite) != txn.Writing { t.Errorf("%d: unexpected writing state: %s", i, txn) } if !isWrite { continue } // Abort for clean shutdown. if _, pErr := client.SendWrappedWith(context.Background(), sender, roachpb.Header{ Txn: txn, }, &roachpb.EndTransactionRequest{ Commit: false, }); pErr != nil { t.Fatal(pErr) } } }
func mvccKey(k interface{}) MVCCKey { switch k := k.(type) { case string: return MakeMVCCMetadataKey(roachpb.Key(k)) case []byte: return MakeMVCCMetadataKey(roachpb.Key(k)) case roachpb.Key: return MakeMVCCMetadataKey(k) case roachpb.RKey: return MakeMVCCMetadataKey(roachpb.Key(k)) default: panic(fmt.Sprintf("unsupported type: %T", k)) } }
// TestTxnCoordSenderBeginTransaction verifies that a command sent with a // not-nil Txn with empty ID gets a new transaction initialized. func TestTxnCoordSenderBeginTransaction(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() defer teardownHeartbeats(sender) txn := client.NewTxn(context.Background(), *s.DB) // Put request will create a new transaction. key := roachpb.Key("key") txn.InternalSetPriority(10) txn.Proto.Isolation = enginepb.SNAPSHOT txn.Proto.Name = "test txn" if err := txn.Put(key, []byte("value")); err != nil { t.Fatal(err) } if txn.Proto.Name != "test txn" { t.Errorf("expected txn name to be %q; got %q", "test txn", txn.Proto.Name) } if txn.Proto.Priority != 10 { t.Errorf("expected txn priority 10; got %d", txn.Proto.Priority) } if !bytes.Equal(txn.Proto.Key, key) { t.Errorf("expected txn Key to match %q != %q", key, txn.Proto.Key) } if txn.Proto.Isolation != enginepb.SNAPSHOT { t.Errorf("expected txn isolation to be SNAPSHOT; got %s", txn.Proto.Isolation) } }
// TestTxnCoordSenderSingleRoundtripTxn checks that a batch which completely // holds the writing portion of a Txn (including EndTransaction) does not // launch a heartbeat goroutine at all. func TestTxnCoordSenderSingleRoundtripTxn(t *testing.T) { defer leaktest.AfterTest(t)() stopper := stop.NewStopper() manual := hlc.NewManualClock(123) clock := hlc.NewClock(manual.UnixNano, 20*time.Nanosecond) senderFunc := func(_ context.Context, ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) { br := ba.CreateReply() txnClone := ba.Txn.Clone() br.Txn = &txnClone br.Txn.Writing = true return br, nil } ambient := log.AmbientContext{Tracer: tracing.NewTracer()} ts := NewTxnCoordSender( ambient, senderFn(senderFunc), clock, false, stopper, MakeTxnMetrics(metric.TestSampleInterval), ) // Stop the stopper manually, prior to trying the transaction. This has the // effect of returning a NodeUnavailableError for any attempts at launching // a heartbeat goroutine. stopper.Stop() var ba roachpb.BatchRequest key := roachpb.Key("test") ba.Add(&roachpb.BeginTransactionRequest{Span: roachpb.Span{Key: key}}) ba.Add(&roachpb.PutRequest{Span: roachpb.Span{Key: key}}) ba.Add(&roachpb.EndTransactionRequest{}) ba.Txn = &roachpb.Transaction{Name: "test"} _, pErr := ts.Send(context.Background(), ba) if pErr != nil { t.Fatal(pErr) } }
// runMVCCScan first creates test data (and resets the benchmarking // timer). It then performs b.N MVCCScans in increments of numRows // keys over all of the data in the Engine instance, restarting at // the beginning of the keyspace, as many times as necessary. func runMVCCScan(emk engineMaker, numRows, numVersions, valueSize int, b *testing.B) { // Use the same number of keys for all of the mvcc scan // benchmarks. Using a different number of keys per test gives // preferential treatment to tests with fewer keys. Note that the // datasets all fit in cache and the cache is pre-warmed. const numKeys = 100000 eng, _ := setupMVCCData(emk, numVersions, numKeys, valueSize, b) defer eng.Close() b.SetBytes(int64(numRows * valueSize)) b.ResetTimer() keyBuf := append(make([]byte, 0, 64), []byte("key-")...) for i := 0; i < b.N; i++ { // Choose a random key to start scan. keyIdx := rand.Int31n(int32(numKeys - numRows)) startKey := roachpb.Key(encoding.EncodeUvarintAscending(keyBuf[:4], uint64(keyIdx))) walltime := int64(5 * (rand.Int31n(int32(numVersions)) + 1)) ts := makeTS(walltime, 0) kvs, _, _, err := MVCCScan(context.Background(), eng, startKey, keyMax, int64(numRows), ts, true, nil) if err != nil { b.Fatalf("failed scan: %s", err) } if len(kvs) != numRows { b.Fatalf("failed to scan: %d != %d", len(kvs), numRows) } } b.StopTimer() }
// runMVCCGet first creates test data (and resets the benchmarking // timer). It then performs b.N MVCCGets. func runMVCCGet(emk engineMaker, numVersions, valueSize int, b *testing.B) { const overhead = 48 // Per key/value overhead (empirically determined) const targetSize = 512 << 20 // 512 MB // Adjust the number of keys so that each test has approximately the same // amount of data. numKeys := targetSize / ((overhead + valueSize) * (1 + (numVersions-1)/2)) eng, _ := setupMVCCData(emk, numVersions, numKeys, valueSize, b) defer eng.Close() b.SetBytes(int64(valueSize)) b.ResetTimer() keyBuf := append(make([]byte, 0, 64), []byte("key-")...) for i := 0; i < b.N; i++ { // Choose a random key to retrieve. keyIdx := rand.Int31n(int32(numKeys)) key := roachpb.Key(encoding.EncodeUvarintAscending(keyBuf[:4], uint64(keyIdx))) walltime := int64(5 * (rand.Int31n(int32(numVersions)) + 1)) ts := makeTS(walltime, 0) if v, _, err := MVCCGet(context.Background(), eng, key, ts, true, nil); err != nil { b.Fatalf("failed get: %s", err) } else if v == nil { b.Fatalf("failed get (key not found): %d@%d", keyIdx, walltime) } else if valueBytes, err := v.GetBytes(); err != nil { b.Fatal(err) } else if len(valueBytes) != valueSize { b.Fatalf("unexpected value size: %d", len(valueBytes)) } } b.StopTimer() }
func TestDropIndexInterleaved(t *testing.T) { defer leaktest.AfterTest(t)() const chunkSize = 200 params, _ := createTestServerParams() params.Knobs = base.TestingKnobs{ SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ BackfillChunkSize: chunkSize, }, } s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() numRows := 2*chunkSize + 1 createKVInterleavedTable(t, sqlDB, numRows) tableDesc := sqlbase.GetTableDescriptor(kvDB, "t", "kv") tablePrefix := roachpb.Key(keys.MakeTablePrefix(uint32(tableDesc.ID))) checkKeyCount(t, kvDB, tablePrefix, 3*numRows) if _, err := sqlDB.Exec(`DROP INDEX t.intlv@intlv_idx`); err != nil { t.Fatal(err) } checkKeyCount(t, kvDB, tablePrefix, 2*numRows) // Ensure that index is not active. tableDesc = sqlbase.GetTableDescriptor(kvDB, "t", "intlv") if _, _, err := tableDesc.FindIndexByName("intlv_idx"); err == nil { t.Fatalf("table descriptor still contains index after index is dropped") } }
// TestDropTableInterleaved tests dropping a table that is interleaved within // another table. func TestDropTableInterleaved(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, kvDB := serverutils.StartServer(t, params) defer s.Stopper().Stop() numRows := 2*sql.TableTruncateChunkSize + 1 createKVInterleavedTable(t, sqlDB, numRows) tableDesc := sqlbase.GetTableDescriptor(kvDB, "t", "kv") tablePrefix := roachpb.Key(keys.MakeTablePrefix(uint32(tableDesc.ID))) checkKeyCount(t, kvDB, tablePrefix, 3*numRows) if _, err := sqlDB.Exec(`DROP TABLE t.intlv`); err != nil { t.Fatal(err) } checkKeyCount(t, kvDB, tablePrefix, numRows) // Test that deleted table cannot be used. This prevents regressions where // name -> descriptor ID caches might make this statement erronously work. if _, err := sqlDB.Exec(`SELECT * FROM t.intlv`); !testutils.IsError( err, `table "t.intlv" does not exist`, ) { t.Fatalf("different error than expected: %v", err) } }
// TestRangeLookupWithOpenTransaction verifies that range lookups are // done in such a way (e.g. using inconsistent reads) that they // proceed in the event that a write intent is extant at the meta // index record being read. func TestRangeLookupWithOpenTransaction(t *testing.T) { defer leaktest.AfterTest(t)() s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop() db := createTestClient(t, s.Stopper(), s.ServingAddr()) // Create an intent on the meta1 record by writing directly to the // engine. key := testutils.MakeKey(keys.Meta1Prefix, roachpb.KeyMax) now := s.Clock().Now() txn := roachpb.NewTransaction("txn", roachpb.Key("foobar"), 0, enginepb.SERIALIZABLE, now, 0) if err := engine.MVCCPutProto( context.Background(), s.(*server.TestServer).Engines()[0], nil, key, now, txn, &roachpb.RangeDescriptor{}); err != nil { t.Fatal(err) } // Now, with an intent pending, attempt (asynchronously) to read // from an arbitrary key. This will cause the distributed sender to // do a range lookup, which will encounter the intent. We're // verifying here that the range lookup doesn't fail with a write // intent error. If it did, it would go into a deadloop attempting // to push the transaction, which in turn requires another range // lookup, etc, ad nauseam. if _, err := db.Get(context.TODO(), "a"); err != nil { t.Fatal(err) } }
// TestTxnInitialTimestamp verifies that the timestamp requested // before the Txn is created is honored. func TestTxnInitialTimestamp(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() defer teardownHeartbeats(sender) txn := client.NewTxn(context.Background(), *s.DB) // Request a specific timestamp. refTimestamp := s.Clock.Now().Add(42, 69) txn.Proto.OrigTimestamp = refTimestamp // Put request will create a new transaction. key := roachpb.Key("key") txn.InternalSetPriority(10) txn.Proto.Isolation = enginepb.SNAPSHOT txn.Proto.Name = "test txn" if err := txn.Put(key, []byte("value")); err != nil { t.Fatal(err) } if txn.Proto.OrigTimestamp != refTimestamp { t.Errorf("expected txn orig ts to be %s; got %s", refTimestamp, txn.Proto.OrigTimestamp) } if txn.Proto.Timestamp != refTimestamp { t.Errorf("expected txn ts to be %s; got %s", refTimestamp, txn.Proto.Timestamp) } }
// TestTxnCoordSenderAddIntentOnError verifies that intents are tracked if // the transaction is, even on error. func TestTxnCoordSenderAddIntentOnError(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() // Create a transaction with intent at "a". key := roachpb.Key("x") txn := client.NewTxn(context.Background(), *s.DB) // Write so that the coordinator begins tracking this txn. if err := txn.Put("x", "y"); err != nil { t.Fatal(err) } err, ok := txn.CPut(key, []byte("x"), []byte("born to fail")).(*roachpb.ConditionFailedError) if !ok { t.Fatal(err) } sender.Lock() txnID := *txn.Proto.ID intentSpans, _ := roachpb.MergeSpans(sender.txns[txnID].keys) expSpans := []roachpb.Span{{Key: key, EndKey: []byte("")}} equal := !reflect.DeepEqual(intentSpans, expSpans) sender.Unlock() if err := txn.Rollback(); err != nil { t.Fatal(err) } if !equal { t.Fatalf("expected stored intents %v, got %v", expSpans, intentSpans) } }
// TestTxnCoordSenderGCTimeout verifies that the coordinator cleans up extant // transactions and intents after the lastUpdateNanos exceeds the timeout. func TestTxnCoordSenderGCTimeout(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() // Set heartbeat interval to 1ms for testing. sender.heartbeatInterval = 1 * time.Millisecond txn := client.NewTxn(context.Background(), *s.DB) key := roachpb.Key("a") if err := txn.Put(key, []byte("value")); err != nil { t.Fatal(err) } // Now, advance clock past the default client timeout. // Locking the TxnCoordSender to prevent a data race. sender.Lock() s.Manual.Increment(defaultClientTimeout.Nanoseconds() + 1) sender.Unlock() txnID := *txn.Proto.ID util.SucceedsSoon(t, func() error { // Locking the TxnCoordSender to prevent a data race. sender.Lock() _, ok := sender.txns[txnID] sender.Unlock() if ok { return errors.Errorf("expected garbage collection") } return nil }) verifyCleanup(key, sender, s.Eng, t) }
// TestTxnCoordIdempotentCleanup verifies that cleanupTxnLocked is idempotent. func TestTxnCoordIdempotentCleanup(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() defer teardownHeartbeats(sender) txn := client.NewTxn(context.Background(), *s.DB) ba := txn.NewBatch() ba.Put(roachpb.Key("a"), []byte("value")) if err := txn.Run(ba); err != nil { t.Fatal(err) } sender.Lock() // Clean up twice successively. sender.cleanupTxnLocked(context.Background(), txn.Proto) sender.cleanupTxnLocked(context.Background(), txn.Proto) sender.Unlock() // For good measure, try to commit (which cleans up once more if it // succeeds, which it may not if the previous cleanup has already // terminated the heartbeat goroutine) ba = txn.NewBatch() ba.AddRawRequest(&roachpb.EndTransactionRequest{}) err := txn.Run(ba) if err != nil && !testutils.IsError(err, errNoState.Error()) { t.Fatal(err) } }
// TestTxnCoordSenderCleanupOnAborted verifies that if a txn receives a // TransactionAbortedError, the coordinator cleans up the transaction. func TestTxnCoordSenderCleanupOnAborted(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() // Create a transaction with intent at "a". key := roachpb.Key("a") txn1 := client.NewTxn(context.Background(), *s.DB) txn1.InternalSetPriority(1) if err := txn1.Put(key, []byte("value")); err != nil { t.Fatal(err) } // Push the transaction (by writing key "a" with higher priority) to abort it. txn2 := client.NewTxn(context.Background(), *s.DB) txn2.InternalSetPriority(2) if err := txn2.Put(key, []byte("value2")); err != nil { t.Fatal(err) } // Now end the transaction and verify we've cleanup up, even though // end transaction failed. err := txn1.CommitOrCleanup() assertTransactionAbortedError(t, err) if err := txn2.CommitOrCleanup(); err != nil { t.Fatal(err) } verifyCleanup(key, sender, s.Eng, t) }
// checks ResumeSpan returned in a ScanResponse. func checkResumeSpanScanResults( t *testing.T, spans [][]string, results []client.Result, expResults [][]string, expCount int, ) { for i, res := range results { rowLen := len(res.Rows) // Check ResumeSpan when request has been processed. if rowLen > 0 { if rowLen == len(expResults[i]) { // The key can be empty once the entire response is seen. It // is not guaranteed to be empty. if res.ResumeSpan.Key == nil { continue } } // The next start key is always greater than or equal to the last // key.Next() seen. It is either set to last key.Next, or the end // key of the range that the last key was a part of. if key, expKey := string(res.ResumeSpan.Key), string(roachpb.Key(expResults[i][rowLen-1]).Next()); key < expKey { t.Errorf("%s: expected resume key %d, %d to be %q; got %q", errInfo(), i, expCount, expKey, key) } } else { // The row was not read; the resume span key <= first seen key if key, expKey := string(res.ResumeSpan.Key), expResults[i][0]; key > expKey { t.Errorf("%s: expected resume key %d, %d to be %q; got %q", errInfo(), i, expCount, expKey, key) } } // The EndKey is untouched. if key, expKey := string(res.ResumeSpan.EndKey), spans[i][1]; key != expKey { t.Errorf("%s: expected resume endkey %d, %d to be %q; got %q", errInfo(), i, expCount, expKey, key) } } }