Linux 核心資料結構:Radix 樹

Alick發表於2015-06-22

正如你所知道的, Linux 核心通過許多不同庫以及函式提供各種資料結構以及演算法。這個部分我們將介紹其中一個資料結構 Radix tree。Linux 核心中有兩個檔案與 radix tree 的實現和 API 相關:

首先說明一下什麼是 radix tree ,Radix tree 是一個 壓縮 trietrie 是一種通過儲存關聯陣列(associative array)來提供 關鍵字-值(key-value) 儲存與查詢的資料結構。通常關鍵字是字串,不過也可以是其他資料型別。 Trie 結構的節點與 n-tree 不同,其節點中並不儲存關鍵字,取而代之的是儲存單個字元標籤。關鍵字查詢時,通過從樹的根開始遍歷關鍵字相關的所有字元標籤節點,直至到達最終的葉子節點。下面是個例子:

這個例子中,我們可以看到 trie 所儲存的關鍵字資訊 gocat,壓縮 trie 或 radix treetrie 所不同的是,對於只有一個孩子的中間節點將被壓縮。

Linux 核心中的 Radix 樹將值對映為整型關鍵字,Radix 的資料結構定義在 include/linux/radix-tree.h 檔案中 :

上面這個是 radix 樹的 root 節點的結構體,它包括三個成員:

  • height:從葉節點向上計算出的樹高度。
  • gfp_mask:記憶體申請的標識。
  • rnode:子節點指標。

這裡首先要討論的結構體成員是 gfp_mask :

Linux 底層的記憶體申請介面需要提供一類標識(flag) – gfp_mask ,用於描述記憶體申請的行為。這個以 GFP_ 字首開頭的記憶體申請控制標識主要包括,GFP_NOIO 禁止所有 IO 操作但允許睡眠等待記憶體,__GFP_HIGHMEM 允許申請核心的高階記憶體,GFP_ATOMIC 高優先順序申請記憶體且操作不允許被睡眠。

接下來說的節結構體成員是 rnode

這個結構體中包括這幾個內容,節點與父節點的偏移以及到樹底端的高度、子節點的個數、節點的儲存資料域,具體描述如下:

  • path:與父節點的偏移以及到樹底端的高度
  • count:子節點的個數。
  • parent:父節點的指標。
  • private_data:儲存資料內容緩衝區。
  • rcu_head:用於節點釋放的 RCU 連結串列。
  • private_list – 儲存資料。

結構體 radix_tree_node 的最後兩個成員 tagsslots 是非常重要且需要特別注意的。每個 Radix 樹節點都可以包括一個指向儲存資料指標的 slots 集合,空閒 slots 的指標指向 NULL。 Linux 核心的 Radix 樹結構體中還包含用於記錄節點儲存狀態的標籤 tags 成員,標籤通過位設定指示 Radix 樹的資料儲存狀態。

至此,我們瞭解到 radix 樹的結構,接下來看一下 radix 樹所提供的 API。

Linux 核心 radix 樹 API

我們從資料結構的初始化開始看,radix 樹支援兩種方式初始化。

第一個是使用巨集 RADIX_TREE

正如你看到,只需要提供 name 引數,就能夠使用 RADIX_TREE 巨集完成 radix 的定義以及初始化,RADIX_TREE 巨集的實現非常簡單:

RADIX_TREE 巨集首先使用 name 定義了一個 radix_tree_root 例項,並用 RADIX_TREE_INIT 巨集帶引數 mask 進行初始化。巨集 RADIX_TREE_INITradix_tree_root 初始化為預設屬性,並將 gfp_mask 初始化為入參 mask

第二種方式是手工定義 radix_tree_root 變數,之後再使用 mask 呼叫 INIT_RADIX_TREE 巨集對變數進行初始化。

INIT_RADIX_TREE 巨集定義:

巨集 INIT_RADIX_TREE 所初始化的屬性與 RADIX_TREE_INIT 一致

接下來是 radix 樹的節點插入以及刪除,這兩個函式:

  • radix_tree_insert;
  • radix_tree_delete.

第一個函式 radix_tree_insert 需要三個入參:

  • radix 樹 root 節點結構
  • 索引關鍵字
  • 需要插入儲存的資料

第二個函式 radix_tree_delete 除了不需要儲存資料引數外,其他與 radix_tree_insert 一致。

radix 樹的查詢實現有以下幾個函式:

  • radix_tree_lookup;
  • radix_tree_gang_lookup;
  • radix_tree_lookup_slot;

第一個函式 radix_tree_lookup 需要兩個引數:

  • radix 樹 root 節點結構
  • 索引關鍵字

這個函式通過給定的關鍵字查詢 radix 樹,並返關鍵字所對應的結點。

第二個函式 radix_tree_gang_lookup 具有以下特徵:

函式返回查詢到記錄的條目數,並根據關鍵字進行排序,返回的總結點數不超過入參 max_items 的大小。

最後一個函式 radix_tree_lookup_slot 返回結點 slot 中所儲存的資料。

連結

相關文章