nginx源码分析--数组链表

来源:互联网 发布:珠海知想科技官网 编辑:程序博客网 时间:2024/05/18 02:13

数组和链表的优缺点我们都知道,nginx的数组链表结合了这两种数据结构的优点,表面是链表,链表里每个节点是一个固定大小的数组。结构如下图。
这里写图片描述
ngx_list.h

/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */#ifndef _NGX_LIST_H_INCLUDED_#define _NGX_LIST_H_INCLUDED_#include <ngx_config.h>#include <ngx_core.h>typedef struct ngx_list_part_s  ngx_list_part_t;/*    ngx_list是一个数组链表,表面是一个链表,然后链表里的每一个节点都是一个固定大小的数组,    ngx_list_t是整个结构的领导者,他指向ngx_list_part_s,ngx_list_part_s指向数组的存储空间,    因为链表中每个节点,对应的数组可以存储多少个元素,每个元素的大小是固定的,所以这些元数据是存在ngx_list_s中,    没必要每个节点都存一份。ngx_list_part_s就是这个链表中的节点结构体,*/struct ngx_list_part_s {    void             *elts; // 数组首地址    ngx_uint_t        nelts; // 数组已经存储了多少个元素    ngx_list_part_t  *next; // 指向下一个节点的指针};typedef struct {    /*        最后一个数组节点的结构体指针,这个指针指向的节点是当前也是唯一一个可以用来存储数据的节点,        每次需要存储数据的时候,都是从last指针指向的节点开始找的,如果存满了就继续增加节点,此时last指向新的        节点,last一直指向当前可以存储数据的数据节点。    */    ngx_list_part_t  *last;     ngx_list_part_t   part; // 第一个数组节点的结构体    size_t            size; // 数组中,每个元素的大小    ngx_uint_t        nalloc; // 每个数组节点可以存储多少个元素    ngx_pool_t       *pool; // 用来分配内存的pool} ngx_list_t;ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);/*    初始化数组链表函数    @param list需要初始化的链表结构体    @param pool 用于分配内存的pool    @param n 该数组分配共可以存储几个元素    @param size 该数组中每个元素的大小    @return NGX_OK | NGX_ERROR*/static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size){    // 分配一个n*size大小的数组。并用赋值给第一个链表节点的list->part.elts,指向数组的首地址    list->part.elts = ngx_palloc(pool, n * size);    if (list->part.elts == NULL) {        return NGX_ERROR;    }    // 数组已存0个元素    list->part.nelts = 0;    // 下一个链表节点    list->part.next = NULL;    // 此时,第一个节点是最后一个节点,需要取地址    list->last = &list->part;    // 每个链表节点中,每个数组元素的大小    list->size = size;     // 每个链表节点中,数组最多可以存储多少个元素    list->nalloc = n;    list->pool = pool;    return NGX_OK;}/* * *  the iteration through the list: * *  part = &list.part; *  data = part->elts; * *  for (i = 0 ;; i++) { * *      if (i >= part->nelts) { *          if (part->next == NULL) { *              break; *          } * *          part = part->next; *          data = part->elts; *          i = 0; *      } * *      ...  data[i] ... * *  } */void *ngx_list_push(ngx_list_t *list);#endif /* _NGX_LIST_H_INCLUDED_ */

ngx_list.c

/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */#include <ngx_config.h>#include <ngx_core.h>/*    创建数组链表函数    @param pool 用于分配内存的pool    @param n 该数组分配共可以存储几个元素    @param size 该数组中每个元素的大小    @return 指向数组链表的结构体指针 ngx_list_t*/ngx_list_t * ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size){    ngx_list_t  *list;    // 分配一个ngx_list_t结构体大小的空间,用来存储数组链表的一些信息    list = ngx_palloc(pool, sizeof(ngx_list_t));    if (list == NULL) {        return NULL;    }    // 分配n * size大小的数组,并初始化第一个数组节点,使得第一个数组节点的指针指向分配的内存    list->part.elts = ngx_palloc(pool, n * size);    if (list->part.elts == NULL) {        return NULL;    }    // 同ngx_list_init函数    list->part.nelts = 0;    list->part.next = NULL;    list->last = &list->part;    list->size = size;    list->nalloc = n;    list->pool = pool;    return list;}/*    返回可以用来存储数据的首地址,如果第一个数组节点没有空间就往后面的节点找,如果都没有空间就动态增加数组节点    @param l 存储数据的链表    @return 可以用来存储数据的首地址*/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管理        last->elts = ngx_palloc(l->pool, l->nalloc * l->size);        if (last->elts == NULL) {            return NULL;        }        // 新开辟的数组存储了0个元素        last->nelts = 0;        // 该数组节点是最后一个数组节点,next为NULL        last->next = NULL;        // 把新开辟的数组节点插入到链表的最后面        l->last->next = last;        // 此时新开辟的数组节点是最后一个节点,也是唯一一个可用节点,可用的意思是还可以用来存储元素        l->last = last;    }    // 不管需不需要新增数组节点,last->elts + l->size * last->nelts此时都指向第一个可用的地址    elt = (char *) last->elts + l->size * last->nelts;    // 存储的元素个数加1    last->nelts++;    // 返回可存储数据的首地址,nginx里都是返回一个地址,然后在push函数外进行数据存储,而不是在push函数里操作    return elt;}
0 0
原创粉丝点击