3.2表格(TABLE)
3.2.1表格概述
盡管a
PR_array_header_t數(shù)組已經(jīng)可以完成大部分的任務(wù),但是對(duì)于Apache而言,apr_array_header_t更傾向于內(nèi)部數(shù)據(jù)結(jié)構(gòu),它通常作為其余的線性數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)基礎(chǔ),比如表格、隊(duì)列以及哈希表。表格是Apache中用的最頻繁的數(shù)據(jù)結(jié)構(gòu),比如HTTP請(qǐng)求中的域以及配置文件中的命令都是通過表格進(jìn)行保存的。不過與通常的表格的含義不太相似,Apache表格更加與perl中的哈希表相似,唯一的區(qū)別就是在Apache表格中同樣的鍵值你可以存在兩次,而且表格是大小寫字母敏感的。
Apache中表格的數(shù)據(jù)結(jié)構(gòu)是apr_table_t結(jié)構(gòu),該結(jié)構(gòu)在apache的apr_table.h中定義如下:
strUCt apr_table_t {
apr_array_header_t a;
#ifdef MAKE_TABLE_PROFILE
void *creator;
#endif
apr_uint32_t index_initialized;
int index_first[TABLE_HASH_SIZE];
int index_last[TABLE_HASH_SIZE];
};
從表格的結(jié)構(gòu)可以看出,表格的內(nèi)部還是數(shù)組結(jié)構(gòu),表格的各種操作實(shí)質(zhì)上無(wú)非就是對(duì)數(shù)組元素操作的一種封裝而已。為了保持向下兼容,apr_array_header_t必須位于表格結(jié)構(gòu)的首部。由于表格結(jié)構(gòu)是Apache中新的數(shù)據(jù)結(jié)構(gòu),因此假如需要某些舊的只支持?jǐn)?shù)組的版本假如需要使用表格,只要使用將apr_table_t強(qiáng)制轉(zhuǎn)換為apr_array_header_t結(jié)構(gòu)就可以了。
creator用來(lái)跟蹤表格的創(chuàng)建者。另外為了能夠加快對(duì)表格的訪問,結(jié)構(gòu)中增加了三個(gè)輔助的成員變量,即index_initialized,index_first,index_last。index_intialized是一個(gè)32位的無(wú)符號(hào)整數(shù),共對(duì)應(yīng)了32 Í 8個(gè)bit,系統(tǒng)中用256位中的第n位來(lái)記錄當(dāng)前分配空間的第n個(gè)元素是否已經(jīng)被初始化,假如初始化,該位為1,否則0。因此我們可以看到表格中的元素最多也只能為256個(gè)。
表格中的一個(gè)元素要被使用之前必須對(duì)其所在的區(qū)域進(jìn)行初始化,初始化非常的簡(jiǎn)單,只是將index_initialized中對(duì)應(yīng)的bit位置為1即可。可以通過宏TABLE_SET_INDEX_INITIALIZED實(shí)現(xiàn)初始化。
#define TABLE_SET_INDEX_INITIALIZED(t, i) ((t)->index_initialized = (1 << (i)))
而判定一個(gè)對(duì)應(yīng)的元素是否被初始化,則用宏TABLE_INDEX_IS_INITIALIZED實(shí)現(xiàn):
#define TABLE_INDEX_IS_INITIALIZED(t, i) ((t)->index_initialized & (1 << (i)))
index_last和index_first數(shù)組的用法我們?cè)诤竺娴牟糠謺?huì)具體描述。
表格中存放的每一個(gè)元素用結(jié)構(gòu)apr_table_entry_t描述:
struct apr_table_entry_t {
char *key;
char *val;
apr_uint32_t key_checksum;
};
結(jié)構(gòu)中,key是鍵值,目前用來(lái)標(biāo)記表格中的每個(gè)元素,通常只有在對(duì)表格中的元素進(jìn)行迭代的時(shí)候才能對(duì)該值進(jìn)行檢查。在以后的版本中,該值可能被設(shè)置為NULL。val則是當(dāng)前元素的值。Key_checksum則是對(duì)鍵值key的校驗(yàn)值,一般在表格內(nèi)部使用。
由于表格的核心數(shù)據(jù)結(jié)構(gòu)還是apr_array_header_t結(jié)構(gòu),因此對(duì)表格的大部分操作實(shí)際上還是對(duì)數(shù)組類型的操作。只不過此時(shí)數(shù)組的每個(gè)元素結(jié)構(gòu)變成了apr_table_entry_t而已。下面我們來(lái)看看表格是如何進(jìn)行操作的。
3.2.2創(chuàng)建表格
為了創(chuàng)建一個(gè)表格,我們可以使用函數(shù)ap_make_table和apr_make_table,前者適用于Apache1.3,后者適用于2.0版本。函數(shù)定義生命如下:
APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts)
{
apr_table_t *t = apr_palloc(p, sizeof(apr_table_t));
make_array_core(&t->a, p, nelts, sizeof(apr_table_entry_t), 0);
#ifdef MAKE_TABLE_PROFILE
t->creator = __builtin_return_address(0);
#endif
t->index_initialized = 0;
return t;
}
函數(shù)首先從內(nèi)存池p中分配處apr_table_t結(jié)構(gòu)大小的內(nèi)存塊,然后調(diào)用make_array_core(&t->a, p, nelts, sizeof(apr_table_entry_t), 0)為創(chuàng)建apr_table_t的內(nèi)部數(shù)組a,數(shù)組個(gè)數(shù)為nelts個(gè),每個(gè)元素的大小為sizeof(apr_table_entry_t)。假如nelts為零,函數(shù)將推遲內(nèi)存分配直到表格第一次使用為止。正如在數(shù)組部分看到的,表格會(huì)自動(dòng)的分配其需要的內(nèi)存空間,而不需要手工干涉。另外數(shù)組創(chuàng)建之后index_initialized被初始化為0,此時(shí)沒有任何數(shù)據(jù)被使用。
下面的代碼演示了表格的創(chuàng)建操作:
apr_table_t *my_table;
my_table = apr_table_make(r->pool,10);
至此函數(shù)將創(chuàng)建了一個(gè)空空如也的表格,下面要做的就是往里面不斷的放入apr_table_entry_t結(jié)構(gòu)的數(shù)據(jù)了。
除了可以從頭開始創(chuàng)建一個(gè)新的表格,Apache中還答應(yīng)從一個(gè)原有的表格創(chuàng)建一個(gè)相同的表格,我們稱之為表格復(fù)制。表格復(fù)制實(shí)現(xiàn)如下:
APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool_t *p, const apr_table_t *t)
{
apr_table_t *new = apr_palloc(p, sizeof(apr_table_t));
make_array_core(&new->a, p, t->a.nalloc, sizeof(apr_table_entry_t), 0);
memcpy(new->a.elts, t->a.elts, t->a.nelts * sizeof(apr_table_entry_t));
new->a.nelts = t->a.nelts;
memcpy(new->index_first, t->index_first, sizeof(int) * TABLE_HASH_SIZE);
memcpy(new->index_last, t->index_last, sizeof(int) * TABLE_HASH_SIZE);
new->index_initialized = t->index_initialized;
return new;
}
關(guān)于作者
張中慶,目前主要的研究方向是嵌入式瀏覽器,移動(dòng)中間件以及大規(guī)模服務(wù)器設(shè)計(jì)。目前正在進(jìn)行Apache的源代碼分析,計(jì)劃出版《Apache源代碼全景分析》上下冊(cè)。Apache系列文章為本書的草案部分,對(duì)Apache感愛好的朋友可以通過flydish1234 at sina.com.cn與之聯(lián)系!
假如你覺得本文不錯(cuò),請(qǐng)點(diǎn)擊文后的“推薦本文”鏈接!!