为了保证操作的高效性以及对内存的严格控制,nginx自己封装了很多基础的数据结构,这些基本的数据类型在nginx的源码中随处可见,熟悉和掌握各种类型的用法是了解nginx底层原理的基础,下面就一起看看这些独具特色的ngx系风格的数据类型。 (以下未做注释的属性成员都是不太重要的,可忽略。)
相关函数:
初始化: ngx_str_null(&local_conf->hello_string); 赋值: ngx_str_set(&r->headers_out.content_type, "text/html");常用方法: ngx_palloc(ngx_pool_t *pool, size_t size) ngx_pcalloc(r->pool, 1024) ngx_create_temp_buf(r->pool,1024)
描述: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; };描述:对于nginx打开的文件句柄,请求执行完毕后,需要及时关闭掉,否则会出现句柄泄露
struct ngx_pool_cleanup_s { ngx_pool_cleanup_pt handler; //执行清理资源工作的回调方法 void *data; // handler方法需要的参数 ngx_pool_cleanup_t *next; //下一个需要清理的对象 };动态数组:
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倍,并将元素从旧数组拷贝至新数组中。