概述
在volume.config里面可以配置多个volume,比如说有4块磁盘,配了3个volume。每块磁盘都有3个volume,一个磁盘的一个volume是一个stripe,stripe是磁盘级别存储的最小单位。stripe存着若干个存储对象,默认每个对象最小占8000字节(proxy.config.cache.min_average_object_size),每个存储对象表示为一个fragment,默认大小是1M(proxy.config.cache.target_fragment_size),每个对象最大占一个fragment。
一个资源根据其大小可能会存在多个存储对象中。如果足够小,连同这个资源的meta信息一起存储在一个doc中。如果比较大,第一个存储对象保存资源的meta信息,后面跟着若干个fragment存着资源的content。
每个对象对应一个索引(directory),索引存储在内存中,索引是缓存key的md5值,由dir_probe函数计算得到。一个stripe的存储对象对应的directory数量可以用stripe大小除8000得到,每4个directory是一个bucket,一个segment最多有2的14次方个bucket。每个directory占10字节,在ats启动的时候就会根据磁盘的大小计算出最多可以存多少个fragment,也即最多多少个directory,根据directory的个数可以计算出他们占的内存大小。directory包括了某个存储对象在磁盘上的位置信息,其中最重要的是偏移量(offset)和“大概大小”(big, size)其结构如下:
缓存相关有几个比较核心的结构体,每个结构中有几个核心的成员。如下是简单介绍:
class vol
len: stripe的大小
segments: stripe中segment的个数
buckets: segment中bucket的个数
Queue<CacheVC, Continuation::Link_link> agg: 一个写队列,每个元素是一个CacheVC
struct OpenDirEntry包含了一个有效的资源的基本信息,struct OpenDir里面有一个变量是bucket,是一个由OpenDirEntry组成的数据,记录了bucket的读写操作
writing_vec: 目前有人在执行写操作
reading_vec: 目前有人在执行读操作
struct Doc
magic: 判断document是否有效
total_len: 整个资源到当前的fragment为止的大小,不包括响应头
flen: fragment存的content的大小,再加上72字节就是整个fragment的大小(默认1048576,proxy.config.cache.target_fragment_size)
hlen: 头的大小,整个资源的metadata的大小
key: 当前fragment的某一个alternate的key,经常被用来与CacheVC::key做比较,CacheVC::key貌似是当前正在处理的key
first_key: 一个资源可能对应多个fragment,first_key是第一个fragment的key,同一个资源多个fragment有相同的first_key
len:fragment的数据大小
对于小文件:len = hlen + total_len + 72
doc->data():返回了相应body数据地址
class CacheVC
seek_to:range的起始地址
offset:第一个fragment的偏移量+整个请求范围发了的数据大小
doc_pos:这个fragment已经发送的游标位置
key:当前fragment的目标alternate的key,第一个存响应体的fragment的key,也即earliest_key,如果资源占了多个fragment,first_key和key不相同
first_key: 资源的第一个fragment的key,如果资源只包含在一个fragment中,这个字段貌似没用
doc_len:当前资源的目标alternate的总大小,不包括响应头
length:等待被写入agg_buf的长度
frag_len:一个fragment的大小,不包括72字节
不得不提到几个重要的宏:
设置某一个continuation的回调函数
SET_CONTINUATION_HANDLER(c, &CacheVC::openReadStartHead);
#define SET_CONTINUATION_HANDLER(_c,_h)
(_c->handler = ((ContinuationHandler) _h))
#endif
设置回调函数
SET_HANDLER(&CacheVC::handleReadDone);
#define SET_HANDLER(_h)
(handler = ((ContinuationHandler)_h))
#endif
函数执行只是修改了handler
设置暂时的回调函数,保存原来的回调函数
#define PUSH_HANDLER(_x) do {
save_handler = handler; handler = (ContinuationHandler)(_x);
} while (0)
函数执行是一个push的操作,将原来的handler“推向”了save_handler,将_x“推向”了handler
恢复原来的回调函数
#define POP_HANDLER do {
handler = save_handler;
} while (0)
函数执行是一个pop的操作,将save_handler“弹出”到handler,执行完了之后handler和save_handler指向相同的函数,原来的handler没了
几个dir相关的小函数
dir_segment
这个函数是一个宏定义#define dir_segment(_s, _d) vol_dir_segment(_d, _s)
vol_dir_segment(Vol *d, int s)
{
return (Dir *) (((char *) d->dir) + (s * d->buckets) * DIR_DEPTH * SIZEOF_DIR);
}
vol_dir_segment的最后一个参数是这个vol中segment的序号
vol的dir的地址 + segment的序号 * 一个bucket中dir的数量(默认4个) * 一个dir的长度(默认10字节),最后返回的是segment的第一个dir
这个函数可以判断dir是否存在于ssd中
#define dir_inssd(_e) (((_e)->w[4] >> 15) & 1)
dir_bucket
TS_INLINE Dir *
dir_bucket(int b, Dir *seg)
{
return dir_in_seg(seg, b * DIR_DEPTH);
}
#define dir_in_seg(_s, _i) ((Dir*)(((char*)(_s)) + (SIZEOF_DIR *(_i))))
segment的第一个dir + vol中bucket的序号 * 一个bucket中dir的数量(默认4个) * 一个dir的长度(默认10字节),最后返回的是bucket的第一个dir
vol_offset
#define vol_offset(d, e) ((d)->start + (off_t) ((off_t)dir_offset(e) * CACHE_BLOCK_SIZE) - CACHE_BLOCK_SIZE)
转载于:https://blog.51cto.com/11490450/1861846
最后
以上就是疯狂宝马为你收集整理的ATS缓存概述的全部内容,希望文章能够帮你解决ATS缓存概述所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复