Chinaunix首页 | 论坛 | 博客
  • 博客访问: 165216
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 675
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-26 00:58
文章分类
文章存档

2014年(2)

2013年(41)

我的朋友

分类: C/C++

2013-08-07 10:23:06

首先说说缓冲这部分的工作流程:

1.客户端发来GET或者HEAD请求,包好If-None-Match或者If-Match,以及一串由服务器发送的ETAG码。

2.服务器收到请求,先在缓存系统中查找是否应该文件,如果有返回该文件的相关信息。如果没有将该文件的缓存信息,则stat读取该文件的相关信息加入缓存树中。

3.缓存中的文件信息中包含符文的ETAG码,核对是否与客户端发来的ETAG一致,如果一致,返回304,否则返回200与文件内容,并告知新的ETAG码。

这篇文章主要介绍下状态缓存模块和ETAG

第一ETAG部分

什么是ETAG:简单的说,ETAG就是文件的一个身份标识,如果文件变化了,那么它对应的ETAG也会改变。比如apachelighttpdetag生成都是使用inode+mtime+size三部分组成,只要文件改变,这个一定会变的。

如果客户要访问某一文件,发现该文件之前访问过,且没有改变,那么就可以利用客户端的缓存文件,而不需要重新下载一次,节约网络资源。

这部分代码保存在etag.c

使用inode+mtime+size生成etag标签

etag_is_equal(buffer *etag, const char *matches);//比较两个etag是否相等

int etag_create(buffer *etag, struct stat *st, etag_flags_t flags);//根据标签生成初始的etag

int etag_mutate(buffer *mut, buffer *etag);//通常用来将初始的etag进行算法变形

这部分代码很简单,说说功能,不详细解释了。

第二部分,文件状态的缓存。

使用状态缓存就是为了节约stat()函数调用的时间(难道这个函数很占用资源?这里的原理不很理解)

首先介绍下大概的流程:总共有两个树,一棵是文件树,一棵是目录树。fam这个服务仅仅监控目录文件的变化。

首先在文件树中查找文件,如果找到该文件,而且上次节点改变时间戳与服务器时间戳一样(说明文件最近加入缓存,没有改变),返回该文件。

如果时间戳不对应,说明文件可能变了,在目录树种看看目录有没有改变,如果目录变了则认为文件一定变了,重新缓存然后返回,如果没有改变,说明目录下文件也没有改变,那么返回节点。

如果没有找到文件所在目录,重新缓存。

如果没有找到文件,重新缓存。

整个过程主要用到下面三个结构体:

typedef struct {

splay_tree *files; 树的每个节点保存一个stat_cache_entry;

buffer *dir_name; /* for building the dirname from the filename */

splay_tree *dirs; 该树的节点是fam_dir_entry

FAMConnection *fam;  //整个缓存模块只需要一个连接,然后每个文件需要一个请求

int    fam_fcce_ndx;

buffer *hash_key;  保存hash值

} stat_cache;

typedef struct {

buffer *name;   //文件名

buffer *etag;   //文件的etag

struct stat st;   //文件的状态

time_t stat_ts;  //上次这个节点改变的时间

char is_symlink;  //标记是否是符号链接文件

int    dir_version;  //对应的目录版本号

int    dir_ndx;

buffer *content_type;   //文件的类型,对应http协议中的content-type

} stat_cache_entry;

typedef struct {

FAMRequest *req;    //fam请求

FAMConnection *fc;   //fam连接,来自stat_cache结构体

buffer *name;   //目录的名字

int version;//版本号

} fam_dir_entry;

stat_cache *stat_cache_init(void) 

static stat_cache_entry * stat_cache_entry_init(void) 

static void stat_cache_entry_free(void *data)

static fam_dir_entry * fam_dir_entry_init(void) 

void stat_cache_free(stat_cache *sc)

static void fam_dir_entry_free(void *data)

上面的初始化函数无非就是申请空间,赋初值。不解释了。

static uint32_t hashme(buffer *str) 采用DJB hash的方法对要加入树的数据进行hash,然后保存hash

static int stat_cache_attr_get(buffer *buf, char *name)  //XFS系统获取文件属性

handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent) 根据传入的事件类型,处理事件

这个函数的流程图:

handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **ret_sce)

注意问题1首先在stat_cache_handle_fdevent函数可以看出,当目录改变(文件改变也会使目录改变)时候版本号+1.但文件对应的版本号没变,所以两个版本号比较久可以判断文件是否变动。

问题2:符号连接

static int stat_cache_lstatt(server *srv, buffer *dname, struct stat *lst)  判断dirname保存的文件名是否是符号链接

大家注意在上面的流程图中,比较文件的时候先查找hash,然后对比了文件名。而目录则没有比较文件名。

关于这个函数,我有下面几个问题没搞懂:

第一处

ctrl的作用

第二处

buffer_append_long(sc->hash_key, con->conf.follow_symlink);

conf.follow-syslink应该来自配置文件,为什么不保存在svr中而是con中呢?

第三处

svr是全局变量,

所有线程共享

buffer_copy_string_buffer(sc->hash_key, name);

改变了svr中sc的这个值,其他的线程受影响

第五处

获取mimetype值

static int stat_cache_tag_old_entries(server *srv, splay_tree *t, int *keys, size_t *ndx) 

int stat_cache_trigger_cleanup(server *srv) 

这两个函数配合,删除距上次被访问超过2秒的节点

知识点1:http://blog.csdn.net/liuaigui/article/details/5050697

DJB HASH

知识点2

int attr_get (const char *path, const char *attrname, char *attrvalue, int *valuelength, int flags);

需要包含attr/attributes.h  只有XFS系统可以只用

知识点3

etag只有在GET和HEAD的时候有效,如果不是这个请求但是使用了etag,返回412

知识点4:linux时间处理  DST  GMT   struct tm  

如果对一个DST时间,调用strchr(“....GMT”),会返回什么?   CST  时区问题

知识点5:strchr   strptime函数的使用

知识点6

If-None-Match 和 ETAG

Last-Modified 与If-Modified-Since

ETags和If-None-Match是一种常用的判断资源是否改变的方法。类似于Last-Modified和HTTP-IF-MODIFIED- SINCE。但是有所不同的是Last-Modified和HTTP-IF-MODIFIED-SINCE只判断资源的最后修改时间,而ETags和 If-None-Match可以是资源任何的任何属性

当客户端再次请求该资源时,将在HTTP Request中加入If-None-Match信息(ETags的值)。如果服务器验证资源的ETags没有改变(该资源没有改变),将返回一个304状态;否则,服务器将返回200状态,并返回该资源和新的ETags。

当一个请求中ETag和LastModified都在,两个都满足才返回304

知识点5::stat和lstat的区别:当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;而stat返回的是该链接指向的文件的信息。

知识点6

FAM可以把监控文件的变化反映在一个文件描述符内,这样就可以使用select等模型来接受通知

FAM API

FAMCancelMonitor 当你的程序结束监管文件或者目录的时候调用,此时不再监管fr指定的文件。调用该函数后会发送一个FAMAcknowledge的事件,意味着你可以重新使用request number了

FAMClose   关闭fam连接

FAMPending

FAMNextEvent

FAMCONNECTION_GETFD

int FAMOpen(FAMConnection* fc)

FAMCONNECTION_GETFD(fc)

int FAMOpen2(FAMConnection* fc, const char* appName)

nt FAMMonitorDirectory(FAMConnection *fc, char *filename,FAMRequest* fr, void* userData) //随意提供,如果制定文件发生变动,该数据会保存在返回的FAMEvent的userdata部分,用来传递信息

int FAMMonitorFile(FAMConnection *fc,char *filename,FAMRequest* fr,void* userData)

FAMConnection

结构体中包含一个socket文件描述符,用来和程序通信,告诉程序什么时候文件发生改变

如果采用select来获取通知,就需要获取FAMConection中包含的文件描述符。

如果用poll模式,可以直接调用FAMPending(),该函数不等待,相当于设置0的poll。

得到通知后,由FAMNextEvent来获取下一个通知事件

FAMRequest监管目录或者文件的时候初始化

阅读(1530) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~