理想状况下,一个文件第一次访问,缓存查询结果是MISS。第二次以及之后的请求查询结果都是HIT,直到资源在缓存中过期。第二次查询在ats中的行为是内存MISS并且磁盘HIT,这里讨论这种状况。主要函数和流程如下:

wKioL1gF9UfT_x_sAADWRh52iIU145.png

Cache::open_read: 首先需要计算的到vol,因为需要知道资源在哪个vol上才能确定是否存在,每个vol都是独立存在的。获取锁之后运行了dir_probe函数,确定了缓存查询的结果。获取了dir,对CacheVC对象的key和dir进行了初始化。生成一个CacheVC对象,之后的操作都是这个CacheVC对象是事儿了。设置回调函数为Cache::openReadStartHead,设置完回调函数会执行do_read_call,最终do_read_call返回了EVENT_RETURN,执行了事件回调函数,就是刚刚设置的Cache::openReadStartHead。

dir_probe: 通过md5值计算得到资源所在的segemnt和bucket,进而得到目标dir,如果dir是否“正确”,如果正确就认为命中了。

CacheVC::do_read_call: 初始化doc_pos为0。解析dir,获取fragment大概大小(dir_approx_size)。决定是否应该写到ssd中(dir_inssd),如果已经是从ssd中读了,就肯定不写了。每个vol都会对应自己的ssd,每个vol都会维护一些历史数据用来判断热度相关的数据。最终将回调函数PUSH为CacheVC::handleRead并执行,最终返回了EVENT_RETURN给Cache::open_read。关于设置回调函数用到的宏,在“ATS缓存概述”中有简单的介绍。

CacheVC::handleRead: 获取偏移量(dir_get_offset)。 在内存中查询(vol->ram_cache->get函数会根据records.config中的配置项proxy.config.cache.ram_cache.algorithm指向不同的函数)。如果查询没有命中,生成一个iobufferdata buf(可以理解为内存中开了一块空间),生成一个char*变量指向buf的data。将磁盘中的内容memcpy到内存中。设置回调函数为 CacheVC::handleReadDone,将返回 EVENT_RETURN给CacheVC::do_read_call。

CacheVC::handleReadDone:主要工作是执行了put函数,根据records.config中的配置项proxy.config.cache.ram_cache.algorithm,put有LRU和CLFUS两个实现。主要工作就是将资源加入到淘汰机制。对回调函数进行POP操作,将在CacheVC::do_read_call函数中PUSH的CacheVC::handleRead函数POP掉。最后执行事件回调函数,就是Cache::open_read函数中设置的Cache::openReadStartHead函数。

CacheVC::openReadStartHead: 之后的逻辑与读小文件(内存命中)相同。