github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/tikv/mock-tikv/cluster.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 "sync" 18 19 "github.com/insionng/yougam/libraries/golang/protobuf/proto" 20 "github.com/insionng/yougam/libraries/pingcap/kvproto/pkg/metapb" 21 ) 22 23 // Cluster simulates a TiKV cluster. It focuses on management and the change of 24 // meta data. A Cluster mainly includes following 3 kinds of meta data: 25 // 1) Region: A Region is a fragment of TiKV's data whose range is [start, end). 26 // The data of a Region is duplicated to multiple Peers and distributed in 27 // multiple Stores. 28 // 2) Peer: A Peer is a replica of a Region's data. All peers of a Region form 29 // a group, each group elects a Leader to provide services. 30 // 3) Store: A Store is a storage/service node. Try to think it as a TiKV server 31 // process. Only the store with request's Region's leader Peer could respond 32 // to client's request. 33 type Cluster struct { 34 mu sync.RWMutex 35 id uint64 36 stores map[uint64]*Store 37 regions map[uint64]*Region 38 } 39 40 // NewCluster creates an empty cluster. It needs to be bootstrapped before 41 // providing service. 42 func NewCluster() *Cluster { 43 return &Cluster{ 44 stores: make(map[uint64]*Store), 45 regions: make(map[uint64]*Region), 46 } 47 } 48 49 // AllocID creates an unique ID in cluster. The ID could be used as either 50 // StoreID, RegionID, or PeerID. 51 func (c *Cluster) AllocID() uint64 { 52 c.mu.Lock() 53 defer c.mu.Unlock() 54 55 return c.allocID() 56 } 57 58 // AllocIDs creates multiple IDs. 59 func (c *Cluster) AllocIDs(n int) []uint64 { 60 c.mu.Lock() 61 defer c.mu.Unlock() 62 63 var ids []uint64 64 for len(ids) < n { 65 ids = append(ids, c.allocID()) 66 } 67 return ids 68 } 69 70 func (c *Cluster) allocID() uint64 { 71 c.id++ 72 return c.id 73 } 74 75 // GetStore returns a Store's meta. 76 func (c *Cluster) GetStore(storeID uint64) *metapb.Store { 77 c.mu.RLock() 78 defer c.mu.RUnlock() 79 80 if store := c.stores[storeID]; store != nil { 81 return proto.Clone(store.meta).(*metapb.Store) 82 } 83 return nil 84 } 85 86 // GetStoreByAddr returns a Store's meta by an addr. 87 func (c *Cluster) GetStoreByAddr(addr string) *metapb.Store { 88 c.mu.RLock() 89 defer c.mu.RUnlock() 90 91 for _, s := range c.stores { 92 if s.meta.GetAddress() == addr { 93 return proto.Clone(s.meta).(*metapb.Store) 94 } 95 } 96 return nil 97 } 98 99 // AddStore add a new Store to the cluster. 100 func (c *Cluster) AddStore(storeID uint64, addr string) { 101 c.mu.Lock() 102 defer c.mu.Unlock() 103 104 c.stores[storeID] = newStore(storeID, addr) 105 } 106 107 // RemoveStore removes a Store from the cluster. 108 func (c *Cluster) RemoveStore(storeID uint64) { 109 c.mu.Lock() 110 defer c.mu.Unlock() 111 112 delete(c.stores, storeID) 113 } 114 115 // GetRegion returns a Region's meta and leader ID. 116 func (c *Cluster) GetRegion(regionID uint64) (*metapb.Region, uint64) { 117 c.mu.RLock() 118 defer c.mu.RUnlock() 119 120 r := c.regions[regionID] 121 if r == nil { 122 return nil, 0 123 } 124 return proto.Clone(r.meta).(*metapb.Region), r.leader 125 } 126 127 // GetRegionByKey returns the Region whose range contains the key. 128 func (c *Cluster) GetRegionByKey(key []byte) *metapb.Region { 129 c.mu.RLock() 130 defer c.mu.RUnlock() 131 132 for _, r := range c.regions { 133 if regionContains(r.meta.StartKey, r.meta.EndKey, key) { 134 return proto.Clone(r.meta).(*metapb.Region) 135 } 136 } 137 return nil 138 } 139 140 // Bootstrap creates the first Region. The Stores should be in the Cluster before 141 // bootstrap. 142 func (c *Cluster) Bootstrap(regionID uint64, storeIDs, peerIDs []uint64, leaderStoreID uint64) { 143 c.mu.Lock() 144 defer c.mu.Unlock() 145 146 if len(storeIDs) != len(peerIDs) { 147 panic("len(storeIDs) != len(peerIDs)") 148 } 149 c.regions[regionID] = newRegion(regionID, storeIDs, peerIDs, leaderStoreID) 150 } 151 152 // AddPeer adds a new Peer for the Region on the Store. 153 func (c *Cluster) AddPeer(regionID, storeID, peerID uint64) { 154 c.mu.Lock() 155 defer c.mu.Unlock() 156 157 c.regions[regionID].addPeer(peerID, storeID) 158 } 159 160 // RemovePeer removes the Peer from the Region. Note that if the Peer is leader, 161 // the Region will have no leader before calling ChangeLeader(). 162 func (c *Cluster) RemovePeer(regionID, storeID uint64) { 163 c.mu.Lock() 164 defer c.mu.Unlock() 165 166 c.regions[regionID].removePeer(storeID) 167 } 168 169 // ChangeLeader sets the Region's leader Peer. Caller should guarantee the Peer 170 // exists. 171 func (c *Cluster) ChangeLeader(regionID, leaderStoreID uint64) { 172 c.mu.Lock() 173 defer c.mu.Unlock() 174 175 c.regions[regionID].changeLeader(leaderStoreID) 176 } 177 178 // GiveUpLeader sets the Region's leader to 0. The Region will have no leader 179 // before calling ChangeLeader(). 180 func (c *Cluster) GiveUpLeader(regionID uint64) { 181 c.ChangeLeader(regionID, 0) 182 } 183 184 // Split splits a Region at the key and creates new Region. 185 func (c *Cluster) Split(regionID, newRegionID uint64, key []byte, peerIDs []uint64, leaderPeerID uint64) { 186 c.mu.Lock() 187 defer c.mu.Unlock() 188 189 newRegion := c.regions[regionID].split(newRegionID, key, peerIDs, leaderPeerID) 190 c.regions[newRegionID] = newRegion 191 } 192 193 // Merge merges 2 Regions, their key ranges should be adjacent. 194 func (c *Cluster) Merge(regionID1, regionID2 uint64) { 195 c.mu.Lock() 196 defer c.mu.Unlock() 197 198 c.regions[regionID1].merge(c.regions[regionID2].meta.GetEndKey()) 199 delete(c.regions, regionID2) 200 } 201 202 // Region is the Region meta data. 203 type Region struct { 204 meta *metapb.Region 205 leader uint64 206 } 207 208 func newPeerMeta(peerID, storeID uint64) *metapb.Peer { 209 return &metapb.Peer{ 210 Id: proto.Uint64(peerID), 211 StoreId: proto.Uint64(storeID), 212 } 213 } 214 215 func newRegion(regionID uint64, storeIDs, peerIDs []uint64, leaderPeerID uint64) *Region { 216 if len(storeIDs) != len(peerIDs) { 217 panic("len(storeIDs) != len(peerIds)") 218 } 219 var peers []*metapb.Peer 220 for i := range storeIDs { 221 peers = append(peers, newPeerMeta(peerIDs[i], storeIDs[i])) 222 } 223 meta := &metapb.Region{ 224 Id: proto.Uint64(regionID), 225 Peers: peers, 226 } 227 return &Region{ 228 meta: meta, 229 leader: leaderPeerID, 230 } 231 } 232 233 func (r *Region) addPeer(peerID, storeID uint64) { 234 r.meta.Peers = append(r.meta.Peers, newPeerMeta(peerID, storeID)) 235 r.incConfVer() 236 } 237 238 func (r *Region) removePeer(peerID uint64) { 239 for i, peer := range r.meta.Peers { 240 if peer.GetId() == peerID { 241 r.meta.Peers = append(r.meta.Peers[:i], r.meta.Peers[i+1:]...) 242 break 243 } 244 } 245 if r.leader == peerID { 246 r.leader = 0 247 } 248 r.incConfVer() 249 } 250 251 func (r *Region) changeLeader(leaderStoreID uint64) { 252 r.leader = leaderStoreID 253 } 254 255 func (r *Region) split(newRegionID uint64, key []byte, peerIDs []uint64, leaderPeerID uint64) *Region { 256 if len(r.meta.Peers) != len(peerIDs) { 257 panic("len(r.meta.Peers) != len(peerIDs)") 258 } 259 var storeIDs []uint64 260 for _, peer := range r.meta.Peers { 261 storeIDs = append(storeIDs, peer.GetStoreId()) 262 } 263 region := newRegion(newRegionID, storeIDs, peerIDs, leaderPeerID) 264 region.updateKeyRange(key, r.meta.EndKey) 265 r.updateKeyRange(r.meta.StartKey, key) 266 return region 267 } 268 269 func (r *Region) merge(endKey []byte) { 270 r.meta.EndKey = endKey 271 r.incVersion() 272 } 273 274 func (r *Region) updateKeyRange(start, end []byte) { 275 r.meta.StartKey = start 276 r.meta.EndKey = end 277 r.incVersion() 278 } 279 280 func (r *Region) incConfVer() { 281 r.meta.RegionEpoch = &metapb.RegionEpoch{ 282 ConfVer: proto.Uint64(r.meta.GetRegionEpoch().GetConfVer() + 1), 283 Version: proto.Uint64(r.meta.GetRegionEpoch().GetVersion()), 284 } 285 } 286 287 func (r *Region) incVersion() { 288 r.meta.RegionEpoch = &metapb.RegionEpoch{ 289 ConfVer: proto.Uint64(r.meta.GetRegionEpoch().GetConfVer()), 290 Version: proto.Uint64(r.meta.GetRegionEpoch().GetVersion() + 1), 291 } 292 } 293 294 // Store is the Store's meta data. 295 type Store struct { 296 meta *metapb.Store 297 } 298 299 func newStore(storeID uint64, addr string) *Store { 300 return &Store{ 301 meta: &metapb.Store{ 302 Id: proto.Uint64(storeID), 303 Address: proto.String(addr), 304 }, 305 } 306 }