OSDN Git Service

split block (#180)
[bytom/vapor.git] / database / cache.go
index c963f25..a525262 100644 (file)
@@ -2,67 +2,111 @@ package database
 
 import (
        "fmt"
-       "sync"
 
-       "github.com/golang/groupcache/lru"
        "github.com/golang/groupcache/singleflight"
 
+       "github.com/vapor/common"
        "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/bc/types"
 )
 
-const maxCachedBlocks = 30
+const (
+       maxCachedBlockHeaders      = 1000
+       maxCachedBlockTransactions = 1000
+)
+
+type fillBlockHeaderFn func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
+type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error)
 
-func newBlockCache(fillFn func(hash *bc.Hash) (*types.Block, error)) blockCache {
+func newBlockCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn) blockCache {
        return blockCache{
-               lru:    lru.New(maxCachedBlocks),
-               fillFn: fillFn,
+               lruBlockHeaders: common.NewCache(maxCachedBlockHeaders),
+               lruBlockTxs:     common.NewCache(maxCachedBlockTransactions),
+
+               fillBlockHeaderFn:      fillBlockHeader,
+               fillBlockTransactionFn: fillBlockTxs,
        }
 }
 
 type blockCache struct {
-       mu     sync.Mutex
-       lru    *lru.Cache
-       fillFn func(hash *bc.Hash) (*types.Block, error)
-       single singleflight.Group
+       lruBlockHeaders *common.Cache
+       lruBlockTxs     *common.Cache
+
+       fillBlockHeaderFn      func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
+       fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error)
+
+       singleBlockHeader singleflight.Group
+       singleBlockTxs    singleflight.Group
 }
 
-func (c *blockCache) lookup(hash *bc.Hash) (*types.Block, error) {
-       if b, ok := c.get(hash); ok {
-               return b, nil
+func (c *blockCache) lookupBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
+       if bH, ok := c.getBlockHeader(hash); ok {
+               return bH, nil
        }
 
-       block, err := c.single.Do(hash.String(), func() (interface{}, error) {
-               b, err := c.fillFn(hash)
+       blockHeader, err := c.singleBlockHeader.Do(hash.String(), func() (interface{}, error) {
+               bH, err := c.fillBlockHeaderFn(hash, height)
                if err != nil {
                        return nil, err
                }
 
-               if b == nil {
-                       return nil, fmt.Errorf("There are no block with given hash %s", hash.String())
+               if bH == nil {
+                       return nil, fmt.Errorf("There are no blockHeader with given hash %s", hash.String())
                }
 
-               c.add(b)
-               return b, nil
+               c.addBlockHeader(bH)
+               return bH, nil
        })
        if err != nil {
                return nil, err
        }
-       return block.(*types.Block), nil
+       return blockHeader.(*types.BlockHeader), nil
 }
 
-func (c *blockCache) get(hash *bc.Hash) (*types.Block, bool) {
-       c.mu.Lock()
-       block, ok := c.lru.Get(*hash)
-       c.mu.Unlock()
-       if block == nil {
+func (c *blockCache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) {
+       if bTxs, ok := c.getBlockTransactions(hash); ok {
+               return bTxs, nil
+       }
+
+       blockTransactions, err := c.singleBlockTxs.Do(hash.String(), func() (interface{}, error) {
+               bTxs, err := c.fillBlockTransactionFn(hash)
+               if err != nil {
+                       return nil, err
+               }
+
+               if bTxs == nil {
+                       return nil, fmt.Errorf("There are no block transactions with given hash %s", hash.String())
+               }
+
+               c.addBlockTxs(*hash, bTxs)
+               return bTxs, nil
+       })
+       if err != nil {
+               return nil, err
+       }
+       return blockTransactions.([]*types.Tx), nil
+}
+
+func (c *blockCache) getBlockHeader(hash *bc.Hash) (*types.BlockHeader, bool) {
+       blockHeader, ok := c.lruBlockHeaders.Get(*hash)
+       if blockHeader == nil {
                return nil, ok
        }
-       return block.(*types.Block), ok
+       return blockHeader.(*types.BlockHeader), ok
+}
+
+func (c *blockCache) getBlockTransactions(hash *bc.Hash) ([]*types.Tx, bool) {
+       txs, ok := c.lruBlockTxs.Get(*hash)
+       if txs == nil {
+               return nil, ok
+       }
+       return txs.([]*types.Tx), ok
+}
+
+func (c *blockCache) addBlockHeader(blockHeader *types.BlockHeader) {
+       c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader)
 }
 
-func (c *blockCache) add(block *types.Block) {
-       c.mu.Lock()
-       c.lru.Add(block.Hash(), block)
-       c.mu.Unlock()
+func (c *blockCache) addBlockTxs(hash bc.Hash, txs []*types.Tx) {
+       c.lruBlockTxs.Add(hash, txs)
 }