niginx源码分析二----基础数据结构

为了保证操作的高效性以及对内存的严格控制,nginx自己封装了很多基础的数据结构,这些基本的数据类型在nginx的源码中随处可见,熟悉和掌握各种类型的用法是了解nginx底层原理的基础,下面就一起看看这些独具特色的ngx系风格的数据类型。
(以下未做注释的属性成员都是不太重要的,可忽略。)

ngx_str_t

相关函数:

初始化:
ngx_str_null(&local_conf->hello_string);
赋值:
ngx_str_set(&r->headers_out.content_type, "text/html");

ngx_buf_t

描述:缓冲区ngx_buf_t是nginx处理大数据的关键,它既应用于内存数据也应用于磁盘数据,ngx_buf_t本质上提供了一些指针成员和标志位。
位置: ngx_buf.h
定义:
struct ngx_buf_s {
    u_char          *pos;         /* pos是告诉使用者本次应该从pos这个位置开始处理内存中的数据,因为同一个ngx_buf_t可能被多次反复处理,pos的作用类似文件处理过程中的文件指针*/
    u_char          *last;        /* last 表示有效的内容到此为止, 一般pos到last之间的内容是希望nginx处理的内容*/

    off_t            file_pos;     /* 处理文件时,file_pos和file_last作用和post,last作用类似*/
    off_t            file_last;

    u_char          *start;         /* start of buffer */
    u_char          *end;           /* end of buffer */
    ngx_buf_tag_t    tag;           /* 表示当前缓冲区的类型,例如由哪个模块使用就指向这个模块ngx_module_t变量的地址*/
    ngx_file_t      *file;          /* 引用的文件*/
    ngx_buf_t       *shadow;        /* 当前缓冲区的影子缓冲区,非重点*/


    /* the buf's content could be changed */
    unsigned         temporary:1;

    /*
     * the buf's content is in a memory cache or in a read only memory
     * and must not be changed
     */
    unsigned         memory:1;

    /* the buf's content is mmap()ed and must not be changed */
    unsigned         mmap:1;       /* 标志位:为1时表示这段内存是由mmap系统映射过来的,不可以被修改*/

    unsigned         recycled:1;    /* 标志位:为1时表示这段内存可回收*/
    unsigned         in_file:1;     /* 标志位:为1时表示处理的这段缓冲区是文件而不是内存*/
    unsigned         flush:1;       /* 标志位:为1时表示需要执行flush操作*/
    unsigned         sync:1;        /* 标志位:为1时表示以同步的方式处理这块内存,需谨慎*/
    unsigned         last_buf:1;    /* 标志位:表示是否是最后一块缓冲区*/
    unsigned         last_in_chain:1;  /* 标志位:表示是否是ngx_chain_t中的最后一块缓冲区*/

    unsigned         last_shadow:1;   /*标志位:表示是否是最后一个影子缓冲区,和shadow配合使用*/
    unsigned         temp_file:1;     /*标志位:表示当前缓存区是否属于临时文件*/

    /* STUB */ int   num;
};

常用方法:
ngx_palloc(ngx_pool_t *pool, size_t size)
ngx_pcalloc(r->pool, 1024)
ngx_create_temp_buf(r->pool,1024)

ngx_file_t

描述:nginx通过ngx_file_t结构体来描述某个文件
位置: ngx_file.h

struct ngx_file_s {
    ngx_fd_t                   fd;   	//文件句柄描述符
    ngx_str_t                  name;     //文件名称
    ngx_file_info_t            info;      //文件大小等资源信息,实际就是Linux系统定义的stat结构

    off_t                      offset;     //该偏移量告诉Nginx现在文件处理到哪里了,一般不用设置它,Nginx框架会根据当前发送状态设置它
    off_t                      sys_offset;  //当前文件系统偏移量,一般不用设置它,同样由nginx框架设置

    ngx_log_t                 *log;   //日志对象,相关的日志文件会输出到log指定的日志文件中

#if (NGX_THREADS || NGX_COMPAT)
    ngx_int_t                (*thread_handler)(ngx_thread_task_t *task,
                                               ngx_file_t *file);
    void                      *thread_ctx;
    ngx_thread_task_t         *thread_task;
#endif

#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
    ngx_event_aio_t           *aio;
#endif

    unsigned                   valid_info:1;
    unsigned                   directio:1;
};

ngx_pool_cleanup_t

描述:对于nginx打开的文件句柄,请求执行完毕后,需要及时关闭掉,否则会出现句柄泄露

struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler;    //执行清理资源工作的回调方法
    void                 *data;       // handler方法需要的参数
    ngx_pool_cleanup_t   *next;        //下一个需要清理的对象
};

ngx_array_t

动态数组:

typedef struct {
    void        *elts;          // 数组元素的起始地址
    ngx_uint_t   nelts;       //  当前已经存放的数组元素个数
    size_t       size;          // 每个元素所占用的空间大小
    ngx_uint_t   nalloc;       // 数组中能存放的元素总数
    ngx_pool_t  *pool;       // 该数组所属的内存池地址
} ngx_array_t;

nginx提供的五个方法:

  • 创建数组,并分配n个大小为size的空间
ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
{
    ngx_array_t *a;
    // 先申请结构体ngx_array_t的内存
    a = ngx_palloc(p, sizeof(ngx_array_t));
    if (a == NULL) {
        return NULL;
    }
	// 然后调用ngx_array_init申请各元素的内存空间
    if (ngx_array_init(a, p, n, size) != NGX_OK) {
        return NULL;
    }
    return a;
}
  • 销毁数组
void
ngx_array_destroy(ngx_array_t *a)
{
    ngx_pool_t  *p;

    p = a->pool;
	// 如果内存池的起始可用地址正好是数组a的结束地址,则直接把起始可用地址往前移动数组的长度大小位置即可
    if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
        p->d.last -= a->size * a->nalloc;
    }
	// 继续将p的last指针往前移动一个ngx_array_t 结构体的大小位置,回收掉结构体本身占用的那部分内存
    if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
        p->d.last = (u_char *) a;
    }
}
  • 数组初始化
 ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{  
    array->nelts = 0;
    array->size = size;
    array->nalloc = n;
    array->pool = pool;

    array->elts = ngx_palloc(pool, n * size);
    if (array->elts == NULL) {
        return NGX_ERROR;
    }

    return NGX_OK;
}
  • 添加一个元素
void *
ngx_array_push(ngx_array_t *a)
{
    void        *elt, *new;
    size_t       size;
    ngx_pool_t  *p;
	// 数组中元素已经达到了最大值,需要扩容
    if (a->nelts == a->nalloc) {

        /* the array is full */

        size = a->size * a->nalloc;

        p = a->pool;
		// 如果内存池中剩余的空间比一个数组元素还大,则将内存池的last指针往后移动一个单位。
        if ((u_char *) a->elts + size == p->d.last
            && p->d.last + a->size <= p->d.end)
        {
            /*
             * the array allocation is the last in the pool
             * and there is space for new allocation
             */

            p->d.last += a->size;
            a->nalloc++;
		// 当前内存池剩余空间已不足以容纳一个元素,则需要重新申请动态数组,并且是申请的空间大小是原来的2倍,然后将旧数组中的元素拷贝至新数组,这个过程可能会耗时较长
        } else {
            /* allocate a new array */

            new = ngx_palloc(p, 2 * size);
            if (new == NULL) {
                return NULL;
            }

            ngx_memcpy(new, a->elts, size);
            a->elts = new;
            a->nalloc *= 2;
        }
    }

    elt = (u_char *) a->elts + a->size * a->nelts;
    a->nelts++;

    return elt;
}
  • 添加n个元素

void *
ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
{
    void        *elt, *new;
    size_t       size;
    ngx_uint_t   nalloc;
    ngx_pool_t  *p;

    size = n * a->size;

    if (a->nelts + n > a->nalloc) {

        /* the array is full */

        p = a->pool;

        if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
            && p->d.last + size <= p->d.end)
        {
            /*
             * the array allocation is the last in the pool
             * and there is space for new allocation
             */

            p->d.last += size;
            a->nalloc += n;

        } else {
            /* allocate a new array */

            nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);

            new = ngx_palloc(p, nalloc * a->size);
            if (new == NULL) {
                return NULL;
            }

            ngx_memcpy(new, a->elts, a->nelts * a->size);
            a->elts = new;
            a->nalloc = nalloc;
        }
    }

    elt = (u_char *) a->elts + a->size * a->nelts;
    a->nelts += n;

    return elt;
}

说明: ngx_array_push和ngx_array_push_n都可能触发数组的扩容操作,扩容的时候会判断当前内存池是否有足够的空间,如果有,则只需要扩容一个或者n个元素大小的空间;如果内存不足够,则会重新申请动态数组的空间,并且申请的空间大小为原来的2倍,并将元素从旧数组拷贝至新数组中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值