func TestExplainTrace(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() s, sqlDB, _ := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(`CREATE DATABASE test; CREATE TABLE test.foo (id INT PRIMARY KEY)`); err != nil { t.Fatal(err) } rows, err := sqlDB.Query(`EXPLAIN (TRACE) INSERT INTO test.foo VALUES (1)`) if err != nil { t.Fatal(err) } expParts := []string{"coordinator", "node 1"} var parts []string pretty := rowsToStrings(rows) for _, row := range pretty[1:] { part := row[3] // Operation if ind := sort.SearchStrings(parts, part); ind == len(parts) || parts[ind] != part { parts = append(parts, part) sort.Strings(parts) } } sort.Strings(expParts) if err := rows.Err(); err != nil { t.Fatal(err) } if !reflect.DeepEqual(expParts, parts) { t.Fatalf("expected %v, got %v\n\nResults:\n%v", expParts, parts, prettyPrint(pretty)) } }
// TestStoreRangeMergeTwoEmptyRanges tries to merge two empty ranges // together. func TestStoreRangeMergeTwoEmptyRanges(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() if _, _, err := createSplitRanges(store); err != nil { t.Fatal(err) } // Merge the b range back into the a range. args := adminMergeArgs(roachpb.KeyMin) _, err := client.SendWrapped(rg1(store), nil, &args) if err != nil { t.Fatal(err) } // Verify the merge by looking up keys from both ranges. rangeA := store.LookupReplica([]byte("a"), nil) rangeB := store.LookupReplica([]byte("c"), nil) if !reflect.DeepEqual(rangeA, rangeB) { t.Fatalf("ranges were not merged %+v=%+v", rangeA.Desc(), rangeB.Desc()) } }
// TestStoreRangeMergeStats starts by splitting a range, then writing random data // to both sides of the split. It then merges the ranges and verifies the merged // range has stats consistent with recomputations. func TestStoreRangeMergeStats(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, manual := createTestStore(t) defer stopper.Stop() // Split the range. aDesc, bDesc, err := createSplitRanges(store) if err != nil { t.Fatal(err) } // Write some values left and right of the proposed split key. writeRandomDataToRange(t, store, aDesc.RangeID, []byte("aaa")) writeRandomDataToRange(t, store, bDesc.RangeID, []byte("ccc")) // Get the range stats for both ranges now that we have data. var msA, msB engine.MVCCStats snap := store.Engine().NewSnapshot() defer snap.Close() if err := engine.MVCCGetRangeStats(context.Background(), snap, aDesc.RangeID, &msA); err != nil { t.Fatal(err) } if err := engine.MVCCGetRangeStats(context.Background(), snap, bDesc.RangeID, &msB); err != nil { t.Fatal(err) } // Stats should agree with recomputation. if err := verifyRecomputedStats(snap, aDesc, msA, manual.UnixNano()); err != nil { t.Fatalf("failed to verify range A's stats before split: %v", err) } if err := verifyRecomputedStats(snap, bDesc, msB, manual.UnixNano()); err != nil { t.Fatalf("failed to verify range B's stats before split: %v", err) } manual.Increment(100) // Merge the b range back into the a range. args := adminMergeArgs(roachpb.KeyMin) if _, err := client.SendWrapped(rg1(store), nil, &args); err != nil { t.Fatal(err) } rngMerged := store.LookupReplica(aDesc.StartKey, nil) // Get the range stats for the merged range and verify. snap = store.Engine().NewSnapshot() defer snap.Close() var msMerged engine.MVCCStats if err := engine.MVCCGetRangeStats(context.Background(), snap, rngMerged.RangeID, &msMerged); err != nil { t.Fatal(err) } // Merged stats should agree with recomputation. if err := verifyRecomputedStats(snap, rngMerged.Desc(), msMerged, manual.UnixNano()); err != nil { t.Errorf("failed to verify range's stats after merge: %v", err) } }
// TestStoreRangeMergeLastRange verifies that merging the last range // fails. func TestStoreRangeMergeLastRange(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() // Merge last range. args := adminMergeArgs(roachpb.KeyMin) if _, pErr := client.SendWrapped(rg1(store), nil, &args); !testutils.IsPError(pErr, "cannot merge final range") { t.Fatalf("expected 'cannot merge final range' error; got %s", pErr) } }
// TestStoreRangeSplitAtTablePrefix verifies a range can be split at // UserTableDataMin and still gossip the SystemConfig properly. func TestStoreRangeSplitAtTablePrefix(t *testing.T) { defer leaktest.AfterTest(t) defer config.TestingDisableTableSplits()() store, stopper := createTestStore(t) defer stopper.Stop() key := keys.MakeNonColumnKey(append([]byte(nil), keys.UserTableDataMin...)) args := adminSplitArgs(key, key) _, err := client.SendWrapped(rg1(store), nil, &args) if err != nil { t.Fatalf("%q: split unexpected error: %s", key, err) } desc := &sql.TableDescriptor{} descBytes, err := desc.Marshal() if err != nil { t.Fatal(err) } // Update SystemConfig to trigger gossip. if err := store.DB().Txn(func(txn *client.Txn) error { txn.SetSystemConfigTrigger() // We don't care about the values, just the keys. k := sql.MakeDescMetadataKey(sql.ID(keys.MaxReservedDescID + 1)) return txn.Put(k, desc) }); err != nil { t.Fatal(err) } successChan := make(chan struct{}, 1) store.Gossip().RegisterCallback(gossip.KeySystemConfig, func(_ string, content roachpb.Value) { contentBytes, err := content.GetBytes() if err != nil { t.Fatal(err) } if bytes.Contains(contentBytes, descBytes) { select { case successChan <- struct{}{}: default: } } }) select { case <-time.After(time.Second): t.Errorf("expected a schema gossip containing %q, but did not see one", descBytes) case <-successChan: } }
// TestStoreRangeSplitInsideRow verifies an attempt to split a range inside of // a table row will cause a split at a boundary between rows. func TestStoreRangeSplitInsideRow(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() // Manually create some the column keys corresponding to the table: // // CREATE TABLE t (id STRING PRIMARY KEY, col1 INT, col2 INT) tableKey := keys.MakeTablePrefix(keys.MaxReservedDescID + 1) rowKey := roachpb.Key(encoding.EncodeVarintAscending(append([]byte(nil), tableKey...), 1)) rowKey = encoding.EncodeStringAscending(encoding.EncodeVarintAscending(rowKey, 1), "a") col1Key := keys.MakeColumnKey(append([]byte(nil), rowKey...), 1) col2Key := keys.MakeColumnKey(append([]byte(nil), rowKey...), 2) // We don't care about the value, so just store any old thing. if pErr := store.DB().Put(col1Key, "column 1"); pErr != nil { t.Fatal(pErr) } if pErr := store.DB().Put(col2Key, "column 2"); pErr != nil { t.Fatal(pErr) } // Split between col1Key and col2Key by splitting before col2Key. args := adminSplitArgs(col2Key, col2Key) _, pErr := client.SendWrapped(rg1(store), nil, &args) if pErr != nil { t.Fatalf("%s: split unexpected error: %s", col1Key, pErr) } rng1 := store.LookupReplica(col1Key, nil) rng2 := store.LookupReplica(col2Key, nil) // Verify the two columns are still on the same range. if !reflect.DeepEqual(rng1, rng2) { t.Fatalf("%s: ranges differ: %+v vs %+v", roachpb.Key(col1Key), rng1, rng2) } // Verify we split on a row key. if startKey := rng1.Desc().StartKey; !startKey.Equal(rowKey) { t.Fatalf("%s: expected split on %s, but found %s", roachpb.Key(col1Key), roachpb.Key(rowKey), startKey) } // Verify the previous range was split on a row key. rng3 := store.LookupReplica(tableKey, nil) if endKey := rng3.Desc().EndKey; !endKey.Equal(rowKey) { t.Fatalf("%s: expected split on %s, but found %s", roachpb.Key(col1Key), roachpb.Key(rowKey), endKey) } }
// TestSetupRangeTree ensures that SetupRangeTree correctly setups up the range // tree and first node. SetupRangeTree is called via store.BootstrapRange. func TestSetupRangeTree(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() db := store.DB() tree, nodes := loadTree(t, db) expectedTree := storage.RangeTree{ RootKey: roachpb.RKeyMin, } if !reflect.DeepEqual(tree, expectedTree) { t.Fatalf("tree roots do not match - expected:%+v actual:%+v", expectedTree, tree) } VerifyTree(t, tree, nodes, "setup") }
// TestStoreRangeSplitAtRangeBounds verifies a range cannot be split // at its start or end keys (would create zero-length range!). This // sort of thing might happen in the wild if two split requests // arrived for same key. The first one succeeds and second would try // to split at the start of the newly split range. func TestStoreRangeSplitAtRangeBounds(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() args := adminSplitArgs(roachpb.KeyMin, []byte("a")) if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr != nil { t.Fatal(pErr) } // This second split will try to split at end of first split range. if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr == nil { t.Fatalf("split succeeded unexpectedly") } // Now try to split at start of new range. args = adminSplitArgs(roachpb.KeyMin, []byte("a")) if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr == nil { t.Fatalf("split succeeded unexpectedly") } }
// TestStoreRangeSplitConcurrent verifies that concurrent range splits // of the same range are executed serially, and all but the first fail // because the split key is invalid after the first split succeeds. func TestStoreRangeSplitConcurrent(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() splitKey := roachpb.Key("a") concurrentCount := int32(10) wg := sync.WaitGroup{} wg.Add(int(concurrentCount)) failureCount := int32(0) for i := int32(0); i < concurrentCount; i++ { go func() { args := adminSplitArgs(roachpb.KeyMin, splitKey) _, pErr := client.SendWrapped(rg1(store), nil, &args) if pErr != nil { atomic.AddInt32(&failureCount, 1) } wg.Done() }() } wg.Wait() if failureCount != concurrentCount-1 { t.Fatalf("concurrent splits succeeded unexpectedly; failureCount=%d", failureCount) } // Verify everything ended up as expected. if a, e := store.ReplicaCount(), 2; a != e { t.Fatalf("expected %d stores after concurrent splits; actual count=%d", e, a) } rng := store.LookupReplica(roachpb.RKeyMin, nil) newRng := store.LookupReplica(roachpb.RKey(splitKey), nil) if !bytes.Equal(newRng.Desc().StartKey, splitKey) || !bytes.Equal(splitKey, rng.Desc().EndKey) { t.Errorf("ranges mismatched, wanted %q=%q=%q", newRng.Desc().StartKey, splitKey, rng.Desc().EndKey) } if !bytes.Equal(newRng.Desc().EndKey, roachpb.RKeyMax) || !bytes.Equal(rng.Desc().StartKey, roachpb.RKeyMin) { t.Errorf("new ranges do not cover KeyMin-KeyMax, but only %q-%q", rng.Desc().StartKey, newRng.Desc().EndKey) } }
func BenchmarkStoreRangeSplit(b *testing.B) { defer tracing.Disable()() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(b) defer stopper.Stop() // Perform initial split of ranges. sArgs := adminSplitArgs(roachpb.KeyMin, []byte("b")) if _, err := client.SendWrapped(rg1(store), nil, &sArgs); err != nil { b.Fatal(err) } // Write some values left and right of the split key. aDesc := store.LookupReplica([]byte("a"), nil).Desc() bDesc := store.LookupReplica([]byte("c"), nil).Desc() writeRandomDataToRange(b, store, aDesc.RangeID, []byte("aaa")) writeRandomDataToRange(b, store, bDesc.RangeID, []byte("ccc")) // Merge the b range back into the a range. mArgs := adminMergeArgs(roachpb.KeyMin) if _, err := client.SendWrapped(rg1(store), nil, &mArgs); err != nil { b.Fatal(err) } b.ResetTimer() for i := 0; i < b.N; i++ { // Split the range. b.StartTimer() if _, err := client.SendWrapped(rg1(store), nil, &sArgs); err != nil { b.Fatal(err) } // Merge the ranges. b.StopTimer() if _, err := client.SendWrapped(rg1(store), nil, &mArgs); err != nil { b.Fatal(err) } } }
func BenchmarkReplicaSnapshot(b *testing.B) { defer tracing.Disable()() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(b) // We want to manually control the size of the raft log. store.DisableRaftLogQueue(true) defer stopper.Stop() const rangeID = 1 const keySize = 1 << 7 // 128 B const valSize = 1 << 10 // 1 KiB const snapSize = 1 << 25 // 32 MiB rep, err := store.GetReplica(rangeID) if err != nil { b.Fatal(err) } src := rand.New(rand.NewSource(0)) for i := 0; i < snapSize/(keySize+valSize); i++ { key := keys.MakeRowSentinelKey(randutil.RandBytes(src, keySize)) val := randutil.RandBytes(src, valSize) pArgs := putArgs(key, val) if _, pErr := client.SendWrappedWith(rep, nil, roachpb.Header{ RangeID: rangeID, }, &pArgs); pErr != nil { b.Fatal(pErr) } } b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := rep.GetSnapshot(); err != nil { b.Fatal(err) } } }
// TestTree is a similar to the TestTree test in range_tree_test but this one // performs actual splits and merges. func TestTree(t *testing.T) { defer leaktest.AfterTest(t) defer config.TestingDisableTableSplits()() store, stopper := createTestStore(t) defer stopper.Stop() db := store.DB() keys := []string{"m", "f", "e", "d", "c", "b", "a", "g", "h", "i", "j", "k", "l", "s", "r", "q", "p", "o", "n", "t", "u", "v", "w", "x", "y", "z", } for _, key := range keys { if err := db.AdminSplit(key); err != nil { t.Fatal(err) } tree, nodes := loadTree(t, db) VerifyTree(t, tree, nodes, key) } // To test merging, we just call AdminMerge on the lowest key to merge all // ranges back into a single one. // TODO(bdarnell): re-enable this when merging is more reliable. // https://github.com/cockroachdb/cockroach/issues/2433 /* for i := 0; i < len(keys); i++ { if err := db.AdminMerge(roachpb.KeyMin); err != nil { t.Fatal(err) } tree, nodes := loadTree(t, db) VerifyTree(t, tree, nodes, fmt.Sprintf("remove %d", i)) } */ }
// TestGetZoneConfig exercises config.GetZoneConfig and the sql hook for it. func TestGetZoneConfig(t *testing.T) { defer leaktest.AfterTest(t) // Disable splitting. We're using bad attributes in zone configs // to be able to match. defer config.TestingDisableTableSplits()() s, sqlDB, _ := setup(t) defer cleanup(s, sqlDB) expectedCounter := uint32(keys.MaxReservedDescID + 1) // Naming scheme for database and tables: // db1 has tables tb11 and tb12 // db2 has tables tb21 and tb22 db1 := expectedCounter if _, err := sqlDB.Exec(`CREATE DATABASE db1`); err != nil { t.Fatal(err) } expectedCounter++ db2 := expectedCounter if _, err := sqlDB.Exec(`CREATE DATABASE db2`); err != nil { t.Fatal(err) } expectedCounter++ tb11 := expectedCounter if _, err := sqlDB.Exec(`CREATE TABLE db1.tb1 (k INT PRIMARY KEY, v INT)`); err != nil { t.Fatal(err) } expectedCounter++ tb12 := expectedCounter if _, err := sqlDB.Exec(`CREATE TABLE db1.tb2 (k INT PRIMARY KEY, v INT)`); err != nil { t.Fatal(err) } expectedCounter++ tb21 := expectedCounter if _, err := sqlDB.Exec(`CREATE TABLE db2.tb1 (k INT PRIMARY KEY, v INT)`); err != nil { t.Fatal(err) } expectedCounter++ tb22 := expectedCounter if _, err := sqlDB.Exec(`CREATE TABLE db2.tb2 (k INT PRIMARY KEY, v INT)`); err != nil { t.Fatal(err) } expectedCounter++ cfg, err := forceNewConfig(t, s) if err != nil { t.Fatalf("failed to get latest system config: %s", err) } // We have no custom zone configs. testCases := []struct { key roachpb.RKey zoneCfg config.ZoneConfig }{ {roachpb.RKeyMin, *config.DefaultZoneConfig}, {keys.Addr(keys.TableDataPrefix), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(1), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(keys.MaxReservedDescID), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(db1), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(db2), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(tb11), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(tb12), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(tb21), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(tb22), *config.DefaultZoneConfig}, } for tcNum, tc := range testCases { zoneCfg, err := cfg.GetZoneConfigForKey(tc.key) if err != nil { t.Fatalf("#%d: err=%s", tcNum, err) } if !reflect.DeepEqual(*zoneCfg, tc.zoneCfg) { t.Errorf("#%d: bad zone config.\nexpected: %+v\ngot: %+v", tcNum, tc.zoneCfg, zoneCfg) } } // Now set some zone configs. We don't have a nice way of using table // names for this, so we do raw puts. // Here is the list of dbs/tables and whether they have a custom zone config: // db1: true // tb1: true // tb2: false // db1: false // tb1: true // tb2: false db1Cfg := config.ZoneConfig{ReplicaAttrs: []roachpb.Attributes{{[]string{"db1"}}}} tb11Cfg := config.ZoneConfig{ReplicaAttrs: []roachpb.Attributes{{[]string{"db1.tb1"}}}} tb21Cfg := config.ZoneConfig{ReplicaAttrs: []roachpb.Attributes{{[]string{"db2.tb1"}}}} for objID, objZone := range map[uint32]config.ZoneConfig{ db1: db1Cfg, tb11: tb11Cfg, tb21: tb21Cfg, } { buf, err := proto.Marshal(&objZone) if err != nil { t.Fatal(err) } if _, err = sqlDB.Exec(`INSERT INTO system.zones VALUES ($1, $2)`, objID, buf); err != nil { t.Fatalf("problem writing zone %+v: %s", objZone, err) } } cfg, err = forceNewConfig(t, s) if err != nil { t.Fatalf("failed to get latest system config: %s", err) } testCases = []struct { key roachpb.RKey zoneCfg config.ZoneConfig }{ {roachpb.RKeyMin, *config.DefaultZoneConfig}, {keys.Addr(keys.TableDataPrefix), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(1), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(keys.MaxReservedDescID), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(db1), db1Cfg}, {keys.MakeTablePrefix(db2), *config.DefaultZoneConfig}, {keys.MakeTablePrefix(tb11), tb11Cfg}, {keys.MakeTablePrefix(tb12), db1Cfg}, {keys.MakeTablePrefix(tb21), tb21Cfg}, {keys.MakeTablePrefix(tb22), *config.DefaultZoneConfig}, } for tcNum, tc := range testCases { zoneCfg, err := cfg.GetZoneConfigForKey(tc.key) if err != nil { t.Fatalf("#%d: err=%s", tcNum, err) } if !reflect.DeepEqual(*zoneCfg, tc.zoneCfg) { t.Errorf("#%d: bad zone config.\nexpected: %+v\ngot: %+v", tcNum, tc.zoneCfg, zoneCfg) } } }
// TestStoreRecoverFromEngine verifies that the store recovers all ranges and their contents // after being stopped and recreated. func TestStoreRecoverFromEngine(t *testing.T) { defer leaktest.AfterTest(t) defer config.TestingDisableTableSplits()() rangeID := roachpb.RangeID(1) splitKey := roachpb.Key("m") key1 := roachpb.Key("a") key2 := roachpb.Key("z") manual := hlc.NewManualClock(0) clock := hlc.NewClock(manual.UnixNano) engineStopper := stop.NewStopper() defer engineStopper.Stop() eng := engine.NewInMem(roachpb.Attributes{}, 1<<20, engineStopper) var rangeID2 roachpb.RangeID get := func(store *storage.Store, rangeID roachpb.RangeID, key roachpb.Key) int64 { args := getArgs(key) resp, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rangeID, }, &args) if err != nil { t.Fatal(err) } return mustGetInt(resp.(*roachpb.GetResponse).Value) } validate := func(store *storage.Store) { if val := get(store, rangeID, key1); val != 13 { t.Errorf("key %q: expected 13 but got %v", key1, val) } if val := get(store, rangeID2, key2); val != 28 { t.Errorf("key %q: expected 28 but got %v", key2, val) } } // First, populate the store with data across two ranges. Each range contains commands // that both predate and postdate the split. func() { stopper := stop.NewStopper() defer stopper.Stop() store := createTestStoreWithEngine(t, eng, clock, true, nil, stopper) increment := func(rangeID roachpb.RangeID, key roachpb.Key, value int64) (*roachpb.IncrementResponse, *roachpb.Error) { args := incrementArgs(key, value) resp, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rangeID, }, &args) incResp, _ := resp.(*roachpb.IncrementResponse) return incResp, err } if _, err := increment(rangeID, key1, 2); err != nil { t.Fatal(err) } if _, err := increment(rangeID, key2, 5); err != nil { t.Fatal(err) } splitArgs := adminSplitArgs(roachpb.KeyMin, splitKey) if _, err := client.SendWrapped(rg1(store), nil, &splitArgs); err != nil { t.Fatal(err) } rangeID2 = store.LookupReplica(roachpb.RKey(key2), nil).RangeID if rangeID2 == rangeID { t.Errorf("got same range id after split") } if _, err := increment(rangeID, key1, 11); err != nil { t.Fatal(err) } if _, err := increment(rangeID2, key2, 23); err != nil { t.Fatal(err) } validate(store) }() // Now create a new store with the same engine and make sure the expected data is present. // We must use the same clock because a newly-created manual clock will be behind the one // we wrote with and so will see stale MVCC data. store := createTestStoreWithEngine(t, eng, clock, false, nil, engineStopper) // Raft processing is initialized lazily; issue a no-op write request on each key to // ensure that is has been started. incArgs := incrementArgs(key1, 0) if _, err := client.SendWrapped(rg1(store), nil, &incArgs); err != nil { t.Fatal(err) } incArgs = incrementArgs(key2, 0) if _, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rangeID2, }, &incArgs); err != nil { t.Fatal(err) } validate(store) }
// TestStoreRangeSplitStats starts by splitting the system keys from user-space // keys and verifying that the user space side of the split (which is empty), // has all zeros for stats. It then writes random data to the user space side, // splits it halfway and verifies the two splits have stats exactly equaling // the pre-split. func TestStoreRangeSplitStats(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, manual := createTestStore(t) defer stopper.Stop() // Split the range after the last table data key. keyPrefix := keys.MakeTablePrefix(keys.MaxReservedDescID + 1) keyPrefix = keys.MakeNonColumnKey(keyPrefix) args := adminSplitArgs(roachpb.KeyMin, keyPrefix) if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr != nil { t.Fatal(pErr) } // Verify empty range has empty stats. rng := store.LookupReplica(keyPrefix, nil) // NOTE that this value is expected to change over time, depending on what // we store in the sys-local keyspace. Update it accordingly for this test. if err := verifyRangeStats(store.Engine(), rng.RangeID, engine.MVCCStats{LastUpdateNanos: manual.UnixNano()}); err != nil { t.Fatal(err) } // Write random data. writeRandomDataToRange(t, store, rng.RangeID, keyPrefix) // Get the range stats now that we have data. snap := store.Engine().NewSnapshot() defer snap.Close() var ms engine.MVCCStats if err := engine.MVCCGetRangeStats(context.Background(), snap, rng.RangeID, &ms); err != nil { t.Fatal(err) } if err := verifyRecomputedStats(snap, rng.Desc(), ms, manual.UnixNano()); err != nil { t.Fatalf("failed to verify range's stats before split: %v", err) } manual.Increment(100) // Split the range at approximate halfway point ("Z" in string "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"). midKey := append([]byte(nil), keyPrefix...) midKey = append(midKey, []byte("Z")...) midKey = keys.MakeNonColumnKey(midKey) args = adminSplitArgs(keyPrefix, midKey) if _, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rng.RangeID, }, &args); pErr != nil { t.Fatal(pErr) } snap = store.Engine().NewSnapshot() defer snap.Close() var msLeft, msRight engine.MVCCStats if err := engine.MVCCGetRangeStats(context.Background(), snap, rng.RangeID, &msLeft); err != nil { t.Fatal(err) } rngRight := store.LookupReplica(midKey, nil) if err := engine.MVCCGetRangeStats(context.Background(), snap, rngRight.RangeID, &msRight); err != nil { t.Fatal(err) } // The stats should be exactly equal when added. expMS := engine.MVCCStats{ LiveBytes: msLeft.LiveBytes + msRight.LiveBytes, KeyBytes: msLeft.KeyBytes + msRight.KeyBytes, ValBytes: msLeft.ValBytes + msRight.ValBytes, IntentBytes: msLeft.IntentBytes + msRight.IntentBytes, LiveCount: msLeft.LiveCount + msRight.LiveCount, KeyCount: msLeft.KeyCount + msRight.KeyCount, ValCount: msLeft.ValCount + msRight.ValCount, IntentCount: msLeft.IntentCount + msRight.IntentCount, } ms.SysBytes, ms.SysCount = 0, 0 ms.LastUpdateNanos = 0 if expMS != ms { t.Errorf("expected left and right ranges to equal original: %+v + %+v != %+v", msLeft, msRight, ms) } // Stats should both have the new timestamp. now := manual.UnixNano() if lTs := msLeft.LastUpdateNanos; lTs != now { t.Errorf("expected left range stats to have new timestamp, want %d, got %d", now, lTs) } if rTs := msRight.LastUpdateNanos; rTs != now { t.Errorf("expected right range stats to have new timestamp, want %d, got %d", now, rTs) } // Stats should agree with recomputation. if err := verifyRecomputedStats(snap, rng.Desc(), msLeft, now); err != nil { t.Fatalf("failed to verify left range's stats after split: %v", err) } if err := verifyRecomputedStats(snap, rngRight.Desc(), msRight, now); err != nil { t.Fatalf("failed to verify right range's stats after split: %v", err) } }
// TestStoreSplitReadRace prevents regression of #3148. It begins a couple of // read requests and lets them complete while a split is happening; the reads // hit the second half of the split. If the split happens non-atomically with // respect to the reads (and in particular their update of the timestamp // cache), then some of them may not be reflected in the timestamp cache of the // new range, in which case this test would fail. func TestStoreSplitReadRace(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() splitKey := roachpb.Key("a") key := func(i int) roachpb.Key { splitCopy := append([]byte(nil), splitKey.Next()...) return append(splitCopy, []byte(fmt.Sprintf("%03d", i))...) } getContinues := make(chan struct{}) var getStarted sync.WaitGroup sCtx := storage.TestStoreContext() sCtx.TestingKnobs.TestingCommandFilter = func(filterArgs storageutils.FilterArgs) *roachpb.Error { if et, ok := filterArgs.Req.(*roachpb.EndTransactionRequest); ok { st := et.InternalCommitTrigger.GetSplitTrigger() if st == nil || !st.UpdatedDesc.EndKey.Equal(splitKey) { return nil } close(getContinues) } else if filterArgs.Req.Method() == roachpb.Get && bytes.HasPrefix(filterArgs.Req.Header().Key, splitKey.Next()) { getStarted.Done() <-getContinues } return nil } store, stopper, _ := createTestStoreWithContext(t, &sCtx) defer stopper.Stop() now := store.Clock().Now() var wg sync.WaitGroup ts := func(i int) roachpb.Timestamp { return now.Add(0, int32(1000+i)) } const num = 10 for i := 0; i < num; i++ { wg.Add(1) getStarted.Add(1) go func(i int) { defer wg.Done() args := getArgs(key(i)) var h roachpb.Header h.Timestamp = ts(i) if _, pErr := client.SendWrappedWith(rg1(store), nil, h, &args); pErr != nil { t.Fatal(pErr) } }(i) } getStarted.Wait() wg.Add(1) func() { defer wg.Done() args := adminSplitArgs(roachpb.KeyMin, splitKey) if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr != nil { t.Fatal(pErr) } }() wg.Wait() for i := 0; i < num; i++ { var h roachpb.Header h.Timestamp = now args := putArgs(key(i), []byte("foo")) keyAddr, err := keys.Addr(args.Key) if err != nil { t.Fatal(err) } h.RangeID = store.LookupReplica(keyAddr, nil).RangeID _, respH, pErr := storage.SendWrapped(store, context.Background(), h, &args) if pErr != nil { t.Fatal(pErr) } if respH.Timestamp.Less(ts(i)) { t.Fatalf("%d: expected Put to be forced higher than %s by timestamp caches, but wrote at %s", i, ts(i), respH.Timestamp) } } }
// TestRangeLookupUseReverse tests whether the results and the results count // are correct when scanning in reverse order. func TestRangeLookupUseReverse(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() // Init test ranges: // ["","a"), ["a","c"), ["c","e"), ["e","g") and ["g","\xff\xff"). splits := []roachpb.AdminSplitRequest{ adminSplitArgs(roachpb.Key("g"), roachpb.Key("g")), adminSplitArgs(roachpb.Key("e"), roachpb.Key("e")), adminSplitArgs(roachpb.Key("c"), roachpb.Key("c")), adminSplitArgs(roachpb.Key("a"), roachpb.Key("a")), } for _, split := range splits { _, pErr := client.SendWrapped(rg1(store), nil, &split) if pErr != nil { t.Fatalf("%q: split unexpected error: %s", split.SplitKey, pErr) } } // Resolve the intents. scanArgs := roachpb.ScanRequest{ Span: roachpb.Span{ Key: keys.RangeMetaKey(roachpb.RKeyMin.Next()), EndKey: keys.RangeMetaKey(roachpb.RKeyMax), }, } util.SucceedsSoon(t, func() error { _, pErr := client.SendWrapped(rg1(store), nil, &scanArgs) return pErr.GoError() }) revScanArgs := func(key []byte, maxResults int32) *roachpb.RangeLookupRequest { return &roachpb.RangeLookupRequest{ Span: roachpb.Span{ Key: key, }, MaxRanges: maxResults, Reverse: true, } } // Test cases. testCases := []struct { request *roachpb.RangeLookupRequest expected []roachpb.RangeDescriptor }{ // Test key in the middle of the range. { request: revScanArgs(keys.RangeMetaKey(roachpb.RKey("f")), 2), // ["e","g") and ["c","e"). expected: []roachpb.RangeDescriptor{ {StartKey: roachpb.RKey("e"), EndKey: roachpb.RKey("g")}, {StartKey: roachpb.RKey("c"), EndKey: roachpb.RKey("e")}, }, }, // Test key in the end key of the range. { request: revScanArgs(keys.RangeMetaKey(roachpb.RKey("g")), 3), // ["e","g"), ["c","e") and ["a","c"). expected: []roachpb.RangeDescriptor{ {StartKey: roachpb.RKey("e"), EndKey: roachpb.RKey("g")}, {StartKey: roachpb.RKey("c"), EndKey: roachpb.RKey("e")}, {StartKey: roachpb.RKey("a"), EndKey: roachpb.RKey("c")}, }, }, { request: revScanArgs(keys.RangeMetaKey(roachpb.RKey("e")), 2), // ["c","e") and ["a","c"). expected: []roachpb.RangeDescriptor{ {StartKey: roachpb.RKey("c"), EndKey: roachpb.RKey("e")}, {StartKey: roachpb.RKey("a"), EndKey: roachpb.RKey("c")}, }, }, // Test Meta2KeyMax. { request: revScanArgs(keys.Meta2KeyMax, 2), // ["e","g") and ["g","\xff\xff") expected: []roachpb.RangeDescriptor{ {StartKey: roachpb.RKey("g"), EndKey: roachpb.RKey("\xff\xff")}, {StartKey: roachpb.RKey("e"), EndKey: roachpb.RKey("g")}, }, }, // Test Meta1KeyMax. { request: revScanArgs(keys.Meta1KeyMax, 1), // ["","a") expected: []roachpb.RangeDescriptor{ {StartKey: roachpb.RKeyMin, EndKey: roachpb.RKey("a")}, }, }, } for _, test := range testCases { resp, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ ReadConsistency: roachpb.INCONSISTENT, }, test.request) if pErr != nil { t.Fatalf("RangeLookup error: %s", pErr) } rlReply := resp.(*roachpb.RangeLookupResponse) // Checks the results count. if int32(len(rlReply.Ranges)) != test.request.MaxRanges { t.Fatalf("returned results count, expected %d,but got %d", test.request.MaxRanges, len(rlReply.Ranges)) } // Checks the range descriptors. for i, rng := range test.expected { if !(rng.StartKey.Equal(rlReply.Ranges[i].StartKey) && rng.EndKey.Equal(rlReply.Ranges[i].EndKey)) { t.Fatalf("returned range is not correct, expected %v ,but got %v", rng, rlReply.Ranges[i]) } } } }
// TestStoreRangeSplit executes a split of a range and verifies that the // resulting ranges respond to the right key ranges and that their stats // have been properly accounted for and requests can't be replayed. func TestStoreRangeSplitIdempotency(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() rangeID := roachpb.RangeID(1) splitKey := roachpb.Key("m") content := roachpb.Key("asdvb") // First, write some values left and right of the proposed split key. pArgs := putArgs([]byte("c"), content) if _, pErr := client.SendWrapped(rg1(store), nil, &pArgs); pErr != nil { t.Fatal(pErr) } pArgs = putArgs([]byte("x"), content) if _, pErr := client.SendWrapped(rg1(store), nil, &pArgs); pErr != nil { t.Fatal(pErr) } // Increments are a good way of testing idempotency. Up here, we // address them to the original range, then later to the one that // contains the key. txn := roachpb.NewTransaction("test", []byte("c"), 10, roachpb.SERIALIZABLE, store.Clock().Now(), 0) lIncArgs := incrementArgs([]byte("apoptosis"), 100) lTxn := *txn lTxn.Sequence++ if _, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ Txn: &lTxn, }, &lIncArgs); pErr != nil { t.Fatal(pErr) } rIncArgs := incrementArgs([]byte("wobble"), 10) rTxn := *txn rTxn.Sequence++ if _, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ Txn: &rTxn, }, &rIncArgs); pErr != nil { t.Fatal(pErr) } // Get the original stats for key and value bytes. var ms engine.MVCCStats if err := engine.MVCCGetRangeStats(context.Background(), store.Engine(), rangeID, &ms); err != nil { t.Fatal(err) } keyBytes, valBytes := ms.KeyBytes, ms.ValBytes // Split the range. args := adminSplitArgs(roachpb.KeyMin, splitKey) if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr != nil { t.Fatal(pErr) } // Verify no intents remains on range descriptor keys. splitKeyAddr, err := keys.Addr(splitKey) if err != nil { t.Fatal(err) } for _, key := range []roachpb.Key{keys.RangeDescriptorKey(roachpb.RKeyMin), keys.RangeDescriptorKey(splitKeyAddr)} { if _, _, err := engine.MVCCGet(context.Background(), store.Engine(), key, store.Clock().Now(), true, nil); err != nil { t.Fatal(err) } } rng := store.LookupReplica(roachpb.RKeyMin, nil) rngDesc := rng.Desc() newRng := store.LookupReplica([]byte("m"), nil) newRngDesc := newRng.Desc() if !bytes.Equal(newRngDesc.StartKey, splitKey) || !bytes.Equal(splitKey, rngDesc.EndKey) { t.Errorf("ranges mismatched, wanted %q=%q=%q", newRngDesc.StartKey, splitKey, rngDesc.EndKey) } if !bytes.Equal(newRngDesc.EndKey, roachpb.RKeyMax) || !bytes.Equal(rngDesc.StartKey, roachpb.RKeyMin) { t.Errorf("new ranges do not cover KeyMin-KeyMax, but only %q-%q", rngDesc.StartKey, newRngDesc.EndKey) } // Try to get values from both left and right of where the split happened. gArgs := getArgs([]byte("c")) if reply, pErr := client.SendWrapped(rg1(store), nil, &gArgs); pErr != nil { t.Fatal(pErr) } else if replyBytes, pErr := reply.(*roachpb.GetResponse).Value.GetBytes(); pErr != nil { t.Fatal(pErr) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } gArgs = getArgs([]byte("x")) if reply, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: newRng.RangeID, }, &gArgs); pErr != nil { t.Fatal(pErr) } else if replyBytes, err := reply.(*roachpb.GetResponse).Value.GetBytes(); err != nil { t.Fatal(err) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } // Send out an increment request copied from above (same txn/sequence) // which remains in the old range. _, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ Txn: &lTxn, }, &lIncArgs) if _, ok := pErr.GetDetail().(*roachpb.TransactionRetryError); !ok { t.Fatalf("unexpected idempotency failure: %v", pErr) } // Send out the same increment copied from above (same txn/sequence), but // now to the newly created range (which should hold that key). _, pErr = client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: newRng.RangeID, Txn: &rTxn, }, &rIncArgs) if _, ok := pErr.GetDetail().(*roachpb.TransactionRetryError); !ok { t.Fatalf("unexpected idempotency failure: %v", pErr) } // Compare stats of split ranges to ensure they are non zero and // exceed the original range when summed. var left, right engine.MVCCStats if err := engine.MVCCGetRangeStats(context.Background(), store.Engine(), rangeID, &left); err != nil { t.Fatal(err) } lKeyBytes, lValBytes := left.KeyBytes, left.ValBytes if err := engine.MVCCGetRangeStats(context.Background(), store.Engine(), newRng.RangeID, &right); err != nil { t.Fatal(err) } rKeyBytes, rValBytes := right.KeyBytes, right.ValBytes if lKeyBytes == 0 || rKeyBytes == 0 { t.Errorf("expected non-zero key bytes; got %d, %d", lKeyBytes, rKeyBytes) } if lValBytes == 0 || rValBytes == 0 { t.Errorf("expected non-zero val bytes; got %d, %d", lValBytes, rValBytes) } if lKeyBytes+rKeyBytes <= keyBytes { t.Errorf("left + right key bytes don't match; %d + %d <= %d", lKeyBytes, rKeyBytes, keyBytes) } if lValBytes+rValBytes <= valBytes { t.Errorf("left + right val bytes don't match; %d + %d <= %d", lValBytes, rValBytes, valBytes) } }
// TestStoreRangeMergeWithData attempts to merge two collocate ranges // each containing data. func TestStoreRangeMergeWithData(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() content := roachpb.Key("testing!") aDesc, bDesc, err := createSplitRanges(store) if err != nil { t.Fatal(err) } // Write some values left and right of the proposed split key. pArgs := putArgs([]byte("aaa"), content) if _, err := client.SendWrapped(rg1(store), nil, &pArgs); err != nil { t.Fatal(err) } pArgs = putArgs([]byte("ccc"), content) if _, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: bDesc.RangeID, }, &pArgs); err != nil { t.Fatal(err) } // Confirm the values are there. gArgs := getArgs([]byte("aaa")) if reply, err := client.SendWrapped(rg1(store), nil, &gArgs); err != nil { t.Fatal(err) } else if replyBytes, err := reply.(*roachpb.GetResponse).Value.GetBytes(); err != nil { t.Fatal(err) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } gArgs = getArgs([]byte("ccc")) if reply, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: bDesc.RangeID, }, &gArgs); err != nil { t.Fatal(err) } else if replyBytes, err := reply.(*roachpb.GetResponse).Value.GetBytes(); err != nil { t.Fatal(err) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } // Merge the b range back into the a range. args := adminMergeArgs(roachpb.KeyMin) if _, err := client.SendWrapped(rg1(store), nil, &args); err != nil { t.Fatal(err) } // Verify no intents remains on range descriptor keys. for _, key := range []roachpb.Key{keys.RangeDescriptorKey(aDesc.StartKey), keys.RangeDescriptorKey(bDesc.StartKey)} { if _, _, err := engine.MVCCGet(context.Background(), store.Engine(), key, store.Clock().Now(), true, nil); err != nil { t.Fatal(err) } } // Verify the merge by looking up keys from both ranges. rangeA := store.LookupReplica([]byte("a"), nil) rangeB := store.LookupReplica([]byte("c"), nil) rangeADesc := rangeA.Desc() rangeBDesc := rangeB.Desc() if !reflect.DeepEqual(rangeA, rangeB) { t.Fatalf("ranges were not merged %+v=%+v", rangeADesc, rangeBDesc) } if !bytes.Equal(rangeADesc.StartKey, roachpb.RKeyMin) { t.Fatalf("The start key is not equal to KeyMin %q=%q", rangeADesc.StartKey, roachpb.RKeyMin) } if !bytes.Equal(rangeADesc.EndKey, roachpb.RKeyMax) { t.Fatalf("The end key is not equal to KeyMax %q=%q", rangeADesc.EndKey, roachpb.RKeyMax) } // Try to get values from after the merge. gArgs = getArgs([]byte("aaa")) if reply, err := client.SendWrapped(rg1(store), nil, &gArgs); err != nil { t.Fatal(err) } else if replyBytes, err := reply.(*roachpb.GetResponse).Value.GetBytes(); err != nil { t.Fatal(err) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } gArgs = getArgs([]byte("ccc")) if reply, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rangeB.RangeID, }, &gArgs); err != nil { t.Fatal(err) } else if replyBytes, err := reply.(*roachpb.GetResponse).Value.GetBytes(); err != nil { t.Fatal(err) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } // Put new values after the merge on both sides. pArgs = putArgs([]byte("aaaa"), content) if _, err := client.SendWrapped(rg1(store), nil, &pArgs); err != nil { t.Fatal(err) } pArgs = putArgs([]byte("cccc"), content) if _, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rangeB.RangeID, }, &pArgs); err != nil { t.Fatal(err) } // Try to get the newly placed values. gArgs = getArgs([]byte("aaaa")) if reply, err := client.SendWrapped(rg1(store), nil, &gArgs); err != nil { t.Fatal(err) } else if replyBytes, err := reply.(*roachpb.GetResponse).Value.GetBytes(); err != nil { t.Fatal(err) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } gArgs = getArgs([]byte("cccc")) if reply, err := client.SendWrapped(rg1(store), nil, &gArgs); err != nil { t.Fatal(err) } else if replyBytes, err := reply.(*roachpb.GetResponse).Value.GetBytes(); err != nil { t.Fatal(err) } else if !bytes.Equal(replyBytes, content) { t.Fatalf("actual value %q did not match expected value %q", replyBytes, content) } }
// TestStoreRangeSplitStats starts by splitting the system keys from user-space // keys and verifying that the user space side of the split (which is empty), // has all zeros for stats. It then writes random data to the user space side, // splits it halfway and verifies the two splits have stats exactly equaling // the pre-split. func TestStoreRangeSplitStats(t *testing.T) { defer leaktest.AfterTest(t) defer config.TestingDisableTableSplits()() store, stopper := createTestStore(t) defer stopper.Stop() // Split the range after the last table data key. keyPrefix := keys.MakeTablePrefix(keys.MaxReservedDescID + 1) keyPrefix = keys.MakeNonColumnKey(keyPrefix) args := adminSplitArgs(roachpb.KeyMin, keyPrefix) if _, pErr := client.SendWrapped(rg1(store), nil, &args); pErr != nil { t.Fatal(pErr) } // Verify empty range has empty stats. rng := store.LookupReplica(keyPrefix, nil) // NOTE that this value is expected to change over time, depending on what // we store in the sys-local keyspace. Update it accordingly for this test. if err := verifyRangeStats(store.Engine(), rng.RangeID, engine.MVCCStats{}); err != nil { t.Fatal(err) } // Write random data. src := rand.New(rand.NewSource(0)) for i := 0; i < 100; i++ { key := append([]byte(nil), keyPrefix...) key = append(key, randutil.RandBytes(src, int(src.Int31n(1<<7)))...) key = keys.MakeNonColumnKey(key) val := randutil.RandBytes(src, int(src.Int31n(1<<8))) pArgs := putArgs(key, val) if _, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rng.RangeID, }, &pArgs); pErr != nil { t.Fatal(pErr) } } // Get the range stats now that we have data. var ms engine.MVCCStats if err := engine.MVCCGetRangeStats(store.Engine(), rng.RangeID, &ms); err != nil { t.Fatal(err) } // Split the range at approximate halfway point ("Z" in string "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"). midKey := append([]byte(nil), keyPrefix...) midKey = append(midKey, []byte("Z")...) midKey = keys.MakeNonColumnKey(midKey) args = adminSplitArgs(keyPrefix, midKey) if _, pErr := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: rng.RangeID, }, &args); pErr != nil { t.Fatal(pErr) } var msLeft, msRight engine.MVCCStats if err := engine.MVCCGetRangeStats(store.Engine(), rng.RangeID, &msLeft); err != nil { t.Fatal(err) } rngRight := store.LookupReplica(midKey, nil) if err := engine.MVCCGetRangeStats(store.Engine(), rngRight.RangeID, &msRight); err != nil { t.Fatal(err) } // The stats should be exactly equal when added. expMS := engine.MVCCStats{ LiveBytes: msLeft.LiveBytes + msRight.LiveBytes, KeyBytes: msLeft.KeyBytes + msRight.KeyBytes, ValBytes: msLeft.ValBytes + msRight.ValBytes, IntentBytes: msLeft.IntentBytes + msRight.IntentBytes, LiveCount: msLeft.LiveCount + msRight.LiveCount, KeyCount: msLeft.KeyCount + msRight.KeyCount, ValCount: msLeft.ValCount + msRight.ValCount, IntentCount: msLeft.IntentCount + msRight.IntentCount, } ms.SysBytes, ms.SysCount = 0, 0 if !reflect.DeepEqual(expMS, ms) { t.Errorf("expected left and right ranges to equal original: %+v + %+v != %+v", msLeft, msRight, ms) } }
func TestLogic(t *testing.T) { defer leaktest.AfterTest(t)() // TODO(marc): splitting ranges at table boundaries causes // a blocked task and won't drain. Investigate and fix. defer config.TestingDisableTableSplits()() var globs []string if *bigtest { const logicTestPath = "../../sqllogictest" if _, err := os.Stat(logicTestPath); os.IsNotExist(err) { fullPath, err := filepath.Abs(logicTestPath) if err != nil { t.Fatal(err) } t.Fatalf("unable to find sqllogictest repo: %s\n"+ "git clone https://github.com/cockroachdb/sqllogictest %s", logicTestPath, fullPath) return } globs = []string{ logicTestPath + "/test/index/between/*/*.test", logicTestPath + "/test/index/commute/*/*.test", logicTestPath + "/test/index/delete/*/*.test", logicTestPath + "/test/index/in/*/*.test", logicTestPath + "/test/index/orderby/*/*.test", logicTestPath + "/test/index/orderby_nosort/*/*.test", // TODO(pmattis): We don't support aggregate functions. // logicTestPath + "/test/random/expr/*.test", // TODO(pmattis): We don't support tables without primary keys. // logicTestPath + "/test/select*.test", // TODO(pmattis): We don't support views. // logicTestPath + "/test/index/view/*/*.test", // TODO(pmattis): We don't support joins. // [uses joins] logicTestPath + "/test/index/random/*/*.test", // [uses joins] logicTestPath + "/test/random/aggregates/*.test", // [uses joins] logicTestPath + "/test/random/groupby/*.test", // [uses joins] logicTestPath + "/test/random/select/*.test", } } else { globs = []string{*logictestdata} } var paths []string for _, g := range globs { match, err := filepath.Glob(g) if err != nil { t.Fatal(err) } paths = append(paths, match...) } if len(paths) == 0 { t.Fatalf("No testfiles found (globs: %v)", globs) } total := 0 for _, p := range paths { if testing.Verbose() || log.V(1) { fmt.Printf("Running logic test on file: %s\n", p) } l := logicTest{T: t} l.run(p) total += l.progress } fmt.Printf("%d tests passed\n", total) }
// TestRenameTable tests the table descriptor changes during // a rename operation. func TestRenameTable(t *testing.T) { defer leaktest.AfterTest(t) defer config.TestingDisableTableSplits()() s, sqlDB, kvDB := setup(t) defer cleanup(s, sqlDB) counter := int64(keys.MaxReservedDescID + 1) // Table creation should fail, and nothing should have been written. oldDBID := sql.ID(counter) if _, err := sqlDB.Exec(`CREATE DATABASE test`); err != nil { t.Fatal(err) } counter++ // Create table in 'test'. tableCounter := counter oldName := "foo" if _, err := sqlDB.Exec(`CREATE TABLE test.foo (k INT PRIMARY KEY, v int)`); err != nil { t.Fatal(err) } counter++ // Check the table descriptor. desc := &sql.Descriptor{} tableDescKey := sql.MakeDescMetadataKey(sql.ID(tableCounter)) if err := kvDB.GetProto(tableDescKey, desc); err != nil { t.Fatal(err) } tableDesc := desc.GetTable() if tableDesc.Name != oldName { t.Fatalf("Wrong table name, expected %s, got: %+v", oldName, tableDesc) } if tableDesc.ParentID != oldDBID { t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", oldDBID, tableDesc) } // Create database test2. newDBID := sql.ID(counter) if _, err := sqlDB.Exec(`CREATE DATABASE test2`); err != nil { t.Fatal(err) } counter++ // Move table to test2 and change its name as well. newName := "bar" if _, err := sqlDB.Exec(`ALTER TABLE test.foo RENAME TO test2.bar`); err != nil { t.Fatal(err) } // Check the table descriptor again. if err := kvDB.GetProto(tableDescKey, desc); err != nil { t.Fatal(err) } tableDesc = desc.GetTable() if tableDesc.Name != newName { t.Fatalf("Wrong table name, expected %s, got: %+v", newName, tableDesc) } if tableDesc.ParentID != newDBID { t.Fatalf("Wrong parent ID on table, expected %d, got: %+v", newDBID, tableDesc) } }
// TestStoreRangeMergeMetadataCleanup tests that all metadata of a // subsumed range is cleaned up on merge. func TestStoreRangeMergeMetadataCleanup(t *testing.T) { defer leaktest.AfterTest(t)() defer config.TestingDisableTableSplits()() store, stopper, _ := createTestStore(t) defer stopper.Stop() scan := func(f func(roachpb.KeyValue) (bool, error)) { if _, err := engine.MVCCIterate(context.Background(), store.Engine(), roachpb.KeyMin, roachpb.KeyMax, roachpb.ZeroTimestamp, true, nil, false, f); err != nil { t.Fatal(err) } } content := roachpb.Key("testing!") // Write some values left of the proposed split key. pArgs := putArgs([]byte("aaa"), content) if _, err := client.SendWrapped(rg1(store), nil, &pArgs); err != nil { t.Fatal(err) } // Collect all the keys. preKeys := make(map[string]struct{}) scan(func(kv roachpb.KeyValue) (bool, error) { preKeys[string(kv.Key)] = struct{}{} return false, nil }) // Split the range. _, bDesc, err := createSplitRanges(store) if err != nil { t.Fatal(err) } // Write some values right of the split key. pArgs = putArgs([]byte("ccc"), content) if _, err := client.SendWrappedWith(rg1(store), nil, roachpb.Header{ RangeID: bDesc.RangeID, }, &pArgs); err != nil { t.Fatal(err) } // Merge the b range back into the a range. args := adminMergeArgs(roachpb.KeyMin) if _, err := client.SendWrapped(rg1(store), nil, &args); err != nil { t.Fatal(err) } // Collect all the keys again. postKeys := make(map[string]struct{}) scan(func(kv roachpb.KeyValue) (bool, error) { postKeys[string(kv.Key)] = struct{}{} return false, nil }) // Compute the new keys. for k := range preKeys { delete(postKeys, k) } // Keep only the subsumed range's local keys. localRangeKeyPrefix := string(keys.MakeRangeIDPrefix(bDesc.RangeID)) for k := range postKeys { if !strings.HasPrefix(k, localRangeKeyPrefix) { delete(postKeys, k) } } if numKeys := len(postKeys); numKeys > 0 { var buf bytes.Buffer fmt.Fprintf(&buf, "%d keys were not cleaned up:\n", numKeys) for k := range postKeys { fmt.Fprintf(&buf, "%q\n", k) } t.Fatal(buf.String()) } }