OSDN Git Service

new repo
[bytom/vapor.git] / database / leveldb / cache.go
1 package leveldb
2
3 import (
4         "fmt"
5         "sync"
6
7         "github.com/golang/groupcache/lru"
8         "github.com/golang/groupcache/singleflight"
9
10         "github.com/vapor/protocol/bc"
11         "github.com/vapor/protocol/bc/types"
12 )
13
14 const maxCachedBlocks = 30
15
16 func newBlockCache(fillFn func(hash *bc.Hash) *types.Block) blockCache {
17         return blockCache{
18                 lru:    lru.New(maxCachedBlocks),
19                 fillFn: fillFn,
20         }
21 }
22
23 type blockCache struct {
24         mu     sync.Mutex
25         lru    *lru.Cache
26         fillFn func(hash *bc.Hash) *types.Block
27         single singleflight.Group
28 }
29
30 func (c *blockCache) lookup(hash *bc.Hash) (*types.Block, error) {
31         if b, ok := c.get(hash); ok {
32                 return b, nil
33         }
34
35         block, err := c.single.Do(hash.String(), func() (interface{}, error) {
36                 b := c.fillFn(hash)
37                 if b == nil {
38                         return nil, fmt.Errorf("There are no block with given hash %s", hash.String())
39                 }
40
41                 c.add(b)
42                 return b, nil
43         })
44         if err != nil {
45                 return nil, err
46         }
47         return block.(*types.Block), nil
48 }
49
50 func (c *blockCache) get(hash *bc.Hash) (*types.Block, bool) {
51         c.mu.Lock()
52         block, ok := c.lru.Get(*hash)
53         c.mu.Unlock()
54         if block == nil {
55                 return nil, ok
56         }
57         return block.(*types.Block), ok
58 }
59
60 func (c *blockCache) add(block *types.Block) {
61         c.mu.Lock()
62         c.lru.Add(block.Hash(), block)
63         c.mu.Unlock()
64 }