OSDN Git Service

add_cache_for_get_prev_checkpoint (#1908)
authorPoseidon <shenao.78@163.com>
Wed, 21 Apr 2021 07:23:24 +0000 (15:23 +0800)
committerGitHub <noreply@github.com>
Wed, 21 Apr 2021 07:23:24 +0000 (15:23 +0800)
* add_cache_for_get_prev_checkpoint

* opt code

* no need lock

Co-authored-by: Paladz <yzhu101@uottawa.ca>
common/concurrent_lru.go [new file with mode: 0644]
protocol/consensus/casper.go

diff --git a/common/concurrent_lru.go b/common/concurrent_lru.go
new file mode 100644 (file)
index 0000000..68e6e5e
--- /dev/null
@@ -0,0 +1,62 @@
+package common
+
+import (
+       "sync"
+
+       "github.com/golang/groupcache/lru"
+)
+
+// Cache is an LRU cache. It is safe for concurrent access.
+type Cache struct {
+       cache *lru.Cache
+       sync.RWMutex
+}
+
+// NewCache creates a new Cache.
+// If maxEntries is zero, the cache has no limit and it's assumed
+// that eviction is done by the caller.
+func NewCache(maxEntries int) *Cache {
+       return &Cache{cache: lru.New(maxEntries)}
+}
+
+// Add adds a value to the cache.
+func (c *Cache) Add(key, value interface{}) {
+       c.Lock()
+       defer c.Unlock()
+       c.cache.Add(key, value)
+}
+
+// Get looks up a key's value from the cache.
+func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
+       c.Lock()
+       defer c.Unlock()
+       return c.cache.Get(key)
+}
+
+// Remove removes the provided key from the cache.
+func (c *Cache) Remove(key interface{}) {
+       c.Lock()
+       defer c.Unlock()
+       c.cache.Remove(key)
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *Cache) RemoveOldest() {
+       c.Lock()
+       defer c.Unlock()
+       c.cache.RemoveOldest()
+}
+
+// Len returns the number of items in the cache.
+func (c *Cache) Len() int {
+       c.RLock()
+       defer c.RUnlock()
+       return c.cache.Len()
+}
+
+// Clear purges all stored items from the cache.
+func (c *Cache) Clear() {
+       c.Lock()
+       defer c.Unlock()
+       c.cache.Clear()
+}
index 5db8d19..ce324a0 100644 (file)
@@ -4,6 +4,7 @@ import (
        "encoding/hex"
        "sync"
 
+       "github.com/bytom/bytom/common"
        "github.com/bytom/bytom/errors"
        "github.com/bytom/bytom/math/checked"
        "github.com/bytom/bytom/protocol"
@@ -35,6 +36,8 @@ type Casper struct {
 
        // pubKey -> conflicting verifications
        evilValidators map[string][]*Verification
+       // block hash -> previous checkpoint hash
+       prevCheckpointCache *common.Cache
 }
 
 // Best chain return the chain containing the justified checkpoint of the largest height
@@ -56,9 +59,6 @@ func (c *Casper) Validators(blockHash *bc.Hash) ([]*state.Validator, error) {
                return nil, err
        }
 
-       c.mu.RLock()
-       defer c.mu.RUnlock()
-
        checkpoint, err := c.store.GetCheckpoint(hash)
        if err != nil {
                return nil, err
@@ -387,16 +387,26 @@ func chainOfMaxJustifiedHeight(node *treeNode, justifiedHeight uint64) (uint64,
 }
 
 func (c *Casper) prevCheckpointHash(blockHash *bc.Hash) (*bc.Hash, error) {
+       if data, ok := c.prevCheckpointCache.Get(blockHash); ok {
+               return data.(*bc.Hash), nil
+       }
+
        for {
                block, err := c.store.GetBlockHeader(blockHash)
                if err != nil {
                        return nil, err
                }
 
-               height := block.Height - 1
-               blockHash = &block.PreviousBlockHash
-               if height%state.BlocksOfEpoch == 0 {
-                       return blockHash, nil
+               prevHeight, prevHash := block.Height-1, block.PreviousBlockHash
+               if data, ok := c.prevCheckpointCache.Get(prevHash); ok {
+                       return data.(*bc.Hash), nil
+               }
+
+               if prevHeight%state.BlocksOfEpoch == 0 {
+                       c.prevCheckpointCache.Add(blockHash, &prevHash)
+                       return &prevHash, nil
                }
+
+               blockHash = &prevHash
        }
 }