7

Nginx源码分析-基础数据结构(一)

 2 years ago
source link: https://atticuslab.com/2020/10/05/nginx-annotated-3/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

为了进行平台无关层(PAL, Platform Abstraction Layer)抽象, 优化数据结构对内存空间的占用以及同一代码风格等因素, Nginx为此定义,封装了一些基本数据结构。

整型的封装

typedef intptr_t    ngx_int_t;
2
typedef uintptr_t   ngx_uint_t;

ngx_str_t字符串封装

该结构定义在/src/core/ngx_string.h文件中, ngx_str_t只有两个成员,其中data指针指向字符串起始地址,len表示字符串的有效长度。注意,ngx_str_t的data成员指向的并不是普通的字符串,
因为这段字符串未必会以’\0’作为结尾,所以使用时必须根据长度len来使用data成员。

typedef struct {
2
    size_t  len;
3
    u_char  *data;
4
}
5
6
if (0 == ngx_strncmp(r->method_name.data,"PUT", r->method_name.len)) {
7
    /* ... */
8
}
9
#define ngx_strcmp(s1, s2, n) strncmp((const char *)s1, (const char*)s2, n)

ngx_list_t链表容器

ngx_list_t不是一个单纯的链表,是一种存储数组的链表,定义在/src/core/ngx_list.h文件中。这样设计的目的是为了:

  1. 存储元素更加灵活,可以是任何一种数据结构。
  2. 链表元素需要占用的内存由ngx_list_t管理,它已经通过数组分配好了。
  3. 通过数组偏移量来访问元素,比零散的小块内存效率更高。
typedef struct ngx_list_part_s ngx_list_part_t;
2
3
struct ngx_list_part_s {
4
    void              *elts;    /* 指向数组起始地址 */
5
    ngx_uint_t        nelts;    /* 表示数组中已经使用了多少个元素 */
6
    ngx_list_part_t   *next;    /* 下一个链表元素ngx_list_part_t的地址 */
7
}
8
9
typedef struct {
    ngx_list_part_t     *last;  /* 指向链表的最后一个数组元素 */
    ngx_list_part_t     part;   /* 链表的首个数组元素 */
    size_t              size;   /* 每个数组元素占用空间大小 */
    /* 每个ngx_list_part_t数组的容量,即最多可存储多少个数据 */
    ngx_uint_t          nalloc; 
    ngx_pool_t          *pool;  /* 管理内存分配的内存池对象 */
} ngx_list_t;

ngx_list_t接口

ngx_list_init接口用于初始化一个已有的链表,size,n分别对应ngx_list_t中的sizenalloc

static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, \
2
            ngx_pool_t *pool, ngx_uint_t n, size_t size) 
3
{
4
    list->part.elts = ngx_palloc(pool, n * size); 
5
    if (list->part.elts == NULL) {
6
        return NGX_ERROR;
7
    }
8
9
    list->part.nelts = 0;
    list->part.next = NULL;
    list->last = &list->part;
    list->size = size;
    list->nalloc = n;
    list->pool = pool;
    return NGX_OK;
}

ngx_list_create接口用于创建新的链表,size是每个元素的大小,n是每个链表数组可容纳元素的个数。

ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size) 
2
{
3
    ngx_list_t  *list;
4
5
    list = ngx_palloc(pool, sizeof(ngx_list_t));
6
    if (list == NULL) {
7
        return NULL;
8
    }
9
    if (ngx_list_init(list, pool, n, size) != NGX_OK) {
        return NULL;
    }
    return list;
}

ngx_list_push表示添加新的元素,传入参数是ngx_list_t链表。

