這個(gè)cache主要是針對(duì)stat()函數(shù)調(diào)用結(jié)果的一個(gè)cache,這么做有兩個(gè)考慮,一個(gè)當(dāng)然是緩存stat()函數(shù)調(diào)用的結(jié)果,比如需要向客戶端發(fā)送一個(gè)文件的內(nèi)容時(shí),需要知道這個(gè)文件的尺寸,一般都是通過stat()調(diào)用得來;如果僅僅是這樣,那似乎這個(gè)cache是沒有太大必要的,所以還有第二層的考量,http協(xié)議中有一個(gè)所謂的etag的概念,比如你接收了一個(gè)文件,http協(xié)議中帶了一個(gè)字段last-modified存放這個(gè)文件請(qǐng)求的時(shí)間,同時(shí)有針對(duì)這個(gè)文件的etag值,下一次再次請(qǐng)求時(shí),如果該文件沒有更新過,那么直接使用客戶端瀏覽器中緩存的結(jié)果即可.有關(guān)這部分的內(nèi)容可以參考
這里. 這里,關(guān)于"文件是否被更改過",在lighttpd中,有三種判斷的標(biāo)準(zhǔn),分別是typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t;
簡單的理解,就是從inode number值,mtime(修改時(shí)間),文件尺寸三種標(biāo)準(zhǔn)來判斷,而這些,都是可以從stat函數(shù)的返回值也就是stat
結(jié)構(gòu)體中獲得的.
下面來具體看這個(gè)cache的實(shí)現(xiàn),我也不貼代碼了,還是看偽代碼好了,關(guān)于這部分實(shí)現(xiàn),可以看lighttpd中的stat_cache.c文件:
根據(jù)查找的文件名算出一個(gè)hash值,
根據(jù)這個(gè)hash值去sptree中搜索,這個(gè)結(jié)構(gòu)體中cache住之前查詢的結(jié)果
假如可以在cache中找到記錄,還要將記錄的時(shí)間與服務(wù)器當(dāng)前的時(shí)間做比較,如果一致才認(rèn)為是找到了cache,返回結(jié)果.
程序繼續(xù)往下走,這個(gè)時(shí)候只有兩種可能,一種是沒有找到,另一種找到了但是時(shí)間不對(duì)應(yīng),因此很可能cache中的信息已經(jīng)過期了.
此時(shí),需要到文件所在的目錄去查找,對(duì)于緩存目錄結(jié)果的cache而言,如果找到了需要查看緩存數(shù)據(jù)的版本號(hào),以這個(gè)來定義是否一致
假如找到了目錄信息,版本號(hào)也一致,并且之前也找到了文件的cache,那么認(rèn)為cache中緩存的文件信息沒有過時(shí),返回結(jié)果.
程序繼續(xù)往下走,此時(shí)可以確定cache中要么是沒有要找的信息,要么是信息過期.
這時(shí)需要真正調(diào)用stat()函數(shù)獲取文件相關(guān)的信息,并且插入到cache中,
同時(shí),如果文件的目錄信息之前是沒有的,也需要將文件所在目錄的信息插入到cache中,同時(shí)保存cache數(shù)據(jù)的當(dāng)前時(shí)間點(diǎn).
最后,還需要針對(duì)etag做一些處理,根據(jù)之前說的etag類型將相關(guān)信息存放到cache中,這里只需要etag值不會(huì)重復(fù)就可以.
提到cache目錄信息這一點(diǎn),lighttpd采用了FAM的API,使用這個(gè)API,可以把需要監(jiān)控是否發(fā)生變化的目錄加入到一個(gè)集合中,這個(gè)集合可以對(duì)應(yīng)一個(gè)fd,這樣,就可以select/epoll等多路復(fù)用I/O處理器在文件目錄情況發(fā)生變化的時(shí)候去異步通知服務(wù)器更新cache中關(guān)于該目錄的情況了.
關(guān)于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