Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request for RemoveWithoutEvict API. #171

Open
StLeoX opened this issue Feb 4, 2024 · 1 comment · May be fixed by #176
Open

Request for RemoveWithoutEvict API. #171

StLeoX opened this issue Feb 4, 2024 · 1 comment · May be fixed by #176

Comments

@StLeoX
Copy link

StLeoX commented Feb 4, 2024

lru always calls onEvict once when Remove is called. In a case where the element that I want to remove is already processed, and the processing logic is different from onEvict, I want to simply remove the element RemoveWithoutEvict API, it may be written as follow:

 func (c *Cache[K, V]) RemoveWithoutEvict(key K) (present bool) {
     c.lock.Lock()
     present = c.lru.Remove(key)
     c.lock.Unlock()
     return
 }
@bodgit bodgit linked a pull request Apr 2, 2024 that will close this issue
@turtletowerz
Copy link

Second this, it would essentially allow for an LRU Pool where values can be removed and added with a capacity limit. I also wanted to offer a temporary solution I found to this annoying issue.

This is an example I created based off of bodgit/sevenzip

import (
	"io"

	lru "github.com/hashicorp/golang-lru/v2"
)

type cacher struct {
	cache *lru.Cache[int64, io.ReadCloser]
}

func NewCache() (*cacher, error) {
	cache, err := lru.NewWithEvict(10, func(key int64, value io.ReadCloser) {
		if value != nil {
			// Do something here. The value has been removed and you
			// can catch the eviction To have some conditional action.
			value.Close()
		}
	})
	if err != nil {
		return nil, err
	}

	return &cacher{cache}, nil
}

func (c *cacher) Get(offset int64) (io.ReadCloser, bool) {
	if v, ok := c.cache.Peek(offset); ok {

		// Update the value to nil so we know that
		// it has been removed but NOT evicted.
		c.cache.Add(offset, nil)

		// Remove the value which forces an eviction
		// of the nil value and return the actual value.
		return v, c.cache.Remove(offset)
	}
	return nil, false
}

func (c *cacher) Add(offset int64, rc io.ReadCloser) bool {
	// Don't allow nil values to be added.
	if rc == nil {
		return false
	}
	return c.cache.Add(offset, rc)
}

Note that this will only work with values comparable to nil, and it works under the assumption that no values in your LRU cache will be nil. When getting a value you can force update an entry to nil, and then conditionally do an action during eviction to do a "fake" eviction while keeping the actual value. This is pretty useful for things like files that may need to be closed during eviction but not when you just want to Get the value.

@bodgit this could be a temporary fix for your PR for sevenzip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants