Mnesia 事件处理
2009-04-11
| 張貼者:
M-OSCAR
Mnesia会产生两类事件:系统事件(system events)和表事件(table events),用户可创建一个进程来订阅Mnesia所产生的事件,有如下两个相关的函数:
mnesia:subscribe(EventCategory)
当有事件发生时发送一个事件的copy给调用此函数的进程。
mnesia:unsubscribe(EventCategory)
取消事件订阅,不再接收Mnesia产生的事件。
EventCategory可以是system、{table, Tab, simple}或{table, Tab, detailed}。事件会以进程间消息的形式发送给订阅了Mnesia事件的进程,系统事件的格式为{mnesia_system_event, Event},表事件的格式则为{mnesia_table_event, Event}。
System Events
系统事件有如下几种:
{mnesia_up, Node}
Mnesia在节点Node上被启动;
{mnesia_down, Node}
Mnesia在节点Node上停止了运行;
{mnesia_checkpoint_activated, Checkpoint}
一个与本节点相关的checkpoint被激活了;
{mnesia_checkpoint_deactivated, Checkpoint}
一个与本节点相关的checkpoint被激死(:P)了~~
{mnesia_overload, Details}
本节点上的Mnesia负载过重,可能因为对硬碟的读写请求超过了Mnesia的处理能力,如果不做任何处理可能会导致硬碟空间不足;也可能是Mnesia处理事务的速度跟不上事务的请求速度,事务堆栈可能会越来越大,直至耗尽内存或请求速度减缓。对存在异地备份或位于远程节点上的表发起大量的脏操作(dirty updates)时也可能会引发此事件;
{inconsistent|_database, Context, Node}
Mnesia发现数据库可能存在不一致的情况;
{mnesia_fatal, Format, Args, BinaryCore}
Mnesia发生了致命错误,即将在短时间内终止;
{mnesia_info, Format, Args}
调试系统时,Mnesia发现了一些应用程序可能感兴趣的东东;
{mnesia_error, Format, Args}
Mnesia发生了错误;
{mnesia_user, Event}
某应用程序触发了函数mnesia:report_event(Event),可用于调试Mnesia。
Table Events
表事件在数据表被更新时发生,分为simple和detailed两种,simple事件包括:
{write, NewRecord, ActivityId}
有新记录被写入;
{delete_object, OldRecord, ActivityId}
记录OldRecord可能被删除了(可能?),如果表类型为bag,则可能还存在其他与OldRecord主键相同的记录;
{delete, {Tab, Key}, ActivityId}
一个或多个记录可能被删除了(可能??),表里所有主键为Key的记录都已被删除;
detailed事件包括:
{write, Table, NewRecord, [OldRecords], ActivityId}
有新记录被写入;
{delete, Table, What, [OldRecords], ActivityId}
可能有记录被删除(又是可能....),What可能是{Table, Key}或{RecordName, Key, ....}
mnesia:subscribe(EventCategory)
当有事件发生时发送一个事件的copy给调用此函数的进程。
mnesia:unsubscribe(EventCategory)
取消事件订阅,不再接收Mnesia产生的事件。
EventCategory可以是system、{table, Tab, simple}或{table, Tab, detailed}。事件会以进程间消息的形式发送给订阅了Mnesia事件的进程,系统事件的格式为{mnesia_system_event, Event},表事件的格式则为{mnesia_table_event, Event}。
System Events
系统事件有如下几种:
{mnesia_up, Node}
Mnesia在节点Node上被启动;
{mnesia_down, Node}
Mnesia在节点Node上停止了运行;
{mnesia_checkpoint_activated, Checkpoint}
一个与本节点相关的checkpoint被激活了;
{mnesia_checkpoint_deactivated, Checkpoint}
一个与本节点相关的checkpoint被激死(:P)了~~
{mnesia_overload, Details}
本节点上的Mnesia负载过重,可能因为对硬碟的读写请求超过了Mnesia的处理能力,如果不做任何处理可能会导致硬碟空间不足;也可能是Mnesia处理事务的速度跟不上事务的请求速度,事务堆栈可能会越来越大,直至耗尽内存或请求速度减缓。对存在异地备份或位于远程节点上的表发起大量的脏操作(dirty updates)时也可能会引发此事件;
{inconsistent|_database, Context, Node}
Mnesia发现数据库可能存在不一致的情况;
{mnesia_fatal, Format, Args, BinaryCore}
Mnesia发生了致命错误,即将在短时间内终止;
{mnesia_info, Format, Args}
调试系统时,Mnesia发现了一些应用程序可能感兴趣的东东;
{mnesia_error, Format, Args}
Mnesia发生了错误;
{mnesia_user, Event}
某应用程序触发了函数mnesia:report_event(Event),可用于调试Mnesia。
Table Events
表事件在数据表被更新时发生,分为simple和detailed两种,simple事件包括:
{write, NewRecord, ActivityId}
有新记录被写入;
{delete_object, OldRecord, ActivityId}
记录OldRecord可能被删除了(可能?),如果表类型为bag,则可能还存在其他与OldRecord主键相同的记录;
{delete, {Tab, Key}, ActivityId}
一个或多个记录可能被删除了(可能??),表里所有主键为Key的记录都已被删除;
detailed事件包括:
{write, Table, NewRecord, [OldRecords], ActivityId}
有新记录被写入;
{delete, Table, What, [OldRecords], ActivityId}
可能有记录被删除(又是可能....),What可能是{Table, Key}或{RecordName, Key, ....}
Posted In
erlang,
mnesia
|
0
意見
|
用qlc进行数据排序与筛选
| 張貼者:
M-OSCAR
Erlang有一个类似SQL的数据检索机制,叫做QLC(Query Interface to Mnesia, ETS, Dets, etc),可用于对Mnesia、ETS/DETS的数据表进行数据检索,包括常见的按指定域排序(ORDER BY)、按条件筛选(WHERE...)以及限制返回的结果长度(COUNT)。看个简单的例子:
-module(test).
-export([start/0]).
-include_lib("stdlib/include/qlc.hrl").
start() ->
QH1 = qlc:q([{X, Y} || X <- [8,3,6,2], Y <- [b,a,c]]),
%以第一个值作为key进行排序
QH2 = qlc:keysort(1, QH1, [{order, ascending}]),
QC = qlc:cursor(QH2),
%获取前两条记录
qlc:next_answers(QC, 2),
%获取剩余的其他记录
qlc:next_answers(QC, all_remainning).
Posted In
erlang,
mnesia
|
0
意見
|
动态增删Mnesia数据库节点
2009-04-10
| 張貼者:
M-OSCAR
Mnesia支持动态的增删节点以进行数据转移或备份:
OK,现在可以在新节点上添加表备份、分块等等了,如果不再需要某个节点,可以这样删除节点:
首先启动新节点上面的mnesia
> rpc:call(Node, mnesia, start, []).
添加新节点
> {ok, _} = mnesia:change_config(extra_db_nodes, [Node]).
修改新节点上的schema表的类型
> {atomic, ok} = mnesia:change_table_copy_type(schema, Node, disc_copies).
OK,现在可以在新节点上添加表备份、分块等等了,如果不再需要某个节点,可以这样删除节点:
首先关闭该节点上的mnesia
> rpc:call(Node, mnesia, stop, []).
删掉该节点上的schema表
> {atomic, ok} = mnesia:del_table_copy(schema, Node).
> ok = mnesia:delete_schema([Node]).
Posted In
erlang,
mnesia
|
0
意見
|
Local Content Tables
| 張貼者:
M-OSCAR
分布於多個節點上的同一個表,在各節點的備份上都保持有相同的數据,不過呢有時可能需要同一個表在不同節點備份上有不同的內容,這時就需要用到Local Content Tables了~~
如果我們創建表的時候將其屬性設置為{local_content, true},表同樣會分布多個備份到我們所指定的節點上,但寫操作僅會影響本地節點,不會同步到其他節點的備份上。另外當mnesia啟動時,這樣的表也僅會從本地讀取初始化數据,不會等待其他節點上的備份~~
感覺有點像表的分塊哦~~
如果我們創建表的時候將其屬性設置為{local_content, true},表同樣會分布多個備份到我們所指定的節點上,但寫操作僅會影響本地節點,不會同步到其他節點的備份上。另外當mnesia啟動時,這樣的表也僅會從本地讀取初始化數据,不會等待其他節點上的備份~~
感覺有點像表的分塊哦~~
Posted In
erlang,
mnesia
|
0
意見
|
Mnesia Table Fragmentation
| 張貼者:
M-OSCAR
The Concept
Mnesia支持將一個龐大的數据表分割為多個分塊,每個分塊跟一個普通的表一樣,可以備份可以創建索引等。讀寫數据的時候,Mnesia通過mnesia_frag模塊(一個mnesia_access callback behaviour)來定位實際數据位于哪個分塊里:首先mnesia_frag根据記錄的key記算一個hash值,然后根据該hash值決定表分塊的名稱,最后用普通的數据庫讀寫函數來堆該表分塊進行讀寫。若事前不知道記錄的key,則mnesia會搜索所有的分塊來尋找匹配的記錄。
下面的代碼描述如何將一個已存在的mnesia數据表轉化為一個分塊的表,以及如何動態的添加新分塊:
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)的返回值。
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)的返回值。
Posted In
erlang,
mnesia
|
0
意見
|
Mnesia写入数据错误?
2009-04-08
| 張貼者:
M-OSCAR
Q:我创建了如下一个Mnesia表,为何写入数据时会出现bad type错误呢??
A:第一次执行dirty_write时提示没有找到message表,当表名和表所存储的record名相同时,写入数据时可以忽略表名,但现在表名并非message而是msg,好吧我们指定一个表名再写入试试,这次却出现了第二个错误提示类型错误,郁闷,原来当表名和record名不同时,创建表的时候应另外添加一个参数{record_name, ...},即:
这样就可以正常插入数据了~~
> rd(message, {to, from, content}).
> mnesia:create_table(msg, [{attributes, record_info(fields, message)}]).
> mnesia:dirty_write({message, jojo, oscar, <<"missing you">>}).
** exception exit: {aborted,{no_exists,message}}
in function mnesia:abort/1
> mnesia:dirty_write(msg, {message, jojo, oscar, <<"test">>}).
** exception exit: {aborted,{bad_type,
#message{to = jojo, from = oscar, content = <<"test">>}}}
in function mnesia:abort/1A:第一次执行dirty_write时提示没有找到message表,当表名和表所存储的record名相同时,写入数据时可以忽略表名,但现在表名并非message而是msg,好吧我们指定一个表名再写入试试,这次却出现了第二个错误提示类型错误,郁闷,原来当表名和record名不同时,创建表的时候应另外添加一个参数{record_name, ...},即:
> mnesia:create_table(msg, [
{attributes, record_info(fields, message)},
{record_name, message}]).
这样就可以正常插入数据了~~
Posted In
erlang,
mnesia
|
0
意見
|
Mnesia Fragmenting
2009-03-24
| 張貼者:
M-OSCAR
本文参考自Nick Gerakines的Dynamically sizing a fragmented mnesia store,原文请看这里~~
Mnesia在32位系统下单个表最大只能存储4G的数据,很多情况下这显然系不够的,不过不要紧,Mnesia可以将单个表分拆成多个分块(Fragment),这些块可以分布到不同节点节点不同主机上,被分块的表和其他表一样可以备份复制等等~~
创建和初始化数据库表
首先我们运行三个节点node1@m、node2@m和node3@m并将它们连接起来(详细可以参看Interconnecting Erlang Nodes),然后在node1上初始化一个表,将该表分成三块,分布在上述的三个节点上:
(以下代码省略了部分返回结果)
添加新分块到新节点上
OK,可以看到数据已经自动的分布到各个节点上的分块里了~~
Mnesia在32位系统下单个表最大只能存储4G的数据,很多情况下这显然系不够的,不过不要紧,Mnesia可以将单个表分拆成多个分块(Fragment),这些块可以分布到不同节点节点不同主机上,被分块的表和其他表一样可以备份复制等等~~
创建和初始化数据库表
首先我们运行三个节点node1@m、node2@m和node3@m并将它们连接起来(详细可以参看Interconnecting Erlang Nodes),然后在node1上初始化一个表,将该表分成三块,分布在上述的三个节点上:
(以下代码省略了部分返回结果)
初始化schema
node1 > Nodes=[node() | nodes()].
node1 > mnesia:create_schema(Nodes).
启动所有节点上的Mnesia
node1 > mnesia:start().
node2 > mnesia:start().
node3 > mnesia:start().
在Node1上创建和初始化数据表
node1 > rd(test,{key,value}).
node1 > FragProps=[
{node_pool,Nodes},
{n_fragments,3},
{n_disc_only_copies,1}].
node1 > mnesia:create_table(test,[
{frag_properties,FragProps},
{attributes,record_info(fields,test)}]).
node1 > Write=fun() ->
[mnesia:write({test,K,K}) || K<-lists:seq(1,1000)]
end.
node1 > mnesia:activity(sync_dirty,Write,[],mnesia_frag).
检查一下数据都写到哪里去了
node1 > Info=fun(Item) -> mnesia:info(test,Item) end.
node1 > mnesia:activity(sync_dirty,Info,[frag_size],mnesia_frag).
[{test,230},{test_frag2,524},{test_frag3,246}]
添加新分块到新节点上
启动新节点node4
$ erl -sname node4
node4 > mnesia:start().
连接并添加新节点
node1 > net_adm:ping('node4@m').
node1 > mnesia:change_config(extra_db_nodes,['node4@m']).
通过mnesia:info()我们发现新节点的类新为ram_copies,这与其他几个节点不兼容
所以要先对node4上的表进行类型转换
node4 > change_table_copy_type(schema,node(),disc_copies).
添加新分块到新节点上,可以向同一节点添加多个分块
node1 > mnesia:change_table_frag(test,{add_frag,['node4@m']}).
node1 > mnesia:change_table_frag(test,{add_frag,['node4@m']}).
node1 > mnesia:change_table_frag(test,{add_frag,['node4@m']}).
node1 > mnesia:activity(sync_dirty,Info,[frag_dist],mnesia_frag).
[{'node1@m',1},
{'node2@m',1},
{'node3@m',1},
{'node4@m',3}]
node1 > mnesia:activity(sync_dirty,Info,[frag_size],mnesia_frag).
[{test,121},
{test_frag2,115},
{test_frag3,246},
{test_frag4,291},
{test_frag5,109},
{test_frag6,118}]
OK,可以看到数据已经自动的分布到各个节点上的分块里了~~
Posted In
erlang,
mnesia
|
0
意見
|
Mnesia Indexing
2009-03-23
| 張貼者:
M-OSCAR
Data retrieval and matching can be performed very efficiently if we know the key for the record. Conversely, if the key is not known, all records in a table must be searched. The larger the table the more time consuming it will become. To remedy this problem Mnesia’s indexing capabilities are used to improve data retrieval and matching of records.
The following two functions manipulate indexes on existing tables:
1 > mnesia:add_table_index(employee, salary).
The indexing capabilities of Mnesia are utilized with the following three functions, which retrieve and match records on the basis of index entries in the database.
The following two functions manipulate indexes on existing tables:
- mnesia:add table index(Tab, AttributeName) -> {aborted, R} |fatomic, ok}
- mnesia:del table index(Tab, AttributeName) -> {aborted, R} |fatomic, ok}
1 > mnesia:add_table_index(employee, salary).
The indexing capabilities of Mnesia are utilized with the following three functions, which retrieve and match records on the basis of index entries in the database.
- mnesia:index read(Tab, SecondaryKey, AttributeName) -> transaction abort | RecordList. Avoids an exhaustive search of the entire table, by looking up the SecondaryKey in the index to find the primary keys.
- mnesia:index match object(Pattern, AttributeName) -> transaction abort | RecordList. Avoids an exhaustive search of the entire table, by looking up the secondary key in the index to find the primary keys. The secondary key is found in the AttributeName field of the Pattern. The secondary key must be bound.
- mnesia:match object(Pattern) -> transaction abort | RecordList. Uses indices to avoid exhaustive search of the entire table. Unlike the other functions above, this function may utilize any index as long as the secondary key is bound.
Posted In
erlang,
mnesia
|
0
意見
|
Mnesia Database Management System
| 張貼者:
M-OSCAR
详细讲解Mnesia数据库,由简介入门到诸如分布式、容错、数据表分块等各种特性都涵盖到了,好文档,值得分享~~点这里下载~~
另附一个Google搜出的文档《Mnesia table fragmentation 过程及算法分析》(中文),通过案例详细讲解了Mnesia的分片机制和原理~~
另附一个Google搜出的文档《Mnesia table fragmentation 过程及算法分析》(中文),通过案例详细讲解了Mnesia的分片机制和原理~~
Posted In
erlang,
mnesia
|
0
意見
|
訂閱:
文章 (Atom)