Update golang-lru

This commit is contained in:
Frank Denis 2023-08-08 14:21:12 +02:00
parent 894d20191f
commit 7cc5a051c7
12 changed files with 235 additions and 65 deletions

2
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185
github.com/hashicorp/go-immutable-radix v1.3.1 github.com/hashicorp/go-immutable-radix v1.3.1
github.com/hashicorp/golang-lru v0.5.0 github.com/hashicorp/golang-lru v1.0.2
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb
github.com/jedisct1/dlog v0.0.0-20230513092435-93bc2a55ad59 github.com/jedisct1/dlog v0.0.0-20230513092435-93bc2a55ad59
github.com/jedisct1/go-clocksmith v0.0.0-20230211133011-392c1afea73e github.com/jedisct1/go-clocksmith v0.0.0-20230211133011-392c1afea73e

3
go.sum
View File

@ -32,8 +32,9 @@ github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwM
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb h1:PGufWXXDq9yaev6xX1YQauaO1MV90e6Mpoq1I7Lz/VM= github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb h1:PGufWXXDq9yaev6xX1YQauaO1MV90e6Mpoq1I7Lz/VM=
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E= github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=

30
vendor/github.com/hashicorp/golang-lru/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,30 @@
linters:
enable:
- megacheck
- revive
- govet
- unconvert
- megacheck
- gas
- gocyclo
- dupl
- misspell
- unparam
- unused
- typecheck
- ineffassign
- stylecheck
- exportloopref
- gocritic
- nakedret
- gosimple
- prealloc
fast: false
disable-all: true
issues:
exclude-rules:
- path: _test\.go
linters:
- dupl
exclude-use-default: false

View File

@ -44,7 +44,7 @@ func New2Q(size int) (*TwoQueueCache, error) {
// New2QParams creates a new TwoQueueCache using the provided // New2QParams creates a new TwoQueueCache using the provided
// parameter values. // parameter values.
func New2QParams(size int, recentRatio float64, ghostRatio float64) (*TwoQueueCache, error) { func New2QParams(size int, recentRatio, ghostRatio float64) (*TwoQueueCache, error) {
if size <= 0 { if size <= 0 {
return nil, fmt.Errorf("invalid size") return nil, fmt.Errorf("invalid size")
} }
@ -138,7 +138,6 @@ func (c *TwoQueueCache) Add(key, value interface{}) {
// Add to the recently seen list // Add to the recently seen list
c.ensureSpace(false) c.ensureSpace(false)
c.recent.Add(key, value) c.recent.Add(key, value)
return
} }
// ensureSpace is used to ensure we have space in the cache // ensureSpace is used to ensure we have space in the cache

View File

@ -1,3 +1,5 @@
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0 Mozilla Public License, version 2.0
1. Definitions 1. Definitions

View File

@ -1,25 +1,7 @@
golang-lru golang-lru
========== ==========
This provides the `lru` package which implements a fixed-size Please upgrade to github.com/hashicorp/golang-lru/v2 for all new code as v1 will
thread safe LRU cache. It is based on the cache in Groupcache. not be updated anymore. The v2 version supports generics and is faster; old code
can specify a specific tag, e.g. github.com/hashicorp/golang-lru/v1.0.2 for
Documentation backwards compatibility.
=============
Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru)
Example
=======
Using the LRU is very simple:
```go
l, _ := New(128)
for i := 0; i < 256; i++ {
l.Add(i, nil)
}
if l.Len() != 128 {
panic(fmt.Sprintf("bad len: %v", l.Len()))
}
```

View File

@ -173,7 +173,6 @@ func (c *ARCCache) Add(key, value interface{}) {
// Add to the recently seen list // Add to the recently seen list
c.t1.Add(key, value) c.t1.Add(key, value)
return
} }
// replace is used to adaptively evict from either T1 or T2 // replace is used to adaptively evict from either T1 or T2

View File

