package database import ( "fmt" "sync" "github.com/golang/groupcache/lru" "github.com/golang/groupcache/singleflight" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" ) const maxCachedBlocks = 30 func newBlockCache(fillFn func(hash *bc.Hash) (*types.Block, error)) blockCache { return blockCache{ lru: lru.New(maxCachedBlocks), fillFn: fillFn, } } type blockCache struct { mu sync.Mutex lru *lru.Cache fillFn func(hash *bc.Hash) (*types.Block, error) single singleflight.Group } func (c *blockCache) lookup(hash *bc.Hash) (*types.Block, error) { if b, ok := c.get(hash); ok { return b, nil } block, err := c.single.Do(hash.String(), func() (interface{}, error) { b, err := c.fillFn(hash) if err != nil { return nil, err } if b == nil { return nil, fmt.Errorf("There are no block with given hash %s", hash.String()) } c.add(b) return b, nil }) if err != nil { return nil, err } return block.(*types.Block), nil } func (c *blockCache) get(hash *bc.Hash) (*types.Block, bool) { c.mu.Lock() block, ok := c.lru.Get(*hash) c.mu.Unlock() if block == nil { return nil, ok } return block.(*types.Block), ok } func (c *blockCache) add(block *types.Block) { c.mu.Lock() c.lru.Add(block.Hash(), block) c.mu.Unlock() }