groupcache源码解析(IRU)

Posted 会跳舞的哈密瓜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了groupcache源码解析(IRU)相关的知识,希望对你有一定的参考价值。

一、什么是LRU

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。

二、代码解析

iru/iru.go

type Cache struct {
  //缓存中最多存储的条数,当MaxEntries为0时没有限制
	MaxEntries int

	//销毁前回调
	OnEvicted func(key Key, value interface{})
	//链表
	ll    *list.List
  //key为任意类型,值为指向链表结点的指针
	cache map[interface{}]*list.Element
}


type Key interface{}

//访问入口结构
type entry struct {
	key   Key
	value interface{}
}
//初始化一个cache
func New(maxEntries int) *Cache {
	return &Cache{
		MaxEntries: maxEntries,
		ll:         list.New(),  //list.New() 初始化链表
		cache:      make(map[interface{}]*list.Element),
	}
}
//向cache中添加一个value
func (c *Cache) Add(key Key, value interface{}) {
	if c.cache == nil {    //如果cache没有初始化先初始化cache和l1
		c.cache = make(map[interface{}]*list.Element)
		c.ll = list.New()
	}
	if ee, ok := c.cache[key]; ok {  //如果key存在将记录移到链表头部,然后将值设置为value(保证最近访问的在最前面)
    c.ll.MoveToFront(ee)   //MoveToFront(e) 中e不能为空
		ee.Value.(*entry).value = value
		return
	}
  //如果key不存在,创建一条记录,插入到链表头部,
	ele := c.ll.PushFront(&entry{key, value})  // PushFront(v interface{})返回的是*Element ,作用是在链表头部插入一个值为v的新元素

	//cache这个map设置key为Key类型的key,value为*list.Element类型的ele
	c.cache[key] = ele
	//链表长度超过最大值,就会出发清理操作
	if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
		c.RemoveOldest()
	}
}
//根据传入的key查询value
func (c *Cache) Get(key Key) (value interface{}, ok bool) {
	if c.cache == nil {
		return
	}
	//如果存在,将ele移到链表头部,返回entry的值
	if ele, hit := c.cache[key]; hit {
		c.ll.MoveToFront(ele)
		return ele.Value.(*entry).value, true
	}
	return
}
//如果key存在,调用removeElement删除链表和缓存中的元素
func (c *Cache) Remove(key Key) {
	if c.cache == nil {
		return
	}
	if ele, hit := c.cache[key]; hit {
		c.removeElement(ele)
	}
}
//移除最久未被访问的元素
func (c *Cache) RemoveOldest() {
	if c.cache == nil {
		return
	}
	ele := c.ll.Back()  //Back()返回链表最后一个元素,如果为空返回nil
	if ele != nil {
		c.removeElement(ele)
	}
}
//
func (c *Cache) removeElement(e *list.Element) {
	c.ll.Remove(e)   // Remove(e) 从链表中移除e返回e.Value
	// Value本身是interface{}类型,通过类型断言转成*entry类型
	kv := e.Value.(*entry)
  // 删除cache这个map中key为kv.key这个元素;也就是链表中删了之后缓存中也得删
	delete(c.cache, kv.key)
  //这里如果回调函数不为空,要执行一下回调函数
	if c.OnEvicted != nil {
		c.OnEvicted(kv.key, kv.value)
	}
}
//返回缓存中缓存的数量,通过Len()获取
func (c *Cache) Len() int {
	if c.cache == nil {
		return 0
	}
	return c.ll.Len()
}
//删除缓存中所有条目,如果有回调函数OnEvicted(),则先调用所有回调函数,然后置空
func (c *Cache) Clear() {
	if c.OnEvicted != nil {
		for _, e := range c.cache {
			kv := e.Value.(*entry)
			c.OnEvicted(kv.key, kv.value)
		}
	}
	c.ll = nil
	c.cache = nil
}

以上是关于groupcache源码解析(IRU)的主要内容,如果未能解决你的问题,请参考以下文章

groupcache源码解析(IRU)

groupcache源码解析-概览

groupcache源码分析

源码分析之groupcache之consistenthash

groupcache源码分析(singleflight防缓存击穿)

groupcache源码分析(singleflight防缓存击穿)