@ -6,10 +6,17 @@
"github.com/hashicorp/golang-lru/simplelru" "github.com/hashicorp/golang-lru/simplelru"
) )
const (
// DefaultEvictedBufferSize defines the default buffer size to store evicted key/val
DefaultEvictedBufferSize = 16
)
// Cache is a thread-safe fixed size LRU cache. // Cache is a thread-safe fixed size LRU cache.
type Cache struct { type Cache struct {
lru simplelru.LRUCache lru *simplelru.LRU
lock sync.RWMutex evictedKeys, evictedVals []interface{}
onEvictedCB func(k, v interface{})
lock sync.RWMutex
} }
// New creates an LRU of the given size. // New creates an LRU of the given size.
@ -19,92 +26,206 @@ func New(size int) (*Cache, error) {
// NewWithEvict constructs a fixed size cache with the given eviction // NewWithEvict constructs a fixed size cache with the given eviction
// callback. // callback.
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) { func NewWithEvict(size int, onEvicted func(key, value interface{})) (c *Cache, err error) {
lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted)) // create a cache with default settings
if err != nil { c = &Cache{
return nil, err onEvictedCB: onEvicted,
} }
c := &Cache{ if onEvicted != nil {
lru: lru, c.initEvictBuffers()
onEvicted = c.onEvicted
} }
return c, nil c.lru, err = simplelru.NewLRU(size, onEvicted)
return
}
func (c *Cache) initEvictBuffers() {
c.evictedKeys = make([]interface{}, 0, DefaultEvictedBufferSize)
c.evictedVals = make([]interface{}, 0, DefaultEvictedBufferSize)
}
// onEvicted save evicted key/val and sent in externally registered callback
// outside of critical section
func (c *Cache) onEvicted(k, v interface{}) {
c.evictedKeys = append(c.evictedKeys, k)
c.evictedVals = append(c.evictedVals, v)
} }
// Purge is used to completely clear the cache. // Purge is used to completely clear the cache.
func (c *Cache) Purge() { func (c *Cache) Purge() {
var ks, vs []interface{}
c.lock.Lock() c.lock.Lock()
c.lru.Purge() c.lru.Purge()
if c.onEvictedCB != nil && len(c.evictedKeys) > 0 {
ks, vs = c.evictedKeys, c.evictedVals
c.initEvictBuffers()
}
c.lock.Unlock() c.lock.Unlock()
// invoke callback outside of critical section
if c.onEvictedCB != nil {
for i := 0; i < len(ks); i++ {
c.onEvictedCB(ks[i], vs[i])
}
}
} }
// Add adds a value to the cache. Returns true if an eviction occurred. // Add adds a value to the cache. Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) (evicted bool) { func (c *Cache) Add(key, value interface{}) (evicted bool) {
var k, v interface{}
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() evicted = c.lru.Add(key, value)
return c.lru.Add(key, value) if c.onEvictedCB != nil && evicted {
k, v = c.evictedKeys[0], c.evictedVals[0]
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
}
c.lock.Unlock()
if c.onEvictedCB != nil && evicted {
c.onEvictedCB(k, v)
}
return
} }
// Get looks up a key's value from the cache. // Get looks up a key's value from the cache.
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() value, ok = c.lru.Get(key)
return c.lru.Get(key) c.lock.Unlock()
return value, ok
} }
// Contains checks if a key is in the cache, without updating the // Contains checks if a key is in the cache, without updating the
// recent-ness or deleting it for being stale. // recent-ness or deleting it for being stale.
func (c *Cache) Contains(key interface{}) bool { func (c *Cache) Contains(key interface{}) bool {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() containKey := c.lru.Contains(key)
return c.lru.Contains(key) c.lock.RUnlock()
return containKey
} }
// Peek returns the key value (or undefined if not found) without updating // Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key. // the "recently used"-ness of the key.
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() value, ok = c.lru.Peek(key)
return c.lru.Peek(key) c.lock.RUnlock()
return value, ok
} }
// ContainsOrAdd checks if a key is in the cache without updating the // ContainsOrAdd checks if a key is in the cache without updating the
// recent-ness or deleting it for being stale, and if not, adds the value. // recent-ness or deleting it for being stale, and if not, adds the value.
// Returns whether found and whether an eviction occurred. // Returns whether found and whether an eviction occurred.
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) { func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) {
var k, v interface{}
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock()
if c.lru.Contains(key) { if c.lru.Contains(key) {
c.lock.Unlock()
return true, false return true, false
} }
evicted = c.lru.Add(key, value) evicted = c.lru.Add(key, value)
if c.onEvictedCB != nil && evicted {
k, v = c.evictedKeys[0], c.evictedVals[0]
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
}
c.lock.Unlock()
if c.onEvictedCB != nil && evicted {
c.onEvictedCB(k, v)
}
return false, evicted return false, evicted
} }
// Remove removes the provided key from the cache. // PeekOrAdd checks if a key is in the cache without updating the
func (c *Cache) Remove(key interface{}) { // recent-ness or deleting it for being stale, and if not, adds the value.
// Returns whether found and whether an eviction occurred.
func (c *Cache) PeekOrAdd(key, value interface{}) (previous interface{}, ok, evicted bool) {
var k, v interface{}
c.lock.Lock() c.lock.Lock()
c.lru.Remove(key) previous, ok = c.lru.Peek(key)
if ok {
c.lock.Unlock()
return previous, true, false
}
evicted = c.lru.Add(key, value)
if c.onEvictedCB != nil && evicted {
k, v = c.evictedKeys[0], c.evictedVals[0]
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
}
c.lock.Unlock() c.lock.Unlock()
if c.onEvictedCB != nil && evicted {
c.onEvictedCB(k, v)
}
return nil, false, evicted
}
// Remove removes the provided key from the cache.
func (c *Cache) Remove(key interface{}) (present bool) {
var k, v interface{}
c.lock.Lock()
present = c.lru.Remove(key)
if c.onEvictedCB != nil && present {
k, v = c.evictedKeys[0], c.evictedVals[0]
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
}
c.lock.Unlock()
if c.onEvictedCB != nil && present {
c.onEvictedCB(k, v)
}
return
}
// Resize changes the cache size.
func (c *Cache) Resize(size int) (evicted int) {
var ks, vs []interface{}
c.lock.Lock()
evicted = c.lru.Resize(size)
if c.onEvictedCB != nil && evicted > 0 {
ks, vs = c.evictedKeys, c.evictedVals
c.initEvictBuffers()
}
c.lock.Unlock()
if c.onEvictedCB != nil && evicted > 0 {
for i := 0; i < len(ks); i++ {
c.onEvictedCB(ks[i], vs[i])
}
}
return evicted
} }
// RemoveOldest removes the oldest item from the cache. // RemoveOldest removes the oldest item from the cache.
func (c *Cache) RemoveOldest() { func (c *Cache) RemoveOldest() (key, value interface{}, ok bool) {
var k, v interface{}
c.lock.Lock() c.lock.Lock()
c.lru.RemoveOldest() key, value, ok = c.lru.RemoveOldest()
if c.onEvictedCB != nil && ok {
k, v = c.evictedKeys[0], c.evictedVals[0]
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
}
c.lock.Unlock() c.lock.Unlock()
if c.onEvictedCB != nil && ok {
c.onEvictedCB(k, v)
}
return
}
// GetOldest returns the oldest entry
func (c *Cache) GetOldest() (key, value interface{}, ok bool) {
c.lock.RLock()
key, value, ok = c.lru.GetOldest()
c.lock.RUnlock()
return
} }
// Keys returns a slice of the keys in the cache, from oldest to newest. // Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *Cache) Keys() []interface{} { func (c *Cache) Keys() []interface{} {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() keys := c.lru.Keys()
return c.lru.Keys() c.lock.RUnlock()
return keys
} }
// Len returns the number of items in the cache. // Len returns the number of items in the cache.
func (c *Cache) Len() int { func (c *Cache) Len() int {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() length := c.lru.Len()
return c.lru.Len() c.lock.RUnlock()
return length
} }

