github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/tikv/region_cache.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 tikv 15 16 import ( 17 "bytes" 18 "sync" 19 20 "github.com/insionng/yougam/libraries/juju/errors" 21 "github.com/insionng/yougam/libraries/ngaut/log" 22 "github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/kvrpcpb" 23 "github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/metapb" 24 "github.com/insionng/yougam/libraries/pingcap/pd/pd-client" 25 ) 26 27 // RegionCache store region cache by region id. 28 type RegionCache struct { 29 pdClient pd.Client 30 mu sync.RWMutex 31 // TODO: store in array and use binary search 32 regions map[RegionVerID]*Region 33 } 34 35 // NewRegionCache new region cache. 36 func NewRegionCache(pdClient pd.Client) *RegionCache { 37 return &RegionCache{ 38 pdClient: pdClient, 39 regions: make(map[RegionVerID]*Region), 40 } 41 } 42 43 // GetRegionByVerID finds a Region by Region's verID. 44 func (c *RegionCache) GetRegionByVerID(id RegionVerID) *Region { 45 c.mu.RLock() 46 defer c.mu.RUnlock() 47 48 return c.regions[id] 49 } 50 51 // GetRegion find in cache, or get new region. 52 func (c *RegionCache) GetRegion(key []byte) (*Region, error) { 53 if r := c.getRegionFromCache(key); r != nil { 54 return r, nil 55 } 56 r, err := c.loadRegion(key) 57 return r, errors.Trace(err) 58 } 59 60 // DropRegion remove some region cache. 61 func (c *RegionCache) DropRegion(id RegionVerID) { 62 c.mu.Lock() 63 defer c.mu.Unlock() 64 65 delete(c.regions, id) 66 } 67 68 // NextPeer picks next peer as new leader, if out of range of peers delete region. 69 func (c *RegionCache) NextPeer(id RegionVerID) { 70 // A and B get the same region and current leader is 1, they both will pick 71 // peer 2 as leader. 72 region := c.GetRegionByVerID(id) 73 if region == nil { 74 return 75 } 76 if leader, err := region.NextPeer(); err != nil { 77 c.mu.Lock() 78 delete(c.regions, id) 79 c.mu.Unlock() 80 } else { 81 c.UpdateLeader(id, leader.GetId()) 82 } 83 } 84 85 // UpdateLeader update some region cache with newer leader info. 86 func (c *RegionCache) UpdateLeader(regionID RegionVerID, leaderID uint64) { 87 old := c.GetRegionByVerID(regionID) 88 if old == nil { 89 log.Debugf("regionCache: cannot find region when updating leader %d,%d", regionID, leaderID) 90 return 91 } 92 var ( 93 peer *metapb.Peer 94 store *metapb.Store 95 err error 96 ) 97 98 curPeerIdx := -1 99 for idx, p := range old.meta.Peers { 100 if p.GetId() == leaderID { 101 peer = p 102 // No need update leader. 103 if idx == old.curPeerIdx { 104 return 105 } 106 curPeerIdx = idx 107 break 108 } 109 } 110 if peer != nil { 111 store, err = c.pdClient.GetStore(peer.GetStoreId()) 112 } 113 114 c.mu.Lock() 115 defer c.mu.Unlock() 116 delete(c.regions, regionID) 117 118 if peer == nil || err != nil { 119 // Can't find the peer in cache, or error occurs when loading 120 // store from PD. 121 // Leave the region deleted, it will be filled later. 122 return 123 } 124 125 c.regions[regionID] = &Region{ 126 meta: old.meta, 127 peer: peer, 128 addr: store.GetAddress(), 129 curPeerIdx: curPeerIdx, 130 } 131 } 132 133 // getRegionFromCache scan all region cache and find which region contains key. 134 func (c *RegionCache) getRegionFromCache(key []byte) *Region { 135 c.mu.RLock() 136 defer c.mu.RUnlock() 137 138 for _, r := range c.regions { 139 if r.Contains(key) { 140 return r 141 } 142 } 143 return nil 144 } 145 146 // loadRegion get region from pd client, and pick the random peer as leader. 147 func (c *RegionCache) loadRegion(key []byte) (*Region, error) { 148 meta, err := c.pdClient.GetRegion(key) 149 if err != nil { 150 // We assume PD will recover soon. 151 return nil, errors.Annotate(err, txnRetryableMark) 152 } 153 if len(meta.Peers) == 0 { 154 return nil, errors.New("receive Region with no peer") 155 } 156 curPeerIdx := 0 157 peer := meta.Peers[curPeerIdx] 158 store, err := c.pdClient.GetStore(peer.GetStoreId()) 159 if err != nil { 160 // We assume PD will recover soon. 161 return nil, errors.Annotate(err, txnRetryableMark) 162 } 163 region := &Region{ 164 meta: meta, 165 peer: peer, 166 addr: store.GetAddress(), 167 curPeerIdx: curPeerIdx, 168 } 169 170 c.mu.Lock() 171 defer c.mu.Unlock() 172 173 if r, ok := c.regions[region.VerID()]; ok { 174 return r, nil 175 } 176 c.regions[region.VerID()] = region 177 return region, nil 178 } 179 180 // Region stores region info. Region is a readonly class. 181 type Region struct { 182 meta *metapb.Region 183 peer *metapb.Peer 184 addr string 185 curPeerIdx int 186 } 187 188 // GetID returns id. 189 func (r *Region) GetID() uint64 { 190 return r.meta.GetId() 191 } 192 193 // RegionVerID is a unique ID that can identify a Region at a specific version. 194 type RegionVerID struct { 195 id uint64 196 confVer uint64 197 ver uint64 198 } 199 200 // VerID returns the Region's RegionVerID. 201 func (r *Region) VerID() RegionVerID { 202 return RegionVerID{ 203 id: r.meta.GetId(), 204 confVer: r.meta.GetRegionEpoch().GetConfVer(), 205 ver: r.meta.GetRegionEpoch().GetVersion(), 206 } 207 } 208 209 // StartKey returns StartKey. 210 func (r *Region) StartKey() []byte { 211 return r.meta.StartKey 212 } 213 214 // EndKey returns EndKey. 215 func (r *Region) EndKey() []byte { 216 return r.meta.EndKey 217 } 218 219 // GetAddress returns address. 220 func (r *Region) GetAddress() string { 221 return r.addr 222 } 223 224 // GetContext constructs kvprotopb.Context from region info. 225 func (r *Region) GetContext() *kvrpcpb.Context { 226 return &kvrpcpb.Context{ 227 RegionId: r.meta.Id, 228 RegionEpoch: r.meta.RegionEpoch, 229 Peer: r.peer, 230 } 231 } 232 233 // Contains checks whether the key is in the region, for the maximum region endKey is empty. 234 // startKey <= key < endKey. 235 func (r *Region) Contains(key []byte) bool { 236 return bytes.Compare(r.meta.GetStartKey(), key) <= 0 && 237 (bytes.Compare(key, r.meta.GetEndKey()) < 0 || len(r.meta.GetEndKey()) == 0) 238 } 239 240 // NextPeer picks next peer as leader, if out of range return error. 241 func (r *Region) NextPeer() (*metapb.Peer, error) { 242 nextPeerIdx := r.curPeerIdx + 1 243 if nextPeerIdx >= len(r.meta.Peers) { 244 return nil, errors.New("out of range of peer") 245 } 246 return r.meta.Peers[nextPeerIdx], nil 247 } 248 249 // regionMissBackoff is for region cache miss retry. 250 func regionMissBackoff() func() error { 251 const ( 252 maxRetry = 2 253 sleepBase = 1 254 sleepCap = 1 255 ) 256 return NewBackoff(maxRetry, sleepBase, sleepCap, NoJitter) 257 }