一、概述

  我们今天开始第一部分“golang技能提升”。这一块我计划分析3个项目,一个是很流行的golang源码阅读入门项目cache2go,接着是非常流行的memcache的go语言版groupcache,最后是docker项目中分出来的核心组件之一containerd,通过这3个项目的源码全解析来达到golang能力上一个台阶的目的。

  在本系列教程的学习过程中,我希望你能够做到如下要求:如果你是一个go语言新手,在看下面的代码分析过程中你肯定会遇到一些自己陌生的编码方式、陌生的知识点,这个过程中我希望你遇到一个点掌握一个点,比如看到下面的代码用到了锁,就去找各种资料把锁相关的知识点学了。看到回调函数,就思考一下人家为什么这些地方都使用回调函数,有什么好处。这样在看完这个项目源码分析后,你就能学到一部分知识模块

二、cache2go是什么

  这是一个在github上开源的项目,原作者这样介绍:

  Concurrency-safe golang caching library with expiration capabilities.

  看懂了吗?简单说就是有心跳机制的并发安全的go语言缓存库。ok,下面我们要分析的这个项目是一个缓存库,并且有2大特性,并发安全和心跳机制!

三、项目结构

项目目录结构如上图所示,可以看到功能实现相关源码文件只有3个:

  • cache.go

  • cacheitem.go

  • cachetable.go

四、关键数据结构

  项目中只涉及到2个复杂的数据类型,分别是:

  • CacheItem

  • CacheTable

  含义和字面意义一致,一个是缓存表,一个是缓存表中的条目。下面分别看一下这2个结构是怎么定义的。

1、CacheItem

  CacheItem类型是用来表示一个单独的缓存条目,源码如下所示,每个字段都很清晰易懂,注释稍长的属性已经中文标注。

 1// CacheItem is an individual cache item
2// Parameter data contains the user-set value in the cache.
3type CacheItem struct {
4    sync.RWMutex
5
6    // The item's key.
7    key interface{}
8    // The item's data.
9    data interface{}
10    //【不被访问后存活时间】
11    // How long will the item live in the cache when not being accessed/kept alive.
12    lifeSpan time.Duration
13
14    // Creation timestamp.
15    createdOn time.Time
16    // Last access timestamp.
17    accessedOn time.Time
18    // How often the item was accessed.
19    accessCount int64
20    //【被删除时触发的回调方法】
21    // Callback method triggered right before removing the item from the cache
22    aboutToExpire func(key interface{})
23}

2、CacheTable

  CacheTable描述了缓存中的一个表项,里面的items属性就是上面讲到的CacheItem类型实例。这里除了常规属性外还有若干函数类型的属性,源码如下所示(最后几行显示样式好像抽筋了~):

 1// CacheTable is a table within the cache
2type CacheTable struct {
3    sync.RWMutex
4
5    // The table's name.
6    name string
7    // All cached items.
8    //【一个表中的所有条目都存在这个map里,map的key是任意类型,值是CacheItem指针类型】
9    items map[interface{}]*CacheItem
10
11    // Timer responsible for triggering cleanup.
12    //【负责触发清除操作的计时器】
13    cleanupTimer *time.Timer
14    // Current timer duration.
15    //【清除操作触发的时间间隔】
16    cleanupInterval time.Duration
17
18    // The logger used for this table.
19    logger *log.Logger
20
21    // Callback method triggered when trying to load a non-existing key.
22    //【需要提取一个不存在的key时触发的回调函数】
23    loadData func(key interface{}, args ...interface{}) *CacheItem
24    // Callback method triggered when adding a new item to the cache.
25    //【增加一个缓存条目时触发的回调函数】
26    addedItem func(item *CacheItem)
27    // Callback method triggered before deleting an item from the cache.
28    //【删除前触发的回调函数】
29    aboutToDeleteItem func(item *CacheItem)
30}

  如上所示,cache2go的核心数据结构很简洁,应该比较容易理解。当然没有完全理解每个字段这样定义的原因也别急,看完下面的代码逻辑后反过来再看数据结构,肯定就明白每个字段的作用了。

五、代码逻辑

  我们的思路是从下往上分析代码,什么意思呢?就是说先看和item相关的操作,再看包含item的table相关的代码,最后看操作table的cache级别的逻辑。所以下面我们要先看cacheitem.go的代码,接着分析cachetable.go,然后看cache.go,最后看3个文件中的源码互相间关联是什么,最后看example,也就是cache怎么玩~

1、cacheitem.go

  如上图,这个源码文件中只包含了一个类型CacheItem和一个函数NewCacheItem()的定义。CacheItem有哪些属性前面已经看过了,下面先看NewCacheItem()函数:

 1// NewCacheItem returns a newly created CacheItem.
