github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/database/cache.go (about) 1 package database 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/bytom/protocol/bc" 11 "github.com/bytom/bytom/protocol/bc/types" 12 ) 13 14 const maxCachedBlocks = 30 15 16 func newBlockCache(fillFn func(hash *bc.Hash) (*types.Block, error)) 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, error) 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, err := c.fillFn(hash) 37 if err != nil { 38 return nil, err 39 } 40 41 if b == nil { 42 return nil, fmt.Errorf("There are no block with given hash %s", hash.String()) 43 } 44 45 c.add(b) 46 return b, nil 47 }) 48 if err != nil { 49 return nil, err 50 } 51 return block.(*types.Block), nil 52 } 53 54 func (c *blockCache) get(hash *bc.Hash) (*types.Block, bool) { 55 c.mu.Lock() 56 block, ok := c.lru.Get(*hash) 57 c.mu.Unlock() 58 if block == nil { 59 return nil, ok 60 } 61 return block.(*types.Block), ok 62 } 63 64 func (c *blockCache) add(block *types.Block) { 65 c.mu.Lock() 66 c.lru.Add(block.Hash(), block) 67 c.mu.Unlock() 68 }