1.简介
groupcache使用Cache(结构体名称)进行数据存储,Cache内部利用lru缓存淘汰策略进行数据淘汰
2. 结构体字段
type Cache struct {
// MaxEntries is the maximum number of cache entries before
// an item is evicted. Zero means no limit.
// 允许使用的最大内存
MaxEntries int
// OnEvicted optionally specifies a callback function to be
// executed when an entry is purged from the cache.
// 数据被淘汰时的钩子函数
OnEvicted func(key Key, value interface{})
// 实现lru的双向链表
ll *list.List
// 使用map进行key 双向链表节点指针的存储, 方便数据的快速访问。 ll 双向链表也存储key value 主要用来lru
cache map[interface{}]*list.Element
}
// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
type Key interface{}
type entry struct {
key Key
value interface{}
}
// New creates a new Cache.
// If maxEntries is zero, the cache has no limit and it's assumed
// that eviction is done by the caller.
func New(maxEntries int) *Cache {
return &Cache{
MaxEntries: maxEntries,
ll: list.New(),
cache: make(map[interface{}]*list.Element),
}
}
3. 数据添加/更新
// Add adds a value to the cache.
func (c *Cache) Add(key Key, value interface{}) {
if c.cache == nil {
// 初始化
c.cache = make(map[interface{}]*list.Element)
c.ll = list.New()
}
// 判断键是否存在
if ee, ok := c.cache[key]; ok {
// 如果键存在,将该节点移到对头
c.ll.MoveToFront(ee)
// 更新值
ee.Value.(*entry).value = value
return
}
// 如果键不存在
// 键值对存在entry下,该节点加到对头, 返回Element
ele := c.ll.PushFront(&entry{key, value})
// map存储该节点
c.cache[key] = ele
// 如果使用内存大于限制时,删除最少对尾元素
if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
c.RemoveOldest()
}
}
1. 数据存在时,更新值,并将该节点移到对头
2. 数据不存在时,生成新节点,并增加到队头,如果超出内存限制时,删除队尾元素
4. 查找数据
// Get looks up a key's value from the cache.
func (c *Cache) Get(key Key) (value interface{}, ok bool) {
if c.cache == nil {
// 如果cache 没有初始化 直接返回 false
return
}
// 判断map是否有该键
if ele, hit := c.cache[key]; hit {
// 如果有该键
// 节点移到队头
c.ll.MoveToFront(ele)
// 返回该值
return ele.Value.(*entry).value, true
}
// 不存在该键时 返回false
return
}
直接通过cache(map结构)查找,如果存在,将该节点移到队头,返回该值,其他情况返回nil, false
5. 删除数据
// Remove removes the provided key from the cache.
func (c *Cache) Remove(key Key) {
if c.cache == nil {
return
}
if ele, hit := c.cache[key]; hit {
// 如果数据存在直接删除该节点
c.removeElement(ele)
}
}
如果key在cache中,直接删除该节点
6. 节点删除
func (c *Cache) removeElement(e *list.Element) {
// 双向链表删除该元素
c.ll.Remove(e)
kv := e.Value.(*entry)
// map 删除该key
delete(c.cache, kv.key)
// 执行删除元素的回调函数
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}
在删除数据和删除队尾元素时,都调用该方法。该方法将数据删除的同时,会执行对应的回调函数
版权声明:本文为qq_22323251原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。