Skip to content

Commit 61c3026

Browse files
authored
*: refine non-global stale-read request retry logic (#851) (#880)
Signed-off-by: crazycs520 <[email protected]>
1 parent 56f822e commit 61c3026

File tree

2 files changed

+51
-17
lines changed

2 files changed

+51
-17
lines changed

internal/locate/region_request.go

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -532,12 +532,12 @@ func (state *tryNewProxy) onNoLeader(selector *replicaSelector) {
532532
type accessFollower struct {
533533
stateBase
534534
// If tryLeader is true, the request can also be sent to the leader when !leader.isSlow()
535-
tryLeader bool
536-
isGlobalStaleRead bool
537-
option storeSelectorOp
538-
leaderIdx AccessIndex
539-
lastIdx AccessIndex
540-
learnerOnly bool
535+
tryLeader bool
536+
isStaleRead bool
537+
option storeSelectorOp
538+
leaderIdx AccessIndex
539+
lastIdx AccessIndex
540+
learnerOnly bool
541541
}
542542

543543
func (state *accessFollower) next(bo *retry.Backoffer, selector *replicaSelector) (*RPCContext, error) {
@@ -558,12 +558,10 @@ func (state *accessFollower) next(bo *retry.Backoffer, selector *replicaSelector
558558
}
559559
}
560560
} else {
561-
// Stale Read request will retry the leader or next peer on error,
562-
// if txnScope is global, we will only retry the leader by using the WithLeaderOnly option,
563-
// if txnScope is local, we will retry both other peers and the leader by the strategy of replicaSelector.
564-
if state.isGlobalStaleRead {
561+
// Stale Read request will retry the leader only by using the WithLeaderOnly option,
562+
if state.isStaleRead {
565563
WithLeaderOnly()(&state.option)
566-
// retry on the leader should not use stale read flag to avoid possible DataIsNotReady error as it always can serve any read
564+
// retry on the leader should not use stale read flag to avoid possible DataIsNotReady error as it always can serve any read.
567565
resetStaleRead = true
568566
}
569567
state.lastIdx++
@@ -766,12 +764,12 @@ func newReplicaSelector(
766764
}
767765
tryLeader := req.ReplicaReadType == kv.ReplicaReadMixed || req.ReplicaReadType == kv.ReplicaReadPreferLeader
768766
state = &accessFollower{
769-
tryLeader: tryLeader,
770-
isGlobalStaleRead: req.IsGlobalStaleRead(),
771-
option: option,
772-
leaderIdx: regionStore.workTiKVIdx,
773-
lastIdx: -1,
774-
learnerOnly: req.ReplicaReadType == kv.ReplicaReadLearner,
767+
tryLeader: tryLeader,
768+
isStaleRead: req.StaleRead,
769+
option: option,
770+
leaderIdx: regionStore.workTiKVIdx,
771+
lastIdx: -1,
772+
learnerOnly: req.ReplicaReadType == kv.ReplicaReadLearner,
775773
}
776774
}
777775

internal/locate/region_request_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,3 +657,39 @@ func (s *testRegionRequestToSingleStoreSuite) TestCloseConnectionOnStoreNotMatch
657657
s.NotNil(regionErr)
658658
s.Equal(target, client.closedAddr)
659659
}
660+
661+
func (s *testRegionRequestToSingleStoreSuite) TestStaleReadRetry() {
662+
req := tikvrpc.NewRequest(tikvrpc.CmdGet, &kvrpcpb.GetRequest{
663+
Key: []byte("key"),
664+
})
665+
req.EnableStaleRead()
666+
req.ReadReplicaScope = "z1" // not global stale read.
667+
region, err := s.cache.LocateRegionByID(s.bo, s.region)
668+
s.Nil(err)
669+
s.NotNil(region)
670+
671+
oc := s.regionRequestSender.client
672+
defer func() {
673+
s.regionRequestSender.client = oc
674+
}()
675+
676+
s.regionRequestSender.client = &fnClient{fn: func(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (response *tikvrpc.Response, err error) {
677+
if req.StaleRead {
678+
// Mock for stale-read request always return DataIsNotReady error when tikv `ResolvedTS` is blocked.
679+
response = &tikvrpc.Response{Resp: &kvrpcpb.GetResponse{
680+
RegionError: &errorpb.Error{DataIsNotReady: &errorpb.DataIsNotReady{}},
681+
}}
682+
} else {
683+
response = &tikvrpc.Response{Resp: &kvrpcpb.GetResponse{Value: []byte("value")}}
684+
}
685+
return response, nil
686+
}}
687+
688+
bo := retry.NewBackofferWithVars(context.Background(), 5, nil)
689+
resp, _, err := s.regionRequestSender.SendReq(bo, req, region.Region, time.Second)
690+
s.Nil(err)
691+
s.NotNil(resp)
692+
regionErr, _ := resp.GetRegionError()
693+
s.Nil(regionErr)
694+
s.Equal([]byte("value"), resp.Resp.(*kvrpcpb.GetResponse).Value)
695+
}

0 commit comments

Comments
 (0)