github.com/theQRL/go-zond@v0.1.1/common/lru/blob_lru.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package lru
    18  
    19  import (
    20  	"math"
    21  	"sync"
    22  )
    23  
    24  // blobType is the type constraint for values stored in SizeConstrainedCache.
    25  type blobType interface {
    26  	~[]byte | ~string
    27  }
    28  
    29  // SizeConstrainedCache is a cache where capacity is in bytes (instead of item count). When the cache
    30  // is at capacity, and a new item is added, older items are evicted until the size
    31  // constraint is met.
    32  //
    33  // OBS: This cache assumes that items are content-addressed: keys are unique per content.
    34  // In other words: two Add(..) with the same key K, will always have the same value V.
    35  type SizeConstrainedCache[K comparable, V blobType] struct {
    36  	size    uint64
    37  	maxSize uint64
    38  	lru     BasicLRU[K, V]
    39  	lock    sync.Mutex
    40  }
    41  
    42  // NewSizeConstrainedCache creates a new size-constrained LRU cache.
    43  func NewSizeConstrainedCache[K comparable, V blobType](maxSize uint64) *SizeConstrainedCache[K, V] {
    44  	return &SizeConstrainedCache[K, V]{
    45  		size:    0,
    46  		maxSize: maxSize,
    47  		lru:     NewBasicLRU[K, V](math.MaxInt),
    48  	}
    49  }
    50  
    51  // Add adds a value to the cache.  Returns true if an eviction occurred.
    52  // OBS: This cache assumes that items are content-addressed: keys are unique per content.
    53  // In other words: two Add(..) with the same key K, will always have the same value V.
    54  // OBS: The value is _not_ copied on Add, so the caller must not modify it afterwards.
    55  func (c *SizeConstrainedCache[K, V]) Add(key K, value V) (evicted bool) {
    56  	c.lock.Lock()
    57  	defer c.lock.Unlock()
    58  
    59  	// Unless it is already present, might need to evict something.
    60  	// OBS: If it is present, we still call Add internally to bump the recentness.
    61  	if !c.lru.Contains(key) {
    62  		targetSize := c.size + uint64(len(value))
    63  		for targetSize > c.maxSize {
    64  			evicted = true
    65  			_, v, ok := c.lru.RemoveOldest()
    66  			if !ok {
    67  				// list is now empty. Break
    68  				break
    69  			}
    70  			targetSize -= uint64(len(v))
    71  		}
    72  		c.size = targetSize
    73  	}
    74  	c.lru.Add(key, value)
    75  	return evicted
    76  }
    77  
    78  // Get looks up a key's value from the cache.
    79  func (c *SizeConstrainedCache[K, V]) Get(key K) (V, bool) {
    80  	c.lock.Lock()
    81  	defer c.lock.Unlock()
    82  
    83  	return c.lru.Get(key)
    84  }