@@ -276,6 +276,12 @@ func refreshEpochs(regionStore *regionStore) {
276
276
}
277
277
}
278
278
279
+ func refreshLivenessStates (regionStore * regionStore ) {
280
+ for _ , store := range regionStore .stores {
281
+ atomic .StoreUint32 (& store .livenessState , uint32 (reachable ))
282
+ }
283
+ }
284
+
279
285
func (s * testRegionRequestToThreeStoresSuite ) TestReplicaSelector () {
280
286
regionLoc , err := s .cache .LocateRegionByID (s .bo , s .regionID )
281
287
s .Nil (err )
@@ -511,6 +517,7 @@ func (s *testRegionRequestToThreeStoresSuite) TestReplicaSelector() {
511
517
// Test accessFollower state with kv.ReplicaReadFollower request type.
512
518
req = tikvrpc .NewReplicaReadRequest (tikvrpc .CmdGet , & kvrpcpb.GetRequest {}, kv .ReplicaReadFollower , nil )
513
519
refreshEpochs (regionStore )
520
+ refreshLivenessStates (regionStore )
514
521
replicaSelector , err = newReplicaSelector (cache , regionLoc .Region , req )
515
522
s .Nil (err )
516
523
s .NotNil (replicaSelector )
@@ -625,10 +632,13 @@ func (s *testRegionRequestToThreeStoresSuite) TestSendReqWithReplicaSelector() {
625
632
region , err := s .cache .LocateRegionByID (s .bo , s .regionID )
626
633
s .Nil (err )
627
634
s .NotNil (region )
635
+ regionStore := s .cache .GetCachedRegionWithRLock (region .Region ).getStore ()
636
+ s .NotNil (regionStore )
628
637
629
638
reloadRegion := func () {
630
639
s .regionRequestSender .replicaSelector .region .invalidate (Other )
631
640
region , _ = s .cache .LocateRegionByID (s .bo , s .regionID )
641
+ regionStore = s .cache .GetCachedRegionWithRLock (region .Region ).getStore ()
632
642
}
633
643
634
644
hasFakeRegionError := func (resp * tikvrpc.Response ) bool {
@@ -660,6 +670,7 @@ func (s *testRegionRequestToThreeStoresSuite) TestSendReqWithReplicaSelector() {
660
670
s .Equal (sender .replicaSelector .targetIdx , AccessIndex (1 ))
661
671
s .True (bo .GetTotalBackoffTimes () == 1 )
662
672
s .cluster .StartStore (s .storeIDs [0 ])
673
+ atomic .StoreUint32 (& regionStore .stores [0 ].livenessState , uint32 (reachable ))
663
674
664
675
// Leader is updated because of send success, so no backoff.
665
676
bo = retry .NewBackoffer (context .Background (), - 1 )
@@ -679,6 +690,7 @@ func (s *testRegionRequestToThreeStoresSuite) TestSendReqWithReplicaSelector() {
679
690
s .True (hasFakeRegionError (resp ))
680
691
s .Equal (bo .GetTotalBackoffTimes (), 1 )
681
692
s .cluster .StartStore (s .storeIDs [1 ])
693
+ atomic .StoreUint32 (& regionStore .stores [1 ].livenessState , uint32 (reachable ))
682
694
683
695
// Leader is changed. No backoff.
684
696
reloadRegion ()
@@ -695,7 +707,7 @@ func (s *testRegionRequestToThreeStoresSuite) TestSendReqWithReplicaSelector() {
695
707
resp , err = sender .SendReq (bo , req , region .Region , time .Second )
696
708
s .Nil (err )
697
709
s .True (hasFakeRegionError (resp ))
698
- s .Equal (bo .GetTotalBackoffTimes (), 2 ) // The unreachable leader is skipped
710
+ s .Equal (bo .GetTotalBackoffTimes (), 3 )
699
711
s .False (sender .replicaSelector .region .isValid ())
700
712
s .cluster .ChangeLeader (s .regionID , s .peerIDs [0 ])
701
713
@@ -929,3 +941,80 @@ func (s *testRegionRequestToThreeStoresSuite) TestReplicaReadFallbackToLeaderReg
929
941
// after region error returned, the region should be invalidated.
930
942
s .False (region .isValid ())
931
943
}
944
+
945
+ func (s * testRegionRequestToThreeStoresSuite ) TestAccessFollowerAfter1TiKVDown () {
946
+ var leaderAddr string
947
+ s .regionRequestSender .client = & fnClient {fn : func (ctx context.Context , addr string , req * tikvrpc.Request , timeout time.Duration ) (response * tikvrpc.Response , err error ) {
948
+ // Returns error when accesses non-leader.
949
+ if leaderAddr != addr {
950
+ return nil , context .DeadlineExceeded
951
+ }
952
+ return & tikvrpc.Response {Resp : & kvrpcpb.GetResponse {
953
+ Value : []byte ("value" ),
954
+ }}, nil
955
+ }}
956
+
957
+ req := tikvrpc .NewRequest (tikvrpc .CmdGet , & kvrpcpb.GetRequest {
958
+ Key : []byte ("key" ),
959
+ })
960
+ req .ReplicaReadType = kv .ReplicaReadMixed
961
+
962
+ loc , err := s .cache .LocateKey (s .bo , []byte ("key" ))
963
+ s .Nil (err )
964
+ region := s .cache .GetCachedRegionWithRLock (loc .Region )
965
+ s .NotNil (region )
966
+ regionStore := region .getStore ()
967
+ leaderAddr = regionStore .stores [regionStore .workTiKVIdx ].addr
968
+ s .NotEqual (leaderAddr , "" )
969
+ for i := 0 ; i < 10 ; i ++ {
970
+ bo := retry .NewBackofferWithVars (context .Background (), 100 , nil )
971
+ resp , _ , err := s .regionRequestSender .SendReqCtx (bo , req , loc .Region , time .Second , tikvrpc .TiKV )
972
+ s .Nil (err )
973
+ s .NotNil (resp )
974
+
975
+ // Since send req to follower will receive error, then all follower will be marked as unreachable and epoch stale.
976
+ allFollowerStoreEpochStale := true
977
+ for i , store := range regionStore .stores {
978
+ if i == int (regionStore .workTiKVIdx ) {
979
+ continue
980
+ }
981
+ if store .epoch == regionStore .storeEpochs [i ] {
982
+ allFollowerStoreEpochStale = false
983
+ break
984
+ } else {
985
+ s .Equal (store .getLivenessState (), unreachable )
986
+ }
987
+ }
988
+ if allFollowerStoreEpochStale {
989
+ break
990
+ }
991
+ }
992
+
993
+ // mock for GC leader reload all regions.
994
+ bo := retry .NewBackofferWithVars (context .Background (), 10 , nil )
995
+ _ , err = s .cache .BatchLoadRegionsWithKeyRange (bo , []byte ("" ), nil , 1 )
996
+ s .Nil (err )
997
+
998
+ loc , err = s .cache .LocateKey (s .bo , []byte ("key" ))
999
+ s .Nil (err )
1000
+ region = s .cache .GetCachedRegionWithRLock (loc .Region )
1001
+ s .NotNil (region )
1002
+ regionStore = region .getStore ()
1003
+ for i , store := range regionStore .stores {
1004
+ if i == int (regionStore .workTiKVIdx ) {
1005
+ continue
1006
+ }
1007
+ // After reload region, the region epoch will be updated, but the store liveness state is still unreachable.
1008
+ s .Equal (store .epoch , regionStore .storeEpochs [i ])
1009
+ s .Equal (store .getLivenessState (), unreachable )
1010
+ }
1011
+
1012
+ for i := 0 ; i < 100 ; i ++ {
1013
+ bo := retry .NewBackofferWithVars (context .Background (), 1 , nil )
1014
+ resp , _ , err := s .regionRequestSender .SendReqCtx (bo , req , loc .Region , time .Second , tikvrpc .TiKV )
1015
+ s .Nil (err )
1016
+ s .NotNil (resp )
1017
+ // since all follower'store is unreachable, the request will be sent to leader, the backoff times should be 0.
1018
+ s .Equal (0 , bo .GetTotalBackoffTimes ())
1019
+ }
1020
+ }
0 commit comments