大文件存储结构和小文件完全不同,小文件占一个fragment就够了,大文件占若干个fragment。大文件第一个分片是doc只存一些信息数据,包括http头,资源的content存在于后面若干个fragment中,默认每个fragment占1048576字节,在proxy.config.cache.target_fragment_size中可以改。一个fragment中有72个字节是doc,剩下的是资源的content。ats会先读第一个fragment,然后以循环的方式读取若干个fragment,直到客户端得到了需要的所有数据。

wKioL1ga9xLSFYbSAAPvh3sQl3M637.png

Cache::open_read: 计算的到vol。运行了dir_probe函数,确定了缓存查询的结果。获取了dir,对CacheVC对象的key和dir进行了初始化。生成一个CacheVC对象,之后的操作都是这个CacheVC对象是事儿了。设置回调函数为Cache::openReadStartHead,设置完回调函数会执行do_read_call。

CacheVC::do_read_call: 初始化doc_pos为0。解析dir,获取fragment大概大小(dir_approx_size)。决定是否应该写到ssd中(dir_inssd),如果已经是从ssd中读了,就肯定不写了。每个vol都会对应自己的ssd,每个vol都会维护一些历史数据用来判断热度相关的数据。最终将回调函数PUSH为CacheVC::handleRead并执行。

CacheVC::handleRead: 获取偏移量(dir_get_offset)。 在内存中查询(vol->ram_cache->get函数会根据records.config中的配置项proxy.config.cache.ram_cache.algorithm指向不同的函数)。如果查询没有命中,生成一个iobufferdata buf(可以理解为内存中开了一块空间),生成一个char*变量指向buf的data。将磁盘中的内容memcpy到内存中。会有两种情况,一种是ramhit会执行CacheVC::handleReadDone,另一种是memhit,直接执行CacheVC::openReadStartHead,区别不大,这里讨论memhit情况。将回调函数POP掉,POP之后的回调函数变为在Cache::open_read设置的Cache::openReadStartHead,最终返回EVENT_RETURN一直向上直到Cache::open_read

CacheVC::openReadStartHead: 函数确定了是大文件还是小文件。挑选了一个alternate,将选定的alternate的key赋值给Cache::key,判断alternate的key和doc->key是否相等。由于大文件的doc只存了一些信息,所以alternate的key和第一个存content的fragment的doc->key。函数最后将buf赋值为NULL,之后将回调函数设置为CacheVC::openReadStartEarliest并且执行。

CacheVC::openReadStartEarliest: 如果hit状态,一般会执行两次。但是如果出于正在下载状态,这个函数会执行若干次,但是获取锁不会成功。按照顺序来讲,CacheVC::openReadStartHead已经获取到了第一个存储content的fragment的key。通过dir_probe函数根据key得到earliest_dir。

CacheVC::do_read_call: 初始化doc_pos为0。解析dir,获取fragment大概大小(dir_approx_size)。决定是否应该写到ssd中(dir_inssd),如果已经是从ssd中读了,就肯定不写了。每个vol都会对应自己的ssd,每个vol都会维护一些历史数据用来判断热度相关的数据。最终将回调函数PUSH为CacheVC::handleRead并执行。

CacheVC::handleRead: 获取偏移量(dir_get_offset)。 在内存中查询(vol->ram_cache->get函数会根据records.config中的配置项proxy.config.cache.ram_cache.algorithm指向不同的函数)。将回调函数设置为CacheVC::handleReadDone,返回EVENT_CONT一直向上给Cache::open_read,事件结束

CacheVC::handleReadDone: 将回调函数POP掉,之后回调函数变为CacheVC::openReadStartEarliest,之后执行回调函数。

CacheVC::openReadStartEarliest: 这次之行时buf已经不是NULL了,计算next_key,设置回调函数为CacheVC::openReadMain并且执行。

CacheVC::openReadMain: 判断客户端请求的range最开始的位置位于哪个fragment,调整offset和doc_pos到合适的位置,offset是整个响应的offset不包含doc所占的72字节,doc_pos是单个fragment的postion包括72字节。这个函数会进入若干次,直到东西全都发完了。最后一次执行的时候,根据CacheVC::openReadStartEarliest计算得到的key,通过dir_probe的到对应的dir,设置回调函数为CacheVC::openReadReadDone,执行CacheVC::do_read_call,最后返回EVENT_CONT。到这里就进入了一个循环,一片一片的读文件发文件,直到请求结束。

CacheVC::handleReadDone: 进入循环之后这个函数由事件出发,将回调函数POP掉之后的回调函数变为CacheVC::openReadReadDone,执行回调函数。

CacheVC::openReadReadDone: fragment数量加1,计算next_key。将回调函数设置为CacheVC::openReadMain并且执行。