github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/tikv/mock-tikv/rpc.go (about)

     1  // Copyright 2016 PingCAP, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package mocktikv
    15  
    16  import (
    17  	"github.com/insionng/yougam/libraries/golang/protobuf/proto"
    18  	"github.com/insionng/yougam/libraries/juju/errors"
    19  	"github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/coprocessor"
    20  	"github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/errorpb"
    21  	"github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/kvrpcpb"
    22  	"github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/metapb"
    23  )
    24  
    25  type rpcHandler struct {
    26  	cluster   *Cluster
    27  	mvccStore *MvccStore
    28  	storeID   uint64
    29  	startKey  []byte
    30  	endKey    []byte
    31  }
    32  
    33  func newRPCHandler(cluster *Cluster, mvccStore *MvccStore, storeID uint64) *rpcHandler {
    34  	return &rpcHandler{
    35  		cluster:   cluster,
    36  		mvccStore: mvccStore,
    37  		storeID:   storeID,
    38  	}
    39  }
    40  
    41  func (h *rpcHandler) handleRequest(req *kvrpcpb.Request) *kvrpcpb.Response {
    42  	resp := &kvrpcpb.Response{
    43  		Type: req.Type,
    44  	}
    45  	if err := h.checkContext(req.GetContext()); err != nil {
    46  		resp.RegionError = err
    47  		return resp
    48  	}
    49  	switch req.GetType() {
    50  	case kvrpcpb.MessageType_CmdGet:
    51  		resp.CmdGetResp = h.onGet(req.CmdGetReq)
    52  	case kvrpcpb.MessageType_CmdScan:
    53  		resp.CmdScanResp = h.onScan(req.CmdScanReq)
    54  	case kvrpcpb.MessageType_CmdPrewrite:
    55  		resp.CmdPrewriteResp = h.onPrewrite(req.CmdPrewriteReq)
    56  	case kvrpcpb.MessageType_CmdCommit:
    57  		resp.CmdCommitResp = h.onCommit(req.CmdCommitReq)
    58  	case kvrpcpb.MessageType_CmdCleanup:
    59  		resp.CmdCleanupResp = h.onCleanup(req.CmdCleanupReq)
    60  	case kvrpcpb.MessageType_CmdCommitThenGet:
    61  		resp.CmdCommitGetResp = h.onCommitThenGet(req.CmdCommitGetReq)
    62  	case kvrpcpb.MessageType_CmdRollbackThenGet:
    63  		resp.CmdRbGetResp = h.onRollbackThenGet(req.CmdRbGetReq)
    64  	case kvrpcpb.MessageType_CmdBatchGet:
    65  		resp.CmdBatchGetResp = h.onBatchGet(req.CmdBatchGetReq)
    66  	}
    67  	return resp
    68  }
    69  
    70  func (h *rpcHandler) checkContext(ctx *kvrpcpb.Context) *errorpb.Error {
    71  	region, leaderID := h.cluster.GetRegion(ctx.GetRegionId())
    72  	// No region found.
    73  	if region == nil {
    74  		return &errorpb.Error{
    75  			Message: proto.String("region not found"),
    76  			RegionNotFound: &errorpb.RegionNotFound{
    77  				RegionId: proto.Uint64(ctx.GetRegionId()),
    78  			},
    79  		}
    80  	}
    81  	var storePeer, leaderPeer *metapb.Peer
    82  	for _, p := range region.Peers {
    83  		if p.GetStoreId() == h.storeID {
    84  			storePeer = p
    85  		}
    86  		if p.GetId() == leaderID {
    87  			leaderPeer = p
    88  		}
    89  	}
    90  	// The Store does not contain a Peer of the Region.
    91  	if storePeer == nil {
    92  		return &errorpb.Error{
    93  			Message: proto.String("region not found"),
    94  			RegionNotFound: &errorpb.RegionNotFound{
    95  				RegionId: proto.Uint64(ctx.GetRegionId()),
    96  			},
    97  		}
    98  	}
    99  	// No leader.
   100  	if leaderPeer == nil {
   101  		return &errorpb.Error{
   102  			Message: proto.String("no leader"),
   103  			NotLeader: &errorpb.NotLeader{
   104  				RegionId: proto.Uint64(ctx.GetRegionId()),
   105  			},
   106  		}
   107  	}
   108  	// The Peer on the Store is not leader.
   109  	if storePeer.GetId() != leaderPeer.GetId() {
   110  		return &errorpb.Error{
   111  			Message: proto.String("not leader"),
   112  			NotLeader: &errorpb.NotLeader{
   113  				RegionId: proto.Uint64(ctx.GetRegionId()),
   114  				Leader:   leaderPeer,
   115  			},
   116  		}
   117  	}
   118  	// Region epoch does not match.
   119  	if !proto.Equal(region.GetRegionEpoch(), ctx.GetRegionEpoch()) {
   120  		return &errorpb.Error{
   121  			Message:    proto.String("stale epoch"),
   122  			StaleEpoch: &errorpb.StaleEpoch{},
   123  		}
   124  	}
   125  	h.startKey, h.endKey = region.StartKey, region.EndKey
   126  	return nil
   127  }
   128  
   129  func (h *rpcHandler) keyInRegion(key []byte) bool {
   130  	return regionContains(h.startKey, h.endKey, key)
   131  }
   132  
   133  func (h *rpcHandler) onGet(req *kvrpcpb.CmdGetRequest) *kvrpcpb.CmdGetResponse {
   134  	if !h.keyInRegion(req.Key) {
   135  		panic("onGet: key not in region")
   136  	}
   137  
   138  	val, err := h.mvccStore.Get(req.Key, req.GetVersion())
   139  	if err != nil {
   140  		return &kvrpcpb.CmdGetResponse{
   141  			Error: convertToKeyError(err),
   142  		}
   143  	}
   144  	return &kvrpcpb.CmdGetResponse{
   145  		Value: val,
   146  	}
   147  }
   148  
   149  func (h *rpcHandler) onScan(req *kvrpcpb.CmdScanRequest) *kvrpcpb.CmdScanResponse {
   150  	if !h.keyInRegion(req.GetStartKey()) {
   151  		panic("onScan: startKey not in region")
   152  	}
   153  	pairs := h.mvccStore.Scan(req.GetStartKey(), h.endKey, int(req.GetLimit()), req.GetVersion())
   154  	return &kvrpcpb.CmdScanResponse{
   155  		Pairs: convertToPbPairs(pairs),
   156  	}
   157  }
   158  
   159  func (h *rpcHandler) onPrewrite(req *kvrpcpb.CmdPrewriteRequest) *kvrpcpb.CmdPrewriteResponse {
   160  	for _, m := range req.Mutations {
   161  		if !h.keyInRegion(m.Key) {
   162  			panic("onPrewrite: key not in region")
   163  		}
   164  	}
   165  	errors := h.mvccStore.Prewrite(req.Mutations, req.PrimaryLock, req.GetStartVersion())
   166  	return &kvrpcpb.CmdPrewriteResponse{
   167  		Errors: convertToKeyErrors(errors),
   168  	}
   169  }
   170  
   171  func (h *rpcHandler) onCommit(req *kvrpcpb.CmdCommitRequest) *kvrpcpb.CmdCommitResponse {
   172  	for _, k := range req.Keys {
   173  		if !h.keyInRegion(k) {
   174  			panic("onCommit: key not in region")
   175  		}
   176  	}
   177  	var resp kvrpcpb.CmdCommitResponse
   178  	err := h.mvccStore.Commit(req.Keys, req.GetStartVersion(), req.GetCommitVersion())
   179  	if err != nil {
   180  		resp.Error = convertToKeyError(err)
   181  	}
   182  	return &resp
   183  }
   184  
   185  func (h *rpcHandler) onCleanup(req *kvrpcpb.CmdCleanupRequest) *kvrpcpb.CmdCleanupResponse {
   186  	if !h.keyInRegion(req.Key) {
   187  		panic("onCleanup: key not in region")
   188  	}
   189  	var resp kvrpcpb.CmdCleanupResponse
   190  	err := h.mvccStore.Cleanup(req.Key, req.GetStartVersion())
   191  	if err != nil {
   192  		if commitTS, ok := err.(ErrAlreadyCommitted); ok {
   193  			resp.CommitVersion = proto.Uint64(uint64(commitTS))
   194  		} else {
   195  			resp.Error = convertToKeyError(err)
   196  		}
   197  	}
   198  	return &resp
   199  }
   200  
   201  func (h *rpcHandler) onCommitThenGet(req *kvrpcpb.CmdCommitThenGetRequest) *kvrpcpb.CmdCommitThenGetResponse {
   202  	if !h.keyInRegion(req.Key) {
   203  		panic("onCommitThenGet: key not in region")
   204  	}
   205  	val, err := h.mvccStore.CommitThenGet(req.Key, req.GetLockVersion(), req.GetCommitVersion(), req.GetGetVersion())
   206  	if err != nil {
   207  		return &kvrpcpb.CmdCommitThenGetResponse{
   208  			Error: convertToKeyError(err),
   209  		}
   210  	}
   211  	return &kvrpcpb.CmdCommitThenGetResponse{
   212  		Value: val,
   213  	}
   214  }
   215  
   216  func (h *rpcHandler) onRollbackThenGet(req *kvrpcpb.CmdRollbackThenGetRequest) *kvrpcpb.CmdRollbackThenGetResponse {
   217  	if !h.keyInRegion(req.Key) {
   218  		panic("onRollbackThenGet: key not in region")
   219  	}
   220  	val, err := h.mvccStore.RollbackThenGet(req.Key, req.GetLockVersion())
   221  	if err != nil {
   222  		return &kvrpcpb.CmdRollbackThenGetResponse{
   223  			Error: convertToKeyError(err),
   224  		}
   225  	}
   226  	return &kvrpcpb.CmdRollbackThenGetResponse{
   227  		Value: val,
   228  	}
   229  }
   230  
   231  func (h *rpcHandler) onBatchGet(req *kvrpcpb.CmdBatchGetRequest) *kvrpcpb.CmdBatchGetResponse {
   232  	for _, k := range req.Keys {
   233  		if !h.keyInRegion(k) {
   234  			panic("onBatchGet: key not in region")
   235  		}
   236  	}
   237  	pairs := h.mvccStore.BatchGet(req.Keys, req.GetVersion())
   238  	return &kvrpcpb.CmdBatchGetResponse{
   239  		Pairs: convertToPbPairs(pairs),
   240  	}
   241  }
   242  
   243  func convertToKeyError(err error) *kvrpcpb.KeyError {
   244  	if locked, ok := err.(*ErrLocked); ok {
   245  		return &kvrpcpb.KeyError{
   246  			Locked: &kvrpcpb.LockInfo{
   247  				Key:         locked.Key,
   248  				PrimaryLock: locked.Primary,
   249  				LockVersion: proto.Uint64(locked.StartTS),
   250  			},
   251  		}
   252  	}
   253  	if retryable, ok := err.(ErrRetryable); ok {
   254  		return &kvrpcpb.KeyError{
   255  			Retryable: proto.String(retryable.Error()),
   256  		}
   257  	}
   258  	return &kvrpcpb.KeyError{
   259  		Abort: proto.String(err.Error()),
   260  	}
   261  }
   262  
   263  func convertToKeyErrors(errs []error) []*kvrpcpb.KeyError {
   264  	var errors []*kvrpcpb.KeyError
   265  	for _, err := range errs {
   266  		if err != nil {
   267  			errors = append(errors, convertToKeyError(err))
   268  		}
   269  	}
   270  	return errors
   271  }
   272  
   273  func convertToPbPairs(pairs []Pair) []*kvrpcpb.KvPair {
   274  	var kvPairs []*kvrpcpb.KvPair
   275  	for _, p := range pairs {
   276  		var kvPair *kvrpcpb.KvPair
   277  		if p.Err == nil {
   278  			kvPair = &kvrpcpb.KvPair{
   279  				Key:   p.Key,
   280  				Value: p.Value,
   281  			}
   282  		} else {
   283  			kvPair = &kvrpcpb.KvPair{
   284  				Error: convertToKeyError(p.Err),
   285  			}
   286  		}
   287  		kvPairs = append(kvPairs, kvPair)
   288  	}
   289  	return kvPairs
   290  }
   291  
   292  // RPCClient sends kv RPC calls to mock cluster.
   293  type RPCClient struct {
   294  	addr      string
   295  	cluster   *Cluster
   296  	mvccStore *MvccStore
   297  }
   298  
   299  // SendKVReq sends a kv request to mock cluster.
   300  func (c *RPCClient) SendKVReq(req *kvrpcpb.Request) (*kvrpcpb.Response, error) {
   301  	store := c.cluster.GetStoreByAddr(c.addr)
   302  	if store == nil {
   303  		return nil, errors.New("connect fail")
   304  	}
   305  	handler := newRPCHandler(c.cluster, c.mvccStore, store.GetId())
   306  	return handler.handleRequest(req), nil
   307  }
   308  
   309  // SendCopReq sends a coprocessor request to mock cluster.
   310  func (c *RPCClient) SendCopReq(req *coprocessor.Request) (*coprocessor.Response, error) {
   311  	store := c.cluster.GetStoreByAddr(c.addr)
   312  	if store == nil {
   313  		return nil, errors.New("connect fail")
   314  	}
   315  	handler := newRPCHandler(c.cluster, c.mvccStore, store.GetId())
   316  	return handler.handleCopRequest(req)
   317  }
   318  
   319  // Close closes the client.
   320  func (c *RPCClient) Close() error {
   321  	return nil
   322  }
   323  
   324  // NewRPCClient creates an RPCClient.
   325  func NewRPCClient(cluster *Cluster, mvccStore *MvccStore, addr string) *RPCClient {
   326  	return &RPCClient{
   327  		addr:      addr,
   328  		cluster:   cluster,
   329  		mvccStore: mvccStore,
   330  	}
   331  }