CloudGeek读源码系列-cache2go源码解析
Posted cloudgeek
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CloudGeek读源码系列-cache2go源码解析相关的知识,希望对你有一定的参考价值。
一、cache2go是什么
- 作者说:Concurrency-safe golang caching library with expiration capabilities.
什么意思呢?
- 有心跳机制的并发安全的go语言缓存库
学习一门语言有一个很好的方法就是阅读优秀的开源项目源码,学习优秀前辈的编码方式,同时发现自己的知识盲区,不断获取新知识!cache2go很精简,代码量很少,非常适合刚接触go语言的同学作为入门级项目来读源码。
下面我会先介绍项目组成,然后讲解核心数据结构,再梳理整个实现逻辑,来帮助大家掌握整个项目。
二、项目结构
项目目录结构如上图所示,可以看到功能实现相关源码文件只有3个:
- cache.go
- cacheitem.go
- cachetable.go
三、关键数据结构
项目中只涉及到2个复杂的数据类型,分别是:
- CacheItem
- CacheTable
含义和字面意义一致,一个是缓存表,一个是缓存表中的条目。下面分别看一下这2个结构是怎么定义的。
1、CacheItem
CacheItem类型是用来表示一个单独的缓存条目,源码如下所示,每个字段都很清晰易懂,注释稍长的属性已经中文标注。
type CacheItem struct { sync.RWMutex // The item‘s key. key interface{} // The item‘s data. data interface{} // How long will the item live in the cache when not being accessed/kept alive.【不被访问后存活时间】 lifeSpan time.Duration // Creation timestamp. createdOn time.Time // Last access timestamp. accessedOn time.Time // How often the item was accessed. accessCount int64 // Callback method triggered right before removing the item from the cache【被删除时触发的回调方法】 aboutToExpire func(key interface{}) }
2、CacheTable
CacheTable描述了缓存中的一个表项,里面的items属性就是上面讲到的CacheItem类型实例。这里除了常规属性外还有若干函数类型的属性,源码如下所示:
type CacheTable struct { sync.RWMutex // The table‘s name. name string // All cached items.【一个表中的所有条目都存在这个map里,map的key是任意类型,值是CacheItem指针类型】 items map[interface{}]*CacheItem // Timer responsible for triggering cleanup.【负责触发清除操作的计时器】 cleanupTimer *time.Timer // Current timer duration.【清除操作触发的时间间隔】 cleanupInterval time.Duration // The logger used for this table. logger *log.Logger // Callback method triggered when trying to load a non-existing key.【需要提取一个不存在的key时触发的回调函数】 loadData func(key interface{}, args ...interface{}) *CacheItem // Callback method triggered when adding a new item to the cache.【增加一个缓存条目时触发的回调函数】 addedItem func(item *CacheItem) // Callback method triggered before deleting an item from the cache.【删除前触发的回调函数】 aboutToDeleteItem func(item *CacheItem) }
如上所示,cache2go的核心数据结构很简洁,应该比较容易理解。当然没有完全理解每个字段这样定义的原因也别急,看完下面的代码逻辑后反过来再看数据结构,肯定就明白每个字段的作用了。
四、代码逻辑
我们的思路是从下往上分析代码,什么意思呢?就是说先看和item相关的操作,再看包含item的table相关的代码,最后看操作table的cache级别的逻辑。所以下面我们要先看cacheitem.go的代码,接着分析cachetable.go,然后看cache.go,最后看3个文件中的源码互相间关联是什么。
1、cacheitem.go
如上图,这个源码文件中只包含了一个类型CacheItem和一个函数NewCacheItem()的定义。CacheItem有哪些属性前面已经看过了,下面先看NewCacheItem()函数:
func NewCacheItem(key interface{}, lifeSpan time.Duration, data interface{}) *CacheItem { t := time.Now() return &CacheItem{ key: key, lifeSpan: lifeSpan, createdOn: t, accessedOn: t, accessCount: 0, aboutToExpire: nil, data: data, } }
- 代码如上所示,NewCacheItem()函数接收3个参数,分别是键、值、存活时间(key、data、lifeSpan),返回一个CacheItem类型实例的指针。
- 其中createOn和accessedOn设置成了当前时间,aboutToExpire也就是被删除时触发的回调方法暂时设置成nil,不难想到这个函数完成后还需要调用其他方法来设置这个属性。
cacheitem.go中除了CacheItem类型的定义,NewCacheItem()函数的定义外,还有一个部分就是CacheItem的方法定义,一共8个
源码看起来行数不少,内容其实很简单,主要是元素获取操作,这里需要留意读写操作都是加了相应的读写锁的,还记得开头提到的cache2go是一个并发安全的程序吗?并发安全就体现在这些地方。下面最复杂的是最后一个回调函数的设置,这个方法的形参是f func(interface{}),也就是说形参名为f,形参类型是func(interface{}),这是一个函数类型,这个函数类型的参数是一个interface{},也就是空接口,因为任意类型都可以被认为实现了空接口,所以这里可以接收任意类型的实参。也就是说f的类型是一个可以接收任意类型参数的函数类型。有点绕,需要静下心来理解一下哦~
源码如下:
// KeepAlive marks an item to be kept for another expireDuration period.【将accessedOn更新为当前时间】 func (item *CacheItem) KeepAlive() { item.Lock() defer item.Unlock() item.accessedOn = time.Now() item.accessCount++ } // LifeSpan returns this item‘s expiration duration. func (item *CacheItem) LifeSpan() time.Duration { // immutable return item.lifeSpan } // AccessedOn returns when this item was last accessed. func (item *CacheItem) AccessedOn() time.Time { item.RLock() defer item.RUnlock() return item.accessedOn } // CreatedOn returns when this item was added to the cache. func (item *CacheItem) CreatedOn() time.Time { // immutable return item.createdOn } // AccessCount returns how often this item has been accessed. func (item *CacheItem) AccessCount() int64 { item.RLock() defer item.RUnlock() return item.accessCount } // Key returns the key of this cached item. func (item *CacheItem) Key() interface{} { // immutable return item.key } // Data returns the value of this cached item. func (item *CacheItem) Data() interface{} { // immutable return item.data } // SetAboutToExpireCallback configures a callback, which will be called right // before the item is about to be removed from the cache.【设置回调函数,当一个item被移除的时候这个函数会被调用】 func (item *CacheItem) SetAboutToExpireCallback(f func(interface{})) { item.Lock() defer item.Unlock() item.aboutToExpire = f }
到这里就看完这个源文件了,是不是很轻松呢~
下面继续看另外2个源码文件吧
2、cachetable.go
3、cache.go
请尝试网页搜索
以上是关于CloudGeek读源码系列-cache2go源码解析的主要内容,如果未能解决你的问题,请参考以下文章