github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/database/cache.go (about)

     1  package database
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/golang/groupcache/lru"
     8  	"github.com/golang/groupcache/singleflight"
     9  
    10  	"github.com/bytom/bytom/protocol/bc"
    11  	"github.com/bytom/bytom/protocol/bc/types"
    12  )
    13  
    14  const maxCachedBlocks = 30
    15  
    16  func newBlockCache(fillFn func(hash *bc.Hash) (*types.Block, error)) blockCache {
    17  	return blockCache{
    18  		lru:    lru.New(maxCachedBlocks),
    19  		fillFn: fillFn,
    20  	}
    21  }
    22  
    23  type blockCache struct {
    24  	mu     sync.Mutex
    25  	lru    *lru.Cache
    26  	fillFn func(hash *bc.Hash) (*types.Block, error)
    27  	single singleflight.Group
    28  }
    29  
    30  func (c *blockCache) lookup(hash *bc.Hash) (*types.Block, error) {
    31  	if b, ok := c.get(hash); ok {
    32  		return b, nil
    33  	}
    34  
    35  	block, err := c.single.Do(hash.String(), func() (interface{}, error) {
    36  		b, err := c.fillFn(hash)
    37  		if err != nil {
    38  			return nil, err
    39  		}
    40  		
    41  		if b == nil {
    42  			return nil, fmt.Errorf("There are no block with given hash %s", hash.String())
    43  		}
    44  
    45  		c.add(b)
    46  		return b, nil
    47  	})
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	return block.(*types.Block), nil
    52  }
    53  
    54  func (c *blockCache) get(hash *bc.Hash) (*types.Block, bool) {
    55  	c.mu.Lock()
    56  	block, ok := c.lru.Get(*hash)
    57  	c.mu.Unlock()
    58  	if block == nil {
    59  		return nil, ok
    60  	}
    61  	return block.(*types.Block), ok
    62  }
    63  
    64  func (c *blockCache) add(block *types.Block) {
    65  	c.mu.Lock()
    66  	c.lru.Add(block.Hash(), block)
    67  	c.mu.Unlock()
    68  }