OSDN Git Service

Merge pull request #375 from Bytom/dev
[bytom/bytom-spv.git] / blockchain / txdb / cache.go
1 package txdb
2
3 import (
4         "fmt"
5         "sync"
6
7         "github.com/golang/groupcache/lru"
8         "github.com/golang/groupcache/singleflight"
9
10         "github.com/bytom/protocol/bc"
11         "github.com/bytom/protocol/bc/legacy"
12 )
13
14 const maxCachedBlocks = 30
15
16 func newBlockCache(fillFn func(hash *bc.Hash) *legacy.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) *legacy.Block
27         single singleflight.Group
28 }
29
30 func (c *blockCache) lookup(hash *bc.Hash) (*legacy.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.(*legacy.Block), nil
48 }
49
50 func (c *blockCache) get(hash *bc.Hash) (*legacy.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.(*legacy.Block), ok
58 }
59
60 func (c *blockCache) add(block *legacy.Block) {
61         c.mu.Lock()
62         c.lru.Add(block.Hash(), block)
63         c.mu.Unlock()
64 }