3. nginx基本数据结构之动态数组ngx_array_t

1490阅读 0评论2015-06-02 mizhouli
分类:LINUX

ngx_array_t 是nginx中的动态数组,当数组容量已满,仍向其插入数据,数组会动态改变数组的容量。
数组的特点是使用下标访问元素,其访问速度是常量。数组使用一块连续内存存储其元素,如果容量固定,可以使用普通数组;但很多场景,数组中元素个数事先未知,如果分配太多内存,会浪费宝贵的内存资源,故开发动态数组。
动态数组现在是一个很常用的数据结构,如 C++ STL 中的 vector 。
现在让我们看一下nginx中的动态数组 ngx_array_t, 其中内置自己的内存池.
ngx_array_t定义

点击(此处)折叠或打开

  1. typedef struct {
  2.     // 数组所有元素的首地址
  3.     void *elts;
  4.     // 数组中已有元素的个数
  5.     ngx_uint_t nelts;
  6.     // 数组中元素的大小
  7.     size_t size;
  8.     // 当前数组的容量,可变
  9.     ngx_uint_t nalloc;
  10.     // 内置的内存池
  11.     ngx_pool_t *pool;
  12. } ngx_array_t;
ngx_array_t的方法

点击(此处)折叠或打开

  1. // 初始化一个已经存在的数组,数组的所有元素的内存在pool中分配
  2.         ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
  3.         // 从内存池 pool 中 分配一个 ngx_array_t 数组对象,并初始化该对象。
  4.         // 与 ngx_array_destroy 配对使用
  5.         ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
  6.         // 销毁一个数组对象,与 ngx_array_create 配对使用
  7.         void ngx_array_destroy(ngx_array_t *a);
  8.         // 在数组的后面获取一个空元素 ,代码中原有的注释可以很容易的帮助我们理解。
  9.         void *ngx_array_push(ngx_array_t *a);
  10.         // 在数组的后面获取n个空元素
  11.         void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
  12.         static ngx_inline ngx_int_t
  13.     /*
  14.      * Copyright (C) Igor Sysoev
  15.      * Copyright (C) Nginx, Inc.
  16.      */
  17.     #include <ngx_config.h>
  18.     #include <ngx_core.h>
  19.     // 从内存池 pool 中 分配一个 ngx_array_t 数组对象,并初始化该对象。
  20.     // 与 ngx_array_destroy 配对使用
  21.     ngx_array_t *
  22.     ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
  23.     {
  24.         ngx_array_t *a;
  25.         a = ngx_palloc(p, sizeof(ngx_array_t));
  26.         if (a == NULL) {
  27.             return NULL;
  28.         }
  29.         if (ngx_array_init(a, p, n, size) != NGX_OK) {
  30.             return NULL;
  31.         }
  32.         return a;
  33.     }
  34.     // 销毁一个数组对象,与 ngx_array_create 配对使用
  35.     void
  36.     ngx_array_destroy(ngx_array_t *a)
  37.     {
  38.         ngx_pool_t *p;
  39.         p = a->pool;
  40.         if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
  41.             p->d.last -= a->size * a->nalloc;
  42.         }
  43.         if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
  44.             p->d.last = (u_char *) a;
  45.         }
  46.     }
  47.     // 在数组的后面获取一个空元素 ,代码中原有的注释可以很容易的帮助我们理解。
  48.     void *
  49.     ngx_array_push(ngx_array_t *a)
  50.     {
  51.         void *elt, *new;
  52.         size_t size;
  53.         ngx_pool_t *p;
  54.         if (a->nelts == a->nalloc) {
  55.             /* the array is full */
  56.             size = a->size * a->nalloc;
  57.             p = a->pool;
  58.             if ((u_char *) a->elts + size == p->d.last
  59.                 && p->d.last + a->size <= p->d.end)
  60.             {
  61.                 /*
  62.                  * the array allocation is the last in the pool
  63.                  * and there is space for new allocation
  64.                  */
  65.                 p->d.last += a->size;
  66.                 a->nalloc++;
  67.             } else {
  68.                 /* allocate a new array */
  69.                 new = ngx_palloc(p, 2 * size);
  70.                 if (new == NULL) {
  71.                     return NULL;
  72.                 }
  73.                 // 重新拷贝原有的内容,会有性能的损失,
  74.                 // 但由于每次重新分配两倍的内存,故重新分配次数会很少
  75.                 ngx_memcpy(new, a->elts, size);
  76.                 a->elts = new;
  77.                 a->nalloc *= 2;
  78.             }
  79.         }
  80.         elt = (u_char *) a->elts + a->size * a->nelts;
  81.         a->nelts++;
  82.         return elt;
  83.     }
  84.     // 在数组的后面获取n个空元素
  85.     void *
  86.     ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
  87.     {
  88.         void *elt, *new;
  89.         size_t size;
  90.         ngx_uint_t nalloc;
  91.         ngx_pool_t *p;
  92.         size = n * a->size;
  93.         if (a->nelts + n > a->nalloc) {
  94.             /* the array is full */
  95.             p = a->pool;
  96.             if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
  97.                 && p->d.last + size <= p->d.end)
  98.             {
  99.                 /*
  100.                  * the array allocation is the last in the pool
  101.                  * and there is space for new allocation
  102.                  */
  103.                 p->d.last += size;
  104.                 a->nalloc += n;
  105.             } else {
  106.                 /* allocate a new array */
  107.                 nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
  108.                 new = ngx_palloc(p, nalloc * a->size);
  109.                 if (new == NULL) {
  110.                     return NULL;
  111.                 }
  112.                 ngx_memcpy(new, a->elts, a->nelts * a->size);
  113.                 a->elts = new;
  114.                 a->nalloc = nalloc;
  115.             }
  116.         }
  117.         elt = (u_char *) a->elts + a->size * a->nelts;
  118.         a->nelts += n;
  119.         return elt;
  120.     }

在nginx_cycle.c的ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle)

点击(此处)折叠或打开

  1. // 可以使用 ngx_inline ngx_int_t
  2.     // ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
  3.     // 简化代码,如下:
  4.     // ngx_int_t ret;
  5.     // n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
  6.     // ret = ngx_array_init(cycle->paths, pool, n, sizeof(ngx_path_t *));
  7.     // if(ret == NGX_ERROR) {
  8.     // ngx_destroy_pool(pool);
  9.     // return NULL;
  10.     // }
  11.     n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
  12.     cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
  13.     if (cycle->paths.elts == NULL) {
  14.         ngx_destroy_pool(pool);
  15.         return NULL;
  16.     }
  17.    
  18.     cycle->paths.nelts = 0;
  19.     cycle->paths.size = sizeof(ngx_path_t *);
  20.     cycle->paths.nalloc = n;
  21.     cycle->paths.pool = pool;





上一篇:2. nginx基本数据结构之ngx_str_t ngx_queue_t
下一篇:4. nginx基本数据结构之链表ngx_list_t