github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/groupcache/groupcache.go (about)

     1  /*
     2  Copyright 2012 Google Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package groupcache provides a data loading mechanism with caching
    18  // and de-duplication that works across a set of peer processes.
    19  //
    20  // Each data Get first consults its local cache, otherwise delegates
    21  // to the requested key's canonical owner, which then checks its cache
    22  // or finally gets the data.  In the common case, many concurrent
    23  // cache misses across a set of peers for the same key result in just
    24  // one cache fill.
    25  package groupcache
    26  
    27  import (
    28  	"errors"
    29  	"math/rand"
    30  	"strconv"
    31  	"sync"
    32  	"sync/atomic"
    33  
    34  	pb "github.com/insionng/yougam/libraries/golang/groupcache/groupcachepb"
    35  	"github.com/insionng/yougam/libraries/golang/groupcache/lru"
    36  	"github.com/insionng/yougam/libraries/golang/groupcache/singleflight"
    37  )
    38  
    39  // A Getter loads data for a key.
    40  type Getter interface {
    41  	// Get returns the value identified by key, populating dest.
    42  	//
    43  	// The returned data must be unversioned. That is, key must
    44  	// uniquely describe the loaded data, without an implicit
    45  	// current time, and without relying on cache expiration
    46  	// mechanisms.
    47  	Get(ctx Context, key string, dest Sink) error
    48  }
    49  
    50  // A GetterFunc implements Getter with a function.
    51  type GetterFunc func(ctx Context, key string, dest Sink) error
    52  
    53  func (f GetterFunc) Get(ctx Context, key string, dest Sink) error {
    54  	return f(ctx, key, dest)
    55  }
    56  
    57  var (
    58  	mu     sync.RWMutex
    59  	groups = make(map[string]*Group)
    60  
    61  	initPeerServerOnce sync.Once
    62  	initPeerServer     func()
    63  )
    64  
    65  // GetGroup returns the named group previously created with NewGroup, or
    66  // nil if there's no such group.
    67  func GetGroup(name string) *Group {
    68  	mu.RLock()
    69  	g := groups[name]
    70  	mu.RUnlock()
    71  	return g
    72  }
    73  
    74  // NewGroup creates a coordinated group-aware Getter from a Getter.
    75  //
    76  // The returned Getter tries (but does not guarantee) to run only one
    77  // Get call at once for a given key across an entire set of peer
    78  // processes. Concurrent callers both in the local process and in
    79  // other processes receive copies of the answer once the original Get
    80  // completes.
    81  //
    82  // The group name must be unique for each getter.
    83  func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
    84  	return newGroup(name, cacheBytes, getter, nil)
    85  }
    86  
    87  // If peers is nil, the peerPicker is called via a sync.Once to initialize it.
    88  func newGroup(name string, cacheBytes int64, getter Getter, peers PeerPicker) *Group {
    89  	if getter == nil {
    90  		panic("nil Getter")
    91  	}
    92  	mu.Lock()
    93  	defer mu.Unlock()
    94  	initPeerServerOnce.Do(callInitPeerServer)
    95  	if _, dup := groups[name]; dup {
    96  		panic("duplicate registration of group " + name)
    97  	}
    98  	g := &Group{
    99  		name:       name,
   100  		getter:     getter,
   101  		peers:      peers,
   102  		cacheBytes: cacheBytes,
   103  		loadGroup:  &singleflight.Group{},
   104  	}
   105  	if fn := newGroupHook; fn != nil {
   106  		fn(g)
   107  	}
   108  	groups[name] = g
   109  	return g
   110  }
   111  
   112  // newGroupHook, if non-nil, is called right after a new group is created.
   113  var newGroupHook func(*Group)
   114  
   115  // RegisterNewGroupHook registers a hook that is run each time
   116  // a group is created.
   117  func RegisterNewGroupHook(fn func(*Group)) {
   118  	if newGroupHook != nil {
   119  		panic("RegisterNewGroupHook called more than once")
   120  	}
   121  	newGroupHook = fn
   122  }
   123  
   124  // RegisterServerStart registers a hook that is run when the first
   125  // group is created.
   126  func RegisterServerStart(fn func()) {
   127  	if initPeerServer != nil {
   128  		panic("RegisterServerStart called more than once")
   129  	}
   130  	initPeerServer = fn
   131  }
   132  
   133  func callInitPeerServer() {
   134  	if initPeerServer != nil {
   135  		initPeerServer()
   136  	}
   137  }
   138  
   139  // A Group is a cache namespace and associated data loaded spread over
   140  // a group of 1 or more machines.
   141  type Group struct {
   142  	name       string
   143  	getter     Getter
   144  	peersOnce  sync.Once
   145  	peers      PeerPicker
   146  	cacheBytes int64 // limit for sum of mainCache and hotCache size
   147  
   148  	// mainCache is a cache of the keys for which this process
   149  	// (amongst its peers) is authorative. That is, this cache
   150  	// contains keys which consistent hash on to this process's
   151  	// peer number.
   152  	mainCache cache
   153  
   154  	// hotCache contains keys/values for which this peer is not
   155  	// authorative (otherwise they would be in mainCache), but
   156  	// are popular enough to warrant mirroring in this process to
   157  	// avoid going over the network to fetch from a peer.  Having
   158  	// a hotCache avoids network hotspotting, where a peer's
   159  	// network card could become the bottleneck on a popular key.
   160  	// This cache is used sparingly to maximize the total number
   161  	// of key/value pairs that can be stored globally.
   162  	hotCache cache
   163  
   164  	// loadGroup ensures that each key is only fetched once
   165  	// (either locally or remotely), regardless of the number of
   166  	// concurrent callers.
   167  	loadGroup flightGroup
   168  
   169  	// Stats are statistics on the group.
   170  	Stats Stats
   171  }
   172  
   173  // flightGroup is defined as an interface which flightgroup.Group
   174  // satisfies.  We define this so that we may test with an alternate
   175  // implementation.
   176  type flightGroup interface {
   177  	// Done is called when Do is done.
   178  	Do(key string, fn func() (interface{}, error)) (interface{}, error)
   179  }
   180  
   181  // Stats are per-group statistics.
   182  type Stats struct {
   183  	Gets           AtomicInt // any Get request, including from peers
   184  	CacheHits      AtomicInt // either cache was good
   185  	PeerLoads      AtomicInt // either remote load or remote cache hit (not an error)
   186  	PeerErrors     AtomicInt
   187  	Loads          AtomicInt // (gets - cacheHits)
   188  	LoadsDeduped   AtomicInt // after singleflight
   189  	LocalLoads     AtomicInt // total good local loads
   190  	LocalLoadErrs  AtomicInt // total bad local loads
   191  	ServerRequests AtomicInt // gets that came over the network from peers
   192  }
   193  
   194  // Name returns the name of the group.
   195  func (g *Group) Name() string {
   196  	return g.name
   197  }
   198  
   199  func (g *Group) initPeers() {
   200  	if g.peers == nil {
   201  		g.peers = getPeers()
   202  	}
   203  }
   204  
   205  func (g *Group) Get(ctx Context, key string, dest Sink) error {
   206  	g.peersOnce.Do(g.initPeers)
   207  	g.Stats.Gets.Add(1)
   208  	if dest == nil {
   209  		return errors.New("groupcache: nil dest Sink")
   210  	}
   211  	value, cacheHit := g.lookupCache(key)
   212  
   213  	if cacheHit {
   214  		g.Stats.CacheHits.Add(1)
   215  		return setSinkView(dest, value)
   216  	}
   217  
   218  	// Optimization to avoid double unmarshalling or copying: keep
   219  	// track of whether the dest was already populated. One caller
   220  	// (if local) will set this; the losers will not. The common
   221  	// case will likely be one caller.
   222  	destPopulated := false
   223  	value, destPopulated, err := g.load(ctx, key, dest)
   224  	if err != nil {
   225  		return err
   226  	}
   227  	if destPopulated {
   228  		return nil
   229  	}
   230  	return setSinkView(dest, value)
   231  }
   232  
   233  // load loads key either by invoking the getter locally or by sending it to another machine.
   234  func (g *Group) load(ctx Context, key string, dest Sink) (value ByteView, destPopulated bool, err error) {
   235  	g.Stats.Loads.Add(1)
   236  	viewi, err := g.loadGroup.Do(key, func() (interface{}, error) {
   237  		// Check the cache again because singleflight can only dedup calls
   238  		// that overlap concurrently.  It's possible for 2 concurrent
   239  		// requests to miss the cache, resulting in 2 load() calls.  An
   240  		// unfortunate goroutine scheduling would result in this callback
   241  		// being run twice, serially.  If we don't check the cache again,
   242  		// cache.nbytes would be incremented below even though there will
   243  		// be only one entry for this key.
   244  		//
   245  		// Consider the following serialized event ordering for two
   246  		// goroutines in which this callback gets called twice for hte
   247  		// same key:
   248  		// 1: Get("key")
   249  		// 2: Get("key")
   250  		// 1: lookupCache("key")
   251  		// 2: lookupCache("key")
   252  		// 1: load("key")
   253  		// 2: load("key")
   254  		// 1: loadGroup.Do("key", fn)
   255  		// 1: fn()
   256  		// 2: loadGroup.Do("key", fn)
   257  		// 2: fn()
   258  		if value, cacheHit := g.lookupCache(key); cacheHit {
   259  			g.Stats.CacheHits.Add(1)
   260  			return value, nil
   261  		}
   262  		g.Stats.LoadsDeduped.Add(1)
   263  		var value ByteView
   264  		var err error
   265  		if peer, ok := g.peers.PickPeer(key); ok {
   266  			value, err = g.getFromPeer(ctx, peer, key)
   267  			if err == nil {
   268  				g.Stats.PeerLoads.Add(1)
   269  				return value, nil
   270  			}
   271  			g.Stats.PeerErrors.Add(1)
   272  			// TODO(bradfitz): log the peer's error? keep
   273  			// log of the past few for /groupcachez?  It's
   274  			// probably boring (normal task movement), so not
   275  			// worth logging I imagine.
   276  		}
   277  		value, err = g.getLocally(ctx, key, dest)
   278  		if err != nil {
   279  			g.Stats.LocalLoadErrs.Add(1)
   280  			return nil, err
   281  		}
   282  		g.Stats.LocalLoads.Add(1)
   283  		destPopulated = true // only one caller of load gets this return value
   284  		g.populateCache(key, value, &g.mainCache)
   285  		return value, nil
   286  	})
   287  	if err == nil {
   288  		value = viewi.(ByteView)
   289  	}
   290  	return
   291  }
   292  
   293  func (g *Group) getLocally(ctx Context, key string, dest Sink) (ByteView, error) {
   294  	err := g.getter.Get(ctx, key, dest)
   295  	if err != nil {
   296  		return ByteView{}, err
   297  	}
   298  	return dest.view()
   299  }
   300  
   301  func (g *Group) getFromPeer(ctx Context, peer ProtoGetter, key string) (ByteView, error) {
   302  	req := &pb.GetRequest{
   303  		Group: &g.name,
   304  		Key:   &key,
   305  	}
   306  	res := &pb.GetResponse{}
   307  	err := peer.Get(ctx, req, res)
   308  	if err != nil {
   309  		return ByteView{}, err
   310  	}
   311  	value := ByteView{b: res.Value}
   312  	// TODO(bradfitz): use res.MinuteQps or something smart to
   313  	// conditionally populate hotCache.  For now just do it some
   314  	// percentage of the time.
   315  	if rand.Intn(10) == 0 {
   316  		g.populateCache(key, value, &g.hotCache)
   317  	}
   318  	return value, nil
   319  }
   320  
   321  func (g *Group) lookupCache(key string) (value ByteView, ok bool) {
   322  	if g.cacheBytes <= 0 {
   323  		return
   324  	}
   325  	value, ok = g.mainCache.get(key)
   326  	if ok {
   327  		return
   328  	}
   329  	value, ok = g.hotCache.get(key)
   330  	return
   331  }
   332  
   333  func (g *Group) populateCache(key string, value ByteView, cache *cache) {
   334  	if g.cacheBytes <= 0 {
   335  		return
   336  	}
   337  	cache.add(key, value)
   338  
   339  	// Evict items from cache(s) if necessary.
   340  	for {
   341  		mainBytes := g.mainCache.bytes()
   342  		hotBytes := g.hotCache.bytes()
   343  		if mainBytes+hotBytes <= g.cacheBytes {
   344  			return
   345  		}
   346  
   347  		// TODO(bradfitz): this is good-enough-for-now logic.
   348  		// It should be something based on measurements and/or
   349  		// respecting the costs of different resources.
   350  		victim := &g.mainCache
   351  		if hotBytes > mainBytes/8 {
   352  			victim = &g.hotCache
   353  		}
   354  		victim.removeOldest()
   355  	}
   356  }
   357  
   358  // CacheType represents a type of cache.
   359  type CacheType int
   360  
   361  const (
   362  	// The MainCache is the cache for items that this peer is the
   363  	// owner for.
   364  	MainCache CacheType = iota + 1
   365  
   366  	// The HotCache is the cache for items that seem popular
   367  	// enough to replicate to this node, even though it's not the
   368  	// owner.
   369  	HotCache
   370  )
   371  
   372  // CacheStats returns stats about the provided cache within the group.
   373  func (g *Group) CacheStats(which CacheType) CacheStats {
   374  	switch which {
   375  	case MainCache:
   376  		return g.mainCache.stats()
   377  	case HotCache:
   378  		return g.hotCache.stats()
   379  	default:
   380  		return CacheStats{}
   381  	}
   382  }
   383  
   384  // cache is a wrapper around an *lru.Cache that adds synchronization,
   385  // makes values always be ByteView, and counts the size of all keys and
   386  // values.
   387  type cache struct {
   388  	mu         sync.RWMutex
   389  	nbytes     int64 // of all keys and values
   390  	lru        *lru.Cache
   391  	nhit, nget int64
   392  	nevict     int64 // number of evictions
   393  }
   394  
   395  func (c *cache) stats() CacheStats {
   396  	c.mu.RLock()
   397  	defer c.mu.RUnlock()
   398  	return CacheStats{
   399  		Bytes:     c.nbytes,
   400  		Items:     c.itemsLocked(),
   401  		Gets:      c.nget,
   402  		Hits:      c.nhit,
   403  		Evictions: c.nevict,
   404  	}
   405  }
   406  
   407  func (c *cache) add(key string, value ByteView) {
   408  	c.mu.Lock()
   409  	defer c.mu.Unlock()
   410  	if c.lru == nil {
   411  		c.lru = &lru.Cache{
   412  			OnEvicted: func(key lru.Key, value interface{}) {
   413  				val := value.(ByteView)
   414  				c.nbytes -= int64(len(key.(string))) + int64(val.Len())
   415  				c.nevict++
   416  			},
   417  		}
   418  	}
   419  	c.lru.Add(key, value)
   420  	c.nbytes += int64(len(key)) + int64(value.Len())
   421  }
   422  
   423  func (c *cache) get(key string) (value ByteView, ok bool) {
   424  	c.mu.Lock()
   425  	defer c.mu.Unlock()
   426  	c.nget++
   427  	if c.lru == nil {
   428  		return
   429  	}
   430  	vi, ok := c.lru.Get(key)
   431  	if !ok {
   432  		return
   433  	}
   434  	c.nhit++
   435  	return vi.(ByteView), true
   436  }
   437  
   438  func (c *cache) removeOldest() {
   439  	c.mu.Lock()
   440  	defer c.mu.Unlock()
   441  	if c.lru != nil {
   442  		c.lru.RemoveOldest()
   443  	}
   444  }
   445  
   446  func (c *cache) bytes() int64 {
   447  	c.mu.RLock()
   448  	defer c.mu.RUnlock()
   449  	return c.nbytes
   450  }
   451  
   452  func (c *cache) items() int64 {
   453  	c.mu.RLock()
   454  	defer c.mu.RUnlock()
   455  	return c.itemsLocked()
   456  }
   457  
   458  func (c *cache) itemsLocked() int64 {
   459  	if c.lru == nil {
   460  		return 0
   461  	}
   462  	return int64(c.lru.Len())
   463  }
   464  
   465  // An AtomicInt is an int64 to be accessed atomically.
   466  type AtomicInt int64
   467  
   468  // Add atomically adds n to i.
   469  func (i *AtomicInt) Add(n int64) {
   470  	atomic.AddInt64((*int64)(i), n)
   471  }
   472  
   473  // Get atomically gets the value of i.
   474  func (i *AtomicInt) Get() int64 {
   475  	return atomic.LoadInt64((*int64)(i))
   476  }
   477  
   478  func (i *AtomicInt) String() string {
   479  	return strconv.FormatInt(i.Get(), 10)
   480  }
   481  
   482  // CacheStats are returned by stats accessors on Group.
   483  type CacheStats struct {
   484  	Bytes     int64
   485  	Items     int64
   486  	Gets      int64
   487  	Hits      int64
   488  	Evictions int64
   489  }