ngx_list_t 介紹
ngx_list_t是Nginx中使用的較爲頻繁的數據結構,數據內容基於指針獲取,內存分配基於內存池進行。由於數據內容存放的是指針,所以理論上ngx_list_t可以用來構建多維鏈表甚至是網絡結構,只是Nginx原始代碼封裝的函數中並不涉及這些數據結構的操作(實際上也不需要)。
1.數據結構
Nginx鏈表的數據結構包含兩個部分ngx_list_part_s和ngx_list_t。ngx_list_part_s爲數據節點,每個數據節點都包含數據指針和鏈表數據已存入數據個數和下一節點的位置。
struct ngx_list_part_s {
void *elts;
ngx_uint_t nelts;/*已存儲元素個數*/
ngx_list_part_t *next;
};
ngx_list_t負責鏈表的管理和操作,表頭結構如下。
typedef struct {
ngx_list_part_t *last;/*鏈表最後一個節點的位置*/
ngx_list_part_t part;/*鏈表第一個節點*/
size_t size;/*鏈表中每個元素的大小,內存分配同樣是等尺寸內存卡分配,便於管理*/
ngx_uint_t nalloc;/*鏈表已分配的元素個數*/
ngx_pool_t *pool;/*鏈表分配內存所在內存池*/
} ngx_list_t;
2.基本操作
2.1初始化鏈表
初始化邏輯很簡單,先在內存池中分配第一個節點,然後將最後一個節點指向第一個節點,最後更新鏈表的管理信息就可以了。
static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
list->part.elts = ngx_palloc(pool, n * size);
if (list->part.elts == NULL) {
return NGX_ERROR;
}
list->part.nelts = 0;
list->part.next = NULL;
list->last = &list->part;
list->size = size;
list->nalloc = n;
list->pool = pool;
return NGX_OK;
}
2.2創建鏈表
ngx_list_t *
ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
ngx_list_t *list;
list = ngx_palloc(pool, sizeof(ngx_list_t));
if (list == NULL) {
return NULL;
}
if (ngx_list_init(list, pool, n, size) != NGX_OK) {
return NULL;
}
return list;
}
2.3添加元素
添加元素時返回最後一個元素之爭,然後在外部邏輯中添加元素內容。
void *
ngx_list_push(ngx_list_t *l)
{
void *elt;
ngx_list_part_t *last;
last = l->last;
if (last->nelts == l->nalloc) {
/* the last part is full, allocate a new list part */
last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
if (last == NULL) {
return NULL;
}
last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
if (last->elts == NULL) {
return NULL;
}
last->nelts = 0;
last->next = NULL;
l->last->next = last;
l->last = last;
}
elt = (char *) last->elts + l->size * last->nelts;
last->nelts++;
return elt;
}
Nginx鏈表結構可以根據需要動態分配內存,從而有效的避免的內存的過度分配,這點對於節約內存很有好處,需要注意的一點是在大量數據的push操作時會帶來內存申請頻率增大的問題。