DEV Community

loading...

Mnesia の同期テストを slave モジュール使って行う

voluntas profile image voluntas ・2 min read

環境

  • Mac OS X 10.9.4
  • Erlang/OTP 17.1

概要

Erlang VM を複数立てて、Mnesia の同期テストを CommonTest ではなく EUnit ではどうやるのか調べていたところ slave モジュールを使えばよいという事だったので、slave モジュールを使ってみることにした。

CommonTest には ct_slave という専用モジュールがある模様。

フロー

  • ノード名を自分に付けます
    • net_kernel:start/1
  • クッキーをセットします
    • erlang:set_cookie/2
  • ノードを 3 つ起動します
    • slave:start/3
    • -setcookie でクッキーを指定する
  • 3 ノード全てで mnesia を起動します
    • mnesia:start/0
  • 1 ノードに対してテーブルを生成します
    • mnesia:create_table/2
  • テーブルを作成したノードに対して他のノードを追加します
    • mnesia:change_config/2
  • テーブルを作成したノードに対してレプリカ対象のテーブルを追加します
    • mnesia:add_table_copy/3
  • テーブルを作成したノードに bacon というキーでカウンターを +1 します
    • mnesia:dirty_update_counter/3
  • 他のノードに対してカウンターの値を取得します
    • mnesia:dirty_read/2
  • 全てのノードでカウンターを増加させる
  • 起動した 3 ノードを終了します
    • slave:stop/1
  • 自分のノード名を削除します
    • net_kernel:stop/0

サンプル

説明

  • ノードは 3 台
  • データベースはオンメモリ
  • 同期は Mnesia 独自を使用

コード

-module(spam).

-export([main/0]).

-include_lib("eunit/include/eunit.hrl").

-record(store, {key :: binary(),
                value :: non_neg_integer()}).

main() ->
    {ok, _Pid} = net_kernel:start([spam, shortnames]),
    true = erlang:set_cookie(node(), spam),

    Host = list_to_atom(net_adm:localhost()),
    Args = "-setcookie spam",

    {ok, N1} = slave:start(Host, n1, Args),
    {ok, N2} = slave:start(Host, n2, Args),
    {ok, N3} = slave:start(Host, n3, Args),

    rpc:call(N1, net_kernel, connect_node, [N2]),
    rpc:call(N1, net_kernel, connect_node, [N3]),

    rpc:call(N1, mnesia, start, []),
    rpc:call(N2, mnesia, start, []),
    rpc:call(N3, mnesia, start, []),

    rpc:call(N1, mnesia, create_table, [store, [{attributes, record_info(fields, store)}]]),

    rpc:call(N1, mnesia, change_config, [extra_db_nodes, node()]),
    [ rpc:call(N1, mnesia, add_table_copy, [store, N, ram_copies]) || N <- nodes() ],

    1 = rpc:call(N1, mnesia, dirty_update_counter, [store, <<"bacon">>, 1]),

    [{store, <<"bacon">>, 1}] = rpc:call(N2, mnesia, dirty_read, [store, <<"bacon">>]),
    [{store, <<"bacon">>, 1}] = rpc:call(N3, mnesia, dirty_read, [store, <<"bacon">>]),

    2 = rpc:call(N2, mnesia, dirty_update_counter, [store, <<"bacon">>, 1]),

    [{store, <<"bacon">>, 2}] = rpc:call(N1, mnesia, dirty_read, [store, <<"bacon">>]),
    [{store, <<"bacon">>, 2}] = rpc:call(N3, mnesia, dirty_read, [store, <<"bacon">>]),

    3 = rpc:call(N1, mnesia, dirty_update_counter, [store, <<"bacon">>, 1]),
    4 = rpc:call(N2, mnesia, dirty_update_counter, [store, <<"bacon">>, 1]),
    5 = rpc:call(N3, mnesia, dirty_update_counter, [store, <<"bacon">>, 1]),

    slave:stop(N1),
    slave:stop(N2),
    slave:stop(N3),

    ok = net_kernel:stop(),
    ok.

spam.erl で保存して、試せます。

$ erl
Erlang/OTP 17 [erts-6.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Eshell V6.1  (abort with ^G)
1> c(spam).
{ok,spam}
2> spam:main().
ok

Discussion (0)

pic
Editor guide