2// Parameter key is the item's cache-key.
3// Parameter lifeSpan determines after which time period without an access the item
4// will get removed from the cache.
5// Parameter data is the item's value.
6func NewCacheItem(key interface{}, lifeSpan time.Duration, data interface{}) *CacheItem {
7    t := time.Now()
8    return &CacheItem{
9        key:           key,
10        lifeSpan:      lifeSpan,
11        createdOn:     t,
12        accessedOn:    t,
13        accessCount:   0,
14        aboutToExpire: nil,
15        data:          data,
16    }
17}
  • 代码如上所示,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的类型是一个可以接收任意类型参数的函数类型。有点绕,需要静下心来理解一下哦~

  源码如下:

 1// KeepAlive marks an item to be kept for another expireDuration period.
2//【将accessedOn更新为当前时间】
3func (item *CacheItem) KeepAlive() {
4    item.Lock()
5    defer item.Unlock()
6    item.accessedOn = time.Now()
7    item.accessCount++
8}
9
10// LifeSpan returns this item's expiration duration.
11func (item *CacheItem) LifeSpan() time.Duration {
12    // immutable
13    return item.lifeSpan
14}
15
16// AccessedOn returns when this item was last accessed.
17func (item *CacheItem) AccessedOn() time.Time {
18    item.RLock()
19    defer item.RUnlock()
20    return item.accessedOn
21}
22
23// CreatedOn returns when this item was added to the cache.
24func (item *CacheItem) CreatedOn() time.Time {
25    // immutable
26    return item.createdOn
27}
28
29// AccessCount returns how often this item has been accessed.
30func (item *CacheItem) AccessCount() int64 {
31    item.RLock()
32    defer item.RUnlock()
33    return item.accessCount
34}
35
36// Key returns the key of this cached item.
37func (item *CacheItem) Key() interface{} {
38    // immutable
39    return item.key
40}
41
42// Data returns the value of this cached item.
43func (item *CacheItem) Data() interface{} {
44    // immutable
45    return item.data
46}
47
48// SetAboutToExpireCallback configures a callback, which will be called right
49// before the item is about to be removed from the cache.
50//【设置回调函数,当一个item被移除的时候这个函数会被调用】
51func (item *CacheItem) SetAboutToExpireCallback(f func(interface{})) {
52    item.Lock()
53    defer item.Unlock()
54    item.aboutToExpire = f
55}

  到这里就看完这个源文件了,是不是很轻松呢~

  上面的一堆方法功能都还是很直观的,今天我们先看到这里,下一讲继续分析cachetable相关代码。

启航 - cache2go源码分析的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

随机推荐

  1. DWM1000 Blink结构 -- 帧过滤第一节

    DWM1000 帧结构分析主要学习DWM1000 帧过滤功能,希望在目前DS-TWR定位系统中增加中断和帧过滤功能,帧过滤功能可以有效减少系统中的各个模块同时收发数据时的干扰问题,从而极大的提供系统稳 ...

  2. hadoop2-HBase的Java API操作

    Hbase提供了丰富的Java API,以及线程池操作,下面我用线程池来展示一下使用Java API操作Hbase. 项目结构如下: 我使用的Hbase的版本是 hbase-0.98.9-hadoop ...

  3. 基于用户协同过滤--UserCF

    UserCF  本系列文章主要介绍推荐系统领域相关算法原理及其实现.本文以项亮大神的<推荐系统实践>作为切入点,介绍推荐系统最基础的算法(可能也是最好用的)--基于用户的协同过滤算法(Us ...

  4. h5、css3基础

    一.html(超文本标记语言) 作用:实现页面布局 页面由许多标记符号组成 由浏览器解释执行 二.html主题创建方式 !(英文状态)+tab html:4s+tab html:5+tab 三.标签 ...

  5. position属性sticky和fixed的区别比较

    position属性之fixed fixed总是以body为定位时的对象,总是根据浏览器窗口来进行元素的定位,通过left,right,top,bottom属性进行定位. <!DOCTYPE h ...

  6. kvm+libvirt虚拟机快照浅析[转]

    浅析snapshots, blockcommit,blockpull 作者:Kashyap Chamarthy <kchamart#redhat.com> Date: Tue, 23 Oc ...

  7. Gradle 学习二

    按照本指南,您将创建一个简单的Gradle项目,调用一些基本的Gradle命令,并了解Gradle如何管理项目 1.初始化项目创建项目目录 ❯ mkdir basic-demo ❯ cd basic- ...

  8. web项目如何使用Material Icons

    使用文档链接 图标库 最简单的使用方法 引入 <link href="https://fonts.googleapis.com/icon?family=Material+Icons&q ...

  9. 巧用PHP中__get()魔术方法

    PHP中的魔术方法有很多,这些魔术方法可以让PHP脚本在某些特定的情况下自动调用.比如 __construct() 每次实例化一个类都会先调用该方法进行初始化.这里我们讲一下__get() 魔术方法的 ...

  10. Centos7 编译安装 Nginx PHP Mariadb Memcached 扩展 ZendOpcache扩展 (实测 笔记 Centos 7.3 + Openssl 1.1.0e + Mariadb 10.1.22 + Nginx 1.12.0 + PHP 7.1.4 + Laravel 5.4 )

    环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7-x86_64-Minimal-1611.iso 安装步骤: 1.准备 1.0 查看硬 ...