github.com/KinWaiYuen/client-go/v2@v2.5.4/tikvrpc/tikvrpc.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/tikvrpc/tikvrpc.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 tikvrpc
    36  
    37  import (
    38  	"context"
    39  	"fmt"
    40  	"sync/atomic"
    41  	"time"
    42  
    43  	"github.com/KinWaiYuen/client-go/v2/kv"
    44  	"github.com/KinWaiYuen/client-go/v2/oracle"
    45  	"github.com/pingcap/errors"
    46  	"github.com/pingcap/kvproto/pkg/coprocessor"
    47  	"github.com/pingcap/kvproto/pkg/debugpb"
    48  	"github.com/pingcap/kvproto/pkg/errorpb"
    49  	"github.com/pingcap/kvproto/pkg/kvrpcpb"
    50  	"github.com/pingcap/kvproto/pkg/metapb"
    51  	"github.com/pingcap/kvproto/pkg/mpp"
    52  	"github.com/pingcap/kvproto/pkg/tikvpb"
    53  )
    54  
    55  // CmdType represents the concrete request type in Request or response type in Response.
    56  type CmdType uint16
    57  
    58  // CmdType values.
    59  const (
    60  	CmdGet CmdType = 1 + iota
    61  	CmdScan
    62  	CmdPrewrite
    63  	CmdCommit
    64  	CmdCleanup
    65  	CmdBatchGet
    66  	CmdBatchRollback
    67  	CmdScanLock
    68  	CmdResolveLock
    69  	CmdGC
    70  	CmdDeleteRange
    71  	CmdPessimisticLock
    72  	CmdPessimisticRollback
    73  	CmdTxnHeartBeat
    74  	CmdCheckTxnStatus
    75  	CmdCheckSecondaryLocks
    76  
    77  	CmdRawGet CmdType = 256 + iota
    78  	CmdRawBatchGet
    79  	CmdRawPut
    80  	CmdRawBatchPut
    81  	CmdRawDelete
    82  	CmdRawBatchDelete
    83  	CmdRawDeleteRange
    84  	CmdRawScan
    85  	CmdGetKeyTTL
    86  	CmdRawCompareAndSwap
    87  
    88  	CmdUnsafeDestroyRange
    89  
    90  	CmdRegisterLockObserver
    91  	CmdCheckLockObserver
    92  	CmdRemoveLockObserver
    93  	CmdPhysicalScanLock
    94  
    95  	CmdStoreSafeTS
    96  	CmdLockWaitInfo
    97  
    98  	CmdCop CmdType = 512 + iota
    99  	CmdCopStream
   100  	CmdBatchCop
   101  	CmdMPPTask
   102  	CmdMPPConn
   103  	CmdMPPCancel
   104  	CmdMPPAlive
   105  
   106  	CmdMvccGetByKey CmdType = 1024 + iota
   107  	CmdMvccGetByStartTs
   108  	CmdSplitRegion
   109  
   110  	CmdDebugGetRegionProperties CmdType = 2048 + iota
   111  
   112  	CmdEmpty CmdType = 3072 + iota
   113  )
   114  
   115  func (t CmdType) String() string {
   116  	switch t {
   117  	case CmdGet:
   118  		return "Get"
   119  	case CmdScan:
   120  		return "Scan"
   121  	case CmdPrewrite:
   122  		return "Prewrite"
   123  	case CmdPessimisticLock:
   124  		return "PessimisticLock"
   125  	case CmdPessimisticRollback:
   126  		return "PessimisticRollback"
   127  	case CmdCommit:
   128  		return "Commit"
   129  	case CmdCleanup:
   130  		return "Cleanup"
   131  	case CmdBatchGet:
   132  		return "BatchGet"
   133  	case CmdBatchRollback:
   134  		return "BatchRollback"
   135  	case CmdScanLock:
   136  		return "ScanLock"
   137  	case CmdResolveLock:
   138  		return "ResolveLock"
   139  	case CmdGC:
   140  		return "GC"
   141  	case CmdDeleteRange:
   142  		return "DeleteRange"
   143  	case CmdRawGet:
   144  		return "RawGet"
   145  	case CmdRawBatchGet:
   146  		return "RawBatchGet"
   147  	case CmdRawPut:
   148  		return "RawPut"
   149  	case CmdRawBatchPut:
   150  		return "RawBatchPut"
   151  	case CmdRawDelete:
   152  		return "RawDelete"
   153  	case CmdRawBatchDelete:
   154  		return "RawBatchDelete"
   155  	case CmdRawDeleteRange:
   156  		return "RawDeleteRange"
   157  	case CmdRawScan:
   158  		return "RawScan"
   159  	case CmdUnsafeDestroyRange:
   160  		return "UnsafeDestroyRange"
   161  	case CmdRegisterLockObserver:
   162  		return "RegisterLockObserver"
   163  	case CmdCheckLockObserver:
   164  		return "CheckLockObserver"
   165  	case CmdRemoveLockObserver:
   166  		return "RemoveLockObserver"
   167  	case CmdPhysicalScanLock:
   168  		return "PhysicalScanLock"
   169  	case CmdCop:
   170  		return "Cop"
   171  	case CmdCopStream:
   172  		return "CopStream"
   173  	case CmdBatchCop:
   174  		return "BatchCop"
   175  	case CmdMPPTask:
   176  		return "DispatchMPPTask"
   177  	case CmdMPPConn:
   178  		return "EstablishMPPConnection"
   179  	case CmdMPPCancel:
   180  		return "CancelMPPTask"
   181  	case CmdMPPAlive:
   182  		return "MPPAlive"
   183  	case CmdMvccGetByKey:
   184  		return "MvccGetByKey"
   185  	case CmdMvccGetByStartTs:
   186  		return "MvccGetByStartTS"
   187  	case CmdSplitRegion:
   188  		return "SplitRegion"
   189  	case CmdCheckTxnStatus:
   190  		return "CheckTxnStatus"
   191  	case CmdCheckSecondaryLocks:
   192  		return "CheckSecondaryLocks"
   193  	case CmdDebugGetRegionProperties:
   194  		return "DebugGetRegionProperties"
   195  	case CmdTxnHeartBeat:
   196  		return "TxnHeartBeat"
   197  	case CmdStoreSafeTS:
   198  		return "StoreSafeTS"
   199  	case CmdLockWaitInfo:
   200  		return "LockWaitInfo"
   201  	}
   202  	return "Unknown"
   203  }
   204  
   205  // Request wraps all kv/coprocessor requests.
   206  type Request struct {
   207  	Type CmdType
   208  	Req  interface{}
   209  	kvrpcpb.Context
   210  	ReadReplicaScope string
   211  	// remove txnScope after tidb removed txnScope
   212  	TxnScope        string
   213  	ReplicaReadType kv.ReplicaReadType // different from `kvrpcpb.Context.ReplicaRead`
   214  	ReplicaReadSeed *uint32            // pointer to follower read seed in snapshot/coprocessor
   215  	StoreTp         EndpointType
   216  	// ForwardedHost is the address of a store which will handle the request. It's different from
   217  	// the address the request sent to.
   218  	// If it's not empty, the store which receive the request will forward it to
   219  	// the forwarded host. It's useful when network partition occurs.
   220  	ForwardedHost string
   221  }
   222  
   223  // NewRequest returns new kv rpc request.
   224  func NewRequest(typ CmdType, pointer interface{}, ctxs ...kvrpcpb.Context) *Request {
   225  	if len(ctxs) > 0 {
   226  		return &Request{
   227  			Type:    typ,
   228  			Req:     pointer,
   229  			Context: ctxs[0],
   230  		}
   231  	}
   232  	return &Request{
   233  		Type: typ,
   234  		Req:  pointer,
   235  	}
   236  }
   237  
   238  // NewReplicaReadRequest returns new kv rpc request with replica read.
   239  func NewReplicaReadRequest(typ CmdType, pointer interface{}, replicaReadType kv.ReplicaReadType, replicaReadSeed *uint32, ctxs ...kvrpcpb.Context) *Request {
   240  	req := NewRequest(typ, pointer, ctxs...)
   241  	req.ReplicaRead = replicaReadType.IsFollowerRead()
   242  	req.ReplicaReadType = replicaReadType
   243  	req.ReplicaReadSeed = replicaReadSeed
   244  	return req
   245  }
   246  
   247  // GetReplicaReadSeed returns ReplicaReadSeed pointer.
   248  func (req *Request) GetReplicaReadSeed() *uint32 {
   249  	if req != nil {
   250  		return req.ReplicaReadSeed
   251  	}
   252  	return nil
   253  }
   254  
   255  // EnableStaleRead enables stale read
   256  func (req *Request) EnableStaleRead() {
   257  	req.StaleRead = true
   258  	req.ReplicaReadType = kv.ReplicaReadMixed
   259  	req.ReplicaRead = false
   260  }
   261  
   262  // IsGlobalStaleRead checks if the request is a global stale read request.
   263  func (req *Request) IsGlobalStaleRead() bool {
   264  	return req.ReadReplicaScope == oracle.GlobalTxnScope &&
   265  		// remove txnScope after tidb remove it
   266  		req.TxnScope == oracle.GlobalTxnScope &&
   267  		req.GetStaleRead()
   268  }
   269  
   270  // IsDebugReq check whether the req is debug req.
   271  func (req *Request) IsDebugReq() bool {
   272  	switch req.Type {
   273  	case CmdDebugGetRegionProperties:
   274  		return true
   275  	}
   276  	return false
   277  }
   278  
   279  // Get returns GetRequest in request.
   280  func (req *Request) Get() *kvrpcpb.GetRequest {
   281  	return req.Req.(*kvrpcpb.GetRequest)
   282  }
   283  
   284  // Scan returns ScanRequest in request.
   285  func (req *Request) Scan() *kvrpcpb.ScanRequest {
   286  	return req.Req.(*kvrpcpb.ScanRequest)
   287  }
   288  
   289  // Prewrite returns PrewriteRequest in request.
   290  func (req *Request) Prewrite() *kvrpcpb.PrewriteRequest {
   291  	return req.Req.(*kvrpcpb.PrewriteRequest)
   292  }
   293  
   294  // Commit returns CommitRequest in request.
   295  func (req *Request) Commit() *kvrpcpb.CommitRequest {
   296  	return req.Req.(*kvrpcpb.CommitRequest)
   297  }
   298  
   299  // Cleanup returns CleanupRequest in request.
   300  func (req *Request) Cleanup() *kvrpcpb.CleanupRequest {
   301  	return req.Req.(*kvrpcpb.CleanupRequest)
   302  }
   303  
   304  // BatchGet returns BatchGetRequest in request.
   305  func (req *Request) BatchGet() *kvrpcpb.BatchGetRequest {
   306  	return req.Req.(*kvrpcpb.BatchGetRequest)
   307  }
   308  
   309  // BatchRollback returns BatchRollbackRequest in request.
   310  func (req *Request) BatchRollback() *kvrpcpb.BatchRollbackRequest {
   311  	return req.Req.(*kvrpcpb.BatchRollbackRequest)
   312  }
   313  
   314  // ScanLock returns ScanLockRequest in request.
   315  func (req *Request) ScanLock() *kvrpcpb.ScanLockRequest {
   316  	return req.Req.(*kvrpcpb.ScanLockRequest)
   317  }
   318  
   319  // ResolveLock returns ResolveLockRequest in request.
   320  func (req *Request) ResolveLock() *kvrpcpb.ResolveLockRequest {
   321  	return req.Req.(*kvrpcpb.ResolveLockRequest)
   322  }
   323  
   324  // GC returns GCRequest in request.
   325  func (req *Request) GC() *kvrpcpb.GCRequest {
   326  	return req.Req.(*kvrpcpb.GCRequest)
   327  }
   328  
   329  // DeleteRange returns DeleteRangeRequest in request.
   330  func (req *Request) DeleteRange() *kvrpcpb.DeleteRangeRequest {
   331  	return req.Req.(*kvrpcpb.DeleteRangeRequest)
   332  }
   333  
   334  // RawGet returns RawGetRequest in request.
   335  func (req *Request) RawGet() *kvrpcpb.RawGetRequest {
   336  	return req.Req.(*kvrpcpb.RawGetRequest)
   337  }
   338  
   339  // RawBatchGet returns RawBatchGetRequest in request.
   340  func (req *Request) RawBatchGet() *kvrpcpb.RawBatchGetRequest {
   341  	return req.Req.(*kvrpcpb.RawBatchGetRequest)
   342  }
   343  
   344  // RawPut returns RawPutRequest in request.
   345  func (req *Request) RawPut() *kvrpcpb.RawPutRequest {
   346  	return req.Req.(*kvrpcpb.RawPutRequest)
   347  }
   348  
   349  // RawBatchPut returns RawBatchPutRequest in request.
   350  func (req *Request) RawBatchPut() *kvrpcpb.RawBatchPutRequest {
   351  	return req.Req.(*kvrpcpb.RawBatchPutRequest)
   352  }
   353  
   354  // RawDelete returns PrewriteRequest in request.
   355  func (req *Request) RawDelete() *kvrpcpb.RawDeleteRequest {
   356  	return req.Req.(*kvrpcpb.RawDeleteRequest)
   357  }
   358  
   359  // RawBatchDelete returns RawBatchDeleteRequest in request.
   360  func (req *Request) RawBatchDelete() *kvrpcpb.RawBatchDeleteRequest {
   361  	return req.Req.(*kvrpcpb.RawBatchDeleteRequest)
   362  }
   363  
   364  // RawDeleteRange returns RawDeleteRangeRequest in request.
   365  func (req *Request) RawDeleteRange() *kvrpcpb.RawDeleteRangeRequest {
   366  	return req.Req.(*kvrpcpb.RawDeleteRangeRequest)
   367  }
   368  
   369  // RawScan returns RawScanRequest in request.
   370  func (req *Request) RawScan() *kvrpcpb.RawScanRequest {
   371  	return req.Req.(*kvrpcpb.RawScanRequest)
   372  }
   373  
   374  // UnsafeDestroyRange returns UnsafeDestroyRangeRequest in request.
   375  func (req *Request) UnsafeDestroyRange() *kvrpcpb.UnsafeDestroyRangeRequest {
   376  	return req.Req.(*kvrpcpb.UnsafeDestroyRangeRequest)
   377  }
   378  
   379  // RawGetKeyTTL returns RawGetKeyTTLRequest in request.
   380  func (req *Request) RawGetKeyTTL() *kvrpcpb.RawGetKeyTTLRequest {
   381  	return req.Req.(*kvrpcpb.RawGetKeyTTLRequest)
   382  }
   383  
   384  // RawCompareAndSwap returns RawCASRequest in request.
   385  func (req *Request) RawCompareAndSwap() *kvrpcpb.RawCASRequest {
   386  	return req.Req.(*kvrpcpb.RawCASRequest)
   387  }
   388  
   389  // RegisterLockObserver returns RegisterLockObserverRequest in request.
   390  func (req *Request) RegisterLockObserver() *kvrpcpb.RegisterLockObserverRequest {
   391  	return req.Req.(*kvrpcpb.RegisterLockObserverRequest)
   392  }
   393  
   394  // CheckLockObserver returns CheckLockObserverRequest in request.
   395  func (req *Request) CheckLockObserver() *kvrpcpb.CheckLockObserverRequest {
   396  	return req.Req.(*kvrpcpb.CheckLockObserverRequest)
   397  }
   398  
   399  // RemoveLockObserver returns RemoveLockObserverRequest in request.
   400  func (req *Request) RemoveLockObserver() *kvrpcpb.RemoveLockObserverRequest {
   401  	return req.Req.(*kvrpcpb.RemoveLockObserverRequest)
   402  }
   403  
   404  // PhysicalScanLock returns PhysicalScanLockRequest in request.
   405  func (req *Request) PhysicalScanLock() *kvrpcpb.PhysicalScanLockRequest {
   406  	return req.Req.(*kvrpcpb.PhysicalScanLockRequest)
   407  }
   408  
   409  // Cop returns coprocessor request in request.
   410  func (req *Request) Cop() *coprocessor.Request {
   411  	return req.Req.(*coprocessor.Request)
   412  }
   413  
   414  // BatchCop returns BatchCop request in request.
   415  func (req *Request) BatchCop() *coprocessor.BatchRequest {
   416  	return req.Req.(*coprocessor.BatchRequest)
   417  }
   418  
   419  // DispatchMPPTask returns dispatch task request in request.
   420  func (req *Request) DispatchMPPTask() *mpp.DispatchTaskRequest {
   421  	return req.Req.(*mpp.DispatchTaskRequest)
   422  }
   423  
   424  // IsMPPAlive returns IsAlive request in request.
   425  func (req *Request) IsMPPAlive() *mpp.IsAliveRequest {
   426  	return req.Req.(*mpp.IsAliveRequest)
   427  }
   428  
   429  // EstablishMPPConn returns EstablishMPPConnectionRequest in request.
   430  func (req *Request) EstablishMPPConn() *mpp.EstablishMPPConnectionRequest {
   431  	return req.Req.(*mpp.EstablishMPPConnectionRequest)
   432  }
   433  
   434  // CancelMPPTask returns canceling task in request
   435  func (req *Request) CancelMPPTask() *mpp.CancelTaskRequest {
   436  	return req.Req.(*mpp.CancelTaskRequest)
   437  }
   438  
   439  // MvccGetByKey returns MvccGetByKeyRequest in request.
   440  func (req *Request) MvccGetByKey() *kvrpcpb.MvccGetByKeyRequest {
   441  	return req.Req.(*kvrpcpb.MvccGetByKeyRequest)
   442  }
   443  
   444  // MvccGetByStartTs returns MvccGetByStartTsRequest in request.
   445  func (req *Request) MvccGetByStartTs() *kvrpcpb.MvccGetByStartTsRequest {
   446  	return req.Req.(*kvrpcpb.MvccGetByStartTsRequest)
   447  }
   448  
   449  // SplitRegion returns SplitRegionRequest in request.
   450  func (req *Request) SplitRegion() *kvrpcpb.SplitRegionRequest {
   451  	return req.Req.(*kvrpcpb.SplitRegionRequest)
   452  }
   453  
   454  // PessimisticLock returns PessimisticLockRequest in request.
   455  func (req *Request) PessimisticLock() *kvrpcpb.PessimisticLockRequest {
   456  	return req.Req.(*kvrpcpb.PessimisticLockRequest)
   457  }
   458  
   459  // PessimisticRollback returns PessimisticRollbackRequest in request.
   460  func (req *Request) PessimisticRollback() *kvrpcpb.PessimisticRollbackRequest {
   461  	return req.Req.(*kvrpcpb.PessimisticRollbackRequest)
   462  }
   463  
   464  // DebugGetRegionProperties returns GetRegionPropertiesRequest in request.
   465  func (req *Request) DebugGetRegionProperties() *debugpb.GetRegionPropertiesRequest {
   466  	return req.Req.(*debugpb.GetRegionPropertiesRequest)
   467  }
   468  
   469  // Empty returns BatchCommandsEmptyRequest in request.
   470  func (req *Request) Empty() *tikvpb.BatchCommandsEmptyRequest {
   471  	return req.Req.(*tikvpb.BatchCommandsEmptyRequest)
   472  }
   473  
   474  // CheckTxnStatus returns CheckTxnStatusRequest in request.
   475  func (req *Request) CheckTxnStatus() *kvrpcpb.CheckTxnStatusRequest {
   476  	return req.Req.(*kvrpcpb.CheckTxnStatusRequest)
   477  }
   478  
   479  // CheckSecondaryLocks returns CheckSecondaryLocksRequest in request.
   480  func (req *Request) CheckSecondaryLocks() *kvrpcpb.CheckSecondaryLocksRequest {
   481  	return req.Req.(*kvrpcpb.CheckSecondaryLocksRequest)
   482  }
   483  
   484  // TxnHeartBeat returns TxnHeartBeatRequest in request.
   485  func (req *Request) TxnHeartBeat() *kvrpcpb.TxnHeartBeatRequest {
   486  	return req.Req.(*kvrpcpb.TxnHeartBeatRequest)
   487  }
   488  
   489  // StoreSafeTS returns StoreSafeTSRequest in request.
   490  func (req *Request) StoreSafeTS() *kvrpcpb.StoreSafeTSRequest {
   491  	return req.Req.(*kvrpcpb.StoreSafeTSRequest)
   492  }
   493  
   494  // LockWaitInfo returns GetLockWaitInfoRequest in request.
   495  func (req *Request) LockWaitInfo() *kvrpcpb.GetLockWaitInfoRequest {
   496  	return req.Req.(*kvrpcpb.GetLockWaitInfoRequest)
   497  }
   498  
   499  // ToBatchCommandsRequest converts the request to an entry in BatchCommands request.
   500  func (req *Request) ToBatchCommandsRequest() *tikvpb.BatchCommandsRequest_Request {
   501  	switch req.Type {
   502  	case CmdGet:
   503  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_Get{Get: req.Get()}}
   504  	case CmdScan:
   505  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_Scan{Scan: req.Scan()}}
   506  	case CmdPrewrite:
   507  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_Prewrite{Prewrite: req.Prewrite()}}
   508  	case CmdCommit:
   509  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_Commit{Commit: req.Commit()}}
   510  	case CmdCleanup:
   511  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_Cleanup{Cleanup: req.Cleanup()}}
   512  	case CmdBatchGet:
   513  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_BatchGet{BatchGet: req.BatchGet()}}
   514  	case CmdBatchRollback:
   515  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_BatchRollback{BatchRollback: req.BatchRollback()}}
   516  	case CmdScanLock:
   517  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_ScanLock{ScanLock: req.ScanLock()}}
   518  	case CmdResolveLock:
   519  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_ResolveLock{ResolveLock: req.ResolveLock()}}
   520  	case CmdGC:
   521  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_GC{GC: req.GC()}}
   522  	case CmdDeleteRange:
   523  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_DeleteRange{DeleteRange: req.DeleteRange()}}
   524  	case CmdRawGet:
   525  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawGet{RawGet: req.RawGet()}}
   526  	case CmdRawBatchGet:
   527  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawBatchGet{RawBatchGet: req.RawBatchGet()}}
   528  	case CmdRawPut:
   529  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawPut{RawPut: req.RawPut()}}
   530  	case CmdRawBatchPut:
   531  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawBatchPut{RawBatchPut: req.RawBatchPut()}}
   532  	case CmdRawDelete:
   533  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawDelete{RawDelete: req.RawDelete()}}
   534  	case CmdRawBatchDelete:
   535  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawBatchDelete{RawBatchDelete: req.RawBatchDelete()}}
   536  	case CmdRawDeleteRange:
   537  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawDeleteRange{RawDeleteRange: req.RawDeleteRange()}}
   538  	case CmdRawScan:
   539  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_RawScan{RawScan: req.RawScan()}}
   540  	case CmdCop:
   541  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_Coprocessor{Coprocessor: req.Cop()}}
   542  	case CmdPessimisticLock:
   543  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_PessimisticLock{PessimisticLock: req.PessimisticLock()}}
   544  	case CmdPessimisticRollback:
   545  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_PessimisticRollback{PessimisticRollback: req.PessimisticRollback()}}
   546  	case CmdEmpty:
   547  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_Empty{Empty: req.Empty()}}
   548  	case CmdCheckTxnStatus:
   549  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_CheckTxnStatus{CheckTxnStatus: req.CheckTxnStatus()}}
   550  	case CmdCheckSecondaryLocks:
   551  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_CheckSecondaryLocks{CheckSecondaryLocks: req.CheckSecondaryLocks()}}
   552  	case CmdTxnHeartBeat:
   553  		return &tikvpb.BatchCommandsRequest_Request{Cmd: &tikvpb.BatchCommandsRequest_Request_TxnHeartBeat{TxnHeartBeat: req.TxnHeartBeat()}}
   554  	}
   555  	return nil
   556  }
   557  
   558  // Response wraps all kv/coprocessor responses.
   559  type Response struct {
   560  	Resp interface{}
   561  }
   562  
   563  // FromBatchCommandsResponse converts a BatchCommands response to Response.
   564  func FromBatchCommandsResponse(res *tikvpb.BatchCommandsResponse_Response) (*Response, error) {
   565  	if res.GetCmd() == nil {
   566  		return nil, errors.New("Unknown command response")
   567  	}
   568  	switch res := res.GetCmd().(type) {
   569  	case *tikvpb.BatchCommandsResponse_Response_Get:
   570  		return &Response{Resp: res.Get}, nil
   571  	case *tikvpb.BatchCommandsResponse_Response_Scan:
   572  		return &Response{Resp: res.Scan}, nil
   573  	case *tikvpb.BatchCommandsResponse_Response_Prewrite:
   574  		return &Response{Resp: res.Prewrite}, nil
   575  	case *tikvpb.BatchCommandsResponse_Response_Commit:
   576  		return &Response{Resp: res.Commit}, nil
   577  	case *tikvpb.BatchCommandsResponse_Response_Cleanup:
   578  		return &Response{Resp: res.Cleanup}, nil
   579  	case *tikvpb.BatchCommandsResponse_Response_BatchGet:
   580  		return &Response{Resp: res.BatchGet}, nil
   581  	case *tikvpb.BatchCommandsResponse_Response_BatchRollback:
   582  		return &Response{Resp: res.BatchRollback}, nil
   583  	case *tikvpb.BatchCommandsResponse_Response_ScanLock:
   584  		return &Response{Resp: res.ScanLock}, nil
   585  	case *tikvpb.BatchCommandsResponse_Response_ResolveLock:
   586  		return &Response{Resp: res.ResolveLock}, nil
   587  	case *tikvpb.BatchCommandsResponse_Response_GC:
   588  		return &Response{Resp: res.GC}, nil
   589  	case *tikvpb.BatchCommandsResponse_Response_DeleteRange:
   590  		return &Response{Resp: res.DeleteRange}, nil
   591  	case *tikvpb.BatchCommandsResponse_Response_RawGet:
   592  		return &Response{Resp: res.RawGet}, nil
   593  	case *tikvpb.BatchCommandsResponse_Response_RawBatchGet:
   594  		return &Response{Resp: res.RawBatchGet}, nil
   595  	case *tikvpb.BatchCommandsResponse_Response_RawPut:
   596  		return &Response{Resp: res.RawPut}, nil
   597  	case *tikvpb.BatchCommandsResponse_Response_RawBatchPut:
   598  		return &Response{Resp: res.RawBatchPut}, nil
   599  	case *tikvpb.BatchCommandsResponse_Response_RawDelete:
   600  		return &Response{Resp: res.RawDelete}, nil
   601  	case *tikvpb.BatchCommandsResponse_Response_RawBatchDelete:
   602  		return &Response{Resp: res.RawBatchDelete}, nil
   603  	case *tikvpb.BatchCommandsResponse_Response_RawDeleteRange:
   604  		return &Response{Resp: res.RawDeleteRange}, nil
   605  	case *tikvpb.BatchCommandsResponse_Response_RawScan:
   606  		return &Response{Resp: res.RawScan}, nil
   607  	case *tikvpb.BatchCommandsResponse_Response_Coprocessor:
   608  		return &Response{Resp: res.Coprocessor}, nil
   609  	case *tikvpb.BatchCommandsResponse_Response_PessimisticLock:
   610  		return &Response{Resp: res.PessimisticLock}, nil
   611  	case *tikvpb.BatchCommandsResponse_Response_PessimisticRollback:
   612  		return &Response{Resp: res.PessimisticRollback}, nil
   613  	case *tikvpb.BatchCommandsResponse_Response_Empty:
   614  		return &Response{Resp: res.Empty}, nil
   615  	case *tikvpb.BatchCommandsResponse_Response_TxnHeartBeat:
   616  		return &Response{Resp: res.TxnHeartBeat}, nil
   617  	case *tikvpb.BatchCommandsResponse_Response_CheckTxnStatus:
   618  		return &Response{Resp: res.CheckTxnStatus}, nil
   619  	case *tikvpb.BatchCommandsResponse_Response_CheckSecondaryLocks:
   620  		return &Response{Resp: res.CheckSecondaryLocks}, nil
   621  	}
   622  	panic("unreachable")
   623  }
   624  
   625  // CopStreamResponse combines tikvpb.Tikv_CoprocessorStreamClient and the first Recv() result together.
   626  // In streaming API, get grpc stream client may not involve any network packet, then region error have
   627  // to be handled in Recv() function. This struct facilitates the error handling.
   628  type CopStreamResponse struct {
   629  	tikvpb.Tikv_CoprocessorStreamClient
   630  	*coprocessor.Response // The first result of Recv()
   631  	Timeout               time.Duration
   632  	Lease                 // Shared by this object and a background goroutine.
   633  }
   634  
   635  // BatchCopStreamResponse comprises the BatchCoprocessorClient , the first result and timeout detector.
   636  type BatchCopStreamResponse struct {
   637  	tikvpb.Tikv_BatchCoprocessorClient
   638  	*coprocessor.BatchResponse
   639  	Timeout time.Duration
   640  	Lease   // Shared by this object and a background goroutine.
   641  }
   642  
   643  // MPPStreamResponse is indeed a wrapped client that can receive data packet from tiflash mpp server.
   644  type MPPStreamResponse struct {
   645  	tikvpb.Tikv_EstablishMPPConnectionClient
   646  	*mpp.MPPDataPacket
   647  	Timeout time.Duration
   648  	Lease
   649  }
   650  
   651  // SetContext set the Context field for the given req to the specified ctx.
   652  func SetContext(req *Request, region *metapb.Region, peer *metapb.Peer) error {
   653  	ctx := &req.Context
   654  	if region != nil {
   655  		ctx.RegionId = region.Id
   656  		ctx.RegionEpoch = region.RegionEpoch
   657  	}
   658  	ctx.Peer = peer
   659  
   660  	switch req.Type {
   661  	case CmdGet:
   662  		req.Get().Context = ctx
   663  	case CmdScan:
   664  		req.Scan().Context = ctx
   665  	case CmdPrewrite:
   666  		req.Prewrite().Context = ctx
   667  	case CmdPessimisticLock:
   668  		req.PessimisticLock().Context = ctx
   669  	case CmdPessimisticRollback:
   670  		req.PessimisticRollback().Context = ctx
   671  	case CmdCommit:
   672  		req.Commit().Context = ctx
   673  	case CmdCleanup:
   674  		req.Cleanup().Context = ctx
   675  	case CmdBatchGet:
   676  		req.BatchGet().Context = ctx
   677  	case CmdBatchRollback:
   678  		req.BatchRollback().Context = ctx
   679  	case CmdScanLock:
   680  		req.ScanLock().Context = ctx
   681  	case CmdResolveLock:
   682  		req.ResolveLock().Context = ctx
   683  	case CmdGC:
   684  		req.GC().Context = ctx
   685  	case CmdDeleteRange:
   686  		req.DeleteRange().Context = ctx
   687  	case CmdRawGet:
   688  		req.RawGet().Context = ctx
   689  	case CmdRawBatchGet:
   690  		req.RawBatchGet().Context = ctx
   691  	case CmdRawPut:
   692  		req.RawPut().Context = ctx
   693  	case CmdRawBatchPut:
   694  		req.RawBatchPut().Context = ctx
   695  	case CmdRawDelete:
   696  		req.RawDelete().Context = ctx
   697  	case CmdRawBatchDelete:
   698  		req.RawBatchDelete().Context = ctx
   699  	case CmdRawDeleteRange:
   700  		req.RawDeleteRange().Context = ctx
   701  	case CmdRawScan:
   702  		req.RawScan().Context = ctx
   703  	case CmdUnsafeDestroyRange:
   704  		req.UnsafeDestroyRange().Context = ctx
   705  	case CmdGetKeyTTL:
   706  		req.RawGetKeyTTL().Context = ctx
   707  	case CmdRawCompareAndSwap:
   708  		req.RawCompareAndSwap().Context = ctx
   709  	case CmdRegisterLockObserver:
   710  		req.RegisterLockObserver().Context = ctx
   711  	case CmdCheckLockObserver:
   712  		req.CheckLockObserver().Context = ctx
   713  	case CmdRemoveLockObserver:
   714  		req.RemoveLockObserver().Context = ctx
   715  	case CmdPhysicalScanLock:
   716  		req.PhysicalScanLock().Context = ctx
   717  	case CmdCop:
   718  		req.Cop().Context = ctx
   719  	case CmdCopStream:
   720  		req.Cop().Context = ctx
   721  	case CmdBatchCop:
   722  		req.BatchCop().Context = ctx
   723  	case CmdMPPTask:
   724  		// Dispatching MPP tasks don't need a region context, because it's a request for store but not region.
   725  	case CmdMvccGetByKey:
   726  		req.MvccGetByKey().Context = ctx
   727  	case CmdMvccGetByStartTs:
   728  		req.MvccGetByStartTs().Context = ctx
   729  	case CmdSplitRegion:
   730  		req.SplitRegion().Context = ctx
   731  	case CmdEmpty:
   732  		req.SplitRegion().Context = ctx
   733  	case CmdTxnHeartBeat:
   734  		req.TxnHeartBeat().Context = ctx
   735  	case CmdCheckTxnStatus:
   736  		req.CheckTxnStatus().Context = ctx
   737  	case CmdCheckSecondaryLocks:
   738  		req.CheckSecondaryLocks().Context = ctx
   739  	default:
   740  		return fmt.Errorf("invalid request type %v", req.Type)
   741  	}
   742  	return nil
   743  }
   744  
   745  // GenRegionErrorResp returns corresponding Response with specified RegionError
   746  // according to the given req.
   747  func GenRegionErrorResp(req *Request, e *errorpb.Error) (*Response, error) {
   748  	var p interface{}
   749  	resp := &Response{}
   750  	switch req.Type {
   751  	case CmdGet:
   752  		p = &kvrpcpb.GetResponse{
   753  			RegionError: e,
   754  		}
   755  	case CmdScan:
   756  		p = &kvrpcpb.ScanResponse{
   757  			RegionError: e,
   758  		}
   759  	case CmdPrewrite:
   760  		p = &kvrpcpb.PrewriteResponse{
   761  			RegionError: e,
   762  		}
   763  	case CmdPessimisticLock:
   764  		p = &kvrpcpb.PessimisticLockResponse{
   765  			RegionError: e,
   766  		}
   767  	case CmdPessimisticRollback:
   768  		p = &kvrpcpb.PessimisticRollbackResponse{
   769  			RegionError: e,
   770  		}
   771  	case CmdCommit:
   772  		p = &kvrpcpb.CommitResponse{
   773  			RegionError: e,
   774  		}
   775  	case CmdCleanup:
   776  		p = &kvrpcpb.CleanupResponse{
   777  			RegionError: e,
   778  		}
   779  	case CmdBatchGet:
   780  		p = &kvrpcpb.BatchGetResponse{
   781  			RegionError: e,
   782  		}
   783  	case CmdBatchRollback:
   784  		p = &kvrpcpb.BatchRollbackResponse{
   785  			RegionError: e,
   786  		}
   787  	case CmdScanLock:
   788  		p = &kvrpcpb.ScanLockResponse{
   789  			RegionError: e,
   790  		}
   791  	case CmdResolveLock:
   792  		p = &kvrpcpb.ResolveLockResponse{
   793  			RegionError: e,
   794  		}
   795  	case CmdGC:
   796  		p = &kvrpcpb.GCResponse{
   797  			RegionError: e,
   798  		}
   799  	case CmdDeleteRange:
   800  		p = &kvrpcpb.DeleteRangeResponse{
   801  			RegionError: e,
   802  		}
   803  	case CmdRawGet:
   804  		p = &kvrpcpb.RawGetResponse{
   805  			RegionError: e,
   806  		}
   807  	case CmdRawBatchGet:
   808  		p = &kvrpcpb.RawBatchGetResponse{
   809  			RegionError: e,
   810  		}
   811  	case CmdRawPut:
   812  		p = &kvrpcpb.RawPutResponse{
   813  			RegionError: e,
   814  		}
   815  	case CmdRawBatchPut:
   816  		p = &kvrpcpb.RawBatchPutResponse{
   817  			RegionError: e,
   818  		}
   819  	case CmdRawDelete:
   820  		p = &kvrpcpb.RawDeleteResponse{
   821  			RegionError: e,
   822  		}
   823  	case CmdRawBatchDelete:
   824  		p = &kvrpcpb.RawBatchDeleteResponse{
   825  			RegionError: e,
   826  		}
   827  	case CmdRawDeleteRange:
   828  		p = &kvrpcpb.RawDeleteRangeResponse{
   829  			RegionError: e,
   830  		}
   831  	case CmdRawScan:
   832  		p = &kvrpcpb.RawScanResponse{
   833  			RegionError: e,
   834  		}
   835  	case CmdUnsafeDestroyRange:
   836  		p = &kvrpcpb.UnsafeDestroyRangeResponse{
   837  			RegionError: e,
   838  		}
   839  	case CmdGetKeyTTL:
   840  		p = &kvrpcpb.RawGetKeyTTLResponse{
   841  			RegionError: e,
   842  		}
   843  	case CmdRawCompareAndSwap:
   844  		p = &kvrpcpb.RawCASResponse{
   845  			RegionError: e,
   846  		}
   847  	case CmdCop:
   848  		p = &coprocessor.Response{
   849  			RegionError: e,
   850  		}
   851  	case CmdCopStream:
   852  		p = &CopStreamResponse{
   853  			Response: &coprocessor.Response{
   854  				RegionError: e,
   855  			},
   856  		}
   857  	case CmdMvccGetByKey:
   858  		p = &kvrpcpb.MvccGetByKeyResponse{
   859  			RegionError: e,
   860  		}
   861  	case CmdMvccGetByStartTs:
   862  		p = &kvrpcpb.MvccGetByStartTsResponse{
   863  			RegionError: e,
   864  		}
   865  	case CmdSplitRegion:
   866  		p = &kvrpcpb.SplitRegionResponse{
   867  			RegionError: e,
   868  		}
   869  	case CmdEmpty:
   870  	case CmdTxnHeartBeat:
   871  		p = &kvrpcpb.TxnHeartBeatResponse{
   872  			RegionError: e,
   873  		}
   874  	case CmdCheckTxnStatus:
   875  		p = &kvrpcpb.CheckTxnStatusResponse{
   876  			RegionError: e,
   877  		}
   878  	case CmdCheckSecondaryLocks:
   879  		p = &kvrpcpb.CheckSecondaryLocksResponse{
   880  			RegionError: e,
   881  		}
   882  	default:
   883  		return nil, fmt.Errorf("invalid request type %v", req.Type)
   884  	}
   885  	resp.Resp = p
   886  	return resp, nil
   887  }
   888  
   889  type getRegionError interface {
   890  	GetRegionError() *errorpb.Error
   891  }
   892  
   893  // GetRegionError returns the RegionError of the underlying concrete response.
   894  func (resp *Response) GetRegionError() (*errorpb.Error, error) {
   895  	if resp.Resp == nil {
   896  		return nil, nil
   897  	}
   898  	err, ok := resp.Resp.(getRegionError)
   899  	if !ok {
   900  		if _, isEmpty := resp.Resp.(*tikvpb.BatchCommandsEmptyResponse); isEmpty {
   901  			return nil, nil
   902  		}
   903  		return nil, fmt.Errorf("invalid response type %v", resp)
   904  	}
   905  	return err.GetRegionError(), nil
   906  }
   907  
   908  // CallRPC launches a rpc call.
   909  // ch is needed to implement timeout for coprocessor streaming, the stream object's
   910  // cancel function will be sent to the channel, together with a lease checked by a background goroutine.
   911  func CallRPC(ctx context.Context, client tikvpb.TikvClient, req *Request) (*Response, error) {
   912  	resp := &Response{}
   913  	var err error
   914  	switch req.Type {
   915  	case CmdGet:
   916  		resp.Resp, err = client.KvGet(ctx, req.Get())
   917  	case CmdScan:
   918  		resp.Resp, err = client.KvScan(ctx, req.Scan())
   919  	case CmdPrewrite:
   920  		resp.Resp, err = client.KvPrewrite(ctx, req.Prewrite())
   921  	case CmdPessimisticLock:
   922  		resp.Resp, err = client.KvPessimisticLock(ctx, req.PessimisticLock())
   923  	case CmdPessimisticRollback:
   924  		resp.Resp, err = client.KVPessimisticRollback(ctx, req.PessimisticRollback())
   925  	case CmdCommit:
   926  		resp.Resp, err = client.KvCommit(ctx, req.Commit())
   927  	case CmdCleanup:
   928  		resp.Resp, err = client.KvCleanup(ctx, req.Cleanup())
   929  	case CmdBatchGet:
   930  		resp.Resp, err = client.KvBatchGet(ctx, req.BatchGet())
   931  	case CmdBatchRollback:
   932  		resp.Resp, err = client.KvBatchRollback(ctx, req.BatchRollback())
   933  	case CmdScanLock:
   934  		resp.Resp, err = client.KvScanLock(ctx, req.ScanLock())
   935  	case CmdResolveLock:
   936  		resp.Resp, err = client.KvResolveLock(ctx, req.ResolveLock())
   937  	case CmdGC:
   938  		resp.Resp, err = client.KvGC(ctx, req.GC())
   939  	case CmdDeleteRange:
   940  		resp.Resp, err = client.KvDeleteRange(ctx, req.DeleteRange())
   941  	case CmdRawGet:
   942  		resp.Resp, err = client.RawGet(ctx, req.RawGet())
   943  	case CmdRawBatchGet:
   944  		resp.Resp, err = client.RawBatchGet(ctx, req.RawBatchGet())
   945  	case CmdRawPut:
   946  		resp.Resp, err = client.RawPut(ctx, req.RawPut())
   947  	case CmdRawBatchPut:
   948  		resp.Resp, err = client.RawBatchPut(ctx, req.RawBatchPut())
   949  	case CmdRawDelete:
   950  		resp.Resp, err = client.RawDelete(ctx, req.RawDelete())
   951  	case CmdRawBatchDelete:
   952  		resp.Resp, err = client.RawBatchDelete(ctx, req.RawBatchDelete())
   953  	case CmdRawDeleteRange:
   954  		resp.Resp, err = client.RawDeleteRange(ctx, req.RawDeleteRange())
   955  	case CmdRawScan:
   956  		resp.Resp, err = client.RawScan(ctx, req.RawScan())
   957  	case CmdUnsafeDestroyRange:
   958  		resp.Resp, err = client.UnsafeDestroyRange(ctx, req.UnsafeDestroyRange())
   959  	case CmdGetKeyTTL:
   960  		resp.Resp, err = client.RawGetKeyTTL(ctx, req.RawGetKeyTTL())
   961  	case CmdRawCompareAndSwap:
   962  		resp.Resp, err = client.RawCompareAndSwap(ctx, req.RawCompareAndSwap())
   963  	case CmdRegisterLockObserver:
   964  		resp.Resp, err = client.RegisterLockObserver(ctx, req.RegisterLockObserver())
   965  	case CmdCheckLockObserver:
   966  		resp.Resp, err = client.CheckLockObserver(ctx, req.CheckLockObserver())
   967  	case CmdRemoveLockObserver:
   968  		resp.Resp, err = client.RemoveLockObserver(ctx, req.RemoveLockObserver())
   969  	case CmdPhysicalScanLock:
   970  		resp.Resp, err = client.PhysicalScanLock(ctx, req.PhysicalScanLock())
   971  	case CmdCop:
   972  		resp.Resp, err = client.Coprocessor(ctx, req.Cop())
   973  	case CmdMPPTask:
   974  		resp.Resp, err = client.DispatchMPPTask(ctx, req.DispatchMPPTask())
   975  	case CmdMPPAlive:
   976  		resp.Resp, err = client.IsAlive(ctx, req.IsMPPAlive())
   977  	case CmdMPPConn:
   978  		var streamClient tikvpb.Tikv_EstablishMPPConnectionClient
   979  		streamClient, err = client.EstablishMPPConnection(ctx, req.EstablishMPPConn())
   980  		resp.Resp = &MPPStreamResponse{
   981  			Tikv_EstablishMPPConnectionClient: streamClient,
   982  		}
   983  	case CmdMPPCancel:
   984  		// it cannot use the ctx with cancel(), otherwise this cmd will fail.
   985  		resp.Resp, err = client.CancelMPPTask(ctx, req.CancelMPPTask())
   986  	case CmdCopStream:
   987  		var streamClient tikvpb.Tikv_CoprocessorStreamClient
   988  		streamClient, err = client.CoprocessorStream(ctx, req.Cop())
   989  		resp.Resp = &CopStreamResponse{
   990  			Tikv_CoprocessorStreamClient: streamClient,
   991  		}
   992  	case CmdBatchCop:
   993  		var streamClient tikvpb.Tikv_BatchCoprocessorClient
   994  		streamClient, err = client.BatchCoprocessor(ctx, req.BatchCop())
   995  		resp.Resp = &BatchCopStreamResponse{
   996  			Tikv_BatchCoprocessorClient: streamClient,
   997  		}
   998  	case CmdMvccGetByKey:
   999  		resp.Resp, err = client.MvccGetByKey(ctx, req.MvccGetByKey())
  1000  	case CmdMvccGetByStartTs:
  1001  		resp.Resp, err = client.MvccGetByStartTs(ctx, req.MvccGetByStartTs())
  1002  	case CmdSplitRegion:
  1003  		resp.Resp, err = client.SplitRegion(ctx, req.SplitRegion())
  1004  	case CmdEmpty:
  1005  		resp.Resp, err = &tikvpb.BatchCommandsEmptyResponse{}, nil
  1006  	case CmdCheckTxnStatus:
  1007  		resp.Resp, err = client.KvCheckTxnStatus(ctx, req.CheckTxnStatus())
  1008  	case CmdCheckSecondaryLocks:
  1009  		resp.Resp, err = client.KvCheckSecondaryLocks(ctx, req.CheckSecondaryLocks())
  1010  	case CmdTxnHeartBeat:
  1011  		resp.Resp, err = client.KvTxnHeartBeat(ctx, req.TxnHeartBeat())
  1012  	case CmdStoreSafeTS:
  1013  		resp.Resp, err = client.GetStoreSafeTS(ctx, req.StoreSafeTS())
  1014  	case CmdLockWaitInfo:
  1015  		resp.Resp, err = client.GetLockWaitInfo(ctx, req.LockWaitInfo())
  1016  	default:
  1017  		return nil, errors.Errorf("invalid request type: %v", req.Type)
  1018  	}
  1019  	if err != nil {
  1020  		return nil, errors.Trace(err)
  1021  	}
  1022  	return resp, nil
  1023  }
  1024  
  1025  // CallDebugRPC launches a debug rpc call.
  1026  func CallDebugRPC(ctx context.Context, client debugpb.DebugClient, req *Request) (*Response, error) {
  1027  	resp := &Response{}
  1028  	var err error
  1029  	switch req.Type {
  1030  	case CmdDebugGetRegionProperties:
  1031  		resp.Resp, err = client.GetRegionProperties(ctx, req.DebugGetRegionProperties())
  1032  	default:
  1033  		return nil, errors.Errorf("invalid request type: %v", req.Type)
  1034  	}
  1035  	return resp, err
  1036  }
  1037  
  1038  // Lease is used to implement grpc stream timeout.
  1039  type Lease struct {
  1040  	Cancel   context.CancelFunc
  1041  	deadline int64 // A time.UnixNano value, if time.Now().UnixNano() > deadline, cancel() would be called.
  1042  }
  1043  
  1044  // Recv overrides the stream client Recv() function.
  1045  func (resp *CopStreamResponse) Recv() (*coprocessor.Response, error) {
  1046  	deadline := time.Now().Add(resp.Timeout).UnixNano()
  1047  	atomic.StoreInt64(&resp.Lease.deadline, deadline)
  1048  
  1049  	ret, err := resp.Tikv_CoprocessorStreamClient.Recv()
  1050  
  1051  	atomic.StoreInt64(&resp.Lease.deadline, 0) // Stop the lease check.
  1052  	return ret, errors.Trace(err)
  1053  }
  1054  
  1055  // Close closes the CopStreamResponse object.
  1056  func (resp *CopStreamResponse) Close() {
  1057  	atomic.StoreInt64(&resp.Lease.deadline, 1)
  1058  	// We also call cancel here because CheckStreamTimeoutLoop
  1059  	// is not guaranteed to cancel all items when it exits.
  1060  	if resp.Lease.Cancel != nil {
  1061  		resp.Lease.Cancel()
  1062  	}
  1063  }
  1064  
  1065  // Recv overrides the stream client Recv() function.
  1066  func (resp *BatchCopStreamResponse) Recv() (*coprocessor.BatchResponse, error) {
  1067  	deadline := time.Now().Add(resp.Timeout).UnixNano()
  1068  	atomic.StoreInt64(&resp.Lease.deadline, deadline)
  1069  
  1070  	ret, err := resp.Tikv_BatchCoprocessorClient.Recv()
  1071  
  1072  	atomic.StoreInt64(&resp.Lease.deadline, 0) // Stop the lease check.
  1073  	return ret, errors.Trace(err)
  1074  }
  1075  
  1076  // Close closes the BatchCopStreamResponse object.
  1077  func (resp *BatchCopStreamResponse) Close() {
  1078  	atomic.StoreInt64(&resp.Lease.deadline, 1)
  1079  	// We also call cancel here because CheckStreamTimeoutLoop
  1080  	// is not guaranteed to cancel all items when it exits.
  1081  	if resp.Lease.Cancel != nil {
  1082  		resp.Lease.Cancel()
  1083  	}
  1084  }
  1085  
  1086  // Recv overrides the stream client Recv() function.
  1087  func (resp *MPPStreamResponse) Recv() (*mpp.MPPDataPacket, error) {
  1088  	deadline := time.Now().Add(resp.Timeout).UnixNano()
  1089  	atomic.StoreInt64(&resp.Lease.deadline, deadline)
  1090  
  1091  	ret, err := resp.Tikv_EstablishMPPConnectionClient.Recv()
  1092  
  1093  	atomic.StoreInt64(&resp.Lease.deadline, 0) // Stop the lease check.
  1094  	return ret, errors.Trace(err)
  1095  }
  1096  
  1097  // Close closes the MPPStreamResponse object.
  1098  func (resp *MPPStreamResponse) Close() {
  1099  	atomic.StoreInt64(&resp.Lease.deadline, 1)
  1100  	// We also call cancel here because CheckStreamTimeoutLoop
  1101  	// is not guaranteed to cancel all items when it exits.
  1102  	if resp.Lease.Cancel != nil {
  1103  		resp.Lease.Cancel()
  1104  	}
  1105  }
  1106  
  1107  // CheckStreamTimeoutLoop runs periodically to check is there any stream request timed out.
  1108  // Lease is an object to track stream requests, call this function with "go CheckStreamTimeoutLoop()"
  1109  // It is not guaranteed to call every Lease.Cancel() putting into channel when exits.
  1110  // If grpc-go supports SetDeadline(https://github.com/grpc/grpc-go/issues/2917), we can stop using this method.
  1111  func CheckStreamTimeoutLoop(ch <-chan *Lease, done <-chan struct{}) {
  1112  	ticker := time.NewTicker(200 * time.Millisecond)
  1113  	defer ticker.Stop()
  1114  	array := make([]*Lease, 0, 1024)
  1115  
  1116  	for {
  1117  		select {
  1118  		case <-done:
  1119  		drainLoop:
  1120  			// Try my best cleaning the channel to make SendRequest which is blocking by it continues.
  1121  			for {
  1122  				select {
  1123  				case <-ch:
  1124  				default:
  1125  					break drainLoop
  1126  				}
  1127  			}
  1128  			return
  1129  		case item := <-ch:
  1130  			array = append(array, item)
  1131  		case now := <-ticker.C:
  1132  			array = keepOnlyActive(array, now.UnixNano())
  1133  		}
  1134  	}
  1135  }
  1136  
  1137  // keepOnlyActive removes completed items, call cancel function for timeout items.
  1138  func keepOnlyActive(array []*Lease, now int64) []*Lease {
  1139  	idx := 0
  1140  	for i := 0; i < len(array); i++ {
  1141  		item := array[i]
  1142  		deadline := atomic.LoadInt64(&item.deadline)
  1143  		if deadline == 0 || deadline > now {
  1144  			array[idx] = array[i]
  1145  			idx++
  1146  		} else {
  1147  			item.Cancel()
  1148  		}
  1149  	}
  1150  	return array[:idx]
  1151  }
  1152  
  1153  // IsGreenGCRequest checks if the request is used by Green GC's protocol. This is used for failpoints to inject errors
  1154  // to specified RPC requests.
  1155  func (req *Request) IsGreenGCRequest() bool {
  1156  	if req.Type == CmdCheckLockObserver ||
  1157  		req.Type == CmdRegisterLockObserver ||
  1158  		req.Type == CmdRemoveLockObserver ||
  1159  		req.Type == CmdPhysicalScanLock {
  1160  		return true
  1161  	}
  1162  	return false
  1163  }
  1164  
  1165  // IsTxnWriteRequest checks if the request is a transactional write request. This is used for failpoints to inject
  1166  // errors to specified RPC requests.
  1167  func (req *Request) IsTxnWriteRequest() bool {
  1168  	if req.Type == CmdPessimisticLock ||
  1169  		req.Type == CmdPrewrite ||
  1170  		req.Type == CmdCommit ||
  1171  		req.Type == CmdBatchRollback ||
  1172  		req.Type == CmdPessimisticRollback ||
  1173  		req.Type == CmdCheckTxnStatus ||
  1174  		req.Type == CmdCheckSecondaryLocks ||
  1175  		req.Type == CmdCleanup ||
  1176  		req.Type == CmdTxnHeartBeat ||
  1177  		req.Type == CmdResolveLock {
  1178  		return true
  1179  	}
  1180  	return false
  1181  }