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  }