github.com/KinWaiYuen/client-go/v2@v2.5.4/internal/locate/region_request_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_request_test.go
    19  //
    20  
    21  // Copyright 2017 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  	"fmt"
    40  	"net"
    41  	"sync"
    42  	"testing"
    43  	"time"
    44  	"unsafe"
    45  
    46  	"github.com/KinWaiYuen/client-go/v2/internal/client"
    47  	"github.com/KinWaiYuen/client-go/v2/internal/mockstore/mocktikv"
    48  	"github.com/KinWaiYuen/client-go/v2/internal/retry"
    49  	"github.com/KinWaiYuen/client-go/v2/tikvrpc"
    50  	"github.com/pingcap/errors"
    51  	"github.com/pingcap/kvproto/pkg/coprocessor"
    52  	"github.com/pingcap/kvproto/pkg/errorpb"
    53  	"github.com/pingcap/kvproto/pkg/kvrpcpb"
    54  	"github.com/pingcap/kvproto/pkg/metapb"
    55  	"github.com/pingcap/kvproto/pkg/mpp"
    56  	"github.com/pingcap/kvproto/pkg/tikvpb"
    57  	"github.com/stretchr/testify/suite"
    58  	"google.golang.org/grpc"
    59  )
    60  
    61  func TestRegionRequestToSingleStore(t *testing.T) {
    62  	suite.Run(t, new(testRegionRequestToSingleStoreSuite))
    63  }
    64  
    65  type testRegionRequestToSingleStoreSuite struct {
    66  	suite.Suite
    67  	cluster             *mocktikv.Cluster
    68  	store               uint64
    69  	peer                uint64
    70  	region              uint64
    71  	cache               *RegionCache
    72  	bo                  *retry.Backoffer
    73  	regionRequestSender *RegionRequestSender
    74  	mvccStore           mocktikv.MVCCStore
    75  }
    76  
    77  func (s *testRegionRequestToSingleStoreSuite) SetupTest() {
    78  	s.mvccStore = mocktikv.MustNewMVCCStore()
    79  	s.cluster = mocktikv.NewCluster(s.mvccStore)
    80  	s.store, s.peer, s.region = mocktikv.BootstrapWithSingleStore(s.cluster)
    81  	pdCli := &CodecPDClient{mocktikv.NewPDClient(s.cluster)}
    82  	s.cache = NewRegionCache(pdCli)
    83  	s.bo = retry.NewNoopBackoff(context.Background())
    84  	client := mocktikv.NewRPCClient(s.cluster, s.mvccStore, nil)
    85  	s.regionRequestSender = NewRegionRequestSender(s.cache, client)
    86  }
    87  
    88  func (s *testRegionRequestToSingleStoreSuite) TearDownTest() {
    89  	s.cache.Close()
    90  	s.mvccStore.Close()
    91  }
    92  
    93  type fnClient struct {
    94  	fn func(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (*tikvrpc.Response, error)
    95  }
    96  
    97  func (f *fnClient) Close() error {
    98  	return nil
    99  }
   100  
   101  func (f *fnClient) SendRequest(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (*tikvrpc.Response, error) {
   102  	return f.fn(ctx, addr, req, timeout)
   103  }
   104  
   105  func (s *testRegionRequestToSingleStoreSuite) TestOnRegionError() {
   106  	req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{
   107  		Key:   []byte("key"),
   108  		Value: []byte("value"),
   109  	})
   110  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   111  	s.Nil(err)
   112  	s.NotNil(region)
   113  
   114  	// test stale command retry.
   115  	func() {
   116  		oc := s.regionRequestSender.client
   117  		defer func() {
   118  			s.regionRequestSender.client = oc
   119  		}()
   120  		s.regionRequestSender.client = &fnClient{func(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (response *tikvrpc.Response, err error) {
   121  			staleResp := &tikvrpc.Response{Resp: &kvrpcpb.GetResponse{
   122  				RegionError: &errorpb.Error{StaleCommand: &errorpb.StaleCommand{}},
   123  			}}
   124  			return staleResp, nil
   125  		}}
   126  		bo := retry.NewBackofferWithVars(context.Background(), 5, nil)
   127  		resp, err := s.regionRequestSender.SendReq(bo, req, region.Region, time.Second)
   128  		s.Nil(err)
   129  		s.NotNil(resp)
   130  		regionErr, _ := resp.GetRegionError()
   131  		s.NotNil(regionErr)
   132  	}()
   133  }
   134  
   135  func (s *testRegionRequestToSingleStoreSuite) TestOnSendFailedWithStoreRestart() {
   136  	req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{
   137  		Key:   []byte("key"),
   138  		Value: []byte("value"),
   139  	})
   140  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   141  	s.Nil(err)
   142  	s.NotNil(region)
   143  	resp, err := s.regionRequestSender.SendReq(s.bo, req, region.Region, time.Second)
   144  	s.Nil(err)
   145  	s.NotNil(resp.Resp)
   146  	s.Nil(s.regionRequestSender.rpcError)
   147  
   148  	// stop store.
   149  	s.cluster.StopStore(s.store)
   150  	_, err = s.regionRequestSender.SendReq(s.bo, req, region.Region, time.Second)
   151  	s.NotNil(err)
   152  	// The RPC error shouldn't be nil since it failed to sent the request.
   153  	s.NotNil(s.regionRequestSender.rpcError)
   154  
   155  	// start store.
   156  	s.cluster.StartStore(s.store)
   157  
   158  	// locate region again is needed
   159  	// since last request on the region failed and region's info had been cleared.
   160  	region, err = s.cache.LocateRegionByID(s.bo, s.region)
   161  	s.Nil(err)
   162  	s.NotNil(region)
   163  	s.NotNil(s.regionRequestSender.rpcError)
   164  	resp, err = s.regionRequestSender.SendReq(s.bo, req, region.Region, time.Second)
   165  	s.Nil(err)
   166  	s.NotNil(resp.Resp)
   167  }
   168  
   169  func (s *testRegionRequestToSingleStoreSuite) TestOnSendFailedWithCloseKnownStoreThenUseNewOne() {
   170  	req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{
   171  		Key:   []byte("key"),
   172  		Value: []byte("value"),
   173  	})
   174  
   175  	// add new store2 and make store2 as leader.
   176  	store2 := s.cluster.AllocID()
   177  	peer2 := s.cluster.AllocID()
   178  	s.cluster.AddStore(store2, fmt.Sprintf("store%d", store2))
   179  	s.cluster.AddPeer(s.region, store2, peer2)
   180  	s.cluster.ChangeLeader(s.region, peer2)
   181  
   182  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   183  	s.Nil(err)
   184  	s.NotNil(region)
   185  	resp, err := s.regionRequestSender.SendReq(s.bo, req, region.Region, time.Second)
   186  	s.Nil(err)
   187  	s.NotNil(resp.Resp)
   188  
   189  	// stop store2 and make store1 as new leader.
   190  	s.cluster.StopStore(store2)
   191  	s.cluster.ChangeLeader(s.region, s.peer)
   192  
   193  	// send to store2 fail and send to new leader store1.
   194  	bo2 := retry.NewBackofferWithVars(context.Background(), 100, nil)
   195  	resp, err = s.regionRequestSender.SendReq(bo2, req, region.Region, time.Second)
   196  	s.Nil(err)
   197  	regionErr, err := resp.GetRegionError()
   198  	s.Nil(err)
   199  	s.Nil(regionErr)
   200  	s.NotNil(resp.Resp)
   201  }
   202  
   203  func (s *testRegionRequestToSingleStoreSuite) TestSendReqCtx() {
   204  	req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{
   205  		Key:   []byte("key"),
   206  		Value: []byte("value"),
   207  	})
   208  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   209  	s.Nil(err)
   210  	s.NotNil(region)
   211  	resp, ctx, err := s.regionRequestSender.SendReqCtx(s.bo, req, region.Region, time.Second, tikvrpc.TiKV)
   212  	s.Nil(err)
   213  	s.NotNil(resp.Resp)
   214  	s.NotNil(ctx)
   215  	req.ReplicaRead = true
   216  	resp, ctx, err = s.regionRequestSender.SendReqCtx(s.bo, req, region.Region, time.Second, tikvrpc.TiKV)
   217  	s.Nil(err)
   218  	s.NotNil(resp.Resp)
   219  	s.NotNil(ctx)
   220  }
   221  
   222  func (s *testRegionRequestToSingleStoreSuite) TestOnSendFailedWithCancelled() {
   223  	req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{
   224  		Key:   []byte("key"),
   225  		Value: []byte("value"),
   226  	})
   227  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   228  	s.Nil(err)
   229  	s.NotNil(region)
   230  	resp, err := s.regionRequestSender.SendReq(s.bo, req, region.Region, time.Second)
   231  	s.Nil(err)
   232  	s.NotNil(resp.Resp)
   233  
   234  	// set store to cancel state.
   235  	s.cluster.CancelStore(s.store)
   236  	// locate region again is needed
   237  	// since last request on the region failed and region's info had been cleared.
   238  	_, err = s.regionRequestSender.SendReq(s.bo, req, region.Region, time.Second)
   239  	s.NotNil(err)
   240  	s.Equal(errors.Cause(err), context.Canceled)
   241  
   242  	// set store to normal state.
   243  	s.cluster.UnCancelStore(s.store)
   244  	region, err = s.cache.LocateRegionByID(s.bo, s.region)
   245  	s.Nil(err)
   246  	s.NotNil(region)
   247  	resp, err = s.regionRequestSender.SendReq(s.bo, req, region.Region, time.Second)
   248  	s.Nil(err)
   249  	s.NotNil(resp.Resp)
   250  }
   251  
   252  func (s *testRegionRequestToSingleStoreSuite) TestNoReloadRegionWhenCtxCanceled() {
   253  	req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{
   254  		Key:   []byte("key"),
   255  		Value: []byte("value"),
   256  	})
   257  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   258  	s.Nil(err)
   259  	s.NotNil(region)
   260  
   261  	sender := s.regionRequestSender
   262  	bo, cancel := s.bo.Fork()
   263  	cancel()
   264  	// Call SendKVReq with a canceled context.
   265  	_, err = sender.SendReq(bo, req, region.Region, time.Second)
   266  	// Check this kind of error won't cause region cache drop.
   267  	s.Equal(errors.Cause(err), context.Canceled)
   268  	s.NotNil(sender.regionCache.getRegionByIDFromCache(s.region))
   269  }
   270  
   271  // cancelContextClient wraps rpcClient and always cancels context before sending requests.
   272  type cancelContextClient struct {
   273  	client.Client
   274  	redirectAddr string
   275  }
   276  
   277  func (c *cancelContextClient) SendRequest(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (*tikvrpc.Response, error) {
   278  	childCtx, cancel := context.WithCancel(ctx)
   279  	cancel()
   280  	return c.Client.SendRequest(childCtx, c.redirectAddr, req, timeout)
   281  }
   282  
   283  // mockTikvGrpcServer mock a tikv gprc server for testing.
   284  type mockTikvGrpcServer struct{}
   285  
   286  // KvGet commands with mvcc/txn supported.
   287  func (s *mockTikvGrpcServer) KvGet(context.Context, *kvrpcpb.GetRequest) (*kvrpcpb.GetResponse, error) {
   288  	return nil, errors.New("unreachable")
   289  }
   290  func (s *mockTikvGrpcServer) KvScan(context.Context, *kvrpcpb.ScanRequest) (*kvrpcpb.ScanResponse, error) {
   291  	return nil, errors.New("unreachable")
   292  }
   293  func (s *mockTikvGrpcServer) KvPrewrite(context.Context, *kvrpcpb.PrewriteRequest) (*kvrpcpb.PrewriteResponse, error) {
   294  	return nil, errors.New("unreachable")
   295  }
   296  func (s *mockTikvGrpcServer) KvCommit(context.Context, *kvrpcpb.CommitRequest) (*kvrpcpb.CommitResponse, error) {
   297  	return nil, errors.New("unreachable")
   298  }
   299  func (s *mockTikvGrpcServer) KvImport(context.Context, *kvrpcpb.ImportRequest) (*kvrpcpb.ImportResponse, error) {
   300  	return nil, errors.New("unreachable")
   301  }
   302  func (s *mockTikvGrpcServer) KvCleanup(context.Context, *kvrpcpb.CleanupRequest) (*kvrpcpb.CleanupResponse, error) {
   303  	return nil, errors.New("unreachable")
   304  }
   305  func (s *mockTikvGrpcServer) KvBatchGet(context.Context, *kvrpcpb.BatchGetRequest) (*kvrpcpb.BatchGetResponse, error) {
   306  	return nil, errors.New("unreachable")
   307  }
   308  func (s *mockTikvGrpcServer) KvBatchRollback(context.Context, *kvrpcpb.BatchRollbackRequest) (*kvrpcpb.BatchRollbackResponse, error) {
   309  	return nil, errors.New("unreachable")
   310  }
   311  func (s *mockTikvGrpcServer) KvScanLock(context.Context, *kvrpcpb.ScanLockRequest) (*kvrpcpb.ScanLockResponse, error) {
   312  	return nil, errors.New("unreachable")
   313  }
   314  func (s *mockTikvGrpcServer) KvResolveLock(context.Context, *kvrpcpb.ResolveLockRequest) (*kvrpcpb.ResolveLockResponse, error) {
   315  	return nil, errors.New("unreachable")
   316  }
   317  func (s *mockTikvGrpcServer) KvPessimisticLock(context.Context, *kvrpcpb.PessimisticLockRequest) (*kvrpcpb.PessimisticLockResponse, error) {
   318  	return nil, errors.New("unreachable")
   319  }
   320  func (s *mockTikvGrpcServer) KVPessimisticRollback(context.Context, *kvrpcpb.PessimisticRollbackRequest) (*kvrpcpb.PessimisticRollbackResponse, error) {
   321  	return nil, errors.New("unreachable")
   322  }
   323  func (s *mockTikvGrpcServer) KvCheckTxnStatus(ctx context.Context, in *kvrpcpb.CheckTxnStatusRequest) (*kvrpcpb.CheckTxnStatusResponse, error) {
   324  	return nil, errors.New("unreachable")
   325  }
   326  func (s *mockTikvGrpcServer) KvCheckSecondaryLocks(ctx context.Context, in *kvrpcpb.CheckSecondaryLocksRequest) (*kvrpcpb.CheckSecondaryLocksResponse, error) {
   327  	return nil, errors.New("unreachable")
   328  }
   329  func (s *mockTikvGrpcServer) KvTxnHeartBeat(ctx context.Context, in *kvrpcpb.TxnHeartBeatRequest) (*kvrpcpb.TxnHeartBeatResponse, error) {
   330  	return nil, errors.New("unreachable")
   331  }
   332  func (s *mockTikvGrpcServer) KvGC(context.Context, *kvrpcpb.GCRequest) (*kvrpcpb.GCResponse, error) {
   333  	return nil, errors.New("unreachable")
   334  }
   335  func (s *mockTikvGrpcServer) KvDeleteRange(context.Context, *kvrpcpb.DeleteRangeRequest) (*kvrpcpb.DeleteRangeResponse, error) {
   336  	return nil, errors.New("unreachable")
   337  }
   338  func (s *mockTikvGrpcServer) RawGet(context.Context, *kvrpcpb.RawGetRequest) (*kvrpcpb.RawGetResponse, error) {
   339  	return nil, errors.New("unreachable")
   340  }
   341  func (s *mockTikvGrpcServer) RawBatchGet(context.Context, *kvrpcpb.RawBatchGetRequest) (*kvrpcpb.RawBatchGetResponse, error) {
   342  	return nil, errors.New("unreachable")
   343  }
   344  func (s *mockTikvGrpcServer) RawPut(context.Context, *kvrpcpb.RawPutRequest) (*kvrpcpb.RawPutResponse, error) {
   345  	return nil, errors.New("unreachable")
   346  }
   347  func (s *mockTikvGrpcServer) RawBatchPut(context.Context, *kvrpcpb.RawBatchPutRequest) (*kvrpcpb.RawBatchPutResponse, error) {
   348  	return nil, errors.New("unreachable")
   349  }
   350  func (s *mockTikvGrpcServer) RawDelete(context.Context, *kvrpcpb.RawDeleteRequest) (*kvrpcpb.RawDeleteResponse, error) {
   351  	return nil, errors.New("unreachable")
   352  }
   353  func (s *mockTikvGrpcServer) RawBatchDelete(context.Context, *kvrpcpb.RawBatchDeleteRequest) (*kvrpcpb.RawBatchDeleteResponse, error) {
   354  	return nil, errors.New("unreachable")
   355  }
   356  func (s *mockTikvGrpcServer) RawScan(context.Context, *kvrpcpb.RawScanRequest) (*kvrpcpb.RawScanResponse, error) {
   357  	return nil, errors.New("unreachable")
   358  }
   359  func (s *mockTikvGrpcServer) RawDeleteRange(context.Context, *kvrpcpb.RawDeleteRangeRequest) (*kvrpcpb.RawDeleteRangeResponse, error) {
   360  	return nil, errors.New("unreachable")
   361  }
   362  func (s *mockTikvGrpcServer) RawBatchScan(context.Context, *kvrpcpb.RawBatchScanRequest) (*kvrpcpb.RawBatchScanResponse, error) {
   363  	return nil, errors.New("unreachable")
   364  }
   365  func (s *mockTikvGrpcServer) RawGetKeyTTL(context.Context, *kvrpcpb.RawGetKeyTTLRequest) (*kvrpcpb.RawGetKeyTTLResponse, error) {
   366  	return nil, errors.New("unreachable")
   367  }
   368  func (s *mockTikvGrpcServer) UnsafeDestroyRange(context.Context, *kvrpcpb.UnsafeDestroyRangeRequest) (*kvrpcpb.UnsafeDestroyRangeResponse, error) {
   369  	return nil, errors.New("unreachable")
   370  }
   371  func (s *mockTikvGrpcServer) RegisterLockObserver(context.Context, *kvrpcpb.RegisterLockObserverRequest) (*kvrpcpb.RegisterLockObserverResponse, error) {
   372  	return nil, errors.New("unreachable")
   373  }
   374  func (s *mockTikvGrpcServer) CheckLockObserver(context.Context, *kvrpcpb.CheckLockObserverRequest) (*kvrpcpb.CheckLockObserverResponse, error) {
   375  	return nil, errors.New("unreachable")
   376  }
   377  func (s *mockTikvGrpcServer) RemoveLockObserver(context.Context, *kvrpcpb.RemoveLockObserverRequest) (*kvrpcpb.RemoveLockObserverResponse, error) {
   378  	return nil, errors.New("unreachable")
   379  }
   380  func (s *mockTikvGrpcServer) PhysicalScanLock(context.Context, *kvrpcpb.PhysicalScanLockRequest) (*kvrpcpb.PhysicalScanLockResponse, error) {
   381  	return nil, errors.New("unreachable")
   382  }
   383  func (s *mockTikvGrpcServer) Coprocessor(context.Context, *coprocessor.Request) (*coprocessor.Response, error) {
   384  	return nil, errors.New("unreachable")
   385  }
   386  func (s *mockTikvGrpcServer) BatchCoprocessor(*coprocessor.BatchRequest, tikvpb.Tikv_BatchCoprocessorServer) error {
   387  	return errors.New("unreachable")
   388  }
   389  func (s *mockTikvGrpcServer) RawCoprocessor(context.Context, *kvrpcpb.RawCoprocessorRequest) (*kvrpcpb.RawCoprocessorResponse, error) {
   390  	return nil, errors.New("unreachable")
   391  }
   392  func (s *mockTikvGrpcServer) DispatchMPPTask(context.Context, *mpp.DispatchTaskRequest) (*mpp.DispatchTaskResponse, error) {
   393  	return nil, errors.New("unreachable")
   394  }
   395  
   396  func (s *mockTikvGrpcServer) IsAlive(context.Context, *mpp.IsAliveRequest) (*mpp.IsAliveResponse, error) {
   397  	return nil, errors.New("unreachable")
   398  }
   399  
   400  func (s *mockTikvGrpcServer) EstablishMPPConnection(*mpp.EstablishMPPConnectionRequest, tikvpb.Tikv_EstablishMPPConnectionServer) error {
   401  	return errors.New("unreachable")
   402  }
   403  func (s *mockTikvGrpcServer) CancelMPPTask(context.Context, *mpp.CancelTaskRequest) (*mpp.CancelTaskResponse, error) {
   404  	return nil, errors.New("unreachable")
   405  }
   406  func (s *mockTikvGrpcServer) Raft(tikvpb.Tikv_RaftServer) error {
   407  	return errors.New("unreachable")
   408  }
   409  func (s *mockTikvGrpcServer) BatchRaft(tikvpb.Tikv_BatchRaftServer) error {
   410  	return errors.New("unreachable")
   411  }
   412  func (s *mockTikvGrpcServer) Snapshot(tikvpb.Tikv_SnapshotServer) error {
   413  	return errors.New("unreachable")
   414  }
   415  func (s *mockTikvGrpcServer) MvccGetByKey(context.Context, *kvrpcpb.MvccGetByKeyRequest) (*kvrpcpb.MvccGetByKeyResponse, error) {
   416  	return nil, errors.New("unreachable")
   417  }
   418  func (s *mockTikvGrpcServer) MvccGetByStartTs(context.Context, *kvrpcpb.MvccGetByStartTsRequest) (*kvrpcpb.MvccGetByStartTsResponse, error) {
   419  	return nil, errors.New("unreachable")
   420  }
   421  func (s *mockTikvGrpcServer) SplitRegion(context.Context, *kvrpcpb.SplitRegionRequest) (*kvrpcpb.SplitRegionResponse, error) {
   422  	return nil, errors.New("unreachable")
   423  }
   424  
   425  func (s *mockTikvGrpcServer) CoprocessorStream(*coprocessor.Request, tikvpb.Tikv_CoprocessorStreamServer) error {
   426  	return errors.New("unreachable")
   427  }
   428  
   429  func (s *mockTikvGrpcServer) BatchCommands(tikvpb.Tikv_BatchCommandsServer) error {
   430  	return errors.New("unreachable")
   431  }
   432  
   433  func (s *mockTikvGrpcServer) ReadIndex(context.Context, *kvrpcpb.ReadIndexRequest) (*kvrpcpb.ReadIndexResponse, error) {
   434  	return nil, errors.New("unreachable")
   435  }
   436  
   437  func (s *mockTikvGrpcServer) CheckLeader(context.Context, *kvrpcpb.CheckLeaderRequest) (*kvrpcpb.CheckLeaderResponse, error) {
   438  	return nil, errors.New("unreachable")
   439  }
   440  
   441  func (s *mockTikvGrpcServer) GetStoreSafeTS(context.Context, *kvrpcpb.StoreSafeTSRequest) (*kvrpcpb.StoreSafeTSResponse, error) {
   442  	return nil, errors.New("unreachable")
   443  }
   444  
   445  func (s *mockTikvGrpcServer) RawCompareAndSwap(context.Context, *kvrpcpb.RawCASRequest) (*kvrpcpb.RawCASResponse, error) {
   446  	return nil, errors.New("unreachable")
   447  }
   448  
   449  func (s *mockTikvGrpcServer) GetLockWaitInfo(context.Context, *kvrpcpb.GetLockWaitInfoRequest) (*kvrpcpb.GetLockWaitInfoResponse, error) {
   450  	return nil, errors.New("unreachable")
   451  }
   452  
   453  func (s *mockTikvGrpcServer) RawChecksum(context.Context, *kvrpcpb.RawChecksumRequest) (*kvrpcpb.RawChecksumResponse, error) {
   454  	return nil, errors.New("unreachable")
   455  }
   456  
   457  func (s *testRegionRequestToSingleStoreSuite) TestNoReloadRegionForGrpcWhenCtxCanceled() {
   458  	// prepare a mock tikv grpc server
   459  	addr := "localhost:56341"
   460  	lis, err := net.Listen("tcp", addr)
   461  	s.Nil(err)
   462  	server := grpc.NewServer()
   463  	tikvpb.RegisterTikvServer(server, &mockTikvGrpcServer{})
   464  	wg := &sync.WaitGroup{}
   465  	wg.Add(1)
   466  	go func() {
   467  		server.Serve(lis)
   468  		wg.Done()
   469  	}()
   470  
   471  	cli := client.NewRPCClient()
   472  	sender := NewRegionRequestSender(s.cache, cli)
   473  	req := tikvrpc.NewRequest(tikvrpc.CmdRawPut, &kvrpcpb.RawPutRequest{
   474  		Key:   []byte("key"),
   475  		Value: []byte("value"),
   476  	})
   477  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   478  	s.Nil(err)
   479  
   480  	bo, cancel := s.bo.Fork()
   481  	cancel()
   482  	_, err = sender.SendReq(bo, req, region.Region, 3*time.Second)
   483  	s.Equal(errors.Cause(err), context.Canceled)
   484  	s.NotNil(s.cache.getRegionByIDFromCache(s.region))
   485  
   486  	// Just for covering error code = codes.Canceled.
   487  	client1 := &cancelContextClient{
   488  		Client:       client.NewRPCClient(),
   489  		redirectAddr: addr,
   490  	}
   491  	sender = NewRegionRequestSender(s.cache, client1)
   492  	sender.SendReq(s.bo, req, region.Region, 3*time.Second)
   493  
   494  	// cleanup
   495  	server.Stop()
   496  	wg.Wait()
   497  	cli.Close()
   498  	client1.Close()
   499  }
   500  
   501  func (s *testRegionRequestToSingleStoreSuite) TestOnMaxTimestampNotSyncedError() {
   502  	req := tikvrpc.NewRequest(tikvrpc.CmdPrewrite, &kvrpcpb.PrewriteRequest{})
   503  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   504  	s.Nil(err)
   505  	s.NotNil(region)
   506  
   507  	// test retry for max timestamp not synced
   508  	func() {
   509  		oc := s.regionRequestSender.client
   510  		defer func() {
   511  			s.regionRequestSender.client = oc
   512  		}()
   513  		count := 0
   514  		s.regionRequestSender.client = &fnClient{func(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (response *tikvrpc.Response, err error) {
   515  			count++
   516  			var resp *tikvrpc.Response
   517  			if count < 3 {
   518  				resp = &tikvrpc.Response{Resp: &kvrpcpb.PrewriteResponse{
   519  					RegionError: &errorpb.Error{MaxTimestampNotSynced: &errorpb.MaxTimestampNotSynced{}},
   520  				}}
   521  			} else {
   522  				resp = &tikvrpc.Response{Resp: &kvrpcpb.PrewriteResponse{}}
   523  			}
   524  			return resp, nil
   525  		}}
   526  		bo := retry.NewBackofferWithVars(context.Background(), 5, nil)
   527  		resp, err := s.regionRequestSender.SendReq(bo, req, region.Region, time.Second)
   528  		s.Nil(err)
   529  		s.NotNil(resp)
   530  	}()
   531  }
   532  
   533  func (s *testRegionRequestToSingleStoreSuite) TestGetRegionByIDFromCache() {
   534  	region, err := s.cache.LocateRegionByID(s.bo, s.region)
   535  	s.Nil(err)
   536  	s.NotNil(region)
   537  
   538  	// test kv epochNotMatch return empty regions
   539  	s.cache.OnRegionEpochNotMatch(s.bo, &RPCContext{Region: region.Region, Store: &Store{storeID: s.store}}, []*metapb.Region{})
   540  	s.Nil(err)
   541  	r := s.cache.getRegionByIDFromCache(s.region)
   542  	s.Nil(r)
   543  
   544  	// refill cache
   545  	region, err = s.cache.LocateRegionByID(s.bo, s.region)
   546  	s.Nil(err)
   547  	s.NotNil(region)
   548  
   549  	// test kv load new region with new start-key and new epoch
   550  	v2 := region.Region.confVer + 1
   551  	r2 := metapb.Region{Id: region.Region.id, RegionEpoch: &metapb.RegionEpoch{Version: region.Region.ver, ConfVer: v2}, StartKey: []byte{1}}
   552  	st := &Store{storeID: s.store}
   553  	s.cache.insertRegionToCache(&Region{meta: &r2, store: unsafe.Pointer(st), lastAccess: time.Now().Unix()})
   554  	region, err = s.cache.LocateRegionByID(s.bo, s.region)
   555  	s.Nil(err)
   556  	s.NotNil(region)
   557  	s.Equal(region.Region.confVer, v2)
   558  	s.Equal(region.Region.ver, region.Region.ver)
   559  
   560  	v3 := region.Region.confVer + 1
   561  	r3 := metapb.Region{Id: region.Region.id, RegionEpoch: &metapb.RegionEpoch{Version: v3, ConfVer: region.Region.confVer}, StartKey: []byte{2}}
   562  	st = &Store{storeID: s.store}
   563  	s.cache.insertRegionToCache(&Region{meta: &r3, store: unsafe.Pointer(st), lastAccess: time.Now().Unix()})
   564  	region, err = s.cache.LocateRegionByID(s.bo, s.region)
   565  	s.Nil(err)
   566  	s.NotNil(region)
   567  	s.Equal(region.Region.confVer, region.Region.confVer)
   568  	s.Equal(region.Region.ver, v3)
   569  }