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

提供 lrucache 的适配实现 #3

Open
flycash opened this issue Aug 24, 2023 · 5 comments
Open

提供 lrucache 的适配实现 #3

flycash opened this issue Aug 24, 2023 · 5 comments

Comments

@flycash
Copy link
Contributor

flycash commented Aug 24, 2023

目前在 GO 语言里面,有一个比较有名的项目,叫做 https://github.com/hashicorp/golang-lru,把这个适配过来我们的 Cache 接口。

同样保持面向依赖注入的风格。

@hookokoko
Copy link

想确认下是想要实现这种效果吗?

type ELRUCache struct {
	Cache  // interface类型,后续注入不同的cache实现,比如内存、redis、红黑树等
	List *list.List
}

func main() {
	var elru ELRUCache
	elru = ELRUCache{c{}, list.New()}  // c{}实现了Cache接口
        ...
}

@xuhaidong1
Copy link

有个问题,golang-lru.expirable golang-lru只提供了统一的key过期时间,不支持对key指定过期时间,如果适配过来的话对key指定过期时间这个功能就需要阉割掉了;如果我们既要用golang-lru又要自己管理过期时间的话,实现方式和这个关闭的pr差不多,但会存在并发问题。这样看来最合适的办法是自研一个lrucache...

@flycash
Copy link
Contributor Author

flycash commented Aug 29, 2023

我草!这么坑?

@flycash
Copy link
Contributor Author

flycash commented Aug 29, 2023

那还是算了,我们自己搞一个吧

@flycash flycash closed this as completed Aug 29, 2023
@flycash flycash reopened this Sep 26, 2023
@Stone-afk
Copy link
Collaborator

简单实现

type EvictCallback[K comparable, V any] func(key K, value V)

type LRU[K comparable, V any] struct {
	capacity int
	list     *list.List
	data     map[K]*list.Element
	onEvict  EvictCallback[K, V]
}

func NewLRU[K comparable, V any]() *LRU[K, V] {
	return &LRU[K, V]{
		list:     list.New(),
		data:     make(map[K]*list.Element, 16),
		capacity: 200,
	}
}

func (l *LRU[K, V]) Purge() {
	for k, v := range l.data {
		if l.onEvict != nil {
			entry := v.Value.(*Entry)
			l.onEvict(entry.key, entry.value)
		}
		l.delete(k)
	}
	l.list.Init()
}


func (l *LRU[K, V]) Add(key K, value V, expiration time.Time) (evicted bool) {
	ent := &Entry{key: key, value: value, expiration: expiration}
	if elem, ok := l.data[key]; ok {
		elem.Value = ent
		l.list.MoveToFront(elem)
		return false
	}
	elem := l.list.PushFront(ent)
	l.data[key] = elem
	evict := l.Len() > l.capacity
	if evict {
		l.removeOldest()
	}
	return evict
}

func (l *LRU[K, V]) removeOldest() {
	if ent := l.list.Back(); ent != nil {
		l.removeElement(ent)
	}
}

func (l *LRU[K, V]) removeElement(e *list.Element) {
	l.list.Remove(e)
	entry := e.Value.(*Entry)
	l.delete(entry.key)
	if l.onEvict != nil {
		l.onEvict(entry.key, entry.value)
	}
}

func (l *LRU[K, V]) Get(key K) (value V, ok bool) {
	if elem, ok := l.data[key]; ok {
		entry := elem.Value.(*Entry)
		if entry.expiration.Before(time.Now()) {
			l.list.Remove(elem)
			l.delete(key)
			return
		}
		l.list.MoveToFront(elem)
		return entry.value, true
	}
	return
}

type Cache struct {
	ecache.Cache
	lru  *LRU[string, any]
	lock sync.RWMutex
}


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

No branches or pull requests

4 participants