7.nginx源码分析之数据结构:ngx_array_t
2016-10-28 23:31
459 查看
nginx源码分析之数据结构:ngx_array_t
头文件定义
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;
elts 是实际存储的其实位置;
nelts 数组实际元素个数;
size 单个数组元素的大小;
nalloc 数组的容量,如果超过该容量会触发数组进行扩容;
pool 数组申请所在的内存池指针(可能是链表);
如图所示:
关于数组的接口生命如下所示:
//数组的创建、销毁(并没有真正的销毁数组)、添加一个元素和添加n个元素 ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size); void ngx_array_destroy(ngx_array_t *a); void *ngx_array_push(ngx_array_t *a); void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
接口实现
ngx_array_create 数组创建关于上述接口的实现在ngx_array.c中:
ngx_array_t * ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size) { ngx_array_t *a; //在内存池申请数组的控制信息 a = ngx_palloc(p, sizeof(ngx_array_t)); if (a == NULL) { return NULL; } //对数组进行初始化,并且申请n个size大小的成员空间 if (ngx_array_init(a, p, n, size) != NGX_OK) { return NULL; } return a; }
关于ngx_array_init的实现如下所示,这个是一个静态的函数:
static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size) { /* * set "array->nelts" before "array->elts", otherwise MSVC thinks * that "array->nelts" may be used without having been initialized */ //对数组的控制信息进行初始化 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; }
ngx_array_destroy数组的销毁
void ngx_array_destroy(ngx_array_t *a) { ngx_pool_t *p; p = a->pool; //数组所存储的内存池 //这里的销毁并没有真正的释放内存,只是把数组所对应的内存池的last指针向前移动了a->size * a->nalloc个字节 if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) { p->d.last -= a->size * a->nalloc; } //删除数组的控制信息 if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) { p->d.last = (u_char *) a; } }
ngx_array_push向数组中添加一个元素
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; //指向数组对应的内存池 //内存池的数量足够扩展数组为2倍空间,则直接扩展 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++; } 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; }
ngx_array_push_n向数组中添加n个元素
添加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_t是nginx中一个比较精简的数据结构,希望大家快速掌握。相关文章推荐
- Nginx 源码分析-- ngx_array、ngx_list基本数据结构
- nginx 源码学习(六) 基本数据结构 ngx_array_t
- nginx源码初读(5)--让烦恼从数据结构开始(ngx_array)
- nginx源码分析—数组结构ngx_array_t
- nginx源码分析—数组结构ngx_array_t
- nginx源码分析—数组结构ngx_array_t
- nginx源码分析—数组结构ngx_array_t
- 6.nginx源码分析之数据结构:ngx_pool_t
- 10.nginx源码分析之数据结构:ngx__rbtree_t
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- Nginx源码分析 - 基础数据结构篇 - 数组结构 ngx_array.c
- 5.nginx源码分析之数据结构:ngx_string
- 9.nginx源码分析之数据结构:ngx__queue_t
- nginx源码分析—数组结构ngx_array_t
- Nginx源码分析—数组结构ngx_array_t
- Nginx源码分析---数组结构ngx_array_t
- Nginx源码分析之ngx_array_t
- 文章2:Nginx源码分析-ngx_array_t动态数组
- ngx源码分析--数据结构 队列ngx_queue_t
- nginx源码分析之ngx_array_t