理想状况下,一个文件第一次访问,缓存查询结果是MISS。第二次以及之后的请求查询结果都是HIT,直到资源在缓存中过期。第二次查询在ats中的行为是内存MISS并且磁盘HIT,这里讨论这种状况。主要函数和流程如下:
Cache::open_read: 计算的到vol。运行了dir_probe函数,确定了缓存查询的结果。获取了dir,对CacheVC对象的key和dir进行了初始化。生成一个CacheVC对象,之后的操作都是这个CacheVC对象是事儿了。设置回调函数为Cache::openReadStartHead,设置完回调函数会执行do_read_call,最终do_read_call返回了EVENT_RETURN,执行了事件回调函数。与读小文件内存命中不同,这里执行的回调函数是在CacheVC::handleRead中设置的CacheVC::handleReadDone。
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。
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: 之后的逻辑与读小文件(内存命中)相同。