diff --git a/store/tikv/region_request.go b/store/tikv/region_request.go index 4765e649a23a1..b32bc896dff5e 100644 --- a/store/tikv/region_request.go +++ b/store/tikv/region_request.go @@ -280,7 +280,7 @@ func (s *RegionRequestSender) SendReqCtx( var lastPeerID uint64 if rpcCtx != nil { - lastPeerID = rpcCtx.lastPeerID + lastPeerID = rpcCtx.Peer.GetId() } rpcCtx, err = s.getRPCContext(bo, req, regionID, et, opts...) if err != nil { @@ -337,6 +337,12 @@ func (s *RegionRequestSender) SendReqCtx( if err != nil { return nil, nil, errors.Trace(err) } + failpoint.Inject("mockDataIsNotReadyError", func(val failpoint.Value) { + regionErr = &errorpb.Error{} + if tryTimesLimit, ok := val.(int); ok && tryTimes <= tryTimesLimit { + regionErr.DataIsNotReady = &errorpb.DataIsNotReady{} + } + }) if regionErr != nil { retry, opts, err = s.onRegionError(bo, rpcCtx, req.ReplicaReadSeed, regionErr) if err != nil { diff --git a/store/tikv/region_request_test.go b/store/tikv/region_request_test.go index d3ed401be3e5c..3fa37f50f9645 100644 --- a/store/tikv/region_request_test.go +++ b/store/tikv/region_request_test.go @@ -24,6 +24,7 @@ import ( . "github.com/pingcap/check" "github.com/pingcap/errors" + "github.com/pingcap/failpoint" "github.com/pingcap/kvproto/pkg/coprocessor" "github.com/pingcap/kvproto/pkg/coprocessor_v2" "github.com/pingcap/kvproto/pkg/errorpb" @@ -218,9 +219,34 @@ func (s *testRegionRequestToThreeStoresSuite) TestGetRPCContextWithExcludedPeerI c.Assert(rpcCtx.Peer.GetId(), Equals, s.leaderPeer) } -// TODO: test whether the Stale Read request will retry the leader or next peer on error. -// func (s *testRegionRequestToThreeStoresSuite) TestStaleReadRetry(c *C) { -// } +// Test whether the Stale Read request will retry the leader or next peer on error. +func (s *testRegionRequestToThreeStoresSuite) TestStaleReadRetry(c *C) { + region, err := s.cache.LocateRegionByID(s.bo, s.regionID) + c.Assert(err, IsNil) + c.Assert(region, NotNil) + var seed uint32 = 0 + req := tikvrpc.NewReplicaReadRequest(tikvrpc.CmdGet, &kvrpcpb.GetRequest{}, kv.ReplicaReadMixed, &seed) + req.EnableStaleRead() + // Retry 3 times. + c.Assert(failpoint.Enable("github.com/pingcap/tidb/store/tikv/mockDataIsNotReadyError", `return(3)`), IsNil) + resp, ctx, err := s.regionRequestSender.SendReqCtx(s.bo, req, region.Region, time.Second, tikvrpc.TiKV) + c.Assert(err, IsNil) + c.Assert(resp.Resp, NotNil) + c.Assert(ctx, NotNil) + peerID := ctx.Peer.GetId() + + region, err = s.cache.LocateRegionByID(s.bo, s.regionID) + c.Assert(err, IsNil) + c.Assert(region, NotNil) + // Retry 1 time. + c.Assert(failpoint.Enable("github.com/pingcap/tidb/store/tikv/mockDataIsNotReadyError", `return(1)`), IsNil) + resp, ctx, err = s.regionRequestSender.SendReqCtx(s.bo, req, region.Region, time.Second, tikvrpc.TiKV) + c.Assert(err, IsNil) + c.Assert(resp.Resp, NotNil) + c.Assert(ctx, NotNil) + c.Assert(peerID, Not(Equals), ctx.Peer.GetId()) + c.Assert(failpoint.Disable("github.com/pingcap/tidb/store/tikv/mockDataIsNotReadyError"), IsNil) +} func (s *testRegionRequestToSingleStoreSuite) TestOnSendFailedWithStoreRestart(c *C) { req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{