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  }