import (
"fmt"
"strconv"
- "sync"
- "github.com/golang/groupcache/lru"
"github.com/golang/groupcache/singleflight"
"github.com/vapor/common"
type fillBlockHeaderFn func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error)
+type fillVoteResultFn func(seq uint64) (*state.VoteResult, error)
-func newBlockCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn) blockCache {
+func newBlockCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillVoteResult fillVoteResultFn) blockCache {
return blockCache{
lruBlockHeaders: common.NewCache(maxCachedBlockHeaders),
lruBlockTxs: common.NewCache(maxCachedBlockTransactions),
+ lruVoteResults: common.NewCache(maxCachedVoteResults),
fillBlockHeaderFn: fillBlockHeader,
fillBlockTransactionFn: fillBlockTxs,
+ fillVoteResultFn: fillVoteResult,
}
}
type blockCache struct {
lruBlockHeaders *common.Cache
lruBlockTxs *common.Cache
+ lruVoteResults *common.Cache
fillBlockHeaderFn func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error)
+ fillVoteResultFn func(seq uint64) (*state.VoteResult, error)
singleBlockHeader singleflight.Group
singleBlockTxs singleflight.Group
+ singleVoteResult singleflight.Group
}
func (c *blockCache) lookupBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
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 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) addBlockTxs(hash bc.Hash, txs []*types.Tx) {
- c.lruBlockTxs.Add(hash, txs)
-}
-
-func newVoteResultCache(fillFn func(seq uint64) (*state.VoteResult, error)) voteResultCache {
- return voteResultCache{
- lru: lru.New(maxCachedVoteResults),
- fillFn: fillFn,
- }
-}
-
-type voteResultCache struct {
- mu sync.Mutex
- lru *lru.Cache
- fillFn func(seq uint64) (*state.VoteResult, error)
- single singleflight.Group
-}
-
-func (vrc *voteResultCache) lookup(seq uint64) (*state.VoteResult, error) {
- if voteResult, ok := vrc.get(seq); ok {
- return voteResult, nil
+func (c *blockCache) lookupVoteResult(seq uint64) (*state.VoteResult, error) {
+ if vr, ok := c.getVoteResult(seq); ok {
+ return vr, nil
}
seqStr := strconv.FormatUint(seq, 10)
- voteResult, err := vrc.single.Do(seqStr, func() (interface{}, error) {
- v, err := vrc.fillFn(seq)
+ voteResult, err := c.singleVoteResult.Do(seqStr, func() (interface{}, error) {
+ v, err := c.fillVoteResultFn(seq)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("There are no vote result with given seq %s", seqStr)
}
- vrc.add(v)
+ c.addVoteResult(v)
return v, nil
})
if err != nil {
return voteResult.(*state.VoteResult), nil
}
-func (vrc *voteResultCache) get(seq uint64) (*state.VoteResult, bool) {
- vrc.mu.Lock()
- voteResult, ok := vrc.lru.Get(seq)
- vrc.mu.Unlock()
+func (c *blockCache) getBlockHeader(hash *bc.Hash) (*types.BlockHeader, bool) {
+ blockHeader, ok := c.lruBlockHeaders.Get(*hash)
+ if blockHeader == nil {
+ return nil, 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) getVoteResult(seq uint64) (*state.VoteResult, bool) {
+ voteResult, ok := c.lruVoteResults.Get(seq)
if voteResult == nil {
return nil, ok
}
return voteResult.(*state.VoteResult), ok
}
-func (vrc *voteResultCache) add(voteResult *state.VoteResult) {
- vrc.mu.Lock()
- vrc.lru.Add(voteResult.Seq, voteResult)
- vrc.mu.Unlock()
+func (c *blockCache) addBlockHeader(blockHeader *types.BlockHeader) {
+ c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader)
}
+
+func (c *blockCache) addBlockTxs(hash bc.Hash, txs []*types.Tx) {
+ c.lruBlockTxs.Add(hash, txs)
+}
+
+func (c *blockCache) addVoteResult(voteResult *state.VoteResult) {
+ c.lruVoteResults.Add(voteResult.Seq, voteResult)
+}
+
+// func newVoteResultCache(fillFn func(seq uint64) (*state.VoteResult, error)) voteResultCache {
+// return voteResultCache{
+// lru: lru.New(maxCachedVoteResults),
+// fillFn: fillFn,
+// }
+// }
+
+// type voteResultCache struct {
+// mu sync.Mutex
+// lru *lru.Cache
+// fillFn func(seq uint64) (*state.VoteResult, error)
+// single singleflight.Group
+// }
},
}
}
+ newVoteResult := func(seq uint64) *state.VoteResult {
+ return &state.VoteResult{
+ Seq: seq,
+ }
+ }
blocks := make(map[bc.Hash]*types.Block)
for i := 0; i < maxCachedBlockHeaders+10; i++ {
block := newBlock(uint64(i))
blocks[block.Hash()] = block
}
+ voteResults := make(map[uint64]*state.VoteResult)
+ for i := 0; i < maxCachedVoteResults+10; i++ {
+ voteResult := newVoteResult(uint64(i))
+ voteResults[voteResult.Seq] = voteResult
+ }
fillBlockHeaderFn := func(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
return &blocks[*hash].BlockHeader, nil
return blocks[*hash].Transactions, nil
}
- cache := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn)
+ fillVoteResultFn := func(seq uint64) (*state.VoteResult, error) {
+ return voteResults[seq], nil
+ }
+
+ cache := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn)
for i := 0; i < maxCachedBlockHeaders+10; i++ {
block := newBlock(uint64(i))
t.Fatalf("can't find new block")
}
}
-}
-
-func TestVoteResultCache(t *testing.T) {
- newVoteResult := func(seq uint64) *state.VoteResult {
- return &state.VoteResult{
- Seq: seq,
- }
- }
- voteResults := make(map[uint64]*state.VoteResult)
- for i := 0; i < maxCachedVoteResults+10; i++ {
- voteResult := newVoteResult(uint64(i))
- voteResults[voteResult.Seq] = voteResult
- }
-
- cache := newVoteResultCache(func(seq uint64) (*state.VoteResult, error) {
- return voteResults[seq], nil
- })
for i := 0; i < maxCachedVoteResults+10; i++ {
voteResult := newVoteResult(uint64(i))
- cache.lookup(voteResult.Seq)
+ cache.lookupVoteResult(voteResult.Seq)
}
for i := 0; i < 10; i++ {
voteResult := newVoteResult(uint64(i))
- if v, _ := cache.get(voteResult.Seq); v != nil {
+ if v, _ := cache.getVoteResult(voteResult.Seq); v != nil {
t.Fatalf("find old vote result")
}
}
for i := 10; i < maxCachedVoteResults+10; i++ {
voteResult := newVoteResult(uint64(i))
- if v, _ := cache.get(voteResult.Seq); v == nil {
+ if v, _ := cache.getVoteResult(voteResult.Seq); v == nil {
t.Fatalf("can't find new vote result")
}
}
// It satisfies the interface protocol.Store, and provides additional
// methods for querying current data.
type Store struct {
- db dbm.DB
- bc blockCache
- vrc voteResultCache
+ db dbm.DB
+ bCache blockCache
}
func calcBlockHeaderKey(height uint64, hash *bc.Hash) []byte {
fillBlockTxsFn := func(hash *bc.Hash) ([]*types.Tx, error) {
return GetBlockTransactions(db, hash)
}
- bc := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn)
- vrc := newVoteResultCache(func(seq uint64) (*state.VoteResult, error) {
+ fillVoteResultFn := func(seq uint64) (*state.VoteResult, error) {
return GetVoteResult(db, seq)
- })
+ }
+ bc := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn)
return &Store{
- db: db,
- bc: bc,
- vrc: vrc,
+ db: db,
+ bCache: bc,
}
}
// BlockExist check if the block is stored in disk
func (s *Store) BlockExist(hash *bc.Hash, height uint64) bool {
- blockHeader, err := s.bc.lookupBlockHeader(hash, height)
+ blockHeader, err := s.bCache.lookupBlockHeader(hash, height)
return err == nil && blockHeader != nil
}
// GetBlockHeader return the BlockHeader by given hash
func (s *Store) GetBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
- blockHeader, err := s.bc.lookupBlockHeader(hash, height)
+ blockHeader, err := s.bCache.lookupBlockHeader(hash, height)
if err != nil {
return nil, err
}
// GetBlockTransactions return the Block transactions by given hash
func (s *Store) GetBlockTransactions(hash *bc.Hash) ([]*types.Tx, error) {
- txs, err := s.bc.lookupBlockTxs(hash)
+ txs, err := s.bCache.lookupBlockTxs(hash)
if err != nil {
return nil, err
}
// GetVoteResult retrive the voting result in specified vote sequence
func (s *Store) GetVoteResult(seq uint64) (*state.VoteResult, error) {
- return s.vrc.lookup(seq)
+ return s.bCache.lookupVoteResult(seq)
}
func (s *Store) LoadBlockIndex(stateBestHeight uint64) (*state.BlockIndex, error) {