这个cache主要是针对stat()函数调用结果的一个cache,这么做有两个考虑,一个当然是缓存stat()函数调用的结果,比如需要向客户端发送一个文件的内容时,需要知道这个文件的尺寸,一般都是通过stat()调用得来;如果仅仅是这样,那似乎这个cache是没有太大必要的,所以还有第二层的考量,http协议中有一个所谓的etag的概念,比如你接收了一个文件,http协议中带了一个字段last-modified存放这个文件请求的时间,同时有针对这个文件的etag值,下一次再次请求时,如果该文件没有更新过,那么直接使用客户端浏览器中缓存的结果即可.有关这部分的内容可以参考
这里. 这里,关于"文件是否被更改过",在lighttpd中,有三种判断的标准,分别是typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t;
简单的理解,就是从inode number值,mtime(修改时间),文件尺寸三种标准来判断,而这些,都是可以从stat函数的返回值也就是stat
结构体中获得的.
下面来具体看这个cache的实现,我也不贴代码了,还是看伪代码好了,关于这部分实现,可以看lighttpd中的stat_cache.c文件:
根据查找的文件名算出一个hash值,
根据这个hash值去sptree中搜索,这个结构体中cache住之前查询的结果
假如可以在cache中找到记录,还要将记录的时间与服务器当前的时间做比较,如果一致才认为是找到了cache,返回结果.
程序继续往下走,这个时候只有两种可能,一种是没有找到,另一种找到了但是时间不对应,因此很可能cache中的信息已经过期了.
此时,需要到文件所在的目录去查找,对于缓存目录结果的cache而言,如果找到了需要查看缓存数据的版本号,以这个来定义是否一致
假如找到了目录信息,版本号也一致,并且之前也找到了文件的cache,那么认为cache中缓存的文件信息没有过时,返回结果.
程序继续往下走,此时可以确定cache中要么是没有要找的信息,要么是信息过期.
这时需要真正调用stat()函数获取文件相关的信息,并且插入到cache中,
同时,如果文件的目录信息之前是没有的,也需要将文件所在目录的信息插入到cache中,同时保存cache数据的当前时间点.
最后,还需要针对etag做一些处理,根据之前说的etag类型将相关信息存放到cache中,这里只需要etag值不会重复就可以.
提到cache目录信息这一点,lighttpd采用了FAM的API,使用这个API,可以把需要监控是否发生变化的目录加入到一个集合中,这个集合可以对应一个fd,这样,就可以select/epoll等多路复用I/O处理器在文件目录情况发生变化的时候去异步通知服务器更新cache中关于该目录的情况了.
关于FAM API,可以参考这里:
http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=bks&fname=/SGI_Developer/books/IIDsktp_IG/sgi_html/ch08.html