OSDN Git Service

V0.1 vote result cache (#182)
authorChengcheng Zhang <943420582@qq.com>
Mon, 17 Jun 2019 06:16:16 +0000 (14:16 +0800)
committerPaladz <yzhu101@uottawa.ca>
Mon, 17 Jun 2019 06:16:16 +0000 (14:16 +0800)
* add voteResultCache lookup get add

* add GetVoteResult

* add TestVoteResultCache

* embed vote result cache in blockCache

* update

database/cache.go
database/cache_test.go
database/store.go

index a525262..01366a1 100644 (file)
@@ -2,41 +2,50 @@ package database
 
 import (
        "fmt"
+       "strconv"
 
        "github.com/golang/groupcache/singleflight"
 
        "github.com/vapor/common"
        "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/bc/types"
+       "github.com/vapor/protocol/state"
 )
 
 const (
        maxCachedBlockHeaders      = 1000
        maxCachedBlockTransactions = 1000
+       maxCachedVoteResults       = 144 // int(60 * 60 * 24 * 1000 / consensus.BlockTimeInterval / consensus.RoundVoteBlockNums)
 )
 
 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) {
@@ -87,6 +96,31 @@ func (c *blockCache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) {
        return blockTransactions.([]*types.Tx), 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 := c.singleVoteResult.Do(seqStr, func() (interface{}, error) {
+               v, err := c.fillVoteResultFn(seq)
+               if err != nil {
+                       return nil, err
+               }
+
+               if v == nil {
+                       return nil, fmt.Errorf("There are no vote result with given seq %s", seqStr)
+               }
+
+               c.addVoteResult(v)
+               return v, nil
+       })
+       if err != nil {
+               return nil, err
+       }
+       return voteResult.(*state.VoteResult), nil
+}
+
 func (c *blockCache) getBlockHeader(hash *bc.Hash) (*types.BlockHeader, bool) {
        blockHeader, ok := c.lruBlockHeaders.Get(*hash)
        if blockHeader == nil {
@@ -103,6 +137,14 @@ func (c *blockCache) getBlockTransactions(hash *bc.Hash) ([]*types.Tx, bool) {
        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 (c *blockCache) addBlockHeader(blockHeader *types.BlockHeader) {
        c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader)
 }
@@ -110,3 +152,7 @@ func (c *blockCache) addBlockHeader(blockHeader *types.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)
+}
index d7116ec..9e71dc2 100644 (file)
@@ -5,6 +5,7 @@ import (
 
        "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/bc/types"
+       "github.com/vapor/protocol/state"
 )
 
 func TestBlockCache(t *testing.T) {
@@ -15,11 +16,21 @@ func TestBlockCache(t *testing.T) {
                        },
                }
        }
+       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
@@ -29,7 +40,11 @@ func TestBlockCache(t *testing.T) {
                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))
@@ -52,4 +67,23 @@ func TestBlockCache(t *testing.T) {
                        t.Fatalf("can't find new block")
                }
        }
+
+       for i := 0; i < maxCachedVoteResults+10; i++ {
+               voteResult := newVoteResult(uint64(i))
+               cache.lookupVoteResult(voteResult.Seq)
+       }
+
+       for i := 0; i < 10; i++ {
+               voteResult := newVoteResult(uint64(i))
+               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.getVoteResult(voteResult.Seq); v == nil {
+                       t.Fatalf("can't find new vote result")
+               }
+       }
 }
index fd53c90..fa76fc0 100644 (file)
@@ -97,20 +97,35 @@ func GetBlockTransactions(db dbm.DB, hash *bc.Hash) ([]*types.Tx, error) {
        return block.Transactions, nil
 }
 
+// GetVoteResult return the vote result by given sequence
+func GetVoteResult(db dbm.DB, seq uint64) (*state.VoteResult, error) {
+       data := db.Get(calcVoteResultKey(seq))
+       if data == nil {
+               return nil, protocol.ErrNotFoundVoteResult
+       }
+
+       voteResult := new(state.VoteResult)
+       if err := json.Unmarshal(data, voteResult); err != nil {
+               return nil, errors.Wrap(err, "unmarshaling vote result")
+       }
+       return voteResult, nil
+}
+
 // NewStore creates and returns a new Store object.
 func NewStore(db dbm.DB) *Store {
        fillBlockHeaderFn := func(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
                return GetBlockHeader(db, hash, height)
        }
-
        fillBlockTxsFn := func(hash *bc.Hash) ([]*types.Tx, error) {
                return GetBlockTransactions(db, hash)
        }
-
-       cache := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn)
+       fillVoteResultFn := func(seq uint64) (*state.VoteResult, error) {
+               return GetVoteResult(db, seq)
+       }
+       bc := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn)
        return &Store{
                db:    db,
-               cache: cache,
+               cache: bc,
        }
 }
 
@@ -187,16 +202,7 @@ func (s *Store) GetStoreStatus() *protocol.BlockStoreState {
 
 // GetVoteResult retrive the voting result in specified vote sequence
 func (s *Store) GetVoteResult(seq uint64) (*state.VoteResult, error) {
-       data := s.db.Get(calcVoteResultKey(seq))
-       if data == nil {
-               return nil, protocol.ErrNotFoundVoteResult
-       }
-
-       vr := &state.VoteResult{}
-       if err := json.Unmarshal(data, vr); err != nil {
-               return nil, errors.Wrap(err, "unmarshaling vote result")
-       }
-       return vr, nil
+       return s.cache.lookupVoteResult(seq)
 }
 
 func (s *Store) LoadBlockIndex(stateBestHeight uint64) (*state.BlockIndex, error) {