[筆記] 解碼Nginx:雙向佇列(Queue)

樑濤發表於2012-12-08

解碼Nginx:雙向佇列(Queue)

樑濤(@無鋒之刃)
2012-12-08

nginx-1.2.5

原始碼檔案

src/core/ngx_queue.h
src/core/ngx_queue.c

設計思路

Nginx提供一個非常簡單的侵入式雙向佇列(雙向連結串列),也即向每個元素嵌入資料結構的連結結點。這樣做的好處在於:
1. 省去對資料結構所用記憶體的管理,進一步減少記憶體碎片;
2. 降低程式碼複雜度。

另外,通過使用額外的哨兵結點機制,簡化了程式碼。

資料結構

  /--------------------------------------------------------------------\
  |                                                                    |
  |     ngx_http_location_queue_t          ngx_http_location_queue_t   |
  |     +-----------------------+          +-----------------------+   |
  |     | ngx_queue_t queue     |          | ngx_queue_t queue     |   |
  |  /--+> +--------------------+ <-\  /---+> +--------------------+ <-/
  \--|--+- | prev               |   \--|---+- | prev               |
     |  |  +--------------------+      |   |  +--------------------+
     |  |  | next               | -----/   |  | next               | --\
     |  +--+--------------------+          +--+--------------------+   |
     |  | ...                   |          | ...                   |   |
     |  |                       |          |                       |   |
     |  |                       |          |                       |   |
     |  +-----------------------+          +-----------------------+   |
     |                                                                 |
     \-----------------------------------------------------------------/

  注意點:
    1. 圖中最左邊的queue即為哨兵結點。

介面函式

以h結點為哨兵的佇列稱之為h佇列。

雙向佇列的各個操作都很簡單,函式名即操作意圖:
1. ngx_queue_init(q)初始化哨兵結點,令prev欄位和next欄位均指向其自身;
2. ngx_queue_empty(q)檢查哨兵結點的prev欄位是否指向其自身,以判斷佇列是否為空;
3. ngx_queue_insert_head(h, x)在哨兵結點和第一個結點之間插入新結點x;
4. ngx_queue_insert_after(h, x)是ngx_queue_insert_head的別名;
5. ngx_queue_insert_tail(h, x)在最後一個結點和哨兵結點之間插入新結點;
6. ngx_queue_head(h)獲取第一個結點;
7. ngx_queue_last(h)獲取最後一個結點;
8. ngx_queue_sentinel(h)獲取哨兵結點(即引數h);
9. ngx_queue_next(q)獲取下一個結點;
10. ngx_queue_prev(q)獲取上一個結點;
11. ngx_queue_remove(x)將結點x從佇列中移除;
12. ngx_queue_split(h, q, n)將h為哨兵結點的佇列中q結點開始到隊尾結點的整個鏈拆分、連結到空的n佇列中,h佇列中的剩餘結點組成新佇列;
13. ngx_queue_add(h, n)將n佇列中的所有結點按順序連結到h佇列末尾,n佇列清空;
14. ngx_queue_middle(queue)使用雙倍步進演算法尋找queue佇列的中間結點;
15. ngx_queue_sort(queue, cmd)使用插入排序演算法對queue佇列進行排序,完成後在next方向上為升序,prev方向為降序。

相關文章