github.com/KinWaiYuen/client-go/v2@v2.5.4/internal/mockstore/mocktikv/session.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/mockstore/mocktikv/session.go 19 // 20 21 // Copyright 2021 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 mocktikv 36 37 import ( 38 "github.com/gogo/protobuf/proto" 39 "github.com/pingcap/kvproto/pkg/errorpb" 40 "github.com/pingcap/kvproto/pkg/kvrpcpb" 41 "github.com/pingcap/kvproto/pkg/metapb" 42 ) 43 44 // Session stores session scope rpc data. 45 type Session struct { 46 cluster *Cluster 47 mvccStore MVCCStore 48 49 // storeID stores id for current request 50 storeID uint64 51 // startKey is used for handling normal request. 52 startKey []byte 53 endKey []byte 54 // rawStartKey is used for handling coprocessor request. 55 rawStartKey []byte 56 rawEndKey []byte 57 // isolationLevel is used for current request. 58 isolationLevel kvrpcpb.IsolationLevel 59 resolvedLocks []uint64 60 } 61 62 // GetIsolationLevel returns the session's isolation level. 63 func (s *Session) GetIsolationLevel() kvrpcpb.IsolationLevel { 64 return s.isolationLevel 65 } 66 67 // GetMVCCStore returns the mock mvcc store. 68 func (s *Session) GetMVCCStore() MVCCStore { 69 return s.mvccStore 70 } 71 72 // GetRawStartKey returns the raw start key of the request. 73 func (s *Session) GetRawStartKey() []byte { 74 return s.rawStartKey 75 } 76 77 // GetRawEndKey returns the raw end key of the request. 78 func (s *Session) GetRawEndKey() []byte { 79 return s.rawEndKey 80 } 81 82 // GetResolvedLocks returns the resolved locks of the request. 83 func (s *Session) GetResolvedLocks() []uint64 { 84 return s.resolvedLocks 85 } 86 87 // CheckRequestContext checks if the context matches the request status. 88 func (s *Session) CheckRequestContext(ctx *kvrpcpb.Context) *errorpb.Error { 89 ctxPeer := ctx.GetPeer() 90 if ctxPeer != nil && ctxPeer.GetStoreId() != s.storeID { 91 return &errorpb.Error{ 92 Message: *proto.String("store not match"), 93 StoreNotMatch: &errorpb.StoreNotMatch{}, 94 } 95 } 96 region, leaderID := s.cluster.GetRegion(ctx.GetRegionId()) 97 // No region found. 98 if region == nil { 99 return &errorpb.Error{ 100 Message: *proto.String("region not found"), 101 RegionNotFound: &errorpb.RegionNotFound{ 102 RegionId: *proto.Uint64(ctx.GetRegionId()), 103 }, 104 } 105 } 106 var storePeer, leaderPeer *metapb.Peer 107 for _, p := range region.Peers { 108 if p.GetStoreId() == s.storeID { 109 storePeer = p 110 } 111 if p.GetId() == leaderID { 112 leaderPeer = p 113 } 114 } 115 // The Store does not contain a Peer of the Region. 116 if storePeer == nil { 117 return &errorpb.Error{ 118 Message: *proto.String("region not found"), 119 RegionNotFound: &errorpb.RegionNotFound{ 120 RegionId: *proto.Uint64(ctx.GetRegionId()), 121 }, 122 } 123 } 124 // No leader. 125 if leaderPeer == nil { 126 return &errorpb.Error{ 127 Message: *proto.String("no leader"), 128 NotLeader: &errorpb.NotLeader{ 129 RegionId: *proto.Uint64(ctx.GetRegionId()), 130 }, 131 } 132 } 133 // The Peer on the Store is not leader. If it's tiflash store , we pass this check. 134 if storePeer.GetId() != leaderPeer.GetId() && !isTiFlashStore(s.cluster.GetStore(storePeer.GetStoreId())) { 135 return &errorpb.Error{ 136 Message: *proto.String("not leader"), 137 NotLeader: &errorpb.NotLeader{ 138 RegionId: *proto.Uint64(ctx.GetRegionId()), 139 Leader: leaderPeer, 140 }, 141 } 142 } 143 // Region epoch does not match. 144 if !proto.Equal(region.GetRegionEpoch(), ctx.GetRegionEpoch()) { 145 nextRegion, _ := s.cluster.GetRegionByKey(region.GetEndKey()) 146 currentRegions := []*metapb.Region{region} 147 if nextRegion != nil { 148 currentRegions = append(currentRegions, nextRegion) 149 } 150 return &errorpb.Error{ 151 Message: *proto.String("epoch not match"), 152 EpochNotMatch: &errorpb.EpochNotMatch{ 153 CurrentRegions: currentRegions, 154 }, 155 } 156 } 157 s.startKey, s.endKey = region.StartKey, region.EndKey 158 s.isolationLevel = ctx.IsolationLevel 159 s.resolvedLocks = ctx.ResolvedLocks 160 return nil 161 } 162 163 func (s *Session) checkRequestSize(size int) *errorpb.Error { 164 // TiKV has a limitation on raft log size. 165 // mocktikv has no raft inside, so we check the request's size instead. 166 if size >= requestMaxSize { 167 return &errorpb.Error{ 168 RaftEntryTooLarge: &errorpb.RaftEntryTooLarge{}, 169 } 170 } 171 return nil 172 } 173 174 func (s *Session) checkRequest(ctx *kvrpcpb.Context, size int) *errorpb.Error { 175 if err := s.CheckRequestContext(ctx); err != nil { 176 return err 177 } 178 return s.checkRequestSize(size) 179 } 180 181 func (s *Session) checkKeyInRegion(key []byte) bool { 182 return regionContains(s.startKey, s.endKey, NewMvccKey(key)) 183 } 184 185 func isTiFlashStore(store *metapb.Store) bool { 186 for _, l := range store.GetLabels() { 187 if l.GetKey() == "engine" && l.GetValue() == "tiflash" { 188 return true 189 } 190 } 191 return false 192 }