github.com/KinWaiYuen/client-go/v2@v2.5.4/internal/locate/region_cache_test.go (about)

     1  // Copyright 2021 TiKV Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // NOTE: The code in this file is based on code from the
    16  // TiDB project, licensed under the Apache License v 2.0
    17  //
    18  // https://github.com/pingcap/tidb/tree/cc5e161ac06827589c4966674597c137cc9e809c/store/tikv/locate/region_cache_test.go
    19  //
    20  
    21  // Copyright 2016 PingCAP, Inc.
    22  //
    23  // Licensed under the Apache License, Version 2.0 (the "License");
    24  // you may not use this file except in compliance with the License.
    25  // You may obtain a copy of the License at
    26  //
    27  //     http://www.apache.org/licenses/LICENSE-2.0
    28  //
    29  // Unless required by applicable law or agreed to in writing, software
    30  // distributed under the License is distributed on an "AS IS" BASIS,
    31  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    32  // See the License for the specific language governing permissions and
    33  // limitations under the License.
    34  
    35  package locate
    36  
    37  import (
    38  	"context"
    39  	"errors"
    40  	"fmt"
    41  	"math/rand"
    42  	"testing"
    43  	"time"
    44  
    45  	"github.com/KinWaiYuen/client-go/v2/internal/mockstore/mocktikv"
    46  	"github.com/KinWaiYuen/client-go/v2/internal/retry"
    47  	"github.com/KinWaiYuen/client-go/v2/kv"
    48  	"github.com/google/btree"
    49  	"github.com/pingcap/kvproto/pkg/errorpb"
    50  	"github.com/pingcap/kvproto/pkg/metapb"
    51  	"github.com/stretchr/testify/suite"
    52  	pd "github.com/tikv/pd/client"
    53  )
    54  
    55  func TestRegionCache(t *testing.T) {
    56  	suite.Run(t, new(testRegionCacheSuite))
    57  }
    58  
    59  type testRegionCacheSuite struct {
    60  	suite.Suite
    61  	mvccStore mocktikv.MVCCStore
    62  	cluster   *mocktikv.Cluster
    63  	store1    uint64 // store1 is leader
    64  	store2    uint64 // store2 is follower
    65  	peer1     uint64 // peer1 is leader
    66  	peer2     uint64 // peer2 is follower
    67  	region1   uint64
    68  	cache     *RegionCache
    69  	bo        *retry.Backoffer
    70  }
    71  
    72  func (s *testRegionCacheSuite) SetupTest() {
    73  	s.mvccStore = mocktikv.MustNewMVCCStore()
    74  	s.cluster = mocktikv.NewCluster(s.mvccStore)
    75  	storeIDs, peerIDs, regionID, _ := mocktikv.BootstrapWithMultiStores(s.cluster, 2)
    76  	s.region1 = regionID
    77  	s.store1 = storeIDs[0]
    78  	s.store2 = storeIDs[1]
    79  	s.peer1 = peerIDs[0]
    80  	s.peer2 = peerIDs[1]
    81  	pdCli := &CodecPDClient{mocktikv.NewPDClient(s.cluster)}
    82  	s.cache = NewRegionCache(pdCli)
    83  	s.bo = retry.NewBackofferWithVars(context.Background(), 5000, nil)
    84  }
    85  
    86  func (s *testRegionCacheSuite) TearDownTest() {
    87  	s.cache.Close()
    88  	s.mvccStore.Close()
    89  }
    90  
    91  func (s *testRegionCacheSuite) storeAddr(id uint64) string {
    92  	return fmt.Sprintf("store%d", id)
    93  }
    94  
    95  func (s *testRegionCacheSuite) checkCache(len int) {
    96  	ts := time.Now().Unix()
    97  	s.Equal(validRegions(s.cache.mu.regions, ts), len)
    98  	s.Equal(validRegionsSearchedByVersions(s.cache.mu.latestVersions, s.cache.mu.regions, ts), len)
    99  	s.Equal(validRegionsInBtree(s.cache.mu.sorted, ts), len)
   100  }
   101  
   102  func validRegionsSearchedByVersions(
   103  	versions map[uint64]RegionVerID,
   104  	regions map[RegionVerID]*Region,
   105  	ts int64,
   106  ) (count int) {
   107  	for _, ver := range versions {
   108  		region, ok := regions[ver]
   109  		if !ok || !region.checkRegionCacheTTL(ts) {
   110  			continue
   111  		}
   112  		count++
   113  	}
   114  	return
   115  }
   116  
   117  func validRegions(regions map[RegionVerID]*Region, ts int64) (len int) {
   118  	for _, region := range regions {
   119  		if !region.checkRegionCacheTTL(ts) {
   120  			continue
   121  		}
   122  		len++
   123  	}
   124  	return
   125  }
   126  
   127  func validRegionsInBtree(t *btree.BTree, ts int64) (len int) {
   128  	t.Descend(func(item btree.Item) bool {
   129  		r := item.(*btreeItem).cachedRegion
   130  		if !r.checkRegionCacheTTL(ts) {
   131  			return true
   132  		}
   133  		len++
   134  		return true
   135  	})
   136  	return
   137  }
   138  
   139  func (s *testRegionCacheSuite) getRegion(key []byte) *Region {
   140  	_, err := s.cache.LocateKey(s.bo, key)
   141  	s.Nil(err)
   142  	r := s.cache.searchCachedRegion(key, false)
   143  	s.NotNil(r)
   144  	return r
   145  }
   146  
   147  func (s *testRegionCacheSuite) getRegionWithEndKey(key []byte) *Region {
   148  	_, err := s.cache.LocateEndKey(s.bo, key)
   149  	s.Nil(err)
   150  	r := s.cache.searchCachedRegion(key, true)
   151  	s.NotNil(r)
   152  	return r
   153  }
   154  
   155  func (s *testRegionCacheSuite) getAddr(key []byte, replicaRead kv.ReplicaReadType, seed uint32) string {
   156  	loc, err := s.cache.LocateKey(s.bo, key)
   157  	s.Nil(err)
   158  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, replicaRead, seed)
   159  	s.Nil(err)
   160  	if ctx == nil {
   161  		return ""
   162  	}
   163  	return ctx.Addr
   164  }
   165  
   166  func (s *testRegionCacheSuite) TestStoreLabels() {
   167  	testcases := []struct {
   168  		storeID uint64
   169  	}{
   170  		{
   171  			storeID: s.store1,
   172  		},
   173  		{
   174  			storeID: s.store2,
   175  		},
   176  	}
   177  	for _, testcase := range testcases {
   178  		s.T().Log(testcase.storeID)
   179  		store := s.cache.getStoreByStoreID(testcase.storeID)
   180  		_, err := store.initResolve(s.bo, s.cache)
   181  		s.Nil(err)
   182  		labels := []*metapb.StoreLabel{
   183  			{
   184  				Key:   "id",
   185  				Value: fmt.Sprintf("%v", testcase.storeID),
   186  			},
   187  		}
   188  		stores := s.cache.getStoresByLabels(labels)
   189  		s.Equal(len(stores), 1)
   190  		s.Equal(stores[0].labels, labels)
   191  	}
   192  }
   193  
   194  func (s *testRegionCacheSuite) TestSimple() {
   195  	seed := rand.Uint32()
   196  	r := s.getRegion([]byte("a"))
   197  	s.NotNil(r)
   198  	s.Equal(r.GetID(), s.region1)
   199  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadLeader, 0), s.storeAddr(s.store1))
   200  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed), s.storeAddr(s.store2))
   201  	s.checkCache(1)
   202  	s.Equal(r.GetMeta(), r.meta)
   203  	s.Equal(r.GetLeaderPeerID(), r.meta.Peers[r.getStore().workTiKVIdx].Id)
   204  	s.cache.mu.regions[r.VerID()].lastAccess = 0
   205  	r = s.cache.searchCachedRegion([]byte("a"), true)
   206  	s.Nil(r)
   207  }
   208  
   209  // TestResolveStateTransition verifies store's resolve state transition. For example,
   210  // a newly added store is in unresolved state and will be resolved soon if it's an up store,
   211  // or in tombstone state if it's a tombstone.
   212  func (s *testRegionCacheSuite) TestResolveStateTransition() {
   213  	cache := s.cache
   214  	bo := retry.NewNoopBackoff(context.Background())
   215  
   216  	// Check resolving normal stores. The resolve state should be resolved.
   217  	for _, storeMeta := range s.cluster.GetAllStores() {
   218  		store := cache.getStoreByStoreID(storeMeta.GetId())
   219  		s.Equal(store.getResolveState(), unresolved)
   220  		addr, err := store.initResolve(bo, cache)
   221  		s.Nil(err)
   222  		s.Equal(addr, storeMeta.GetAddress())
   223  		s.Equal(store.getResolveState(), resolved)
   224  	}
   225  
   226  	waitResolve := func(s *Store) {
   227  		for i := 0; i < 10; i++ {
   228  			if s.getResolveState() != needCheck {
   229  				break
   230  			}
   231  			time.Sleep(50 * time.Millisecond)
   232  		}
   233  	}
   234  
   235  	// Mark the store needCheck. The resolve state should be resolved soon.
   236  	store := cache.getStoreByStoreID(s.store1)
   237  	store.markNeedCheck(cache.notifyCheckCh)
   238  	waitResolve(store)
   239  	s.Equal(store.getResolveState(), resolved)
   240  
   241  	// Mark the store needCheck and it becomes a tombstone. The resolve state should be tombstone.
   242  	s.cluster.MarkTombstone(s.store1)
   243  	store.markNeedCheck(cache.notifyCheckCh)
   244  	waitResolve(store)
   245  	s.Equal(store.getResolveState(), tombstone)
   246  	s.cluster.StartStore(s.store1)
   247  
   248  	// Mark the store needCheck and it's deleted from PD. The resolve state should be tombstone.
   249  	cache.clear()
   250  	store = cache.getStoreByStoreID(s.store1)
   251  	store.initResolve(bo, cache)
   252  	s.Equal(store.getResolveState(), resolved)
   253  	storeMeta := s.cluster.GetStore(s.store1)
   254  	s.cluster.RemoveStore(s.store1)
   255  	store.markNeedCheck(cache.notifyCheckCh)
   256  	waitResolve(store)
   257  	s.Equal(store.getResolveState(), tombstone)
   258  	s.cluster.AddStore(storeMeta.GetId(), storeMeta.GetAddress(), storeMeta.GetLabels()...)
   259  
   260  	// Mark the store needCheck and its address and labels are changed.
   261  	// The resolve state should be deleted and a new store is added to the cache.
   262  	cache.clear()
   263  	store = cache.getStoreByStoreID(s.store1)
   264  	store.initResolve(bo, cache)
   265  	s.Equal(store.getResolveState(), resolved)
   266  	s.cluster.UpdateStoreAddr(s.store1, store.addr+"0", &metapb.StoreLabel{Key: "k", Value: "v"})
   267  	store.markNeedCheck(cache.notifyCheckCh)
   268  	waitResolve(store)
   269  	s.Equal(store.getResolveState(), deleted)
   270  	newStore := cache.getStoreByStoreID(s.store1)
   271  	s.Equal(newStore.getResolveState(), resolved)
   272  	s.Equal(newStore.addr, store.addr+"0")
   273  	s.Equal(newStore.labels, []*metapb.StoreLabel{{Key: "k", Value: "v"}})
   274  
   275  	// Check initResolve()ing a tombstone store. The resolve state should be tombstone.
   276  	cache.clear()
   277  	s.cluster.MarkTombstone(s.store1)
   278  	store = cache.getStoreByStoreID(s.store1)
   279  	for i := 0; i < 2; i++ {
   280  		addr, err := store.initResolve(bo, cache)
   281  		s.Nil(err)
   282  		s.Equal(addr, "")
   283  		s.Equal(store.getResolveState(), tombstone)
   284  	}
   285  	s.cluster.StartStore(s.store1)
   286  	cache.clear()
   287  
   288  	// Check initResolve()ing a dropped store. The resolve state should be tombstone.
   289  	cache.clear()
   290  	storeMeta = s.cluster.GetStore(s.store1)
   291  	s.cluster.RemoveStore(s.store1)
   292  	store = cache.getStoreByStoreID(s.store1)
   293  	for i := 0; i < 2; i++ {
   294  		addr, err := store.initResolve(bo, cache)
   295  		s.Nil(err)
   296  		s.Equal(addr, "")
   297  		s.Equal(store.getResolveState(), tombstone)
   298  	}
   299  	s.cluster.AddStore(storeMeta.GetId(), storeMeta.GetAddress(), storeMeta.GetLabels()...)
   300  }
   301  
   302  // TestFilterDownPeersOrPeersOnTombstoneOrDroppedStore verifies the RegionCache filter
   303  // region's down peers and peers on tombstone or dropped stores. RegionCache shouldn't
   304  // report errors in such cases if there are available peers.
   305  func (s *testRegionCacheSuite) TestFilterDownPeersOrPeersOnTombstoneOrDroppedStores() {
   306  	key := []byte("a")
   307  	bo := retry.NewBackofferWithVars(context.Background(), 100, nil)
   308  
   309  	verifyGetRPCCtx := func(meta *metapb.Region) {
   310  		loc, err := s.cache.LocateKey(bo, key)
   311  		s.NotNil(loc)
   312  		s.Nil(err)
   313  		ctx, err := s.cache.GetTiKVRPCContext(bo, loc.Region, kv.ReplicaReadLeader, 0)
   314  		s.Nil(err)
   315  		s.NotNil(ctx)
   316  		s.Equal(ctx.Meta, meta)
   317  		ctx, err = s.cache.GetTiKVRPCContext(bo, loc.Region, kv.ReplicaReadFollower, rand.Uint32())
   318  		s.Nil(err)
   319  		s.NotNil(ctx)
   320  		s.Equal(ctx.Meta, meta)
   321  	}
   322  
   323  	// When all peers are normal, the cached region should contain all peers.
   324  	reg, err := s.cache.findRegionByKey(bo, key, false)
   325  	s.NotNil(reg)
   326  	s.Nil(err)
   327  	regInPD, _ := s.cluster.GetRegion(reg.GetID())
   328  	s.Equal(reg.meta, regInPD)
   329  	s.Equal(len(reg.meta.GetPeers()), len(reg.getStore().stores))
   330  	verifyGetRPCCtx(reg.meta)
   331  	s.checkCache(1)
   332  	s.cache.clear()
   333  
   334  	// Shouldn't contain the peer on the tombstone store.
   335  	s.cluster.MarkTombstone(s.store1)
   336  	reg, err = s.cache.findRegionByKey(bo, key, false)
   337  	s.NotNil(reg)
   338  	s.Nil(err)
   339  	s.Equal(len(reg.meta.GetPeers()), len(regInPD.GetPeers())-1)
   340  	s.Equal(len(reg.meta.GetPeers()), len(reg.getStore().stores))
   341  	for _, peer := range reg.meta.GetPeers() {
   342  		s.NotEqual(peer.GetStoreId(), s.store1)
   343  	}
   344  	for _, store := range reg.getStore().stores {
   345  		s.NotEqual(store.storeID, s.store1)
   346  	}
   347  	verifyGetRPCCtx(reg.meta)
   348  	s.checkCache(1)
   349  	s.cache.clear()
   350  	s.cluster.StartStore(s.store1)
   351  
   352  	// Shouldn't contain the peer on the dropped store.
   353  	store := s.cluster.GetStore(s.store1)
   354  	s.cluster.RemoveStore(s.store1)
   355  	reg, err = s.cache.findRegionByKey(bo, key, false)
   356  	s.NotNil(reg)
   357  	s.Nil(err)
   358  	s.Equal(len(reg.meta.GetPeers()), len(regInPD.GetPeers())-1)
   359  	s.Equal(len(reg.meta.GetPeers()), len(reg.getStore().stores))
   360  	for _, peer := range reg.meta.GetPeers() {
   361  		s.NotEqual(peer.GetStoreId(), s.store1)
   362  	}
   363  	for _, store := range reg.getStore().stores {
   364  		s.NotEqual(store.storeID, s.store1)
   365  	}
   366  	verifyGetRPCCtx(reg.meta)
   367  	s.checkCache(1)
   368  	s.cache.clear()
   369  	s.cluster.AddStore(store.GetId(), store.GetAddress(), store.GetLabels()...)
   370  
   371  	// Report an error when there's no available peers.
   372  	s.cluster.MarkTombstone(s.store1)
   373  	s.cluster.MarkTombstone(s.store2)
   374  	_, err = s.cache.findRegionByKey(bo, key, false)
   375  	s.NotNil(err)
   376  	s.Regexp(".*no available peers.", err.Error())
   377  	s.cluster.StartStore(s.store1)
   378  	s.cluster.StartStore(s.store2)
   379  }
   380  
   381  func (s *testRegionCacheSuite) TestUpdateLeader() {
   382  	seed := rand.Uint32()
   383  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   384  	s.Nil(err)
   385  	// tikv-server reports `NotLeader`
   386  	s.cache.UpdateLeader(loc.Region, &metapb.Peer{Id: s.peer2, StoreId: s.store2}, 0)
   387  
   388  	r := s.getRegion([]byte("a"))
   389  	s.NotNil(r)
   390  	s.Equal(r.GetID(), s.region1)
   391  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadLeader, 0), s.storeAddr(s.store2))
   392  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed), s.storeAddr(s.store1))
   393  
   394  	r = s.getRegionWithEndKey([]byte("z"))
   395  	s.NotNil(r)
   396  	s.Equal(r.GetID(), s.region1)
   397  	s.Equal(s.getAddr([]byte("z"), kv.ReplicaReadLeader, 0), s.storeAddr(s.store2))
   398  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed), s.storeAddr(s.store1))
   399  }
   400  
   401  func (s *testRegionCacheSuite) TestUpdateLeader2() {
   402  	seed := rand.Uint32()
   403  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   404  	s.Nil(err)
   405  	// new store3 becomes leader
   406  	store3 := s.cluster.AllocID()
   407  	peer3 := s.cluster.AllocID()
   408  	s.cluster.AddStore(store3, s.storeAddr(store3))
   409  	s.cluster.AddPeer(s.region1, store3, peer3)
   410  	// tikv-server reports `NotLeader`
   411  	s.cache.UpdateLeader(loc.Region, &metapb.Peer{Id: peer3, StoreId: store3}, 0)
   412  
   413  	// Store3 does not exist in cache, causes a reload from PD.
   414  	r := s.getRegion([]byte("a"))
   415  	s.NotNil(r)
   416  	s.Equal(r.GetID(), s.region1)
   417  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadLeader, 0), s.storeAddr(s.store1))
   418  	follower := s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed)
   419  	if seed%2 == 0 {
   420  		s.Equal(follower, s.storeAddr(s.store2))
   421  	} else {
   422  		s.Equal(follower, s.storeAddr(store3))
   423  	}
   424  	follower2 := s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed+1)
   425  	if (seed+1)%2 == 0 {
   426  		s.Equal(follower2, s.storeAddr(s.store2))
   427  	} else {
   428  		s.Equal(follower2, s.storeAddr(store3))
   429  	}
   430  	s.NotEqual(follower, follower2)
   431  
   432  	// tikv-server notifies new leader to pd-server.
   433  	s.cluster.ChangeLeader(s.region1, peer3)
   434  	// tikv-server reports `NotLeader` again.
   435  	s.cache.UpdateLeader(r.VerID(), &metapb.Peer{Id: peer3, StoreId: store3}, 0)
   436  	r = s.getRegion([]byte("a"))
   437  	s.NotNil(r)
   438  	s.Equal(r.GetID(), s.region1)
   439  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadLeader, 0), s.storeAddr(store3))
   440  	follower = s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed)
   441  	if seed%2 == 0 {
   442  		s.Equal(follower, s.storeAddr(s.store1))
   443  	} else {
   444  		s.Equal(follower, s.storeAddr(s.store2))
   445  	}
   446  	follower2 = s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed+1)
   447  	if (seed+1)%2 == 0 {
   448  		s.Equal(follower2, s.storeAddr(s.store1))
   449  	} else {
   450  		s.Equal(follower2, s.storeAddr(s.store2))
   451  	}
   452  	s.NotEqual(follower, follower2)
   453  }
   454  
   455  func (s *testRegionCacheSuite) TestUpdateLeader3() {
   456  	seed := rand.Uint32()
   457  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   458  	s.Nil(err)
   459  	// store2 becomes leader
   460  	s.cluster.ChangeLeader(s.region1, s.peer2)
   461  	// store2 gone, store3 becomes leader
   462  	s.cluster.RemoveStore(s.store2)
   463  	store3 := s.cluster.AllocID()
   464  	peer3 := s.cluster.AllocID()
   465  	s.cluster.AddStore(store3, s.storeAddr(store3))
   466  	s.cluster.AddPeer(s.region1, store3, peer3)
   467  	// tikv-server notifies new leader to pd-server.
   468  	s.cluster.ChangeLeader(s.region1, peer3)
   469  	// tikv-server reports `NotLeader`(store2 is the leader)
   470  	s.cache.UpdateLeader(loc.Region, &metapb.Peer{Id: s.peer2, StoreId: s.store2}, 0)
   471  
   472  	// Store2 does not exist any more, causes a reload from PD.
   473  	r := s.getRegion([]byte("a"))
   474  	s.Nil(err)
   475  	s.NotNil(r)
   476  	s.Equal(r.GetID(), s.region1)
   477  	loc, err = s.cache.LocateKey(s.bo, []byte("a"))
   478  	s.Nil(err)
   479  	// return resolved store2 address and send fail
   480  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, seed)
   481  	s.Nil(err)
   482  	s.Equal(ctx.Addr, "store2")
   483  	s.cache.OnSendFail(retry.NewNoopBackoff(context.Background()), ctx, false, errors.New("send fail"))
   484  	s.cache.checkAndResolve(nil, func(*Store) bool { return true })
   485  	s.cache.UpdateLeader(loc.Region, &metapb.Peer{Id: s.peer2, StoreId: s.store2}, 0)
   486  	addr := s.getAddr([]byte("a"), kv.ReplicaReadLeader, 0)
   487  	s.Equal(addr, "")
   488  	addr = s.getAddr([]byte("a"), kv.ReplicaReadLeader, 0)
   489  	s.Equal(addr, s.storeAddr(store3))
   490  
   491  	addr = s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed)
   492  	addr2 := s.getAddr([]byte("a"), kv.ReplicaReadFollower, seed+1)
   493  	s.NotEqual(addr, s.storeAddr(store3))
   494  	s.NotEqual(addr2, s.storeAddr(store3))
   495  }
   496  
   497  func (s *testRegionCacheSuite) TestSendFailedButLeaderNotChange() {
   498  	// 3 nodes and no.1 is leader.
   499  	store3 := s.cluster.AllocID()
   500  	peer3 := s.cluster.AllocID()
   501  	s.cluster.AddStore(store3, s.storeAddr(store3))
   502  	s.cluster.AddPeer(s.region1, store3, peer3)
   503  	s.cluster.ChangeLeader(s.region1, s.peer1)
   504  
   505  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   506  	s.Nil(err)
   507  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   508  	s.Nil(err)
   509  	s.Equal(ctx.Peer.Id, s.peer1)
   510  	s.Equal(len(ctx.Meta.Peers), 3)
   511  
   512  	// verify follower to be one of store2 and store3
   513  	seed := rand.Uint32()
   514  	ctxFollower1, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   515  	s.Nil(err)
   516  	if seed%2 == 0 {
   517  		s.Equal(ctxFollower1.Peer.Id, s.peer2)
   518  	} else {
   519  		s.Equal(ctxFollower1.Peer.Id, peer3)
   520  	}
   521  	ctxFollower2, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   522  	s.Nil(err)
   523  	if seed%2 == 0 {
   524  		s.Equal(ctxFollower2.Peer.Id, s.peer2)
   525  	} else {
   526  		s.Equal(ctxFollower2.Peer.Id, peer3)
   527  	}
   528  	s.Equal(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   529  
   530  	// send fail leader switch to 2
   531  	s.cache.OnSendFail(s.bo, ctx, false, nil)
   532  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   533  	s.Nil(err)
   534  	s.Equal(ctx.Peer.Id, s.peer2)
   535  
   536  	// verify follower to be one of store1 and store3
   537  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   538  	s.Nil(err)
   539  	if seed%2 == 0 {
   540  		s.Equal(ctxFollower1.Peer.Id, s.peer1)
   541  	} else {
   542  		s.Equal(ctxFollower1.Peer.Id, peer3)
   543  	}
   544  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed+1)
   545  	s.Nil(err)
   546  	if (seed+1)%2 == 0 {
   547  		s.Equal(ctxFollower2.Peer.Id, s.peer1)
   548  	} else {
   549  		s.Equal(ctxFollower2.Peer.Id, peer3)
   550  	}
   551  	s.NotEqual(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   552  
   553  	// access 1 it will return NotLeader, leader back to 2 again
   554  	s.cache.UpdateLeader(loc.Region, &metapb.Peer{Id: s.peer2, StoreId: s.store2}, ctx.AccessIdx)
   555  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   556  	s.Nil(err)
   557  	s.Equal(ctx.Peer.Id, s.peer2)
   558  
   559  	// verify follower to be one of store1 and store3
   560  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   561  	s.Nil(err)
   562  	if seed%2 == 0 {
   563  		s.Equal(ctxFollower1.Peer.Id, s.peer1)
   564  	} else {
   565  		s.Equal(ctxFollower1.Peer.Id, peer3)
   566  	}
   567  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed+1)
   568  	s.Nil(err)
   569  	if (seed+1)%2 == 0 {
   570  		s.Equal(ctxFollower2.Peer.Id, s.peer1)
   571  	} else {
   572  		s.Equal(ctxFollower2.Peer.Id, peer3)
   573  	}
   574  	s.NotEqual(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   575  }
   576  
   577  func (s *testRegionCacheSuite) TestSendFailedInHibernateRegion() {
   578  	// 3 nodes and no.1 is leader.
   579  	store3 := s.cluster.AllocID()
   580  	peer3 := s.cluster.AllocID()
   581  	s.cluster.AddStore(store3, s.storeAddr(store3))
   582  	s.cluster.AddPeer(s.region1, store3, peer3)
   583  	s.cluster.ChangeLeader(s.region1, s.peer1)
   584  
   585  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   586  	s.Nil(err)
   587  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   588  	s.Nil(err)
   589  	s.Equal(ctx.Peer.Id, s.peer1)
   590  	s.Equal(len(ctx.Meta.Peers), 3)
   591  
   592  	// verify follower to be one of store2 and store3
   593  	seed := rand.Uint32()
   594  	ctxFollower1, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   595  	s.Nil(err)
   596  	if seed%2 == 0 {
   597  		s.Equal(ctxFollower1.Peer.Id, s.peer2)
   598  	} else {
   599  		s.Equal(ctxFollower1.Peer.Id, peer3)
   600  	}
   601  	ctxFollower2, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   602  	s.Nil(err)
   603  	if seed%2 == 0 {
   604  		s.Equal(ctxFollower2.Peer.Id, s.peer2)
   605  	} else {
   606  		s.Equal(ctxFollower2.Peer.Id, peer3)
   607  	}
   608  	s.Equal(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   609  
   610  	// send fail leader switch to 2
   611  	s.cache.OnSendFail(s.bo, ctx, false, nil)
   612  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   613  	s.Nil(err)
   614  	s.Equal(ctx.Peer.Id, s.peer2)
   615  
   616  	// verify follower to be one of store1 and store3
   617  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   618  	s.Nil(err)
   619  	if seed%2 == 0 {
   620  		s.Equal(ctxFollower1.Peer.Id, s.peer1)
   621  	} else {
   622  		s.Equal(ctxFollower1.Peer.Id, peer3)
   623  	}
   624  	s.True(ctxFollower1.Peer.Id == s.peer1 || ctxFollower1.Peer.Id == peer3)
   625  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed+1)
   626  	s.Nil(err)
   627  	if (seed+1)%2 == 0 {
   628  		s.Equal(ctxFollower2.Peer.Id, s.peer1)
   629  	} else {
   630  		s.Equal(ctxFollower2.Peer.Id, peer3)
   631  	}
   632  	s.NotEqual(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   633  
   634  	// access 2, it's in hibernate and return 0 leader, so switch to 3
   635  	s.cache.UpdateLeader(loc.Region, nil, ctx.AccessIdx)
   636  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   637  	s.Nil(err)
   638  	s.Equal(ctx.Peer.Id, peer3)
   639  
   640  	// verify follower to be one of store1 and store2
   641  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   642  	s.Nil(err)
   643  	if seed%2 == 0 {
   644  		s.Equal(ctxFollower1.Peer.Id, s.peer1)
   645  	} else {
   646  		s.Equal(ctxFollower1.Peer.Id, s.peer2)
   647  	}
   648  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   649  	s.Nil(err)
   650  	if seed%2 == 0 {
   651  		s.Equal(ctxFollower2.Peer.Id, s.peer1)
   652  	} else {
   653  		s.Equal(ctxFollower2.Peer.Id, s.peer2)
   654  	}
   655  	s.Equal(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   656  
   657  	// again peer back to 1
   658  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   659  	s.Nil(err)
   660  	s.cache.UpdateLeader(loc.Region, nil, ctx.AccessIdx)
   661  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   662  	s.Nil(err)
   663  	s.Equal(ctx.Peer.Id, s.peer1)
   664  
   665  	// verify follower to be one of store2 and store3
   666  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   667  	s.Nil(err)
   668  	if seed%2 == 0 {
   669  		s.Equal(ctxFollower1.Peer.Id, s.peer2)
   670  	} else {
   671  		s.Equal(ctxFollower1.Peer.Id, peer3)
   672  	}
   673  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed+1)
   674  	s.Nil(err)
   675  	if (seed+1)%2 == 0 {
   676  		s.Equal(ctxFollower2.Peer.Id, s.peer2)
   677  	} else {
   678  		s.Equal(ctxFollower2.Peer.Id, peer3)
   679  	}
   680  	s.NotEqual(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   681  }
   682  
   683  func (s *testRegionCacheSuite) TestSendFailInvalidateRegionsInSameStore() {
   684  	// key range: ['' - 'm' - 'z']
   685  	region2 := s.cluster.AllocID()
   686  	newPeers := s.cluster.AllocIDs(2)
   687  	s.cluster.Split(s.region1, region2, []byte("m"), newPeers, newPeers[0])
   688  
   689  	// Check the two regions.
   690  	loc1, err := s.cache.LocateKey(s.bo, []byte("a"))
   691  	s.Nil(err)
   692  	s.Equal(loc1.Region.id, s.region1)
   693  	loc2, err := s.cache.LocateKey(s.bo, []byte("x"))
   694  	s.Nil(err)
   695  	s.Equal(loc2.Region.id, region2)
   696  
   697  	// Send fail on region1
   698  	ctx, _ := s.cache.GetTiKVRPCContext(s.bo, loc1.Region, kv.ReplicaReadLeader, 0)
   699  	s.checkCache(2)
   700  	s.cache.OnSendFail(s.bo, ctx, false, errors.New("test error"))
   701  
   702  	// Get region2 cache will get nil then reload.
   703  	ctx2, err := s.cache.GetTiKVRPCContext(s.bo, loc2.Region, kv.ReplicaReadLeader, 0)
   704  	s.Nil(ctx2)
   705  	s.Nil(err)
   706  }
   707  
   708  func (s *testRegionCacheSuite) TestSendFailedInMultipleNode() {
   709  	// 3 nodes and no.1 is leader.
   710  	store3 := s.cluster.AllocID()
   711  	peer3 := s.cluster.AllocID()
   712  	s.cluster.AddStore(store3, s.storeAddr(store3))
   713  	s.cluster.AddPeer(s.region1, store3, peer3)
   714  	s.cluster.ChangeLeader(s.region1, s.peer1)
   715  
   716  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   717  	s.Nil(err)
   718  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   719  	s.Nil(err)
   720  	s.Equal(ctx.Peer.Id, s.peer1)
   721  	s.Equal(len(ctx.Meta.Peers), 3)
   722  
   723  	// verify follower to be one of store2 and store3
   724  	seed := rand.Uint32()
   725  	ctxFollower1, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   726  	s.Nil(err)
   727  	if seed%2 == 0 {
   728  		s.Equal(ctxFollower1.Peer.Id, s.peer2)
   729  	} else {
   730  		s.Equal(ctxFollower1.Peer.Id, peer3)
   731  	}
   732  	ctxFollower2, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   733  	s.Nil(err)
   734  	if seed%2 == 0 {
   735  		s.Equal(ctxFollower2.Peer.Id, s.peer2)
   736  	} else {
   737  		s.Equal(ctxFollower2.Peer.Id, peer3)
   738  	}
   739  	s.Equal(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   740  
   741  	// send fail leader switch to 2
   742  	s.cache.OnSendFail(s.bo, ctx, false, nil)
   743  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   744  	s.Nil(err)
   745  	s.Equal(ctx.Peer.Id, s.peer2)
   746  
   747  	// verify follower to be one of store1 and store3
   748  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   749  	s.Nil(err)
   750  	if seed%2 == 0 {
   751  		s.Equal(ctxFollower1.Peer.Id, s.peer1)
   752  	} else {
   753  		s.Equal(ctxFollower1.Peer.Id, peer3)
   754  	}
   755  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed+1)
   756  	s.Nil(err)
   757  	if (seed+1)%2 == 0 {
   758  		s.Equal(ctxFollower2.Peer.Id, s.peer1)
   759  	} else {
   760  		s.Equal(ctxFollower2.Peer.Id, peer3)
   761  	}
   762  	s.NotEqual(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   763  
   764  	// send 2 fail leader switch to 3
   765  	s.cache.OnSendFail(s.bo, ctx, false, nil)
   766  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   767  	s.Nil(err)
   768  	s.Equal(ctx.Peer.Id, peer3)
   769  
   770  	// verify follower to be one of store1 and store2
   771  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   772  	s.Nil(err)
   773  	if seed%2 == 0 {
   774  		s.Equal(ctxFollower1.Peer.Id, s.peer1)
   775  	} else {
   776  		s.Equal(ctxFollower1.Peer.Id, s.peer2)
   777  	}
   778  	s.True(ctxFollower1.Peer.Id == s.peer1 || ctxFollower1.Peer.Id == s.peer2)
   779  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   780  	s.Nil(err)
   781  	if seed%2 == 0 {
   782  		s.Equal(ctxFollower2.Peer.Id, s.peer1)
   783  	} else {
   784  		s.Equal(ctxFollower2.Peer.Id, s.peer2)
   785  	}
   786  	s.Equal(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   787  
   788  	// 3 can be access, so switch to 1
   789  	s.cache.UpdateLeader(loc.Region, &metapb.Peer{Id: s.peer1, StoreId: s.store1}, ctx.AccessIdx)
   790  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
   791  	s.Nil(err)
   792  	s.Equal(ctx.Peer.Id, s.peer1)
   793  
   794  	// verify follower to be one of store2 and store3
   795  	ctxFollower1, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed)
   796  	s.Nil(err)
   797  	if seed%2 == 0 {
   798  		s.Equal(ctxFollower1.Peer.Id, s.peer2)
   799  	} else {
   800  		s.Equal(ctxFollower1.Peer.Id, peer3)
   801  	}
   802  	ctxFollower2, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, seed+1)
   803  	s.Nil(err)
   804  	if (seed+1)%2 == 0 {
   805  		s.Equal(ctxFollower2.Peer.Id, s.peer2)
   806  	} else {
   807  		s.Equal(ctxFollower2.Peer.Id, peer3)
   808  	}
   809  	s.NotEqual(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
   810  }
   811  
   812  func (s *testRegionCacheSuite) TestLabelSelectorTiKVPeer() {
   813  	dc1Label := []*metapb.StoreLabel{
   814  		{
   815  			Key:   "zone",
   816  			Value: "dc-1",
   817  		},
   818  	}
   819  	dc2Label := []*metapb.StoreLabel{
   820  		{
   821  			Key:   "zone",
   822  			Value: "dc-2",
   823  		},
   824  	}
   825  	dc3Label := []*metapb.StoreLabel{
   826  		{
   827  			Key:   "zone",
   828  			Value: "dc-3",
   829  		},
   830  	}
   831  	s.cluster.UpdateStoreLabels(s.store1, dc1Label)
   832  	s.cluster.UpdateStoreLabels(s.store2, dc2Label)
   833  
   834  	store3 := s.cluster.AllocID()
   835  	peer3 := s.cluster.AllocID()
   836  	s.cluster.AddStore(store3, s.storeAddr(store3))
   837  	s.cluster.AddPeer(s.region1, store3, peer3)
   838  	s.cluster.UpdateStoreLabels(store3, dc1Label)
   839  	// Region have 3 peer, leader located in dc-1, followers located in dc-1, dc-2
   840  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   841  	s.Nil(err)
   842  	seed := rand.Uint32()
   843  
   844  	testcases := []struct {
   845  		name               string
   846  		t                  kv.ReplicaReadType
   847  		labels             []*metapb.StoreLabel
   848  		expectStoreIDRange map[uint64]struct{}
   849  	}{
   850  		{
   851  			name:   "any Peer,located in dc-1",
   852  			t:      kv.ReplicaReadMixed,
   853  			labels: dc1Label,
   854  			expectStoreIDRange: map[uint64]struct{}{
   855  				s.store1: {},
   856  				store3:   {},
   857  			},
   858  		},
   859  		{
   860  			name:   "any Peer,located in dc-2",
   861  			t:      kv.ReplicaReadMixed,
   862  			labels: dc2Label,
   863  			expectStoreIDRange: map[uint64]struct{}{
   864  				s.store2: {},
   865  			},
   866  		},
   867  		{
   868  			name:   "only follower,located in dc-1",
   869  			t:      kv.ReplicaReadFollower,
   870  			labels: dc1Label,
   871  			expectStoreIDRange: map[uint64]struct{}{
   872  				store3: {},
   873  			},
   874  		},
   875  		{
   876  			name:   "only leader, shouldn't consider labels",
   877  			t:      kv.ReplicaReadLeader,
   878  			labels: dc2Label,
   879  			expectStoreIDRange: map[uint64]struct{}{
   880  				s.store1: {},
   881  			},
   882  		},
   883  		{
   884  			name:   "no label matching, fallback to leader",
   885  			t:      kv.ReplicaReadMixed,
   886  			labels: dc3Label,
   887  			expectStoreIDRange: map[uint64]struct{}{
   888  				s.store1: {},
   889  			},
   890  		},
   891  	}
   892  
   893  	for _, testcase := range testcases {
   894  		s.T().Log(testcase.name)
   895  		ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, testcase.t, seed, WithMatchLabels(testcase.labels))
   896  		s.Nil(err)
   897  		_, exist := testcase.expectStoreIDRange[ctx.Store.storeID]
   898  		s.Equal(exist, true)
   899  	}
   900  }
   901  
   902  func (s *testRegionCacheSuite) TestSplit() {
   903  	seed := rand.Uint32()
   904  	r := s.getRegion([]byte("x"))
   905  	s.Equal(r.GetID(), s.region1)
   906  	s.Equal(s.getAddr([]byte("x"), kv.ReplicaReadLeader, 0), s.storeAddr(s.store1))
   907  	s.Equal(s.getAddr([]byte("x"), kv.ReplicaReadFollower, seed), s.storeAddr(s.store2))
   908  
   909  	// split to ['' - 'm' - 'z']
   910  	region2 := s.cluster.AllocID()
   911  	newPeers := s.cluster.AllocIDs(2)
   912  	s.cluster.Split(s.region1, region2, []byte("m"), newPeers, newPeers[0])
   913  
   914  	// tikv-server reports `NotInRegion`
   915  	s.cache.InvalidateCachedRegion(r.VerID())
   916  	s.checkCache(0)
   917  
   918  	r = s.getRegion([]byte("x"))
   919  	s.Equal(r.GetID(), region2)
   920  	s.Equal(s.getAddr([]byte("x"), kv.ReplicaReadLeader, 0), s.storeAddr(s.store1))
   921  	s.Equal(s.getAddr([]byte("x"), kv.ReplicaReadFollower, seed), s.storeAddr(s.store2))
   922  	s.checkCache(1)
   923  
   924  	r = s.getRegionWithEndKey([]byte("m"))
   925  	s.Equal(r.GetID(), s.region1)
   926  	s.checkCache(2)
   927  }
   928  
   929  func (s *testRegionCacheSuite) TestMerge() {
   930  	// key range: ['' - 'm' - 'z']
   931  	region2 := s.cluster.AllocID()
   932  	newPeers := s.cluster.AllocIDs(2)
   933  	s.cluster.Split(s.region1, region2, []byte("m"), newPeers, newPeers[0])
   934  
   935  	loc, err := s.cache.LocateKey(s.bo, []byte("x"))
   936  	s.Nil(err)
   937  	s.Equal(loc.Region.id, region2)
   938  
   939  	// merge to single region
   940  	s.cluster.Merge(s.region1, region2)
   941  
   942  	// tikv-server reports `NotInRegion`
   943  	s.cache.InvalidateCachedRegion(loc.Region)
   944  	s.checkCache(0)
   945  
   946  	loc, err = s.cache.LocateKey(s.bo, []byte("x"))
   947  	s.Nil(err)
   948  	s.Equal(loc.Region.id, s.region1)
   949  	s.checkCache(1)
   950  }
   951  
   952  func (s *testRegionCacheSuite) TestReconnect() {
   953  	seed := rand.Uint32()
   954  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
   955  	s.Nil(err)
   956  
   957  	// connect tikv-server failed, cause drop cache
   958  	s.cache.InvalidateCachedRegion(loc.Region)
   959  
   960  	r := s.getRegion([]byte("a"))
   961  	s.NotNil(r)
   962  	s.Equal(r.GetID(), s.region1)
   963  	s.Equal(s.getAddr([]byte("a"), kv.ReplicaReadLeader, 0), s.storeAddr(s.store1))
   964  	s.Equal(s.getAddr([]byte("x"), kv.ReplicaReadFollower, seed), s.storeAddr(s.store2))
   965  	s.checkCache(1)
   966  }
   967  
   968  func (s *testRegionCacheSuite) TestRegionEpochAheadOfTiKV() {
   969  	// Create a separated region cache to do this test.
   970  	pdCli := &CodecPDClient{mocktikv.NewPDClient(s.cluster)}
   971  	cache := NewRegionCache(pdCli)
   972  	defer cache.Close()
   973  
   974  	region := createSampleRegion([]byte("k1"), []byte("k2"))
   975  	region.meta.Id = 1
   976  	region.meta.RegionEpoch = &metapb.RegionEpoch{Version: 10, ConfVer: 10}
   977  	cache.insertRegionToCache(region)
   978  
   979  	r1 := metapb.Region{Id: 1, RegionEpoch: &metapb.RegionEpoch{Version: 9, ConfVer: 10}}
   980  	r2 := metapb.Region{Id: 1, RegionEpoch: &metapb.RegionEpoch{Version: 10, ConfVer: 9}}
   981  
   982  	bo := retry.NewBackofferWithVars(context.Background(), 2000000, nil)
   983  
   984  	_, err := cache.OnRegionEpochNotMatch(bo, &RPCContext{Region: region.VerID()}, []*metapb.Region{&r1})
   985  	s.Nil(err)
   986  	_, err = cache.OnRegionEpochNotMatch(bo, &RPCContext{Region: region.VerID()}, []*metapb.Region{&r2})
   987  	s.Nil(err)
   988  	s.Equal(bo.ErrorsNum(), 2)
   989  }
   990  
   991  func (s *testRegionCacheSuite) TestRegionEpochOnTiFlash() {
   992  	// add store3 as tiflash
   993  	store3 := s.cluster.AllocID()
   994  	peer3 := s.cluster.AllocID()
   995  	s.cluster.UpdateStoreAddr(s.store1, s.storeAddr(s.store1), &metapb.StoreLabel{Key: "engine", Value: "tiflash"})
   996  	s.cluster.AddStore(store3, s.storeAddr(store3))
   997  	s.cluster.AddPeer(s.region1, store3, peer3)
   998  	s.cluster.ChangeLeader(s.region1, peer3)
   999  
  1000  	// pre-load region cache
  1001  	loc1, err := s.cache.LocateKey(s.bo, []byte("a"))
  1002  	s.Nil(err)
  1003  	s.Equal(loc1.Region.id, s.region1)
  1004  	lctx, err := s.cache.GetTiKVRPCContext(s.bo, loc1.Region, kv.ReplicaReadLeader, 0)
  1005  	s.Nil(err)
  1006  	s.Equal(lctx.Peer.Id, peer3)
  1007  
  1008  	// epoch-not-match on tiflash
  1009  	ctxTiFlash, err := s.cache.GetTiFlashRPCContext(s.bo, loc1.Region, true)
  1010  	s.Nil(err)
  1011  	s.Equal(ctxTiFlash.Peer.Id, s.peer1)
  1012  	ctxTiFlash.Peer.Role = metapb.PeerRole_Learner
  1013  	r := ctxTiFlash.Meta
  1014  	reqSend := NewRegionRequestSender(s.cache, nil)
  1015  	regionErr := &errorpb.Error{EpochNotMatch: &errorpb.EpochNotMatch{CurrentRegions: []*metapb.Region{r}}}
  1016  	reqSend.onRegionError(s.bo, ctxTiFlash, nil, regionErr)
  1017  
  1018  	// check leader read should not go to tiflash
  1019  	lctx, err = s.cache.GetTiKVRPCContext(s.bo, loc1.Region, kv.ReplicaReadLeader, 0)
  1020  	s.Nil(err)
  1021  	s.NotEqual(lctx.Peer.Id, s.peer1)
  1022  }
  1023  
  1024  const regionSplitKeyFormat = "t%08d"
  1025  
  1026  func createClusterWithStoresAndRegions(regionCnt, storeCount int) *mocktikv.Cluster {
  1027  	cluster := mocktikv.NewCluster(mocktikv.MustNewMVCCStore())
  1028  	_, _, regionID, _ := mocktikv.BootstrapWithMultiStores(cluster, storeCount)
  1029  	for i := 0; i < regionCnt; i++ {
  1030  		rawKey := []byte(fmt.Sprintf(regionSplitKeyFormat, i))
  1031  		ids := cluster.AllocIDs(4)
  1032  		// Make leaders equally distributed on the 3 stores.
  1033  		storeID := ids[0]
  1034  		peerIDs := ids[1:]
  1035  		leaderPeerID := peerIDs[i%3]
  1036  		cluster.SplitRaw(regionID, storeID, rawKey, peerIDs, leaderPeerID)
  1037  		regionID = ids[0]
  1038  	}
  1039  	return cluster
  1040  }
  1041  
  1042  func loadRegionsToCache(cache *RegionCache, regionCnt int) {
  1043  	for i := 0; i < regionCnt; i++ {
  1044  		rawKey := []byte(fmt.Sprintf(regionSplitKeyFormat, i))
  1045  		cache.LocateKey(retry.NewBackofferWithVars(context.Background(), 1, nil), rawKey)
  1046  	}
  1047  }
  1048  
  1049  func (s *testRegionCacheSuite) TestListRegionIDsInCache() {
  1050  	// ['' - 'm' - 'z']
  1051  	region2 := s.cluster.AllocID()
  1052  	newPeers := s.cluster.AllocIDs(2)
  1053  	s.cluster.Split(s.region1, region2, []byte("m"), newPeers, newPeers[0])
  1054  
  1055  	regionIDs, err := s.cache.ListRegionIDsInKeyRange(s.bo, []byte("a"), []byte("z"))
  1056  	s.Nil(err)
  1057  	s.Equal(regionIDs, []uint64{s.region1, region2})
  1058  	regionIDs, err = s.cache.ListRegionIDsInKeyRange(s.bo, []byte("m"), []byte("z"))
  1059  	s.Nil(err)
  1060  	s.Equal(regionIDs, []uint64{region2})
  1061  
  1062  	regionIDs, err = s.cache.ListRegionIDsInKeyRange(s.bo, []byte("a"), []byte("m"))
  1063  	s.Nil(err)
  1064  	s.Equal(regionIDs, []uint64{s.region1, region2})
  1065  }
  1066  
  1067  func (s *testRegionCacheSuite) TestScanRegions() {
  1068  	// Split at "a", "b", "c", "d"
  1069  	regions := s.cluster.AllocIDs(4)
  1070  	regions = append([]uint64{s.region1}, regions...)
  1071  
  1072  	peers := [][]uint64{{s.peer1, s.peer2}}
  1073  	for i := 0; i < 4; i++ {
  1074  		peers = append(peers, s.cluster.AllocIDs(2))
  1075  	}
  1076  
  1077  	for i := 0; i < 4; i++ {
  1078  		s.cluster.Split(regions[i], regions[i+1], []byte{'a' + byte(i)}, peers[i+1], peers[i+1][0])
  1079  	}
  1080  
  1081  	scannedRegions, err := s.cache.scanRegions(s.bo, []byte(""), nil, 100)
  1082  	s.Nil(err)
  1083  	s.Equal(len(scannedRegions), 5)
  1084  	for i := 0; i < 5; i++ {
  1085  		r := scannedRegions[i]
  1086  		_, p, _, _ := r.WorkStorePeer(r.getStore())
  1087  
  1088  		s.Equal(r.meta.Id, regions[i])
  1089  		s.Equal(p.Id, peers[i][0])
  1090  	}
  1091  
  1092  	scannedRegions, err = s.cache.scanRegions(s.bo, []byte("a"), nil, 3)
  1093  	s.Nil(err)
  1094  	s.Equal(len(scannedRegions), 3)
  1095  	for i := 1; i < 4; i++ {
  1096  		r := scannedRegions[i-1]
  1097  		_, p, _, _ := r.WorkStorePeer(r.getStore())
  1098  
  1099  		s.Equal(r.meta.Id, regions[i])
  1100  		s.Equal(p.Id, peers[i][0])
  1101  	}
  1102  
  1103  	scannedRegions, err = s.cache.scanRegions(s.bo, []byte("a1"), nil, 1)
  1104  	s.Nil(err)
  1105  	s.Equal(len(scannedRegions), 1)
  1106  
  1107  	r0 := scannedRegions[0]
  1108  	_, p0, _, _ := r0.WorkStorePeer(r0.getStore())
  1109  	s.Equal(r0.meta.Id, regions[1])
  1110  	s.Equal(p0.Id, peers[1][0])
  1111  
  1112  	// Test region with no leader
  1113  	s.cluster.GiveUpLeader(regions[1])
  1114  	s.cluster.GiveUpLeader(regions[3])
  1115  	scannedRegions, err = s.cache.scanRegions(s.bo, []byte(""), nil, 5)
  1116  	s.Nil(err)
  1117  	for i := 0; i < 3; i++ {
  1118  		r := scannedRegions[i]
  1119  		_, p, _, _ := r.WorkStorePeer(r.getStore())
  1120  
  1121  		s.Equal(r.meta.Id, regions[i*2])
  1122  		s.Equal(p.Id, peers[i*2][0])
  1123  	}
  1124  }
  1125  
  1126  func (s *testRegionCacheSuite) TestBatchLoadRegions() {
  1127  	// Split at "a", "b", "c", "d"
  1128  	regions := s.cluster.AllocIDs(4)
  1129  	regions = append([]uint64{s.region1}, regions...)
  1130  
  1131  	peers := [][]uint64{{s.peer1, s.peer2}}
  1132  	for i := 0; i < 4; i++ {
  1133  		peers = append(peers, s.cluster.AllocIDs(2))
  1134  	}
  1135  
  1136  	for i := 0; i < 4; i++ {
  1137  		s.cluster.Split(regions[i], regions[i+1], []byte{'a' + byte(i)}, peers[i+1], peers[i+1][0])
  1138  	}
  1139  
  1140  	testCases := []struct {
  1141  		startKey      []byte
  1142  		endKey        []byte
  1143  		limit         int
  1144  		expectKey     []byte
  1145  		expectRegions []uint64
  1146  	}{
  1147  		{[]byte(""), []byte("a"), 1, []byte("a"), []uint64{regions[0]}},
  1148  		{[]byte("a"), []byte("b1"), 2, []byte("c"), []uint64{regions[1], regions[2]}},
  1149  		{[]byte("a1"), []byte("d"), 2, []byte("c"), []uint64{regions[1], regions[2]}},
  1150  		{[]byte("c"), []byte("c1"), 2, nil, []uint64{regions[3]}},
  1151  		{[]byte("d"), nil, 2, nil, []uint64{regions[4]}},
  1152  	}
  1153  
  1154  	for _, tc := range testCases {
  1155  		key, err := s.cache.BatchLoadRegionsFromKey(s.bo, tc.startKey, tc.limit)
  1156  		s.Nil(err)
  1157  		if tc.expectKey != nil {
  1158  			s.Equal(key, tc.expectKey)
  1159  		} else {
  1160  			s.Len(key, 0)
  1161  		}
  1162  		loadRegions, err := s.cache.BatchLoadRegionsWithKeyRange(s.bo, tc.startKey, tc.endKey, tc.limit)
  1163  		s.Nil(err)
  1164  		s.Len(loadRegions, len(tc.expectRegions))
  1165  		for i := range loadRegions {
  1166  			s.Equal(loadRegions[i].GetID(), tc.expectRegions[i])
  1167  		}
  1168  	}
  1169  
  1170  	s.checkCache(len(regions))
  1171  }
  1172  
  1173  func (s *testRegionCacheSuite) TestFollowerReadFallback() {
  1174  	// 3 nodes and no.1 is leader.
  1175  	store3 := s.cluster.AllocID()
  1176  	peer3 := s.cluster.AllocID()
  1177  	s.cluster.AddStore(store3, s.storeAddr(store3))
  1178  	s.cluster.AddPeer(s.region1, store3, peer3)
  1179  	s.cluster.ChangeLeader(s.region1, s.peer1)
  1180  
  1181  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
  1182  	s.Nil(err)
  1183  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
  1184  	s.Nil(err)
  1185  	s.Equal(ctx.Peer.Id, s.peer1)
  1186  	s.Equal(len(ctx.Meta.Peers), 3)
  1187  
  1188  	// verify follower to be store2 and store3
  1189  	ctxFollower1, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, 0)
  1190  	s.Nil(err)
  1191  	s.Equal(ctxFollower1.Peer.Id, s.peer2)
  1192  	ctxFollower2, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, 1)
  1193  	s.Nil(err)
  1194  	s.Equal(ctxFollower2.Peer.Id, peer3)
  1195  	s.NotEqual(ctxFollower1.Peer.Id, ctxFollower2.Peer.Id)
  1196  
  1197  	// send fail on store2, next follower read is going to fallback to store3
  1198  	s.cache.OnSendFail(s.bo, ctxFollower1, false, errors.New("test error"))
  1199  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadFollower, 0)
  1200  	s.Nil(err)
  1201  	s.Equal(ctx.Peer.Id, peer3)
  1202  }
  1203  
  1204  func (s *testRegionCacheSuite) TestMixedReadFallback() {
  1205  	// 3 nodes and no.1 is leader.
  1206  	store3 := s.cluster.AllocID()
  1207  	peer3 := s.cluster.AllocID()
  1208  	s.cluster.AddStore(store3, s.storeAddr(store3))
  1209  	s.cluster.AddPeer(s.region1, store3, peer3)
  1210  	s.cluster.ChangeLeader(s.region1, s.peer1)
  1211  
  1212  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
  1213  	s.Nil(err)
  1214  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
  1215  	s.Nil(err)
  1216  	s.Equal(ctx.Peer.Id, s.peer1)
  1217  	s.Equal(len(ctx.Meta.Peers), 3)
  1218  
  1219  	// verify follower to be store1, store2 and store3
  1220  	ctxFollower1, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadMixed, 0)
  1221  	s.Nil(err)
  1222  	s.Equal(ctxFollower1.Peer.Id, s.peer1)
  1223  
  1224  	ctxFollower2, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadMixed, 1)
  1225  	s.Nil(err)
  1226  	s.Equal(ctxFollower2.Peer.Id, s.peer2)
  1227  
  1228  	ctxFollower3, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadMixed, 2)
  1229  	s.Nil(err)
  1230  	s.Equal(ctxFollower3.Peer.Id, peer3)
  1231  
  1232  	// send fail on store2, next follower read is going to fallback to store3
  1233  	s.cache.OnSendFail(s.bo, ctxFollower1, false, errors.New("test error"))
  1234  	ctx, err = s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadMixed, 0)
  1235  	s.Nil(err)
  1236  	s.Equal(ctx.Peer.Id, s.peer2)
  1237  }
  1238  
  1239  func (s *testRegionCacheSuite) TestPeersLenChange() {
  1240  	// 2 peers [peer1, peer2] and let peer2 become leader
  1241  	loc, err := s.cache.LocateKey(s.bo, []byte("a"))
  1242  	s.Nil(err)
  1243  	s.cache.UpdateLeader(loc.Region, &metapb.Peer{Id: s.peer2, StoreId: s.store2}, 0)
  1244  
  1245  	// current leader is peer2 in [peer1, peer2]
  1246  	loc, err = s.cache.LocateKey(s.bo, []byte("a"))
  1247  	s.Nil(err)
  1248  	ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
  1249  	s.Nil(err)
  1250  	s.Equal(ctx.Peer.StoreId, s.store2)
  1251  
  1252  	// simulate peer1 became down in kv heartbeat and loaded before response back.
  1253  	cpMeta := &metapb.Region{
  1254  		Id:          ctx.Meta.Id,
  1255  		StartKey:    ctx.Meta.StartKey,
  1256  		EndKey:      ctx.Meta.EndKey,
  1257  		RegionEpoch: ctx.Meta.RegionEpoch,
  1258  		Peers:       make([]*metapb.Peer, len(ctx.Meta.Peers)),
  1259  	}
  1260  	copy(cpMeta.Peers, ctx.Meta.Peers)
  1261  	cpRegion := &pd.Region{
  1262  		Meta:      cpMeta,
  1263  		DownPeers: []*metapb.Peer{{Id: s.peer1, StoreId: s.store1}},
  1264  	}
  1265  	filterUnavailablePeers(cpRegion)
  1266  	region := &Region{meta: cpRegion.Meta}
  1267  	err = region.init(s.bo, s.cache)
  1268  	s.Nil(err)
  1269  	s.cache.insertRegionToCache(region)
  1270  
  1271  	// OnSendFail should not panic
  1272  	s.cache.OnSendFail(retry.NewNoopBackoff(context.Background()), ctx, false, errors.New("send fail"))
  1273  }
  1274  
  1275  func createSampleRegion(startKey, endKey []byte) *Region {
  1276  	return &Region{
  1277  		meta: &metapb.Region{
  1278  			StartKey: startKey,
  1279  			EndKey:   endKey,
  1280  		},
  1281  	}
  1282  }
  1283  
  1284  func (s *testRegionCacheSuite) TestContains() {
  1285  	s.True(createSampleRegion(nil, nil).Contains([]byte{}))
  1286  	s.True(createSampleRegion(nil, nil).Contains([]byte{10}))
  1287  	s.False(createSampleRegion([]byte{10}, nil).Contains([]byte{}))
  1288  	s.False(createSampleRegion([]byte{10}, nil).Contains([]byte{9}))
  1289  	s.True(createSampleRegion([]byte{10}, nil).Contains([]byte{10}))
  1290  	s.True(createSampleRegion(nil, []byte{10}).Contains([]byte{}))
  1291  	s.True(createSampleRegion(nil, []byte{10}).Contains([]byte{9}))
  1292  	s.False(createSampleRegion(nil, []byte{10}).Contains([]byte{10}))
  1293  	s.False(createSampleRegion([]byte{10}, []byte{20}).Contains([]byte{}))
  1294  	s.True(createSampleRegion([]byte{10}, []byte{20}).Contains([]byte{15}))
  1295  	s.False(createSampleRegion([]byte{10}, []byte{20}).Contains([]byte{30}))
  1296  }
  1297  
  1298  func (s *testRegionCacheSuite) TestContainsByEnd() {
  1299  	s.False(createSampleRegion(nil, nil).ContainsByEnd([]byte{}))
  1300  	s.True(createSampleRegion(nil, nil).ContainsByEnd([]byte{10}))
  1301  	s.False(createSampleRegion([]byte{10}, nil).ContainsByEnd([]byte{}))
  1302  	s.False(createSampleRegion([]byte{10}, nil).ContainsByEnd([]byte{10}))
  1303  	s.True(createSampleRegion([]byte{10}, nil).ContainsByEnd([]byte{11}))
  1304  	s.False(createSampleRegion(nil, []byte{10}).ContainsByEnd([]byte{}))
  1305  	s.True(createSampleRegion(nil, []byte{10}).ContainsByEnd([]byte{10}))
  1306  	s.False(createSampleRegion(nil, []byte{10}).ContainsByEnd([]byte{11}))
  1307  	s.False(createSampleRegion([]byte{10}, []byte{20}).ContainsByEnd([]byte{}))
  1308  	s.True(createSampleRegion([]byte{10}, []byte{20}).ContainsByEnd([]byte{15}))
  1309  	s.False(createSampleRegion([]byte{10}, []byte{20}).ContainsByEnd([]byte{30}))
  1310  }
  1311  
  1312  func (s *testRegionCacheSuite) TestSwitchPeerWhenNoLeader() {
  1313  	var prevCtx *RPCContext
  1314  	for i := 0; i <= len(s.cluster.GetAllStores()); i++ {
  1315  		loc, err := s.cache.LocateKey(s.bo, []byte("a"))
  1316  		s.Nil(err)
  1317  		ctx, err := s.cache.GetTiKVRPCContext(s.bo, loc.Region, kv.ReplicaReadLeader, 0)
  1318  		s.Nil(err)
  1319  		if prevCtx == nil {
  1320  			s.Equal(i, 0)
  1321  		} else {
  1322  			s.NotEqual(ctx.AccessIdx, prevCtx.AccessIdx)
  1323  			s.NotEqual(ctx.Peer, prevCtx.Peer)
  1324  		}
  1325  		s.cache.InvalidateCachedRegionWithReason(loc.Region, NoLeader)
  1326  		s.Equal(s.cache.GetCachedRegionWithRLock(loc.Region).invalidReason, NoLeader)
  1327  		prevCtx = ctx
  1328  	}
  1329  }
  1330  
  1331  func BenchmarkOnRequestFail(b *testing.B) {
  1332  	/*
  1333  			This benchmark simulate many concurrent requests call OnSendRequestFail method
  1334  			after failed on a store, validate that on this scene, requests don't get blocked on the
  1335  		    RegionCache lock.
  1336  	*/
  1337  	regionCnt, storeCount := 998, 3
  1338  	cluster := createClusterWithStoresAndRegions(regionCnt, storeCount)
  1339  	cache := NewRegionCache(mocktikv.NewPDClient(cluster))
  1340  	defer cache.Close()
  1341  	loadRegionsToCache(cache, regionCnt)
  1342  	bo := retry.NewBackofferWithVars(context.Background(), 1, nil)
  1343  	loc, err := cache.LocateKey(bo, []byte{})
  1344  	if err != nil {
  1345  		b.Fatal(err)
  1346  	}
  1347  	region := cache.getRegionByIDFromCache(loc.Region.id)
  1348  	b.ResetTimer()
  1349  	regionStore := region.getStore()
  1350  	store, peer, accessIdx, _ := region.WorkStorePeer(regionStore)
  1351  	b.RunParallel(func(pb *testing.PB) {
  1352  		for pb.Next() {
  1353  			rpcCtx := &RPCContext{
  1354  				Region:     loc.Region,
  1355  				Meta:       region.meta,
  1356  				AccessIdx:  accessIdx,
  1357  				Peer:       peer,
  1358  				Store:      store,
  1359  				AccessMode: tiKVOnly,
  1360  			}
  1361  			r := cache.GetCachedRegionWithRLock(rpcCtx.Region)
  1362  			if r != nil {
  1363  				r.getStore().switchNextTiKVPeer(r, rpcCtx.AccessIdx)
  1364  			}
  1365  		}
  1366  	})
  1367  	if len(cache.mu.regions) != regionCnt*2/3 {
  1368  		b.Fatal(len(cache.mu.regions))
  1369  	}
  1370  }
  1371  
  1372  func (s *testRegionCacheSuite) TestNoBackoffWhenFailToDecodeRegion() {
  1373  	region2 := s.cluster.AllocID()
  1374  	newPeers := s.cluster.AllocIDs(2)
  1375  	k := []byte("k")
  1376  	// Use SplitRaw to split a region with non-memcomparable range keys.
  1377  	s.cluster.SplitRaw(s.region1, region2, k, newPeers, newPeers[0])
  1378  	_, err := s.cache.LocateKey(s.bo, k)
  1379  	s.NotNil(err)
  1380  	s.Equal(0, s.bo.GetTotalBackoffTimes())
  1381  	_, err = s.cache.LocateRegionByID(s.bo, region2)
  1382  	s.NotNil(err)
  1383  	s.Equal(0, s.bo.GetTotalBackoffTimes())
  1384  	_, err = s.cache.scanRegions(s.bo, []byte{}, []byte{}, 10)
  1385  	s.NotNil(err)
  1386  	s.Equal(0, s.bo.GetTotalBackoffTimes())
  1387  }