Mnesia のレプリケーションを試す
Mnesia のレプリケーションをいろいろ試してみたのでメモ。
まずは、下記を mnesia_test.erl というファイル名で保存して、コンパイルする。
-module(mnesia_test). -include_lib("stdlib/include/qlc.hrl"). -record(store, {key, value}). -export([start/0, start/1, restart/1, set/2, get/1]). start() -> mnesia:start(), mnesia:create_schema([node()]), mnesia:create_table(store, [{attributes, record_info(fields, store)}]). start(Nodes) -> mnesia:start(), mnesia:change_config(extra_db_nodes, Nodes), mnesia:add_table_copy(store, node(), ram_copies). restart(Nodes) -> mnesia:start(), mnesia:change_config(extra_db_nodes, Nodes). set(Key, Value) -> Row = #store{key=Key, value=Value}, F = fun() -> mnesia:write(Row) end, mnesia:transaction(F). get(Key) -> do(qlc:q([X#store.value || X <- mnesia:table(store), X#store.key =:= Key])). do(Q) -> F = fun() -> qlc:e(Q) end, {atomic, Results} = mnesia:transaction(F), Results.
次に、erlang ノードを複数起動して動作を確認する。
% erlang -sname a@localhost (a@localhost)1> mnesia_test:start(). {atomic,ok}
% erlang -sname b@localhost (b@localhost)1> mnesia_test:start([a@localhost]). {atomic,ok}
% erlang -sname c@localhost (c@localhost)1> mnesia_test:start([a@localhost, b@localhost]). {atomic,ok}
この状態で、どこかのノードに値を設定すると、他のノードから取得できる。
(c@localhost)2> mnesia_test:set(key1, value1). {atomic,ok}
(a@localhost)2> mnesia_test:get(key1). [value1]
障害が発生したと仮定して、a ノードと c ノードを落としてみる。
(a@localhost)3> init:stop(). ok
(c@localhost)3> init:stop(). ok
この状態で b ノードから値が取れる事を確認してみる。
(b@localhost)2> mnesia_test:get(key1). [value1]
最後に、a ノードと b ノードを復帰させて、値が取得できるか確認してみる。
% erl -sname a@localhost (a@localhost)1> mnesia_test:restart([b@localhost]). {ok,[b@localhost]} (a@localhost)2> mnesia_test:get(key1). [value1]
% erl -sname c@localhost (c@localhost)1> mnesia_test:restart([a@localhost, b@localhost]). {ok,[b@localhost, a@localhost]} (c@localhost)2> mnesia_test:get(key1). [value1]
便利だなー。
おまけ
erlang の分散機能を使ったお遊びをしたのでメモ。
複数のホストで erlang ノードを起動する。とりあえず手元に imac と freebsd があったのでそれを使った。
% erl -sname a@imac
% erl -sname a@bsd
一応、疎通確認。
(a@imac)1> net_adm:ping(a@bsd). pong
freebsd には、mnesia_test.beam が存在していないので imac から送る。
(a@imac)2> {Module, Binary, Filename} = code:get_object_code(mnesia_test). {mnesia_test,<<70,79,82,49,0,0,13,244,66,69,65,77,65,116,111,109,0,0,2,155,0,0, 0,69,11,109,110,...>>, "/path/to/mnesia_test.beam"} (a@imac)3> rpc:call('a@bsd', code, load_binary, [Module, Filename, Binary]). {module,mnesia_test}
mnesia_test を試してみる。
(a@imac)4> mnesia_test:start().
(a@bsd)1> mnesia_test:start(nodes()). {atomic,ok} (a@bsd)2> mnesia_test:set(key2, value2).
(a@imac)5> mnesia_test:get(key2). [value2]
とにかくノードさえどこかのホストで起動して、疎通確認さえしておけば、必要な時に必要なだけ Mnesia で利用できる。