void *ngx_list_push(ngx_list_t *l)
2
{
3
    void             *elt;
4
    ngx_list_part_t  *last;
5
6
    last = l->last;
7
8
    if (last->nelts == l->nalloc) {
9
        /* 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;
20
        }
21
22
        last->nelts = 0;
23
        last->next = NULL;
24
25
        l->last->next = last;
26
        l->last = last;
27
    }
28
29
    elt = (char *) last->elts + l->size * last->nelts;
30
    last->nelts++;
31
32
    return elt;
33
}
34
35
ngx_str_t *str = ngx_list_push(testlist);
36
if(str == NULL) {
37
    return NGX_ERROR;
38
}
39
40
str->len = sizeof("Hello World!");
41
str->data = "Hello World!";

遍历链表容器

Nginx没有提供遍历链表容器的接口,实际上也没必要,可以用如下方法遍历链表中的元素:

/* part用于指向链表中的每一个ngx_list_part_t数组 */
2
ngx_list_part* part = &testlist.part;
3
4
/* 根据链表中的数据类型,把数组里的elts转化为该类型使用 */
5
ngx_str_t* str = part->elts;
6
7
/* i表示元素在链表的每个ngx_list_part_t数组里的序号 */
8
for(i = 0; /* void */; i++) {
9
    if(i >= part->nelts) {
        if(part-next == NULL) {
            /* 如果该指针为空,说明已经遍历完链表 */
            break;
        }
        /* 访问下一个ngx_list_part_t */
        part = part->next;
        str = part->elts;
        i = 0;  /* 准备访问下一个数组 */
20
    }
21
    printf("list element: %*s\n", str[i].len, str[i].data);
22
}

ngx_table_elt_t数据结构

typedef struct {
2
    ngx_uint_t  hash;
3
    ngx_str_t   key;
4
    ngx_str_t   value;
5
    u_char      *lowcase_key;
6
}

ngx_buf_t数据结构

ngx_buf_t是nginx处理大数据块的关键数据结构,定义在core/ngx_buf.h文件中,它即应用于内存数据也应用于磁盘数据,上一章中ngx_buf_t配置读取缓冲区是一个使用该结构的例子。

typedef struct ngx_buf_s  ngx_buf_t;
2
3
struct ngx_buf_s {
4
    /* pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的
5
     * 数据,因为ngx_buf_t可能被多次反复处理。 */
6
7
    u_char          *pos;
8
    u_char          *last;          /* 表示有效内存到此为止 */
9
    /* 处理文件时,file_pos与file_last的含义与处理内存时的post与last的
     * 含义相同 */
    off_t            file_pos;
    off_t            file_last;
    /* 如果ngx_buf_t缓冲区用于内存,则start表示内存起始地址
     * end指向内存末尾地址 */
    u_char          *start;         /* start of buffer */
20
    u_char          *end;           /* end of buffer */
21
22
    /* 表示当前缓冲区类型,例如由哪个模块使用就指向
23
     * 这个模块ngx_module_t变量的地址 */
24
25
    ngx_buf_tag_t    tag;
26
    ngx_file_t      *file;          /* 引用的文件 */
27
    ngx_buf_t       *shadow;        /* 影子缓冲区,当前不知道哪里用 */
28
29
    /* 位域 */
30
    /* the buf's content could be changed */
31
32
    unsigned         temporary:1;   /* 标志位,为1时表示数据在内存中且可修改 */
33
34
    /*
35
     * the buf's content is in a memory cache or in a read only memory
36
     * and must not be changed
37
     */
38
    unsigned         memory:1;      /* 为1时,表示这段内存不可修改 */
39
40
    /* the buf's content is mmap()ed and must not be changed */
41
    unsigned         mmap:1;        /* 为1时表示这段内存mmap映射而来,不可被修改 */
42
43
    unsigned         recycled:1;    /* 为1表示可回收 */
44
    unsigned         in_file:1;     /* 为1表示是文件而不是内存 */
45
    unsigned         flush:1;       /* 为1时表示需要指向flush操作 */
46
    unsigned         sync:1;        /*  */
47
    unsigned         last_buf:1;    /* 是否是最后一块缓冲区 */
48
    unsigned         last_in_chain:1;   /* 是否是当前最后一块待处理缓冲区 */
49
50
    unsigned         last_shadow:1; /*  */
51
    unsigned         temp_file:1;   /* 表示当前缓冲区是否是临时文件 */
52
53
    /* STUB */ int   num;
54
};

ngx_chain_t结构

ngx_chain_t是与ngx_buf_t配合使用的链表数据结构,如果处于最后一个ngx_chain_t结构,则需要把next置为NULL。

typedef struct ngx_chain_s  ngx_chain_t;
2
struct ngx_chain_s {
3
    ngx_buf_t   *buf;
4
    ngx_chain_t *next;
5
};

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK