github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/database/cache.go (about)

     1  package database
     2  
     3  import (
     4  	"encoding/hex"
     5  	"strconv"
     6  
     7  	"github.com/golang/groupcache/singleflight"
     8  
     9  	"github.com/bytom/bytom/common"
    10  	"github.com/bytom/bytom/protocol/bc"
    11  	"github.com/bytom/bytom/protocol/bc/types"
    12  	"github.com/bytom/bytom/protocol/state"
    13  )
    14  
    15  const (
    16  	maxCachedBlockHeaders      = 2048
    17  	maxCachedBlockTransactions = 1024
    18  	maxCachedBlockHashes       = 1024
    19  	maxCachedMainChainHashes   = 1024
    20  	maxCheckPoints             = 256
    21  )
    22  
    23  type fillBlockHeaderFn func(hash *bc.Hash) (*types.BlockHeader, error)
    24  type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error)
    25  type fillBlockHashesFn func(height uint64) ([]*bc.Hash, error)
    26  type fillMainChainHashFn func(height uint64) (*bc.Hash, error)
    27  type fillCheckPointFn func(key []byte) (*state.Checkpoint, error)
    28  
    29  func newCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillBlockHashes fillBlockHashesFn, fillMainChainHash fillMainChainHashFn, fillCheckPoint fillCheckPointFn) cache {
    30  	return cache{
    31  		lruBlockHeaders:    common.NewCache(maxCachedBlockHeaders),
    32  		lruBlockTxs:        common.NewCache(maxCachedBlockTransactions),
    33  		lruBlockHashes:     common.NewCache(maxCachedBlockHashes),
    34  		lruMainChainHashes: common.NewCache(maxCachedMainChainHashes),
    35  		lruCheckPoints:     common.NewCache(maxCheckPoints),
    36  
    37  		fillBlockHeaderFn:      fillBlockHeader,
    38  		fillBlockTransactionFn: fillBlockTxs,
    39  		fillBlockHashesFn:      fillBlockHashes,
    40  		fillMainChainHashFn:    fillMainChainHash,
    41  		fillCheckPointFn:       fillCheckPoint,
    42  	}
    43  }
    44  
    45  type cache struct {
    46  	lruBlockHeaders    *common.Cache
    47  	lruBlockTxs        *common.Cache
    48  	lruBlockHashes     *common.Cache
    49  	lruMainChainHashes *common.Cache
    50  	lruCheckPoints     *common.Cache
    51  
    52  	fillBlockHashesFn      func(uint64) ([]*bc.Hash, error)
    53  	fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error)
    54  	fillBlockHeaderFn      func(hash *bc.Hash) (*types.BlockHeader, error)
    55  	fillMainChainHashFn    func(uint64) (*bc.Hash, error)
    56  	fillCheckPointFn       func(key []byte) (*state.Checkpoint, error)
    57  
    58  	sf singleflight.Group
    59  }
    60  
    61  func (c *cache) removeBlockHeader(blockHeader *types.BlockHeader) {
    62  	c.lruBlockHeaders.Remove(blockHeader.Hash())
    63  }
    64  
    65  func (c *cache) lookupBlockHashesByHeight(height uint64) ([]*bc.Hash, error) {
    66  	if hashes, ok := c.lruBlockHashes.Get(height); ok {
    67  		return hashes.([]*bc.Hash), nil
    68  	}
    69  
    70  	heightStr := strconv.FormatUint(height, 10)
    71  	hashes, err := c.sf.Do("BlockHashesByHeight:"+heightStr, func() (interface{}, error) {
    72  		hashes, err := c.fillBlockHashesFn(height)
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  
    77  		c.lruBlockHashes.Add(height, hashes)
    78  		return hashes, nil
    79  	})
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	return hashes.([]*bc.Hash), nil
    85  }
    86  
    87  func (c *cache) removeBlockHashes(height uint64) {
    88  	c.lruBlockHashes.Remove(height)
    89  }
    90  
    91  func (c *cache) lookupBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
    92  	if data, ok := c.lruBlockHeaders.Get(*hash); ok {
    93  		return data.(*types.BlockHeader), nil
    94  	}
    95  
    96  	blockHeader, err := c.sf.Do("BlockHeader:"+hash.String(), func() (interface{}, error) {
    97  		blockHeader, err := c.fillBlockHeaderFn(hash)
    98  		if err != nil {
    99  			return nil, err
   100  		}
   101  
   102  		c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader)
   103  		return blockHeader, nil
   104  	})
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	return blockHeader.(*types.BlockHeader), nil
   109  }
   110  
   111  func (c *cache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) {
   112  	if data, ok := c.lruBlockTxs.Get(*hash); ok {
   113  		return data.([]*types.Tx), nil
   114  	}
   115  
   116  	blockTxs, err := c.sf.Do("BlockTxs:"+hash.String(), func() (interface{}, error) {
   117  		blockTxs, err := c.fillBlockTransactionFn(hash)
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  
   122  		c.lruBlockTxs.Add(*hash, blockTxs)
   123  		return blockTxs, nil
   124  	})
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	return blockTxs.([]*types.Tx), nil
   129  }
   130  
   131  func (c *cache) lookupMainChainHash(height uint64) (*bc.Hash, error) {
   132  	if hash, ok := c.lruMainChainHashes.Get(height); ok {
   133  		return hash.(*bc.Hash), nil
   134  	}
   135  
   136  	heightStr := strconv.FormatUint(height, 10)
   137  	hash, err := c.sf.Do("BlockHashByHeight:"+heightStr, func() (interface{}, error) {
   138  		hash, err := c.fillMainChainHashFn(height)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  
   143  		c.lruMainChainHashes.Add(height, hash)
   144  		return hash, nil
   145  	})
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	return hash.(*bc.Hash), nil
   151  }
   152  
   153  func (c *cache) removeMainChainHash(height uint64) {
   154  	c.lruMainChainHashes.Remove(height)
   155  }
   156  
   157  func (c *cache) lookupCheckPoint(key []byte) (*state.Checkpoint, error) {
   158  	keyStr := hex.EncodeToString(key)
   159  	if data, ok := c.lruCheckPoints.Get(keyStr); ok {
   160  		return data.(*state.Checkpoint), nil
   161  	}
   162  
   163  	checkpoint, err := c.sf.Do("CheckPoint:"+string(key), func() (interface{}, error) {
   164  		checkPoint, err := c.fillCheckPointFn(key)
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  
   169  		c.lruCheckPoints.Add(keyStr, checkPoint)
   170  		return checkPoint, nil
   171  	})
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	return checkpoint.(*state.Checkpoint), nil
   177  }
   178  
   179  func (c *cache) removeCheckPoint(key []byte) {
   180  	c.lruCheckPoints.Remove(hex.EncodeToString(key))
   181  }