1. 程式人生 > >Nginx基本資料結構之ngx_hash_keys_arrays_t

Nginx基本資料結構之ngx_hash_keys_arrays_t

大家看到在構建一個ngx_hash_wildcard_t的時候,需要對萬用字元的哪些key進行預處理。這個處理起來比較麻煩。而當有一組key,這些裡面既有無萬用字元的key,也有包含萬用字元的key的時候。我們就需要構建三個hash表,一個包含普通的key的hash表,一個包含前向萬用字元的hash表,一個包含後向萬用字元的hash表(或者也可以把這三個hash表組合成一個ngx_hash_combined_t)。在這種情況下,為了讓大家方便的構造這些hash表,nginx提供給了此輔助型別。

該型別以及相關的操作函式也定義在src/core/ngx_hash.h|c裡。我們先來看一下該型別的定義。

typedef struct {
    ngx_uint_t        hsize;

    ngx_pool_t       *pool;
    ngx_pool_t       *temp_pool;

    ngx_array_t       keys;
    ngx_array_t      *keys_hash;

    ngx_array_t       dns_wc_head;
    ngx_array_t      *dns_wc_head_hash;

    ngx_array_t       dns_wc_tail;
    ngx_array_t      *dns_wc_tail_hash;
} ngx_hash_keys_arrays_t;
hsize: 將要構建的hash表的桶的個數。對於使用這個結構中包含的資訊構建的三種類型的hash表都會使用此引數。
pool: 構建這些hash表使用的pool。
temp_pool: 在構建這個型別以及最終的三個hash表過程中可能用到臨時pool。該temp_pool可以在構建完成以後,被銷燬掉。這裡只是存放臨時的一些記憶體消耗。
keys: 存放所有非萬用字元key的陣列。
keys_hash: 這是個二維陣列,第一個維度代表的是bucket的編號,那麼keys_hash[i]中存放的是所有的key算出來的hash值對hsize取模以後的值為i的key。假設有3個key,分別是key1,key2和key3假設hash值算出來以後對hsize取模的值都是i,那麼這三個key的值就順序存放在keys_hash[i][0],keys_hash[i][1], keys_hash[i][2]。該值在呼叫的過程中用來儲存和檢測是否有衝突的key值,也就是是否有重複。
dns_wc_head: 放前向萬用字元key被處理完成以後的值。比如:“*.abc.com” 被處理完成以後,變成 “com.abc.” 被存放在此陣列中。
dns_wc_tail: 存放後向萬用字元key被處理完成以後的值。比如:“mail.xxx.*” 被處理完成以後,變成 “mail.xxx.” 被存放在此陣列中。
dns_wc_head_hash:
  該值在呼叫的過程中用來儲存和檢測是否有衝突的前向萬用字元的key值,也就是是否有重複。
dns_wc_tail_hash:
  該值在呼叫的過程中用來儲存和檢測是否有衝突的後向萬用字元的key值,也就是是否有重複。

在定義一個這個型別的變數,並對欄位pool和temp_pool賦值以後,就可以呼叫函式ngx_hash_add_key把所有的key加入到這個結構中了,該函式會自動實現普通key,帶前向萬用字元的key和帶後向萬用字元的key的分類和檢查,並將這個些值存放到對應的欄位中去, 然後就可以通過檢查這個結構體中的keys、dns_wc_head、dns_wc_tail三個陣列是否為空,來決定是否構建普通hash表,前向萬用字元hash表和後向萬用字元hash表了(在構建這三個型別的hash表的時候,可以分別使用keys、dns_wc_head、dns_wc_tail三個陣列)。

構建出這三個hash表以後,可以組合在一個ngx_hash_combined_t物件中,使用ngx_hash_find_combined進行查詢。或者是仍然保持三個獨立的變數對應這三個hash表,自己決定何時以及在哪個hash表中進行查詢。

ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type);

初始化這個結構,主要是對這個結構中的ngx_array_t型別的欄位進行初始化,成功返回NGX_OK。

ha: 該結構的物件指標。
type: 該欄位有2個值可選擇,即NGX_HASH_SMALL和NGX_HASH_LARGE。用來指明將要建立的hash表的型別,如果是NGX_HASH_SMALL,則有比較小的桶的個數和陣列元素大小。NGX_HASH_LARGE則相反。
ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key,
void *value, ngx_uint_t flags);

一般是迴圈呼叫這個函式,把一組鍵值對加入到這個結構體中。返回NGX_OK是加入成功。返回NGX_BUSY意味著key值重複。

ha: 該結構的物件指標。
key: 引數名自解釋了。
value: 引數名自解釋了。
flags: 有兩個標誌位可以設定,NGX_HASH_WILDCARD_KEY和NGX_HASH_READONLY_KEY。同時要設定的使用邏輯與操作符就可以了。NGX_HASH_READONLY_KEY被設定的時候,在計算hash值的時候,key的值不會被轉成小寫字元,否則會。NGX_HASH_WILDCARD_KEY被設定的時候,說明key裡面可能含有萬用字元,會進行相應的處理。如果兩個標誌位都不設定,傳0。

有關於這個資料結構的使用,可以參考src/http/ngx_http.c中的ngx_http_server_names函式。