driftctl/enumeration/remote/cache/cache.go

103 lines
1.8 KiB
Go
Raw Normal View History

package cache
2021-05-24 17:05:36 +00:00
import (
2021-05-25 10:36:48 +00:00
"container/list"
2021-05-24 17:05:36 +00:00
"sync"
)
2021-05-24 17:05:36 +00:00
type Cache interface {
2021-05-25 10:36:48 +00:00
Put(string, interface{}) bool
2021-05-24 17:05:36 +00:00
Get(string) interface{}
2021-10-08 09:59:58 +00:00
GetAndLock(string) interface{}
Unlock(string)
2021-05-25 10:36:48 +00:00
Len() int
2021-05-24 17:05:36 +00:00
}
2021-05-25 10:36:48 +00:00
type LRUCache struct {
2021-10-08 09:59:58 +00:00
cap int
mu *sync.Mutex
l *list.List
m map[string]*list.Element
lockMap *sync.Map
}
2021-05-25 10:36:48 +00:00
type pair struct {
key string
value interface{}
}
func New(capacity int) Cache {
return &LRUCache{
2021-10-08 09:59:58 +00:00
cap: capacity,
mu: &sync.Mutex{},
l: &list.List{},
m: make(map[string]*list.Element, capacity),
lockMap: &sync.Map{},
2021-05-25 10:36:48 +00:00
}
}
func (c *LRUCache) Get(key string) interface{} {
c.mu.Lock()
defer c.mu.Unlock()
// if the key exists, move to front
if node, ok := c.m[key]; ok {
val := node.Value.(*list.Element).Value.(pair).value
c.l.MoveToFront(node)
return val
}
2021-05-25 10:36:48 +00:00
return nil
}
func (c *LRUCache) Put(key string, value interface{}) bool {
c.mu.Lock()
defer c.mu.Unlock()
2021-05-25 10:36:48 +00:00
2021-06-04 13:26:13 +00:00
if c.cap == 0 {
return false
}
2021-05-25 10:36:48 +00:00
// if the key already exists, move to front and update the value
if node, ok := c.m[key]; ok {
c.l.MoveToFront(node)
node.Value.(*list.Element).Value = pair{key: key, value: value}
return true
2021-05-25 10:36:48 +00:00
}
// if the list is full, delete the last element
2021-05-25 10:36:48 +00:00
if c.l.Len() == c.cap {
idx := c.l.Back().Value.(*list.Element).Value.(pair).key
delete(c.m, idx)
c.l.Remove(c.l.Back())
}
2021-05-25 10:36:48 +00:00
// initialize a new list node
node := &list.Element{
Value: pair{
key: key,
value: value,
},
}
element := c.l.PushFront(node)
c.m[key] = element
return false
}
2021-05-25 10:36:48 +00:00
func (c *LRUCache) Len() int {
return c.l.Len()
}
2021-10-08 09:59:58 +00:00
func (c *LRUCache) GetAndLock(s string) interface{} {
lock, _ := c.lockMap.LoadOrStore(s, &sync.Mutex{})
lock.(*sync.Mutex).Lock()
return c.Get(s)
}
func (c *LRUCache) Unlock(s string) {
lock, exist := c.lockMap.Load(s)
if exist {
lock.(*sync.Mutex).Unlock()
}
}