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 }