OSDN Git Service

update log (#259)
[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         maxCachedBlockHashes       = 8192
18         maxCachedMainChainHashes   = 8192
19         maxCachedConsensusResults  = 128
20 )
21
22 type fillBlockHeaderFn func(hash *bc.Hash) (*types.BlockHeader, error)
23 type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error)
24 type fillBlockHashesFn func(height uint64) ([]*bc.Hash, error)
25 type fillMainChainHashFn func(height uint64) (*bc.Hash, error)
26 type fillConsensusResultFn func(seq uint64) (*state.ConsensusResult, error)
27
28 func newCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillBlockHashes fillBlockHashesFn, fillMainChainHash fillMainChainHashFn, fillConsensusResult fillConsensusResultFn) cache {
29         return cache{
30                 lruBlockHeaders:     common.NewCache(maxCachedBlockHeaders),
31                 lruBlockTxs:         common.NewCache(maxCachedBlockTransactions),
32                 lruBlockHashes:      common.NewCache(maxCachedBlockHashes),
33                 lruMainChainHashes:  common.NewCache(maxCachedMainChainHashes),
34                 lruConsensusResults: common.NewCache(maxCachedConsensusResults),
35
36                 fillBlockHeaderFn:      fillBlockHeader,
37                 fillBlockTransactionFn: fillBlockTxs,
38                 fillBlockHashesFn:      fillBlockHashes,
39                 fillMainChainHashFn:    fillMainChainHash,
40                 fillConsensusResultFn:  fillConsensusResult,
41         }
42 }
43
44 type cache struct {
45         lruBlockHeaders     *common.Cache
46         lruBlockTxs         *common.Cache
47         lruBlockHashes      *common.Cache
48         lruMainChainHashes  *common.Cache
49         lruConsensusResults *common.Cache
50
51         fillBlockHeaderFn      func(hash *bc.Hash) (*types.BlockHeader, error)
52         fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error)
53         fillBlockHashesFn      func(uint64) ([]*bc.Hash, error)
54         fillMainChainHashFn    func(uint64) (*bc.Hash, error)
55         fillConsensusResultFn  func(seq uint64) (*state.ConsensusResult, error)
56
57         sf singleflight.Group
58 }
59
60 func (c *cache) lookupBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
61         if data, ok := c.lruBlockHeaders.Get(*hash); ok {
62                 return data.(*types.BlockHeader), nil
63         }
64
65         blockHeader, err := c.sf.Do("BlockHeader:"+hash.String(), func() (interface{}, error) {
66                 blockHeader, err := c.fillBlockHeaderFn(hash)
67                 if err != nil {
68                         return nil, err
69                 }
70
71                 c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader)
72                 return blockHeader, nil
73         })
74         if err != nil {
75                 return nil, err
76         }
77         return blockHeader.(*types.BlockHeader), nil
78 }
79
80 func (c *cache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) {
81         if data, ok := c.lruBlockTxs.Get(*hash); ok {
82                 return data.([]*types.Tx), nil
83         }
84
85         blockTxs, err := c.sf.Do("BlockTxs:"+hash.String(), func() (interface{}, error) {
86                 blockTxs, err := c.fillBlockTransactionFn(hash)
87                 if err != nil {
88                         return nil, err
89                 }
90
91                 c.lruBlockTxs.Add(*hash, blockTxs)
92                 return blockTxs, nil
93         })
94         if err != nil {
95                 return nil, err
96         }
97         return blockTxs.([]*types.Tx), nil
98 }
99
100 func (c *cache) lookupConsensusResult(seq uint64) (*state.ConsensusResult, error) {
101         if data, ok := c.lruConsensusResults.Get(seq); ok {
102                 return data.(*state.ConsensusResult).Fork(), nil
103         }
104
105         seqStr := strconv.FormatUint(seq, 10)
106         consensusResult, err := c.sf.Do("ConsensusResult:"+seqStr, func() (interface{}, error) {
107                 consensusResult, err := c.fillConsensusResultFn(seq)
108                 if err != nil {
109                         return nil, err
110                 }
111
112                 c.lruConsensusResults.Add(consensusResult.Seq, consensusResult)
113                 return consensusResult, nil
114         })
115         if err != nil {
116                 return nil, err
117         }
118         return consensusResult.(*state.ConsensusResult).Fork(), nil
119 }
120
121 func (c *cache) lookupMainChainHash(height uint64) (*bc.Hash, error) {
122         if hash, ok := c.lruMainChainHashes.Get(height); ok {
123                 return hash.(*bc.Hash), nil
124         }
125
126         heightStr := strconv.FormatUint(height, 10)
127         hash, err := c.sf.Do("BlockHashByHeight:"+heightStr, func() (interface{}, error) {
128                 hash, err := c.fillMainChainHashFn(height)
129                 if err != nil {
130                         return nil, err
131                 }
132
133                 c.lruMainChainHashes.Add(height, hash)
134                 return hash, nil
135         })
136         if err != nil {
137                 return nil, err
138         }
139         return hash.(*bc.Hash), nil
140 }
141
142 func (c *cache) lookupBlockHashesByHeight(height uint64) ([]*bc.Hash, error) {
143         if hashes, ok := c.lruBlockHashes.Get(height); ok {
144                 return hashes.([]*bc.Hash), nil
145         }
146
147         heightStr := strconv.FormatUint(height, 10)
148         hashes, err := c.sf.Do("BlockHashesByHeight:"+heightStr, func() (interface{}, error) {
149                 hashes, err := c.fillBlockHashesFn(height)
150                 if err != nil {
151                         return nil, err
152                 }
153
154                 c.lruBlockHashes.Add(height, hashes)
155                 return hashes, nil
156         })
157         if err != nil {
158                 return nil, err
159         }
160         return hashes.([]*bc.Hash), nil
161 }
162
163 func (c *cache) removeBlockHeader(blockHeader *types.BlockHeader) {
164         c.lruBlockHeaders.Remove(blockHeader.Hash())
165 }
166
167 func (c *cache) removeBlockHashes(height uint64) {
168         c.lruBlockHashes.Remove(height)
169 }
170
171 func (c *cache) removeMainChainHash(height uint64) {
172         c.lruMainChainHashes.Remove(height)
173 }
174
175 func (c *cache) removeConsensusResult(consensusResult *state.ConsensusResult) {
176         c.lruConsensusResults.Remove(consensusResult.Seq)
177 }