OSDN Git Service

Hulk did something
[bytom/vapor.git] / database / cache.go
diff --git a/database/cache.go b/database/cache.go
new file mode 100644 (file)
index 0000000..c963f25
--- /dev/null
@@ -0,0 +1,68 @@
+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()
+}