OSDN Git Service

89ef3a4509ff81c59b1003c5595bd91f04c59541
[bytom/vapor.git] / database / cache.go
1 package database
2
3 import (
4         "strconv"
5
6         "github.com/golang/groupcache/singleflight"
7
8         "github.com/vapor/common"
9         "github.com/vapor/protocol/bc"
10         "github.com/vapor/protocol/bc/types"
11         "github.com/vapor/protocol/state"
12 )
13
14 const (
15         maxCachedBlockHeaders      = 4096
16         maxCachedBlockTransactions = 1024
17         maxCachedVoteResults       = 128
18 )
19
20 type fillBlockHeaderFn func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
21 type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error)
22 type fillVoteResultFn func(seq uint64) (*state.VoteResult, error)
23
24 func newCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillVoteResult fillVoteResultFn) cache {
25         return cache{
26                 lruBlockHeaders: common.NewCache(maxCachedBlockHeaders),
27                 lruBlockTxs:     common.NewCache(maxCachedBlockTransactions),
28                 lruVoteResults:  common.NewCache(maxCachedVoteResults),
29
30                 fillBlockHeaderFn:      fillBlockHeader,
31                 fillBlockTransactionFn: fillBlockTxs,
32                 fillVoteResultFn:       fillVoteResult,
33         }
34 }
35
36 type cache struct {
37         lruBlockHeaders *common.Cache
38         lruBlockTxs     *common.Cache
39         lruVoteResults  *common.Cache
40
41         fillBlockHeaderFn      func(hash *bc.Hash, height uint64) (*types.BlockHeader, error)
42         fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error)
43         fillVoteResultFn       func(seq uint64) (*state.VoteResult, error)
44
45         sf singleflight.Group
46 }
47
48 func (c *cache) lookupBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) {
49         if data, ok := c.lruBlockHeaders.Get(*hash); ok {
50                 return data.(*types.BlockHeader), nil
51         }
52
53         blockHeader, err := c.sf.Do("BlockHeader:"+hash.String(), func() (interface{}, error) {
54                 blockHeader, err := c.fillBlockHeaderFn(hash, height)
55                 if err != nil {
56                         return nil, err
57                 }
58
59                 c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader)
60                 return blockHeader, nil
61         })
62         if err != nil {
63                 return nil, err
64         }
65         return blockHeader.(*types.BlockHeader), nil
66 }
67
68 func (c *cache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) {
69         if data, ok := c.lruBlockTxs.Get(*hash); ok {
70                 return data.([]*types.Tx), nil
71         }
72
73         blockTxs, err := c.sf.Do("BlockTxs:"+hash.String(), func() (interface{}, error) {
74                 blockTxs, err := c.fillBlockTransactionFn(hash)
75                 if err != nil {
76                         return nil, err
77                 }
78
79                 c.lruBlockTxs.Add(hash, blockTxs)
80                 return blockTxs, nil
81         })
82         if err != nil {
83                 return nil, err
84         }
85         return blockTxs.([]*types.Tx), nil
86 }
87
88 func (c *cache) lookupVoteResult(seq uint64) (*state.VoteResult, error) {
89         if data, ok := c.lruVoteResults.Get(seq); ok {
90                 return data.(*state.VoteResult).Fork(), nil
91         }
92
93         seqStr := strconv.FormatUint(seq, 10)
94         voteResult, err := c.sf.Do("VoteResult:"+seqStr, func() (interface{}, error) {
95                 voteResult, err := c.fillVoteResultFn(seq)
96                 if err != nil {
97                         return nil, err
98                 }
99
100                 c.lruVoteResults.Add(voteResult.Seq, voteResult)
101                 return voteResult, nil
102         })
103         if err != nil {
104                 return nil, err
105         }
106         return voteResult.(*state.VoteResult).Fork(), nil
107 }
108
109 func (c *cache) removeBlockHeader(blockHeader *types.BlockHeader) {
110         c.lruBlockHeaders.Remove(blockHeader.Hash())
111 }
112
113 func (c *cache) removeVoteResult(voteResult *state.VoteResult) {
114         c.lruVoteResults.Remove(voteResult.Seq)
115 }