ngx_hash_t是nginx自己的hash表的實現。定義和實現位于src/core/ngx_hash.h|c中。ngx_hash_t的實現也與數據結構教科書上所描述的hash表的實現是大同小異。對于常用的解決沖突的方法有線性探測,二次探測和開鏈法等。ngx_hash_t使用的是最常用的一種,也就是開鏈法,這也是STL中的hash表使用的方法。
但是ngx_hash_t的實現又有其幾個顯著的特點:
1. ngx_hash_t不像其他的hash表的實現,可以插入刪除元素,它只能一次初始化,就構建起整個hash表以后,既不能再刪除,也不能在插入元素了。
1. ngx_hash_t的開鏈并不是真的開了一個鏈表,實際上是開了一段連續的存儲空間,幾乎可以看做是一個數組。這是因為ngx_hash_t在初始化的時候,會經歷一次預計算的過程,提前把每個桶里面會有多少元素放進去給計算出來,這樣就提前知道每個桶的大小了。那么就不需要使用鏈表,一段連續的存儲空間就足夠了。這也從一定程度上節省了內存的使用。
從上面的描述,我們可以看出來,這個值越大,越造成內存的浪費。就兩步,首先是初始化,然后就可以在里面進行查找了。下面我們詳細來看一下。
ngx_hash_t的初始化。
[](http:// "點擊提交Issue,反饋你的意見...")
ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
ngx_uint_t nelts);
首先我們來看一下初始化函數。該函數的第一個參數hinit是初始化的一些參數的一個集合。 names是初始化一個ngx_hash_t所需要的所有key的一個數組。而nelts就是key的個數。下面先看一下ngx_hash_init_t類型,該類型提供了初始化一個hash表所需要的一些基本信息。
[](http:// "點擊提交Issue,反饋你的意見...")
typedef struct {
ngx_hash_t *hash;
ngx_hash_key_pt key;
ngx_uint_t max_size;
ngx_uint_t bucket_size;
char *name;
ngx_pool_t *pool;
ngx_pool_t *temp_pool;
} ngx_hash_init_t;
| hash: | 該字段如果為NULL,那么調用完初始化函數后,該字段指向新創建出來的hash表。如果該字段不為NULL,那么在初始的時候,所有的數據被插入了這個字段所指的hash表中。 |
|-----|-----|
| key: | 指向從字符串生成hash值的hash函數。nginx的源代碼中提供了默認的實現函數ngx_hash_key_lc。 |
| max_size: | hash表中的桶的個數。該字段越大,元素存儲時沖突的可能性越小,每個桶中存儲的元素會更少,則查詢起來的速度更快。當然,這個值越大,越造成內存的浪費也越大,(實際上也浪費不了多少)。 |
| bucket_size: | 每個桶的最大限制大小,單位是字節。如果在初始化一個hash表的時候,發現某個桶里面無法存的下所有屬于該桶的元素,則hash表初始化失敗。 |
| name: | 該hash表的名字。 |
| pool: | 該hash表分配內存使用的pool。 |
| temp_pool: | 該hash表使用的臨時pool,在初始化完成以后,該pool可以被釋放和銷毀掉。 |
下面來看一下存儲hash表key的數組的結構。
[](http:// "點擊提交Issue,反饋你的意見...")
typedef struct {
ngx_str_t key;
ngx_uint_t key_hash;
void *value;
} ngx_hash_key_t;
key和value的含義顯而易見,就不用解釋了。key_hash是對key使用hash函數計算出來的值。 對這兩個結構分析完成以后,我想大家應該都已經明白這個函數應該是如何使用了吧。該函數成功初始化一個hash表以后,返回NGX_OK,否則返回NGX_ERROR。
[](http:// "點擊提交Issue,反饋你的意見...")
void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len);
在hash里面查找key對應的value。實際上這里的key是對真正的key(也就是name)計算出的hash值。len是name的長度。
如果查找成功,則返回指向value的指針,否則返回NULL。
- 上篇:nginx模塊開發篇
- nginx平臺初探
- 初探nginx架構
- nginx基礎概念
- connection
- request
- keepalive
- pipe
- lingering_close
- 基本數據結構
- ngx_str_t
- ngx_pool_t
- ngx_array_t
- ngx_hash_t
- ngx_hash_wildcard_t
- ngx_hash_combined_t
- ngx_hash_keys_arrays_t
- ngx_chain_t
- ngx_buf_t
- ngx_list_t
- ngx_queue_t
- nginx的配置系統
- 指令參數
- 指令上下文
- nginx的模塊化體系結構
- 模塊的分類
- nginx的請求處理
- handler模塊
- handler模塊簡介
- 模塊的基本結構
- 模塊配置結構
- 模塊配置指令
- 模塊上下文結構
- 模塊的定義
- handler模塊的基本結構
- handler模塊的掛載
- handler的編寫步驟
- 示例: hello handler 模塊
- handler模塊的編譯和使用
- 更多handler模塊示例分析
- http access module
- http static module
- http log module
- 過濾模塊
- 過濾模塊簡介
- 過濾模塊的分析
- upstream模塊
- upstream模塊
- upstream模塊接口
- memcached模塊分析
- 本節回顧
- 負載均衡模塊
- 配置
- 指令
- 鉤子
- 初始化配置
- 初始化請求
- peer.get和peer.free回調函數
- 本節回顧
- 其他模塊
- core模塊
- event模塊
- 模塊開發高級篇
- 變量
- 下篇:nginx原理解析篇
- nginx架構詳解
- nginx的源碼目錄結構
- nginx的configure原理
- 模塊編譯順序
- nginx基礎設施
- 內存池
- nginx的啟動階段
- 概述
- 共有流程
- 配置解析
- nginx的請求處理階段
- 接收請求流程
- http請求格式簡介
- 請求頭讀取
- 解析請求行
- 解析請求頭
- 請求體讀取
- 讀取請求體
- 丟棄請求體
- 多階段處理請求
- 多階段執行鏈
- POST_READ階段
- SERVER_REWRITE階段
- FIND_CONFIG階段
- REWRITE階段
- POST_REWRITE階段
- PREACCESS階段
- ACCESS階段
- POST_ACCESS階段
- TRY_FILES階段
- CONTENT階段
- LOG階段
- Nginx filter
- header filter分析
- body filter分析
- ngx_http_copy_filter_module分析
- ngx_http_write_filter_module分析
- subrequest原理解析
- https請求處理解析
- 附錄A 編碼風格
- 附錄B 常用API
- 附錄C 模塊編譯,調試與測試