[筆記] 解碼Nginx:陣列(Array)

樑濤發表於2012-11-24

解碼Nginx:陣列(Array)

樑濤(@無鋒之刃)
2012-11-24 ~ 2012-11-25

nginx-1.2.5

原始碼檔案

src/core/ngx_array.h
src/core/ngx_array.c

設計思路

陣列是非常常用的資料結構。為降低使用時的時間開銷,Nginx對陣列設計做了不少簡化:

  1. 使用從給定記憶體池中預分配好的儲備元素區塊;
  2. 儲備元素區塊無空閒元素供分配時,嘗試從原記憶體池中分配新的空閒元素,或擴充儲備元素區塊以完成分配;
  3. “分配”,或“壓入”,只是取得新的空閒元素的首址,不負責建立實際元素;
  4. “釋放”只是調整原記憶體池的欄位,不負責清理實際元素,或者乾脆推遲釋放時機;
  5. 使用者可以直接訪問陣列的各個欄位,以取得最佳效能。

陣列適用於元素較小、或元素生命週期較短,擴充儲備元素區不會跨越記憶體池中多個ngx_pool_data_t結構體的場景。

資料結構

        ngx_array_create(pool, n, size)            ngx_array_push()/            ...
         |                                         ngx_array_push_n()
         |                                          |
         +- ngx_palloc()-----\                  /---?- ngx_palloc()------\
         |                   |                  |                        |
         \- ngx_palloc()-------------------\    |                        |
                             |             |    |                        |
          ngx_array_t        V             |    |                        |
         +-------------------+             |    |                        |
  /----- | elts              | ======================\                   |
  |      +-------------------+             |    |    H                   |
  |      | nelts             | -------\    |    |    H                   |
  |      +-------------------+        |    |    |    H                   |
  |  /-- | size        bytes |        |    |    |    H                   |
  |  |   +-------------------+        |    |    |    H                   |
  |  |   | nalloc        = n | --\    |    |    |    H                   |
  |  |   +-------------------+   |    |    |    |    H                   |
  |  |   | pool              |   |    |    |    |    H                   |
  |  |   +-------------------+   |    |    |    |    H                   |
  |  |                           |    |    |    |    H                   |
  |  |                           |    |    |    |    H                   |
  |  |                       /-------------/    |    H                   |
  |  |                       |   |    |         |    H                   | 
  |  |                       |   |    |         |    H                   |
  |  |                       V   |    |         |    V                   V
  \----> +-------------------+  -+-  -+-        |    +-------------------+   
     |   | elem 0            |   A    A         |    | elem 0            |
     |   /                   /   |    |         |    /                   /
     |   /                   /   |    |         |    /                   /
     |   |                   |   |    |         |    |                   |
     |   +-------------------+   |    |         |    +-------------------+
     |   | elem 1            |   |    |         |    | elem 1            |
     |   /                   /   |    |         |    /                   /
     |   /                   /   |    |         |    /                   /
     |   |                   |   |    |         |    |                   |
    -+-  +-------------------+   |    |         |    +-------------------+
     A   | elem 2            |   |    |         |    | elem 2            |
     |   /                   /   |    |         |    /                   /
     |   /                   /   |    |         |    /                   /
     V   |                   |   |    V         |    |                   |
    ---  +-------------------+   |   ---        |    +-------------------+
         | unpushed          |   |              |    | elem 3            |
         / elements          /   |              |    /                   /
         /                   /   |              |    /                   /
         /                   /   |              |    |                   |
         /                   /   |              |    +-------------------|
         /                   /   |              |    | elem 4            |
         /                   /   |              |    /                   /
         /                   /   |              |    /                   /
         |                   |   V              |    |                   |
         +-------------------+  ---  <----------/    +-------------------+
         | extended          |                       | elem 5            |
         / area              /                       /                   /
         / (in place)        /                       /                   /
         /                   /                       |                   /
         /                   /                       +-------------------|
         /                   /                       | unpushed          |
         /                   /                       / elements          /
         /                   /                       /                   /
         |        = size * n |                       |                   |
         +-------------------+                       +-------------------+

介面函式

ngx_array_create(pool, n, size)

ngx_array_create()負責動態建立一個陣列,動作序列如下:

  1. 從pool中分配ngx_array_t結構體;
  2. 從pool中分配能容納n個size大小的元素的儲備元素區塊;
  3. 適當地初始化ngx_array_t結構體。

ngx_array_destroy(array)

ngx_array_destroy()負責“釋放”陣列使用的記憶體塊(實際為推遲釋放時機),但不清理其中的各個元素。動作序列如下:

  1. 如果儲備元素區塊位於pool的末尾,直接移動pool->current->d.last指標,指向“釋放”後的地址;
  2. 如果ngx_array_t結構體位於pool的末尾,直接移動pool->current->d.lat指標,指向“釋放”後的地址;
  3. 否則什麼也不做。

ngx_array_push(array)/ngx_array_push_n(array, n)

ngx_array_push()負責向陣列中“壓入”一個元素(實際為取得一個空閒元素的首址),動作序列如下:

  1. 若陣列中還有空閒元素,直接取得其首址並返回;
  2. 若陣列的儲備元素區塊位於pool的儲備記憶體塊中最末位置,且其還有size大小的剩餘空間,則直接分配新的空閒元素並返回;
  3. 重新分配新的儲備元素區塊(原區塊的2倍大小)並複製已有元素,將新區塊首址存入elts欄位後分配新的空閒元素並返回。

ngx_array_push_n()與前者相似,可以一次返回n個新的空閒元素的切片首址。

相關文章