// Test that leases held before a restart are not used after the restart. // See replica.mu.minLeaseProposedTS for the reasons why this isn't allowed. func TestLeaseNotUsedAfterRestart(t *testing.T) { defer leaktest.AfterTest(t)() sc := storage.TestStoreConfig(nil) var leaseAcquisitionTrap atomic.Value // Disable the split queue so that no ranges are split. This makes it easy // below to trap any lease request and infer that it refers to the range we're // interested in. sc.TestingKnobs.DisableSplitQueue = true sc.TestingKnobs.LeaseRequestEvent = func(ts hlc.Timestamp) { val := leaseAcquisitionTrap.Load() if val == nil { return } trapCallback := val.(func(ts hlc.Timestamp)) if trapCallback != nil { trapCallback(ts) } } mtc := &multiTestContext{storeConfig: &sc} mtc.Start(t, 1) defer mtc.Stop() // Send a read, to acquire a lease. getArgs := getArgs([]byte("a")) if _, err := client.SendWrapped(context.Background(), rg1(mtc.stores[0]), &getArgs); err != nil { t.Fatal(err) } // Restart the mtc. Before we do that, we're installing a callback used to // assert that a new lease has been requested. The callback is installed // before the restart, as the lease might be requested at any time and for // many reasons by background processes, even before we send the read below. leaseAcquisitionCh := make(chan error) var once sync.Once leaseAcquisitionTrap.Store(func(_ hlc.Timestamp) { once.Do(func() { close(leaseAcquisitionCh) }) }) mtc.restart() // Send another read and check that the pre-existing lease has not been used. // Concretely, we check that a new lease is requested. if _, err := client.SendWrapped(context.Background(), rg1(mtc.stores[0]), &getArgs); err != nil { t.Fatal(err) } // Check that the Send above triggered a lease acquisition. select { case <-leaseAcquisitionCh: case <-time.After(time.Second): t.Fatalf("read did not acquire a new lease") } }
// 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)() manual := hlc.NewManualClock(123) storeCfg := storage.TestStoreConfig(hlc.NewClock(manual.UnixNano, time.Nanosecond)) storeCfg.TestingKnobs.DisableSplitQueue = true store, stopper := createTestStoreWithConfig(t, storeCfg) defer stopper.Stop() // Split the range. aDesc, bDesc, pErr := createSplitRanges(store) if pErr != nil { t.Fatal(pErr) } // 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. snap := store.Engine().NewSnapshot() defer snap.Close() msA, err := engine.MVCCGetRangeStats(context.Background(), snap, aDesc.RangeID) if err != nil { t.Fatal(err) } msB, err := engine.MVCCGetRangeStats(context.Background(), snap, bDesc.RangeID) if 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(context.Background(), rg1(store), &args); err != nil { t.Fatal(err) } replMerged := store.LookupReplica(aDesc.StartKey, nil) // Get the range stats for the merged range and verify. snap = store.Engine().NewSnapshot() defer snap.Close() msMerged, err := engine.MVCCGetRangeStats(context.Background(), snap, replMerged.RangeID) if err != nil { t.Fatal(err) } // Merged stats should agree with recomputation. if err := verifyRecomputedStats(snap, replMerged.Desc(), msMerged, manual.UnixNano()); err != nil { t.Errorf("failed to verify range's stats after merge: %v", err) } }
// TestStoreRangeMergeTwoEmptyRanges tries to merge two empty ranges together. func TestStoreRangeMergeTwoEmptyRanges(t *testing.T) { defer leaktest.AfterTest(t)() storeCfg := storage.TestStoreConfig(nil) storeCfg.TestingKnobs.DisableSplitQueue = true store, stopper := createTestStoreWithConfig(t, storeCfg) 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(context.Background(), rg1(store), &args) if err != nil { t.Fatal(err) } // Verify the merge by looking up keys from both ranges. replicaA := store.LookupReplica([]byte("a"), nil) replicaB := store.LookupReplica([]byte("c"), nil) if !reflect.DeepEqual(replicaA, replicaB) { t.Fatalf("ranges were not merged %s!=%s", replicaA, replicaB) } }
// TestStoreRangeMergeNonCollocated attempts to merge two ranges // that are not on the same stores. func TestStoreRangeMergeNonCollocated(t *testing.T) { defer leaktest.AfterTest(t)() mtc := startMultiTestContext(t, 4) defer mtc.Stop() store := mtc.stores[0] // Split into 3 ranges argsSplit := adminSplitArgs(roachpb.KeyMin, []byte("d")) if _, pErr := client.SendWrapped(context.Background(), rg1(store), &argsSplit); pErr != nil { t.Fatalf("Can't split range %s", pErr) } argsSplit = adminSplitArgs(roachpb.KeyMin, []byte("b")) if _, pErr := client.SendWrapped(context.Background(), rg1(store), &argsSplit); pErr != nil { t.Fatalf("Can't split range %s", pErr) } rangeA := store.LookupReplica([]byte("a"), nil) rangeADesc := rangeA.Desc() rangeB := store.LookupReplica([]byte("c"), nil) rangeBDesc := rangeB.Desc() rangeC := store.LookupReplica([]byte("e"), nil) rangeCDesc := rangeC.Desc() if bytes.Equal(rangeADesc.StartKey, rangeBDesc.StartKey) { log.Errorf(context.TODO(), "split ranges keys are equal %q!=%q", rangeADesc.StartKey, rangeBDesc.StartKey) } if bytes.Equal(rangeBDesc.StartKey, rangeCDesc.StartKey) { log.Errorf(context.TODO(), "split ranges keys are equal %q!=%q", rangeBDesc.StartKey, rangeCDesc.StartKey) } if bytes.Equal(rangeADesc.StartKey, rangeCDesc.StartKey) { log.Errorf(context.TODO(), "split ranges keys are equal %q!=%q", rangeADesc.StartKey, rangeCDesc.StartKey) } // Replicate the ranges to different sets of stores. Ranges A and C // are collocated, but B is different. mtc.replicateRange(rangeA.RangeID, 1, 2) mtc.replicateRange(rangeB.RangeID, 1, 3) mtc.replicateRange(rangeC.RangeID, 1, 2) // Attempt to merge. rangeADesc = rangeA.Desc() argsMerge := adminMergeArgs(roachpb.Key(rangeADesc.StartKey)) if _, pErr := rangeA.AdminMerge(context.Background(), argsMerge, rangeADesc); !testutils.IsPError(pErr, "ranges not collocated") { t.Fatalf("did not got expected error; got %s", pErr) } }
// TestStoreRangeMergeLastRange verifies that merging the last range // fails. func TestStoreRangeMergeLastRange(t *testing.T) { defer leaktest.AfterTest(t)() storeCfg := storage.TestStoreConfig(nil) storeCfg.TestingKnobs.DisableSplitQueue = true store, stopper := createTestStoreWithConfig(t, storeCfg) defer stopper.Stop() // Merge last range. args := adminMergeArgs(roachpb.KeyMin) if _, pErr := client.SendWrapped(context.Background(), rg1(store), &args); !testutils.IsPError(pErr, "cannot merge final range") { t.Fatalf("expected 'cannot merge final range' error; got %s", pErr) } }
func BenchmarkStoreRangeMerge(b *testing.B) { defer tracing.Disable()() storeCfg := storage.TestStoreConfig(nil) storeCfg.TestingKnobs.DisableSplitQueue = true stopper := stop.NewStopper() defer stopper.Stop() store := createTestStoreWithConfig(b, stopper, storeCfg) // Perform initial split of ranges. sArgs := adminSplitArgs(roachpb.KeyMin, []byte("b")) if _, err := client.SendWrapped(context.Background(), rg1(store), sArgs); err != nil { b.Fatal(err) } // Write some values left and right of the proposed 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")) // Create args to merge the b range back into the a range. mArgs := adminMergeArgs(roachpb.KeyMin) b.ResetTimer() for i := 0; i < b.N; i++ { // Merge the ranges. b.StartTimer() if _, err := client.SendWrapped(context.Background(), rg1(store), mArgs); err != nil { b.Fatal(err) } // Split the range. b.StopTimer() if _, err := client.SendWrapped(context.Background(), rg1(store), sArgs); err != nil { b.Fatal(err) } } }
func (c *Cluster) lookupRange(nodeIdx int, key roachpb.Key) (*roachpb.RangeDescriptor, error) { req := &roachpb.RangeLookupRequest{ Span: roachpb.Span{ Key: keys.RangeMetaKey(keys.MustAddr(key)), }, MaxRanges: 1, } sender := c.Clients[nodeIdx].GetSender() resp, pErr := client.SendWrapped(context.Background(), sender, req) if pErr != nil { return nil, errors.Errorf("%s: lookup range: %s", key, pErr) } return &resp.(*roachpb.RangeLookupResponse).Ranges[0], nil }
// LookupRange returns the descriptor of the range containing key. func (ts *TestServer) LookupRange(key roachpb.Key) (roachpb.RangeDescriptor, error) { rangeLookupReq := roachpb.RangeLookupRequest{ Span: roachpb.Span{ Key: keys.RangeMetaKey(keys.MustAddr(key)), }, MaxRanges: 1, } resp, pErr := client.SendWrapped(context.Background(), ts.DistSender(), &rangeLookupReq) if pErr != nil { return roachpb.RangeDescriptor{}, errors.Errorf( "%q: lookup range unexpected error: %s", key, pErr) } return resp.(*roachpb.RangeLookupResponse).Ranges[0], nil }
// SplitRange splits the range containing splitKey. // The right range created by the split starts at the split key and extends to the // original range's end key. // Returns the new descriptors of the left and right ranges. // // splitKey must correspond to a SQL table key (it must end with a family ID / // col ID). func (ts *TestServer) SplitRange( splitKey roachpb.Key, ) (roachpb.RangeDescriptor, roachpb.RangeDescriptor, error) { splitRKey, err := keys.Addr(splitKey) if err != nil { return roachpb.RangeDescriptor{}, roachpb.RangeDescriptor{}, err } origRangeDesc, err := ts.LookupRange(splitKey) if err != nil { return roachpb.RangeDescriptor{}, roachpb.RangeDescriptor{}, err } if origRangeDesc.StartKey.Equal(splitRKey) { return roachpb.RangeDescriptor{}, roachpb.RangeDescriptor{}, errors.Errorf( "cannot split range %+v at start key %q", origRangeDesc, splitKey) } splitReq := roachpb.AdminSplitRequest{ Span: roachpb.Span{ Key: splitKey, }, SplitKey: splitKey, } _, pErr := client.SendWrapped(context.Background(), ts.DistSender(), &splitReq) if pErr != nil { return roachpb.RangeDescriptor{}, roachpb.RangeDescriptor{}, errors.Errorf( "%q: split unexpected error: %s", splitReq.SplitKey, pErr) } var leftRangeDesc, rightRangeDesc roachpb.RangeDescriptor if err := ts.DB().GetProto(context.TODO(), keys.RangeDescriptorKey(origRangeDesc.StartKey), &leftRangeDesc); err != nil { return roachpb.RangeDescriptor{}, roachpb.RangeDescriptor{}, errors.Wrap(err, "could not look up left-hand side descriptor") } // The split point might not be exactly the one we requested (it can be // adjusted slightly so we don't split in the middle of SQL rows). Update it // to the real point. splitRKey = leftRangeDesc.EndKey if err := ts.DB().GetProto(context.TODO(), keys.RangeDescriptorKey(splitRKey), &rightRangeDesc); err != nil { return roachpb.RangeDescriptor{}, roachpb.RangeDescriptor{}, errors.Wrap(err, "could not look up right-hand side descriptor") } return leftRangeDesc, rightRangeDesc, nil }
// TestProactiveRaftLogTruncate verifies that we proactively truncate the raft // log even when replica scanning is disabled. func TestProactiveRaftLogTruncate(t *testing.T) { defer leaktest.AfterTest(t)() t.Skip("#9772") store, _, stopper := createTestStore(t) defer stopper.Stop() store.SetReplicaScannerActive(false) r, err := store.GetReplica(1) if err != nil { t.Fatal(err) } r.mu.Lock() oldFirstIndex, err := r.FirstIndex() r.mu.Unlock() if err != nil { t.Fatal(err) } // Write a few keys to the range. While writing these keys, the raft log // should be proactively truncated even though replica scanning is disabled. for i := 0; i < 2*RaftLogQueueStaleThreshold; i++ { key := roachpb.Key(fmt.Sprintf("key%02d", i)) args := putArgs(key, []byte(fmt.Sprintf("value%02d", i))) if _, err := client.SendWrapped(context.Background(), store.testSender(), &args); err != nil { t.Fatal(err) } } // Wait for any asynchronous tasks to finish. stopper.Quiesce() r.mu.Lock() newFirstIndex, err := r.FirstIndex() r.mu.Unlock() if err != nil { t.Fatal(err) } if newFirstIndex <= oldFirstIndex { t.Errorf("log was not correctly truncated, old first index:%d, current first index:%d", oldFirstIndex, newFirstIndex) } }
func createSplitRanges( store *storage.Store, ) (*roachpb.RangeDescriptor, *roachpb.RangeDescriptor, *roachpb.Error) { args := adminSplitArgs(roachpb.KeyMin, []byte("b")) if _, err := client.SendWrapped(context.Background(), rg1(store), &args); err != nil { return nil, nil, err } rangeADesc := store.LookupReplica([]byte("a"), nil).Desc() rangeBDesc := store.LookupReplica([]byte("c"), nil).Desc() if bytes.Equal(rangeADesc.StartKey, rangeBDesc.StartKey) { log.Errorf(context.TODO(), "split ranges keys are equal %q!=%q", rangeADesc.StartKey, rangeBDesc.StartKey) } return rangeADesc, rangeBDesc, nil }
// TestServerStartClock tests that a server's clock is not pushed out of thin // air. This used to happen - the simple act of starting was causing a server's // clock to be pushed because we were introducing bogus future timestamps into // our system. func TestServerStartClock(t *testing.T) { defer leaktest.AfterTest(t)() // Set a high max-offset so that, if the server's clock is pushed by // MaxOffset, we don't hide that under the latency of the Start operation // which would allow the physical clock to catch up to the pushed one. params := base.TestServerArgs{ Knobs: base.TestingKnobs{ Store: &storage.StoreTestingKnobs{ MaxOffset: time.Second, }, }, } s, _, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() // Run a command so that we are sure to touch the timestamp cache. This is // actually not needed because other commands run during server // initialization, but we cannot guarantee that's going to stay that way. get := &roachpb.GetRequest{ Span: roachpb.Span{Key: roachpb.Key("a")}, } if _, err := client.SendWrapped( context.Background(), s.KVClient().(*client.DB).GetSender(), get, ); err != nil { t.Fatal(err) } now := s.Clock().Now() // We rely on s.Clock() having been initialized from hlc.UnixNano(), which is a // bit fragile. physicalNow := hlc.UnixNano() serverClockWasPushed := (now.Logical > 0) || (now.WallTime > physicalNow) if serverClockWasPushed { t.Fatalf("time: server %s vs actual %d", now, physicalNow) } }
func TestStoreMetrics(t *testing.T) { defer leaktest.AfterTest(t)() t.Skip("TODO(mrtracy): #9204") mtc := &multiTestContext{} defer mtc.Stop() mtc.Start(t, 3) // Flush RocksDB memtables, so that RocksDB begins using block-based tables. // This is useful, because most of the stats we track don't apply to // memtables. if err := mtc.stores[0].Engine().Flush(); err != nil { t.Fatal(err) } if err := mtc.stores[1].Engine().Flush(); err != nil { t.Fatal(err) } // Disable the raft log truncation which confuses this test. for _, s := range mtc.stores { s.SetRaftLogQueueActive(false) } // Perform a split, which has special metrics handling. splitArgs := adminSplitArgs(roachpb.KeyMin, roachpb.Key("m")) if _, err := client.SendWrapped(context.Background(), rg1(mtc.stores[0]), splitArgs); err != nil { t.Fatal(err) } // Verify range count is as expected checkCounter(t, mtc.stores[0].Metrics().ReplicaCount, 2) // Verify all stats on store0 after split. verifyStats(t, mtc, 0) // Replicate the "right" range to the other stores. replica := mtc.stores[0].LookupReplica(roachpb.RKey("z"), nil) mtc.replicateRange(replica.RangeID, 1, 2) // Verify stats on store1 after replication. verifyStats(t, mtc, 1) // Add some data to the "right" range. dataKey := []byte("z") if _, err := mtc.dbs[0].Inc(context.TODO(), dataKey, 5); err != nil { t.Fatal(err) } mtc.waitForValues(roachpb.Key("z"), []int64{5, 5, 5}) // Verify all stats on store 0 and 1 after addition. verifyStats(t, mtc, 0, 1) // Create a transaction statement that fails, but will add an entry to the // sequence cache. Regression test for #4969. if err := mtc.dbs[0].Txn(context.TODO(), func(txn *client.Txn) error { b := txn.NewBatch() b.CPut(dataKey, 7, 6) return txn.Run(b) }); err == nil { t.Fatal("Expected transaction error, but none received") } // Verify stats after sequence cache addition. verifyStats(t, mtc, 0) checkCounter(t, mtc.stores[0].Metrics().ReplicaCount, 2) // Unreplicate range from the first store. mtc.unreplicateRange(replica.RangeID, 0) // Force GC Scan on store 0 in order to fully remove range. mtc.stores[1].ForceReplicaGCScanAndProcess() mtc.waitForValues(roachpb.Key("z"), []int64{0, 5, 5}) // Verify range count is as expected. checkCounter(t, mtc.stores[0].Metrics().ReplicaCount, 1) checkCounter(t, mtc.stores[1].Metrics().ReplicaCount, 1) // Verify all stats on store0 and store1 after range is removed. verifyStats(t, mtc, 0, 1) verifyRocksDBStats(t, mtc.stores[0]) verifyRocksDBStats(t, mtc.stores[1]) }
// TestGetTruncatableIndexes verifies that old raft log entries are correctly // removed. func TestGetTruncatableIndexes(t *testing.T) { defer leaktest.AfterTest(t)() store, _, stopper := createTestStore(t) defer stopper.Stop() store.SetRaftLogQueueActive(false) r, err := store.GetReplica(1) if err != nil { t.Fatal(err) } getIndexes := func() (uint64, uint64, uint64, error) { r.mu.Lock() firstIndex, err := r.FirstIndex() r.mu.Unlock() if err != nil { return 0, 0, 0, err } truncatableIndexes, oldestIndex, err := getTruncatableIndexes(context.Background(), r) if err != nil { return 0, 0, 0, err } return firstIndex, truncatableIndexes, oldestIndex, nil } aFirst, aTruncatable, aOldest, err := getIndexes() if err != nil { t.Fatal(err) } if aFirst == 0 { t.Errorf("expected first index to be greater than 0, got %d", aFirst) } // Write a few keys to the range. for i := 0; i < RaftLogQueueStaleThreshold+1; i++ { key := roachpb.Key(fmt.Sprintf("key%02d", i)) args := putArgs(key, []byte(fmt.Sprintf("value%02d", i))) if _, err := client.SendWrapped(context.Background(), store.testSender(), &args); err != nil { t.Fatal(err) } } bFirst, bTruncatable, bOldest, err := getIndexes() if err != nil { t.Fatal(err) } if aFirst != bFirst { t.Errorf("expected firstIndex to not change, instead it changed from %d -> %d", aFirst, bFirst) } if aTruncatable >= bTruncatable { t.Errorf("expected truncatableIndexes to increase, instead it changed from %d -> %d", aTruncatable, bTruncatable) } if aOldest >= bOldest { t.Errorf("expected oldestIndex to increase, instead it changed from %d -> %d", aOldest, bOldest) } // Enable the raft log scanner and and force a truncation. store.SetRaftLogQueueActive(true) store.ForceRaftLogScanAndProcess() store.SetRaftLogQueueActive(false) // There can be a delay from when the truncation command is issued and the // indexes updating. var cFirst, cTruncatable, cOldest uint64 util.SucceedsSoon(t, func() error { var err error cFirst, cTruncatable, cOldest, err = getIndexes() if err != nil { t.Fatal(err) } if bFirst == cFirst { return errors.Errorf("truncation did not occur, expected firstIndex to change, instead it remained at %d", cFirst) } return nil }) if bTruncatable < cTruncatable { t.Errorf("expected truncatableIndexes to decrease, instead it changed from %d -> %d", bTruncatable, cTruncatable) } if bOldest >= cOldest { t.Errorf("expected oldestIndex to increase, instead it changed from %d -> %d", bOldest, cOldest) } // Again, enable the raft log scanner and and force a truncation. This time // we expect no truncation to occur. store.SetRaftLogQueueActive(true) store.ForceRaftLogScanAndProcess() store.SetRaftLogQueueActive(false) // Unlike the last iteration, where we expect a truncation and can wait on // it with succeedsSoon, we can't do that here. This check is fragile in // that the truncation triggered here may lose the race against the call to // GetFirstIndex or getTruncatableIndexes, giving a false negative. Fixing // this requires additional instrumentation of the queues, which was deemed // to require too much work at the time of this writing. dFirst, dTruncatable, dOldest, err := getIndexes() if err != nil { t.Fatal(err) } if cFirst != dFirst { t.Errorf("truncation should not have occurred, but firstIndex changed from %d -> %d", cFirst, dFirst) } if cTruncatable != dTruncatable { t.Errorf("truncation should not have occurred, but truncatableIndexes changed from %d -> %d", cTruncatable, dTruncatable) } if cOldest != dOldest { t.Errorf("truncation should not have occurred, but oldestIndex changed from %d -> %d", cOldest, dOldest) } }
// TestStoreRangeMergeMetadataCleanup tests that all metadata of a // subsumed range is cleaned up on merge. func TestStoreRangeMergeMetadataCleanup(t *testing.T) { defer leaktest.AfterTest(t)() storeCfg := storage.TestStoreConfig(nil) storeCfg.TestingKnobs.DisableSplitQueue = true store, stopper := createTestStoreWithConfig(t, storeCfg) defer stopper.Stop() scan := func(f func(roachpb.KeyValue) (bool, error)) { if _, err := engine.MVCCIterate(context.Background(), store.Engine(), roachpb.KeyMin, roachpb.KeyMax, hlc.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(context.Background(), rg1(store), &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(context.Background(), rg1(store), 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(context.Background(), rg1(store), &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()) } }
// TestLeaseMetricsOnSplitAndTransfer verifies that lease-related metrics // are updated after splitting a range and then initiating one successful // and one failing lease transfer. func TestLeaseMetricsOnSplitAndTransfer(t *testing.T) { defer leaktest.AfterTest(t)() var injectLeaseTransferError atomic.Value sc := storage.TestStoreConfig(nil) sc.TestingKnobs.DisableSplitQueue = true sc.TestingKnobs.TestingCommandFilter = func(filterArgs storagebase.FilterArgs) *roachpb.Error { if args, ok := filterArgs.Req.(*roachpb.TransferLeaseRequest); ok { if val := injectLeaseTransferError.Load(); val != nil && val.(bool) { // Note that we can't just return an error here as we only // end up counting failures in the metrics if the command // makes it through to being executed. So use a fake store ID. args.Lease.Replica.StoreID = roachpb.StoreID(1000) } } return nil } mtc := &multiTestContext{storeConfig: &sc} defer mtc.Stop() mtc.Start(t, 2) // Up-replicate to two replicas. keyMinReplica0 := mtc.stores[0].LookupReplica(roachpb.RKeyMin, nil) mtc.replicateRange(keyMinReplica0.RangeID, 1) // Split the key space at key "a". splitKey := roachpb.RKey("a") splitArgs := adminSplitArgs(splitKey.AsRawKey(), splitKey.AsRawKey()) if _, pErr := client.SendWrapped( context.Background(), rg1(mtc.stores[0]), splitArgs, ); pErr != nil { t.Fatal(pErr) } // Now, a successful transfer from LHS replica 0 to replica 1. injectLeaseTransferError.Store(false) if err := mtc.dbs[0].AdminTransferLease( context.TODO(), keyMinReplica0.Desc().StartKey.AsRawKey(), mtc.stores[1].StoreID(), ); err != nil { t.Fatalf("unable to transfer lease to replica 1: %s", err) } // Wait for all replicas to process. testutils.SucceedsSoon(t, func() error { for i := 0; i < 2; i++ { r := mtc.stores[i].LookupReplica(roachpb.RKeyMin, nil) if l, _ := r.GetLease(); l.Replica.StoreID != mtc.stores[1].StoreID() { return errors.Errorf("expected lease to transfer to replica 2: got %s", l) } } return nil }) // Next a failed transfer from RHS replica 0 to replica 1. injectLeaseTransferError.Store(true) keyAReplica0 := mtc.stores[0].LookupReplica(splitKey, nil) if err := mtc.dbs[0].AdminTransferLease( context.TODO(), keyAReplica0.Desc().StartKey.AsRawKey(), mtc.stores[1].StoreID(), ); err == nil { t.Fatal("expected an error transferring to an unknown store ID") } metrics := mtc.stores[0].Metrics() if a, e := metrics.LeaseTransferSuccessCount.Count(), int64(1); a != e { t.Errorf("expected %d lease transfer successes; got %d", e, a) } if a, e := metrics.LeaseTransferErrorCount.Count(), int64(1); a != e { t.Errorf("expected %d lease transfer errors; got %d", e, a) } // Expire current leases and put a key to RHS of split to request // an epoch-based lease. testutils.SucceedsSoon(t, func() error { mtc.expireLeases(context.TODO()) if err := mtc.stores[0].DB().Put(context.TODO(), "a", "foo"); err != nil { return err } // Update replication gauges on store 1 and verify we have 1 each of // expiration and epoch leases. These values are counted from store 1 // because it will have the higher replica IDs. Expire leases to make // sure that epoch-based leases are used for the split range. if err := mtc.stores[1].ComputeMetrics(context.Background(), 0); err != nil { return err } metrics = mtc.stores[1].Metrics() if a, e := metrics.LeaseExpirationCount.Value(), int64(1); a != e { return errors.Errorf("expected %d expiration lease count; got %d", e, a) } if a, e := metrics.LeaseEpochCount.Value(), int64(1); a != e { return errors.Errorf("expected %d epoch lease count; got %d", e, a) } return nil }) }
func TestRangeInfo(t *testing.T) { defer leaktest.AfterTest(t)() mtc := startMultiTestContext(t, 2) defer mtc.Stop() // Up-replicate to two replicas. mtc.replicateRange(mtc.stores[0].LookupReplica(roachpb.RKeyMin, nil).RangeID, 1) // Split the key space at key "a". splitKey := roachpb.RKey("a") splitArgs := adminSplitArgs(splitKey.AsRawKey(), splitKey.AsRawKey()) if _, pErr := client.SendWrapped( context.Background(), rg1(mtc.stores[0]), &splitArgs, ); pErr != nil { t.Fatal(pErr) } // Get the replicas for each side of the split. This is done within // a SucceedsSoon loop to ensure the split completes. var lhsReplica0, lhsReplica1, rhsReplica0, rhsReplica1 *storage.Replica util.SucceedsSoon(t, func() error { lhsReplica0 = mtc.stores[0].LookupReplica(roachpb.RKeyMin, nil) lhsReplica1 = mtc.stores[1].LookupReplica(roachpb.RKeyMin, nil) rhsReplica0 = mtc.stores[0].LookupReplica(splitKey, nil) rhsReplica1 = mtc.stores[1].LookupReplica(splitKey, nil) if lhsReplica0 == rhsReplica0 || lhsReplica1 == rhsReplica1 { return errors.Errorf("replicas not post-split %v, %v, %v, %v", lhsReplica0, rhsReplica0, rhsReplica0, rhsReplica1) } return nil }) lhsLease, _ := lhsReplica0.GetLease() rhsLease, _ := rhsReplica0.GetLease() // Verify range info is not set if unrequested. getArgs := getArgs(splitKey.AsRawKey()) reply, pErr := client.SendWrapped(context.Background(), mtc.distSenders[0], &getArgs) if pErr != nil { t.Fatal(pErr) } if len(reply.Header().RangeInfos) > 0 { t.Errorf("expected empty range infos if unrequested; got %v", reply.Header().RangeInfos) } // Verify range info on a get request. h := roachpb.Header{ ReturnRangeInfo: true, } reply, pErr = client.SendWrappedWith(context.Background(), mtc.distSenders[0], h, &getArgs) if pErr != nil { t.Fatal(pErr) } expRangeInfos := []roachpb.RangeInfo{ { Desc: *rhsReplica0.Desc(), Lease: *rhsLease, }, } if !reflect.DeepEqual(reply.Header().RangeInfos, expRangeInfos) { t.Errorf("on get reply, expected %+v; got %+v", expRangeInfos, reply.Header().RangeInfos) } // Verify range info on a put request. putArgs := putArgs(splitKey.AsRawKey(), []byte("foo")) reply, pErr = client.SendWrappedWith(context.Background(), mtc.distSenders[0], h, &putArgs) if pErr != nil { t.Fatal(pErr) } if !reflect.DeepEqual(reply.Header().RangeInfos, expRangeInfos) { t.Errorf("on put reply, expected %+v; got %+v", expRangeInfos, reply.Header().RangeInfos) } // Verify multiple range infos on a scan request. scanArgs := roachpb.ScanRequest{ Span: roachpb.Span{ Key: keys.SystemMax, EndKey: roachpb.KeyMax, }, } h.Txn = roachpb.NewTransaction("test", roachpb.KeyMin, 1, enginepb.SERIALIZABLE, mtc.clock.Now(), 0) reply, pErr = client.SendWrappedWith(context.Background(), mtc.distSenders[0], h, &scanArgs) if pErr != nil { t.Fatal(pErr) } expRangeInfos = []roachpb.RangeInfo{ { Desc: *lhsReplica0.Desc(), Lease: *lhsLease, }, { Desc: *rhsReplica0.Desc(), Lease: *rhsLease, }, } if !reflect.DeepEqual(reply.Header().RangeInfos, expRangeInfos) { t.Errorf("on scan reply, expected %+v; got %+v", expRangeInfos, reply.Header().RangeInfos) } // Verify multiple range infos and order on a reverse scan request. revScanArgs := roachpb.ReverseScanRequest{ Span: roachpb.Span{ Key: keys.SystemMax, EndKey: roachpb.KeyMax, }, } reply, pErr = client.SendWrappedWith(context.Background(), mtc.distSenders[0], h, &revScanArgs) if pErr != nil { t.Fatal(pErr) } expRangeInfos = []roachpb.RangeInfo{ { Desc: *rhsReplica0.Desc(), Lease: *rhsLease, }, { Desc: *lhsReplica0.Desc(), Lease: *lhsLease, }, } if !reflect.DeepEqual(reply.Header().RangeInfos, expRangeInfos) { t.Errorf("on reverse scan reply, expected %+v; got %+v", expRangeInfos, reply.Header().RangeInfos) } // Change lease holders for both ranges and re-scan. for _, r := range []*storage.Replica{lhsReplica1, rhsReplica1} { replDesc, err := r.GetReplicaDescriptor() if err != nil { t.Fatal(err) } if err = mtc.dbs[0].AdminTransferLease(context.TODO(), r.Desc().StartKey.AsRawKey(), replDesc.StoreID); err != nil { t.Fatalf("unable to transfer lease to replica %s: %s", r, err) } } reply, pErr = client.SendWrappedWith(context.Background(), mtc.distSenders[0], h, &scanArgs) if pErr != nil { t.Fatal(pErr) } lhsLease, _ = lhsReplica1.GetLease() rhsLease, _ = rhsReplica1.GetLease() expRangeInfos = []roachpb.RangeInfo{ { Desc: *lhsReplica1.Desc(), Lease: *lhsLease, }, { Desc: *rhsReplica1.Desc(), Lease: *rhsLease, }, } if !reflect.DeepEqual(reply.Header().RangeInfos, expRangeInfos) { t.Errorf("on scan reply, expected %+v; got %+v", expRangeInfos, reply.Header().RangeInfos) } }
func TestRangeTransferLease(t *testing.T) { defer leaktest.AfterTest(t)() cfg := storage.TestStoreConfig(nil) var filterMu syncutil.Mutex var filter func(filterArgs storagebase.FilterArgs) *roachpb.Error cfg.TestingKnobs.TestingCommandFilter = func(filterArgs storagebase.FilterArgs) *roachpb.Error { filterMu.Lock() filterCopy := filter filterMu.Unlock() if filterCopy != nil { return filterCopy(filterArgs) } return nil } var waitForTransferBlocked atomic.Value waitForTransferBlocked.Store(false) transferBlocked := make(chan struct{}) cfg.TestingKnobs.LeaseTransferBlockedOnExtensionEvent = func( _ roachpb.ReplicaDescriptor) { if waitForTransferBlocked.Load().(bool) { transferBlocked <- struct{}{} waitForTransferBlocked.Store(false) } } mtc := &multiTestContext{} mtc.storeConfig = &cfg mtc.Start(t, 2) defer mtc.Stop() // First, do a write; we'll use it to determine when the dust has settled. leftKey := roachpb.Key("a") incArgs := incrementArgs(leftKey, 1) if _, pErr := client.SendWrapped(context.Background(), mtc.distSenders[0], &incArgs); pErr != nil { t.Fatal(pErr) } // Get the left range's ID. rangeID := mtc.stores[0].LookupReplica(roachpb.RKey("a"), nil).RangeID // Replicate the left range onto node 1. mtc.replicateRange(rangeID, 1) replica0 := mtc.stores[0].LookupReplica(roachpb.RKey("a"), nil) replica1 := mtc.stores[1].LookupReplica(roachpb.RKey("a"), nil) gArgs := getArgs(leftKey) replica0Desc, err := replica0.GetReplicaDescriptor() if err != nil { t.Fatal(err) } // Check that replica0 can serve reads OK. if _, pErr := client.SendWrappedWith( context.Background(), mtc.senders[0], roachpb.Header{Replica: replica0Desc}, &gArgs, ); pErr != nil { t.Fatal(pErr) } { // Transferring the lease to ourself should be a no-op. origLeasePtr, _ := replica0.GetLease() origLease := *origLeasePtr if err := replica0.AdminTransferLease(replica0Desc.StoreID); err != nil { t.Fatal(err) } newLeasePtr, _ := replica0.GetLease() if origLeasePtr != newLeasePtr || origLease != *newLeasePtr { t.Fatalf("expected %+v, but found %+v", origLeasePtr, newLeasePtr) } } { // An invalid target should result in an error. const expected = "unable to find store .* in range" if err := replica0.AdminTransferLease(1000); !testutils.IsError(err, expected) { t.Fatalf("expected %s, but found %v", expected, err) } } // Move the lease to store 1. var newHolderDesc roachpb.ReplicaDescriptor util.SucceedsSoon(t, func() error { var err error newHolderDesc, err = replica1.GetReplicaDescriptor() return err }) if err := replica0.AdminTransferLease(newHolderDesc.StoreID); err != nil { t.Fatal(err) } // Check that replica0 doesn't serve reads any more. replica0Desc, err = replica0.GetReplicaDescriptor() if err != nil { t.Fatal(err) } _, pErr := client.SendWrappedWith( context.Background(), mtc.senders[0], roachpb.Header{Replica: replica0Desc}, &gArgs, ) nlhe, ok := pErr.GetDetail().(*roachpb.NotLeaseHolderError) if !ok { t.Fatalf("expected %T, got %s", &roachpb.NotLeaseHolderError{}, pErr) } if *(nlhe.LeaseHolder) != newHolderDesc { t.Fatalf("expected lease holder %+v, got %+v", newHolderDesc, nlhe.LeaseHolder) } // Check that replica1 now has the lease (or gets it soon). util.SucceedsSoon(t, func() error { if _, pErr := client.SendWrappedWith( context.Background(), mtc.senders[1], roachpb.Header{Replica: replica0Desc}, &gArgs, ); pErr != nil { return pErr.GoError() } return nil }) replica1Lease, _ := replica1.GetLease() // Verify the timestamp cache low water. Because we executed a transfer lease // request, the low water should be set to the new lease start time which is // less than the previous lease's expiration time. if lowWater := replica1.GetTimestampCacheLowWater(); lowWater != replica1Lease.Start { t.Fatalf("expected timestamp cache low water %s, but found %s", replica1Lease.Start, lowWater) } // Make replica1 extend its lease and transfer the lease immediately after // that. Test that the transfer still happens (it'll wait until the extension // is done). extensionSem := make(chan struct{}) filterMu.Lock() filter = func(filterArgs storagebase.FilterArgs) *roachpb.Error { if filterArgs.Sid != mtc.stores[1].Ident.StoreID { return nil } llReq, ok := filterArgs.Req.(*roachpb.RequestLeaseRequest) if !ok { return nil } if llReq.Lease.Replica == newHolderDesc { // Notify the main thread that the extension is in progress and wait for // the signal to proceed. filterMu.Lock() filter = nil filterMu.Unlock() extensionSem <- struct{}{} <-extensionSem } return nil } filterMu.Unlock() // Initiate an extension. var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() shouldRenewTS := replica1Lease.StartStasis.Add(-1, 0) mtc.manualClock.Set(shouldRenewTS.WallTime + 1) if _, pErr := client.SendWrappedWith( context.Background(), mtc.senders[1], roachpb.Header{Replica: replica0Desc}, &gArgs, ); pErr != nil { panic(pErr) } }() <-extensionSem waitForTransferBlocked.Store(true) // Initiate a transfer. wg.Add(1) go func() { defer wg.Done() // Transfer back from replica1 to replica0. if err := replica1.AdminTransferLease(replica0Desc.StoreID); err != nil { panic(err) } }() // Wait for the transfer to be blocked by the extension. <-transferBlocked // Now unblock the extension. extensionSem <- struct{}{} // Check that the transfer to replica1 eventually happens. util.SucceedsSoon(t, func() error { if _, pErr := client.SendWrappedWith( context.Background(), mtc.senders[0], roachpb.Header{Replica: replica0Desc}, &gArgs, ); pErr != nil { return pErr.GoError() } return nil }) filterMu.Lock() filter = nil filterMu.Unlock() wg.Wait() }
// TestStoreRangeMergeWithData attempts to merge two collocate ranges // each containing data. func TestStoreRangeMergeWithData(t *testing.T) { defer leaktest.AfterTest(t)() storeCfg := storage.TestStoreConfig(nil) storeCfg.TestingKnobs.DisableSplitQueue = true store, stopper := createTestStoreWithConfig(t, storeCfg) 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(context.Background(), rg1(store), &pArgs); err != nil { t.Fatal(err) } pArgs = putArgs([]byte("ccc"), content) if _, err := client.SendWrappedWith(context.Background(), rg1(store), 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(context.Background(), rg1(store), &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(context.Background(), rg1(store), 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(context.Background(), rg1(store), &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(context.Background(), rg1(store), &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(context.Background(), rg1(store), 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(context.Background(), rg1(store), &pArgs); err != nil { t.Fatal(err) } pArgs = putArgs([]byte("cccc"), content) if _, err := client.SendWrappedWith(context.Background(), rg1(store), 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(context.Background(), rg1(store), &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(context.Background(), rg1(store), &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) } }
// TestStoreRangeLease verifies that ranges after range 0 get // epoch-based range leases if enabled and expiration-based // otherwise. func TestStoreRangeLease(t *testing.T) { defer leaktest.AfterTest(t)() for _, enableEpoch := range []bool{true, false} { t.Run(fmt.Sprintf("epoch-based leases? %t", enableEpoch), func(t *testing.T) { sc := storage.TestStoreConfig(nil) sc.EnableEpochRangeLeases = enableEpoch mtc := &multiTestContext{storeConfig: &sc} defer mtc.Stop() mtc.Start(t, 1) splitKeys := []roachpb.Key{roachpb.Key("a"), roachpb.Key("b"), roachpb.Key("c")} for _, splitKey := range splitKeys { splitArgs := adminSplitArgs(splitKey, splitKey) if _, pErr := client.SendWrapped(context.Background(), mtc.distSenders[0], splitArgs); pErr != nil { t.Fatal(pErr) } } rLeft := mtc.stores[0].LookupReplica(roachpb.RKeyMin, nil) lease, _ := rLeft.GetLease() if lt := lease.Type(); lt != roachpb.LeaseExpiration { t.Fatalf("expected lease type expiration; got %d", lt) } // After the split, expect an expiration lease for other ranges. for _, key := range splitKeys { repl := mtc.stores[0].LookupReplica(roachpb.RKey(key), nil) lease, _ = repl.GetLease() if lt := lease.Type(); lt != roachpb.LeaseExpiration { t.Fatalf("%s: expected lease type epoch; got %d", key, lt) } } // Allow leases to expire and send commands to ensure we // re-acquire, then check types again. mtc.expireLeases() for _, key := range splitKeys { if _, err := mtc.dbs[0].Inc(context.TODO(), key, 1); err != nil { t.Fatalf("%s failed to increment: %s", key, err) } } // After the expiration, expect an epoch lease for the RHS if // we've enabled epoch based range leases. for _, key := range splitKeys { repl := mtc.stores[0].LookupReplica(roachpb.RKey(key), nil) lease, _ = repl.GetLease() if enableEpoch { if lt := lease.Type(); lt != roachpb.LeaseEpoch { t.Fatalf("expected lease type epoch; got %d", lt) } } else { if lt := lease.Type(); lt != roachpb.LeaseExpiration { t.Fatalf("expected lease type expiration; got %d", lt) } } } }) } }
// TestMultiRangeScanDeleteRange tests that commands which access multiple // ranges are carried out properly. func TestMultiRangeScanDeleteRange(t *testing.T) { defer leaktest.AfterTest(t)() s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop() ts := s.(*TestServer) retryOpts := base.DefaultRetryOptions() retryOpts.Closer = ts.stopper.ShouldQuiesce() ds := kv.NewDistSender(kv.DistSenderConfig{ Clock: s.Clock(), RPCContext: s.RPCContext(), RPCRetryOptions: &retryOpts, }, ts.Gossip()) ambient := log.AmbientContext{Tracer: tracing.NewTracer()} tds := kv.NewTxnCoordSender( ambient, ds, s.Clock(), ts.Cfg.Linearizable, ts.stopper, kv.MakeTxnMetrics(metric.TestSampleInterval), ) if err := ts.node.storeCfg.DB.AdminSplit(context.TODO(), "m"); err != nil { t.Fatal(err) } writes := []roachpb.Key{roachpb.Key("a"), roachpb.Key("z")} get := &roachpb.GetRequest{ Span: roachpb.Span{Key: writes[0]}, } get.EndKey = writes[len(writes)-1] if _, err := client.SendWrapped(context.Background(), tds, get); err == nil { t.Errorf("able to call Get with a key range: %v", get) } var delTS hlc.Timestamp for i, k := range writes { put := roachpb.NewPut(k, roachpb.MakeValueFromBytes(k)) if _, err := client.SendWrapped(context.Background(), tds, put); err != nil { t.Fatal(err) } scan := roachpb.NewScan(writes[0], writes[len(writes)-1].Next()) reply, err := client.SendWrapped(context.Background(), tds, scan) if err != nil { t.Fatal(err) } sr := reply.(*roachpb.ScanResponse) if sr.Txn != nil { // This was the other way around at some point in the past. // Same below for Delete, etc. t.Errorf("expected no transaction in response header") } if rows := sr.Rows; len(rows) != i+1 { t.Fatalf("expected %d rows, but got %d", i+1, len(rows)) } } del := &roachpb.DeleteRangeRequest{ Span: roachpb.Span{ Key: writes[0], EndKey: roachpb.Key(writes[len(writes)-1]).Next(), }, ReturnKeys: true, } reply, err := client.SendWrappedWith(context.Background(), tds, roachpb.Header{Timestamp: delTS}, del) if err != nil { t.Fatal(err) } dr := reply.(*roachpb.DeleteRangeResponse) if dr.Txn != nil { t.Errorf("expected no transaction in response header") } if !reflect.DeepEqual(dr.Keys, writes) { t.Errorf("expected %d keys to be deleted, but got %d instead", writes, dr.Keys) } scan := roachpb.NewScan(writes[0], writes[len(writes)-1].Next()) txn := &roachpb.Transaction{Name: "MyTxn"} reply, err = client.SendWrappedWith(context.Background(), tds, roachpb.Header{Txn: txn}, scan) if err != nil { t.Fatal(err) } sr := reply.(*roachpb.ScanResponse) if txn := sr.Txn; txn == nil || txn.Name != "MyTxn" { t.Errorf("wanted Txn to persist, but it changed to %v", txn) } if rows := sr.Rows; len(rows) > 0 { t.Fatalf("scan after delete returned rows: %v", rows) } }
// TestRaftLogQueue verifies that the raft log queue correctly truncates the // raft log. func TestRaftLogQueue(t *testing.T) { defer leaktest.AfterTest(t)() mtc := &multiTestContext{} // Set maxBytes to something small so we can trigger the raft log truncation // without adding 64MB of logs. const maxBytes = 1 << 16 defer config.TestingSetDefaultZoneConfig(config.ZoneConfig{ RangeMaxBytes: maxBytes, })() // Turn off raft elections so the raft leader won't change out from under // us in this test. sc := storage.TestStoreConfig(nil) sc.RaftTickInterval = math.MaxInt32 sc.RaftElectionTimeoutTicks = 1000000 mtc.storeConfig = &sc defer mtc.Stop() mtc.Start(t, 3) // Write a single value to ensure we have a leader. pArgs := putArgs([]byte("key"), []byte("value")) if _, err := client.SendWrapped(context.Background(), rg1(mtc.stores[0]), pArgs); err != nil { t.Fatal(err) } // Get the raft leader (and ensure one exists). rangeID := mtc.stores[0].LookupReplica([]byte("a"), nil).RangeID raftLeaderRepl := mtc.getRaftLeader(rangeID) if raftLeaderRepl == nil { t.Fatalf("could not find raft leader replica for range %d", rangeID) } originalIndex, err := raftLeaderRepl.GetFirstIndex() if err != nil { t.Fatal(err) } // Disable splits since we're increasing the raft log with puts. for _, store := range mtc.stores { store.SetSplitQueueActive(false) } // Write a collection of values to increase the raft log. value := bytes.Repeat([]byte("a"), 1000) // 1KB for size := int64(0); size < 2*maxBytes; size += int64(len(value)) { pArgs = putArgs([]byte(fmt.Sprintf("key-%d", size)), value) if _, err := client.SendWrapped(context.Background(), rg1(mtc.stores[0]), pArgs); err != nil { t.Fatal(err) } } // Sadly, occasionally the queue has a race with the force processing so // this succeeds within will captures those rare cases. var afterTruncationIndex uint64 testutils.SucceedsSoon(t, func() error { // Force a truncation check. for _, store := range mtc.stores { store.ForceRaftLogScanAndProcess() } // Ensure that firstIndex has increased indicating that the log // truncation has occurred. var err error afterTruncationIndex, err = raftLeaderRepl.GetFirstIndex() if err != nil { t.Fatal(err) } if afterTruncationIndex <= originalIndex { return errors.Errorf("raft log has not been truncated yet, afterTruncationIndex:%d originalIndex:%d", afterTruncationIndex, originalIndex) } return nil }) // Force a truncation check again to ensure that attempting to truncate an // already truncated log has no effect. This check, unlike in the last // iteration, cannot use a succeedsSoon. This check is fragile in that the // truncation triggered here may lose the race against the call to // GetFirstIndex, giving a false negative. Fixing this requires additional // instrumentation of the queues, which was deemed to require too much work // at the time of this writing. for _, store := range mtc.stores { store.ForceRaftLogScanAndProcess() } after2ndTruncationIndex, err := raftLeaderRepl.GetFirstIndex() if err != nil { t.Fatal(err) } if afterTruncationIndex > after2ndTruncationIndex { t.Fatalf("second truncation destroyed state: afterTruncationIndex:%d after2ndTruncationIndex:%d", afterTruncationIndex, after2ndTruncationIndex) } }
// TestStoreRangeLeaseSwitcheroo verifies that ranges can be switched // between expiration and epoch and back. func TestStoreRangeLeaseSwitcheroo(t *testing.T) { defer leaktest.AfterTest(t)() sc := storage.TestStoreConfig(nil) sc.EnableEpochRangeLeases = true mtc := &multiTestContext{storeConfig: &sc} defer mtc.Stop() mtc.Start(t, 1) splitKey := roachpb.Key("a") splitArgs := adminSplitArgs(splitKey, splitKey) if _, pErr := client.SendWrapped(context.Background(), mtc.distSenders[0], splitArgs); pErr != nil { t.Fatal(pErr) } // Allow leases to expire and send commands to ensure we // re-acquire, then check types again. mtc.expireLeases() if _, err := mtc.dbs[0].Inc(context.TODO(), splitKey, 1); err != nil { t.Fatalf("failed to increment: %s", err) } // We started with epoch ranges enabled, so verify we have an epoch lease. repl := mtc.stores[0].LookupReplica(roachpb.RKey(splitKey), nil) lease, _ := repl.GetLease() if lt := lease.Type(); lt != roachpb.LeaseEpoch { t.Fatalf("expected lease type epoch; got %d", lt) } // Stop the store and reverse the epoch range lease setting. mtc.stopStore(0) sc.EnableEpochRangeLeases = false mtc.restartStore(0) mtc.expireLeases() if _, err := mtc.dbs[0].Inc(context.TODO(), splitKey, 1); err != nil { t.Fatalf("failed to increment: %s", err) } // Verify we end up with an expiration lease on restart. repl = mtc.stores[0].LookupReplica(roachpb.RKey(splitKey), nil) lease, _ = repl.GetLease() if lt := lease.Type(); lt != roachpb.LeaseExpiration { t.Fatalf("expected lease type expiration; got %d", lt) } // Now, one more time, switch back to epoch-based. mtc.stopStore(0) sc.EnableEpochRangeLeases = true mtc.restartStore(0) mtc.expireLeases() if _, err := mtc.dbs[0].Inc(context.TODO(), splitKey, 1); err != nil { t.Fatalf("failed to increment: %s", err) } // Verify we end up with an epoch lease on restart. repl = mtc.stores[0].LookupReplica(roachpb.RKey(splitKey), nil) lease, _ = repl.GetLease() if lt := lease.Type(); lt != roachpb.LeaseEpoch { t.Fatalf("expected lease type epoch; got %d", lt) } }
// 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)() storeCfg := storage.TestStoreConfig(nil) storeCfg.TestingKnobs.DisableSplitQueue = true store, stopper := createTestStoreWithConfig(t, storeCfg) 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(context.Background(), rg1(store), &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(context.Background(), rg1(store), &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 expectedPre []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")}, }, expectedPre: []roachpb.RangeDescriptor{ {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")}, }, expectedPre: []roachpb.RangeDescriptor{ {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")}, }, expectedPre: []roachpb.RangeDescriptor{ {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")}, }, expectedPre: []roachpb.RangeDescriptor{ {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 testIdx, test := range testCases { resp, pErr := client.SendWrappedWith(context.Background(), rg1(store), roachpb.Header{ ReadConsistency: roachpb.INCONSISTENT, }, test.request) if pErr != nil { t.Fatalf("%d: RangeLookup error: %s", testIdx, pErr) } rlReply := resp.(*roachpb.RangeLookupResponse) // Checks the results count. if rsCount, preRSCount := len(rlReply.Ranges), len(rlReply.PrefetchedRanges); int32(rsCount+preRSCount) != test.request.MaxRanges { t.Fatalf("%d: returned results count, expected %d, but got %d+%d", testIdx, test.request.MaxRanges, rsCount, preRSCount) } // Checks the range descriptors. for _, rngSlice := range []struct { expect, reply []roachpb.RangeDescriptor }{ {test.expected, rlReply.Ranges}, {test.expectedPre, rlReply.PrefetchedRanges}, } { for i, rng := range rngSlice.expect { if !(rng.StartKey.Equal(rngSlice.reply[i].StartKey) && rng.EndKey.Equal(rngSlice.reply[i].EndKey)) { t.Fatalf("%d: returned range is not correct, expected %v, but got %v", testIdx, rng, rngSlice.reply[i]) } } } } }
// TestMultiRangeScanWithMaxResults tests that commands which access multiple // ranges with MaxResults parameter are carried out properly. func TestMultiRangeScanWithMaxResults(t *testing.T) { defer leaktest.AfterTest(t)() testCases := []struct { splitKeys []roachpb.Key keys []roachpb.Key }{ {[]roachpb.Key{roachpb.Key("m")}, []roachpb.Key{roachpb.Key("a"), roachpb.Key("z")}}, {[]roachpb.Key{roachpb.Key("h"), roachpb.Key("q")}, []roachpb.Key{roachpb.Key("b"), roachpb.Key("f"), roachpb.Key("k"), roachpb.Key("r"), roachpb.Key("w"), roachpb.Key("y")}}, } for i, tc := range testCases { s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop() ts := s.(*TestServer) retryOpts := base.DefaultRetryOptions() retryOpts.Closer = ts.stopper.ShouldQuiesce() ds := kv.NewDistSender(kv.DistSenderConfig{ Clock: s.Clock(), RPCContext: s.RPCContext(), RPCRetryOptions: &retryOpts, }, ts.Gossip()) ambient := log.AmbientContext{Tracer: tracing.NewTracer()} tds := kv.NewTxnCoordSender( ambient, ds, ts.Clock(), ts.Cfg.Linearizable, ts.stopper, kv.MakeTxnMetrics(metric.TestSampleInterval), ) for _, sk := range tc.splitKeys { if err := ts.node.storeCfg.DB.AdminSplit(context.TODO(), sk); err != nil { t.Fatal(err) } } for _, k := range tc.keys { put := roachpb.NewPut(k, roachpb.MakeValueFromBytes(k)) if _, err := client.SendWrapped(context.Background(), tds, put); err != nil { t.Fatal(err) } } // Try every possible ScanRequest startKey. for start := 0; start < len(tc.keys); start++ { // Try every possible maxResults, from 1 to beyond the size of key array. for maxResults := 1; maxResults <= len(tc.keys)-start+1; maxResults++ { scan := roachpb.NewScan(tc.keys[start], tc.keys[len(tc.keys)-1].Next()) reply, err := client.SendWrappedWith( context.Background(), tds, roachpb.Header{MaxSpanRequestKeys: int64(maxResults)}, scan, ) if err != nil { t.Fatal(err) } rows := reply.(*roachpb.ScanResponse).Rows if start+maxResults <= len(tc.keys) && len(rows) != maxResults { t.Errorf("%d: start=%s: expected %d rows, but got %d", i, tc.keys[start], maxResults, len(rows)) } else if start+maxResults == len(tc.keys)+1 && len(rows) != maxResults-1 { t.Errorf("%d: expected %d rows, but got %d", i, maxResults-1, len(rows)) } } } } }
// Test that a lease extension (a RequestLeaseRequest that doesn't change the // lease holder) is not blocked by ongoing reads. // The test relies on two things: // 1) Lease extensions, unlike lease transfers, are not blocked by reads through their // PostCommitTrigger.noConcurrentReads. // 2) Requests with the non-KV flag, such as RequestLeaseRequest, do not // go through the command queue. func TestLeaseExtensionNotBlockedByRead(t *testing.T) { defer leaktest.AfterTest(t)() readBlocked := make(chan struct{}) cmdFilter := func(fArgs storagebase.FilterArgs) *roachpb.Error { if fArgs.Hdr.UserPriority == 42 { // Signal that the read is blocked. readBlocked <- struct{}{} // Wait for read to be unblocked. <-readBlocked } return nil } srv, _, _ := serverutils.StartServer(t, base.TestServerArgs{ Knobs: base.TestingKnobs{ Store: &storage.StoreTestingKnobs{ TestingCommandFilter: cmdFilter, }, }, }) s := srv.(*server.TestServer) defer s.Stopper().Stop() // Start a read and wait for it to block. key := roachpb.Key("a") errChan := make(chan error) go func() { getReq := roachpb.GetRequest{ Span: roachpb.Span{ Key: key, }, } if _, pErr := client.SendWrappedWith(context.Background(), s.DistSender(), roachpb.Header{UserPriority: 42}, &getReq); pErr != nil { errChan <- pErr.GoError() } }() select { case err := <-errChan: t.Fatal(err) case <-readBlocked: // Send the lease request. rKey, err := keys.Addr(key) if err != nil { t.Fatal(err) } _, repDesc, err := s.Stores().LookupReplica(rKey, nil) if err != nil { t.Fatal(err) } leaseReq := roachpb.RequestLeaseRequest{ Span: roachpb.Span{ Key: key, }, Lease: roachpb.Lease{ Start: s.Clock().Now(), StartStasis: s.Clock().Now().Add(time.Second.Nanoseconds(), 0), Expiration: s.Clock().Now().Add(2*time.Second.Nanoseconds(), 0), Replica: repDesc, }, } if _, pErr := client.SendWrapped(context.Background(), s.DistSender(), &leaseReq); pErr != nil { t.Fatal(pErr) } // Unblock the read. readBlocked <- struct{}{} } }