Mnesia表分片

  1. 概述
  2. 要求
  3. 分片表的样例
  4. 启动一个Erlang节点
  5. 用20个表创建分片表
  6. 数据操作
  7. 添加记录
  8. 选择有限的记录
  9. 分片表的列表

概述

本文描述如何创建Mnesia分片表以及如何使用它们。

要求

假如我必须做一个图书索引应用程序。我有一张表用来记录所有可用的图书馆书籍。表的记录结构如下节所述。因为数据量巨大,所以我想把这个表在一个单独的Erlang节点里分片。如果你想分布式处理这个分片的表,你可以参考这篇文章来分布式处理Mnesia的表。与表分片的其他相关工作都保持不变。

分片表的样例

我需要这张表是disk_copies模式。其他模式也以相同的方式操作。

1
-record(book_info, {isbn, name, author, keywords, category, description}).

启动一个Erlang节点

我们的例子节点foo@example默认的磁盘存储路径被设置为在当前路径下的Mnesia.foo@example目录。

1
erl -sname foo

这个路径可以在启动一个Erlang节点的时候通过用 -mnesia dir ‘“/path/of/your/preference”‘ ‘ 启动参数来改写。

让我们创建一个基于磁盘的schema,

1
mnesia:create_schema([node()]).

用20个表创建分片表

在本例中,所有20个分片在相同的Erlang/Mnesia节点里。另外这些分片是disc_copies类型。

1
2
3
4
mnesia:create_table(book_info,
[{frag_properties, [{node_pool, [node()]}, {n_fragments, 20}, {n_disc_copies, 1}]},
{index, [name, keywords, category]},
{attributes, record_info(fields, book_info)}]),

数据操作

为了能够访问在一个分片表的记录,Mnesia必须确定该真实记录属于那个分片。这通过mnesia_frag模块来做到,这个模块实现了mnesia_access回调行为。mnesia_frag封装标准Mnesia操作函数到其函数里,并将其作为参数传递给mnesia:activity/4。

添加记录

创建一个调用mnesia:write/3的函数。

1
2
3
AddFun = fun() ->
mnesia:write(book_info, Record, write)
end

现在如下所示在mnesia:activity/4里调用这个函数:

1
ok = mnesia:activity(transaction, AddFun, [], mnesia_frag).

注意,我已将活动访问上下文用作“事务”。事务可以确保操作要么全部成功要么全部失败(即保证操作的原子性)。我可以使用如下几个访问上下文:

1
2
3
4
5
6
{transaction, Retries}
sync_transaction
{sync_transaction, Retries}
async_dirty
sync_dirty
ets

例如,你想用脏模式做以上的操作,你可以这么写:

1
ok = mnesia:activity(async_dirty, AddFun, [], mnesia_frag).

你可以参考mnesia:activity/4文档来获得更多信息。

选择有限的记录

做为一个例子,让我们选择作者是steve的10条记录。记住10不是硬性限制。用mnesia:select/4函数创建一个函数:

1
2
3
4
5
6
7
MatchHead = #book_info{author = "steve", _ = '_'},
Guard = [],
Result = ['$_'],
MatchSpec = [{MatchHead, Guard, Result}],
SelFun = fun() ->
mnesia:select(book_info, MatchSpec, 10, read)
end,

现在如下所示在mnesia:activity/4里调用这个函数:

1
Result = mnesia:activity(transaction, SelFun, [], mnesia_frag).

Result的结果类型是:

1
Result -> '$end_of_table' | {[Objects], Cont} | transaction abort

在一个分片的表里,如果上述Result结果是{[Objects], Cont},并且返回的对象数量少于我们期望的(10个),那么你需要递归地用Cont(continuation)来调用mnesia:select/1,直到你得到期望数量的结果或者’$end_of_table’。

1
2
3
4
SelFun2 = fun() ->
mnesia:select(Cont)
end,
Result2 = mnesia:activity(transaction, SelFun2, [], mnesia_frag).

Result2的结果类型是:

1
Result2 -> '$end_of_table' | {[Objects], Cont} | transaction abort

分片表的列表

要获取分片表的列表,调用mnesia:table_info/2,并加上 frag_names 选项:

1
mnesia:activity(async_dirty, mnesia:table_info/2, [store, frag_names], mnesia_frag).

本教程到此结束!现在你知道如何写一个基本的Mnesia分片表程序了。

原文链接: [http://www2.erlangcentral.org/wiki/?title=Mnesia_Table_Fragmentation]