全部博文(356)
分类: 服务器与存储
2018-07-16 13:47:02
原文地址:traffic server 关键数据结构 作者:oxwangfeng
输入是url,包括scheme,user,password,host,path,params,query;
根据url生成md5值
proxy/hdrs/URL.cc:url_MD5_get_general)
md5是一种常见的信息摘要算法,md5的计算结果是16个字节;
md5计算分为三部分:MD5_Init(MD5_CTX *c);MD5_Update(MD5_CTX *c, const void *data, size_t len);MD5_Final(unsigned char *md, MD5_CTX *c);
md5_update的输入参数是(buffer内容):
保存object key
在proxy/hdrs/HTTP.h中,有如下函数:
inline void
HTTPInfo::object_key_set(INK_MD5 & md5)
{
int32_t* pi = reinterpret_cast(&md5);
m_alt->m_object_key[0] = pi[0];
m_alt->m_object_key[1] = pi[1];
m_alt->m_object_key[2] = pi[2];
m_alt->m_object_key[3] = pi[3];
}
这个函数就是将url的md5值保存为object的key;由于md5值有16个字节,m_object_key[4]数组有4个元素,每个元素保存4个字节;
由五个十六位构成的数组;总共10个字节;这五个数据主要是保存object在磁盘上的位置信息;
每个索引对应内存数据结构为Dir,是一个由5个16位的整数构成的数组,共10个字节。这些字节维护了一个object保存在磁盘上的所有元信息
它使用Dir的第一个,第五个的所有16位,以及第二个元素的低八位,共40位,存储一个object在disk上的位置。
struct Dir//保存的是索引
{
….
uint16_t w[5];
};
索引维护在磁盘的Directory中,其中header与footer保存的是索引元信息以及cache读写行为的信息,而位于它们之间的就是实际索引存储区。header与footer都是同一个数据结构类型VolHeaderFooter,这个结构中与本文相关的信息如下:
struct VolHeaderFooter//其中header与footer保存的是索引元信息以及cache读写行为的信息
{
unsigned int magic;
VersionNumber version; //版本号;
time_t create_time;
off_t write_pos; //写入到哪个位置 当前磁盘写的位置
off_t last_write_pos; //上次写入的位置
off_t agg_pos; //agg buffer的位置
uint32_t generation; // token generation (vary), this cannot be 0
uint32_t phase;
uint32_t cycle;
uint32_t sync_serial;//索引写到磁盘时,++1;
uint32_t write_serial;//agg数据写到磁盘时,++1;
uint32_t dirty;
uint32_t sector_size;
uint32_t unused; // pad out to 8 byte boundary
#if TS_USE_INTERIM_CACHE == 1
InterimVolHeaderFooter interim_header[8];
#endif
uint16_t freelist[1];
};
作为一个web cache,它实际上保存的就是源服务器对一个http请求的http响应,它包含head和body两个部分,对应上图中的hdr与data。
ts以一个fragment为单位,如果一个http响应,也就是一个object的大小小于一个fragment,则视它为一个小文件,否则,ts认为它是一个大文件。这个fragment的大小是可配置的,在records.config文件中通过修改proxy.config.cache.target_fragment_size即可,默认为1M
如果一个http响应作为一个object是一个小文件,ts是使用一个Doc完全保存该object的内容。这时,hdr保存响应头,data保存响应体
如果一个http响应是一个大文件,这时ts首先单独使用一个Doc保存响应头的内容,而对于响应体,根据fragment的大小,会被切分为好几个fragment,每个fragment使用一个Doc保存。在响应头的head中,frags数组维护的是每个fragment在整个http响应内容中的位置信息。
对于小文件,该object生成的key值保存在first_key中。而对于一个大文件,整个http响应作为一个object生成的key值保存在first_key中,这个key值由响应头对应的Doc使用,由此在cache查找时,首先找到的就是一个http响应的头部。响应头的Doc的元素key保存的是第一个fragment的key值。而对于每个fragment,第一个fragment通过随机算法生成一个随机数作为一个key值保存在其对应的key中,后续的每个fragment的key值都是以前一个fragment的key值为种子随机生成的。
通过随机算法计算每个fragment使用的key值,这样做的好处是使得所获取的key值尽可能离散,从而映射到索引区的不同bucket中,避免了一个bucket不会维护太长的Dir链表。
下图描述各个fragment是如何通过随机数算法联系起来的:
第一个fragment的key值需要保证不和first_key冲突,否则重新随机生成一个,直到不冲突为止。
DLL bucket[OPEN_DIR_BUCKETS];
#define OPEN_DIR_BUCKETS 256
使用bucket存储所有的od(OpenDirEntry的对象);通过对key的前32位进行hash取模(模为OPEN_DIR_BUCKETS),定位od在bucket的索引位置,然后遍历bucket[b]的list,检查每一个元素的first_key是否等于key,如果等于则返回;
在OpenDir::open_write中首先遍历bucket[b]中的OpenDirEntry元素,如果proxy.config.cache.enable_read_while_writer设置为1并且first_key和当前cacheVc的first_key相同,则表示已经有相同的写操作,则将cacheVc插入writes,并且cachevc的od赋值为这个bucket中的od;如果bucket[b]对应的list是空,则新建一个OpenDirEntry,初始化,并且添加到bucket中。
在OpenDir::close_write将od从bucket中删除;调用OpenDir::close_write操作会将cacheVc对象从writes中删除,如果writes对象是空,则删除od;
每次有写操作的时候都会触发上述两个函数;
Bucket主要是记录当前读写操作的行为,记录当前有多少读操作,有多少写操作;如果读写操作完成,则会从bucket中删除;如果增加一个http write,则添加到wirtes,如果有相同的写,则od不需要重建,如果不是相同的写,则需要新建od;
Continuation 是一个通用类,可以用于实现事件驱动的状态机。
通过包括其他状态和方法,Continuation 可以将状态与控制流结合,通常这样的设计用于支持分阶段,事件驱动的控制流程。
一定程度上来讲Continuation是整个异步回调机制的多线程事件编程基础。
在ATS中,Continuation是一个最最基础的抽象结构,后续的所有高级结构,如Action Event VC等都封装Continuation数据结构。
在学术上,这种以Continuation为底层的设计(编程)模型叫做Continuation的编程模型(方法)
这个技术相当古老
后来微软围绕这个方案,改进出了coroutine的编程模型(方法)
注:部分参考别人内容