View File

@ -25,7 +25,7 @@ type entry struct {
// NewLRU constructs an LRU of the given size // NewLRU constructs an LRU of the given size
func NewLRU(size int, onEvict EvictCallback) (*LRU, error) { func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
if size <= 0 { if size <= 0 {
return nil, errors.New("Must provide a positive size") return nil, errors.New("must provide a positive size")
} }
c := &LRU{ c := &LRU{
size: size, size: size,
@ -73,6 +73,9 @@ func (c *LRU) Add(key, value interface{}) (evicted bool) {
func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
if ent, ok := c.items[key]; ok { if ent, ok := c.items[key]; ok {
c.evictList.MoveToFront(ent) c.evictList.MoveToFront(ent)
if ent.Value.(*entry) == nil {
return nil, false
}
return ent.Value.(*entry).value, true return ent.Value.(*entry).value, true
} }
return return
@ -106,7 +109,7 @@ func (c *LRU) Remove(key interface{}) (present bool) {
} }
// RemoveOldest removes the oldest item from the cache. // RemoveOldest removes the oldest item from the cache.
func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) { func (c *LRU) RemoveOldest() (key, value interface{}, ok bool) {
ent := c.evictList.Back() ent := c.evictList.Back()
if ent != nil { if ent != nil {
c.removeElement(ent) c.removeElement(ent)
@ -117,7 +120,7 @@ func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) {
} }
// GetOldest returns the oldest entry // GetOldest returns the oldest entry
func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) { func (c *LRU) GetOldest() (key, value interface{}, ok bool) {
ent := c.evictList.Back() ent := c.evictList.Back()
if ent != nil { if ent != nil {
kv := ent.Value.(*entry) kv := ent.Value.(*entry)
@ -142,6 +145,19 @@ func (c *LRU) Len() int {
return c.evictList.Len() return c.evictList.Len()
} }
// Resize changes the cache size.
func (c *LRU) Resize(size int) (evicted int) {
diff := c.Len() - size
if diff < 0 {
diff = 0
}
for i := 0; i < diff; i++ {
c.removeOldest()
}
c.size = size
return diff
}
// removeOldest removes the oldest item from the cache. // removeOldest removes the oldest item from the cache.
func (c *LRU) removeOldest() { func (c *LRU) removeOldest() {
ent := c.evictList.Back() ent := c.evictList.Back()

View File

@ -1,3 +1,4 @@
// Package simplelru provides simple LRU implementation based on build-in container/list.
package simplelru package simplelru
// LRUCache is the interface for simple LRU cache. // LRUCache is the interface for simple LRU cache.
@ -10,7 +11,7 @@ type LRUCache interface {
// updates the "recently used"-ness of the key. #value, isFound // updates the "recently used"-ness of the key. #value, isFound
Get(key interface{}) (value interface{}, ok bool) Get(key interface{}) (value interface{}, ok bool)
// Check if a key exsists in cache without updating the recent-ness. // Checks if a key exists in cache without updating the recent-ness.
Contains(key interface{}) (ok bool) Contains(key interface{}) (ok bool)
// Returns key's value without updating the "recently used"-ness of the key. // Returns key's value without updating the "recently used"-ness of the key.
@ -31,6 +32,9 @@ type LRUCache interface {
// Returns the number of items in the cache. // Returns the number of items in the cache.
Len() int Len() int
// Clear all cache entries // Clears all cache entries.
Purge() Purge()
// Resizes cache, returning number evicted
Resize(int) int
} }

16
vendor/github.com/hashicorp/golang-lru/testing.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
package lru
import (
"crypto/rand"
"math"
"math/big"
"testing"
)
func getRand(tb testing.TB) int64 {
out, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
if err != nil {
tb.Fatal(err)
}
return out.Int64()
}

4
vendor/modules.txt vendored
View File

@ -38,8 +38,8 @@ github.com/hashicorp/go-immutable-radix
# github.com/hashicorp/go-syslog v1.0.0 # github.com/hashicorp/go-syslog v1.0.0
## explicit ## explicit
github.com/hashicorp/go-syslog github.com/hashicorp/go-syslog
# github.com/hashicorp/golang-lru v0.5.0 # github.com/hashicorp/golang-lru v1.0.2
## explicit ## explicit; go 1.12
github.com/hashicorp/golang-lru github.com/hashicorp/golang-lru
github.com/hashicorp/golang-lru/simplelru github.com/hashicorp/golang-lru/simplelru
# github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb # github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb