Mnesia Table Fragmentation

2009-04-10
The Concept
Mnesia支持將一個龐大的數据表分割為多個分塊,每個分塊跟一個普通的表一樣,可以備份可以創建索引等。讀寫數据的時候,Mnesia通過mnesia_frag模塊(一個mnesia_access callback behaviour)來定位實際數据位于哪個分塊里:首先mnesia_frag根据記錄的key記算一個hash值,然后根据該hash值決定表分塊的名稱,最后用普通的數据庫讀寫函數來堆該表分塊進行讀寫。若事前不知道記錄的key,則mnesia會搜索所有的分塊來尋找匹配的記錄。

下面的代碼描述如何將一個已存在的mnesia數据表轉化為一個分塊的表,以及如何動態的添加新分塊:
(a@oscar) 1> mnesia:start().
ok

當前有a、b、c三個節點正在運行
(a@oscar) 2> mnesia:system_info(running_db_nodes).
[b@oscar, c@oscar, a@oscar]

創建一個表dictionary
(a@oscar) 3> Tab = dictionary.
(a@oscar) 4> mnesia:create_table(Tab, [{ram_copies, [a@oscar, b@oscar]}]).
{atomic, ok}
(a@oscar) 5> Write = fun(Keys) -> [mnesia:write({Tab, K, -K}) || K <- Keys], ok end.
#Fun<....>
(a@oscar) 6> mnesia:activity(sync_dirty, Write, [lists:seq(1, 256)], mnesia_frag).
ok

啟動表分塊
(a@oscar) 7> mnesia:change_table_frag(Tab, {activate, []}).
{atomic, ok}

查看一下与分塊相關屬性
(a@oscar) 8> mnesia:table_info(Tab, frag_properties).
[{base_table, dictionary},
{foreign_key, undefined},
{n_doubles, 0},
{n_fragments, 1},
{next_n_to_split, 1},
{node_pool, [a@oscar, b@oscar, c@oscar]}]

添加分塊
(a@oscar) 9> Info = fun(Item) -> mnesia:table_info(Tab, Item) end.
#Fun<....>
(a@oscar) 10> Dist = mnesia:activity(sync_dirty, Info, [frag_dist], mnesia_frag).
[{c@oscar,0}, {a@oscar,1}, {b@oscar, 1}]
(a@oscar) 11> mnesia:change_table_frag(Tab, {add_frag, Dist}).
{atomic, ok}

再添加兩個分塊
(a@oscar) 12> Dist2 = mnesia:activity(sync_dirty, Info, [frag_dist], mnesia_frag).
[{b@oscar, 1}, {c@oscar, 1}, {a@oscar, 2}]
(a@oscar) 13> mnesia:change_table_frag(Tab, {add_frag, Dist2}).
{atomic, ok}
(a@oscar) 14> Dist3 = mnesia:activity(sync_dirty, Info, [frag_dist], mnesia_frag).
[{a@oscar, 2}, {b@oscar, 2}, {c@oscar, 2}]
(a@oscar) 15> mnesia:change_table_frag(Tab, {add_frag, Dist3}).
{atomic, ok}

從分塊里讀取數据
(a@oscar) 16> Read = fun(Key) -> mnesia:read({Tab, Key}) end.
#Fun<....>
(a@oscar) 17> mnesia:activity(transaction, Read, [12], mnesia_frag).
[{dictionary, 12, -12}]

查看各分塊所包含的數据量
(a@oscar) 18> mnesia:activity(sync_dirty, Info, [frag_size], mnesia_frag).
[{dictionary, 64},
{dictionary_frag2, 64},
{dictionary_frag3, 64},
{dictionary_frag3, 64}]
(哇,這么均衡~~)

Fragmentation Properties
可調用mnesia:table_info(Tab, frag_properties)函數來查看指定表的分塊清況,包含如下屬性(不全):

{n_fragments, Int}:當前表包含有多少個分塊,此屬性可在創建表時設定,或由{add_frag, NodesOrDist}、del_frag等操作所修改,默認值為1。

{node_pool, List}:分塊節點池,可在表創建時指定,或由{add_node, Node}、{del_node, Node}等操作所修改,在創建數据表的時候,mnesia會將表的分塊平均的分布到節點池里的各個節點上,默認為mnesia:system_info(db_nodes)的返回值。

{n_ram_copies, Int}:設定每個分塊應該有多少個ram_copies型備份,默認為0,但若n_disc_copies和n_disc_only_copies都為0,則此屬性會默認為1。

{n_disc_copies, Int}:設定每個分塊應有多少個disc_copies型備份,默認為0。

{n_disc_only_copies, Int}:設定每個分塊應有多少個disc_only_copies型備份,默認為0。

{hash_module, Atom}:此屬性允許用戶指定一個散列模式(hashing schema),此模塊必須實現mnesia_frag_hash回調行為(callback behaviour),默認為mnesia_frag_hash。

Management of Fragmented Tables
函數mnesia:change_table_frag(Tab, Change)用于修改分塊表的配置,其中Change可能為如下值:

{activate, FragProps}:激活已存在表的分塊机制,FragProps應為{node_pool, Nodes}或[]。

deactivate:關閉表的分塊机制,其分塊數必須為1。

{add_frag, NodesOrDist}:向分塊表添加一個新的分塊,其中一個舊分塊里的數据會被重新散列,它們中的約一半會被搬到新的分塊上去。所有其他含有指向該表的外鍵的分塊表都會自動得到一個新分塊,并按同樣的方式重新分布數据。
NodesOrDist可以是一列節點,或函數mnesia:table_info(Tab, frag_dist)的返回值,NodesOrDist應該是一個有序的數組,其中最适合放置新分塊的節點放在最前面的位置,新的分塊會得到与第一個分塊同樣數量的備份。

del_frag:從分塊表里刪除一個分塊,最后一個分塊的所有數据都會被搬到另一個分塊里。

{add_node, Node}:向node_pool里添加一個新節點,新的節點池會改變函數mnesia:table_info(Tab, frag_dist)的返回值。

{del_node, Node}:從node_pool里刪除一個節點,同樣也會改變函數mnesia:table_info(Tab, frag_dist)的返回值。

M-OSCAR | Powered by Blogger | Entries (RSS) | Comments (RSS) | Designed by MB Web Design | XML Coded By Cahayabiru.com