@@ -33,13 +33,14 @@ import (
3333
3434type replicaSelector struct {
3535 baseReplicaSelector
36- replicaReadType kv.ReplicaReadType
37- isStaleRead bool
38- isReadOnlyReq bool
39- option storeSelectorOp
40- target * replica
41- proxy * replica
42- attempts int
36+ replicaReadType kv.ReplicaReadType
37+ isStaleRead bool
38+ isReadOnlyReq bool
39+ option storeSelectorOp
40+ target * replica
41+ proxy * replica
42+ attempts int
43+ regionInvalidatedForRetry bool // set when region is hard-invalidated but this selector should still retry on leader
4344}
4445
4546func newReplicaSelector (
@@ -100,7 +101,13 @@ func buildTiKVReplicas(region *Region) []*replica {
100101}
101102
102103func (s * replicaSelector ) next (bo * retry.Backoffer , req * tikvrpc.Request ) (rpcCtx * RPCContext , err error ) {
103- if ! s .region .isValid () {
104+ if s .regionInvalidatedForRetry {
105+ // Allow one more attempt on this selector even though the region is
106+ // invalidated. This is set by onRegionNotFound so that the current
107+ // request can retry on the leader while concurrent requests are
108+ // stopped by the hard invalidation.
109+ s .regionInvalidatedForRetry = false
110+ } else if ! s .region .isValid () {
104111 metrics .TiKVReplicaSelectorFailureCounter .WithLabelValues ("invalid" ).Inc ()
105112 return nil , nil
106113 }
@@ -528,12 +535,16 @@ func (s *replicaSelector) onRegionNotFound(
528535 leaderIdx := s .region .getStore ().workTiKVIdx
529536 leader := s .replicas [leaderIdx ]
530537 if ! leader .isExhausted (1 , 0 ) {
531- // if the request is not sent to leader, we can retry it with leader and invalidate the region cache asynchronously. It helps in the scenario
532- // where region is split by the leader but not yet created in replica due to replica down.
538+ // if the request is not sent to leader, we can retry it with leader and invalidate the region cache
539+ // immediately. It helps in the scenario where region is split by the leader but not yet created
540+ // in replica due to replica down.
541+ // Hard-invalidate the region so that concurrent requests stop using the stale region,
542+ // but allow this selector to retry on the leader via regionInvalidatedForRetry.
533543 req .ReplicaRead = false
534544 req .ReplicaReadType = kv .ReplicaReadLeader
535545 s .replicaReadType = kv .ReplicaReadLeader
536- s .regionCache .AsyncInvalidateCachedRegion (ctx .Region )
546+ s .regionInvalidatedForRetry = true
547+ s .regionCache .InvalidateCachedRegion (ctx .Region )
537548 return true , nil
538549 }
539550 s .regionCache .InvalidateCachedRegion (ctx .Region )
0 commit comments