読者です 読者をやめる 読者になる 読者になる

Mnesia で分散ノードが落ちて再度追加する動き

erlang mnesia

Mnesia の解説で分散ノードを追加する話しはあるけど、落として再度追加する話しってないなーと思ったので、サンプルコードと共に書いてみました。色々面倒なのでソース読んでなんとかしてください。

とりあえずソース

-module(test).

-compile([export_all,
          native,
          debug_info,
          strong_validation,
          binary,
          compressed,
          warn_obsolete_guard,
          warn_unused_import,
          warn_shadow_vars,
          verbose,
          report]).

-record(store, {key, value1, value2, value3}).

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

a() ->
  net_kernel:start(['a@localhost', shortnames]),
  erlang:set_cookie(node(),'secret'),
  mnesia:start(),
  mnesia:change_config(extra_db_nodes, ['b@localhost']),
  case mnesia:create_table(store,
                           [{record_name, store}, {type, set},
                            {ram_copies, ['a@localhost', 'b@localhost']},
                            {attributes, record_info(fields, store)}]) of
    {atomic, ok} ->
      test_fixtures();
    {aborted, {already_exists,store}} ->
      ok;
    {aborted, _Reason} ->
      ok
  end,
  ok.

b() ->
  net_kernel:start(['b@localhost', shortnames]),
  erlang:set_cookie(node(),'secret'),
  mnesia:start(),
  mnesia:change_config(extra_db_nodes, ['a@localhost']),
  ok.

test_fixtures() ->
  test_fixtures(0, 10000).

test_fixtures(Start, Stop) ->
  crypto:start(),
  F = fun(Key) ->
        Store = #store{key    = Key,
                       value1 = crypto:rand_bytes(16),
                       value2 = crypto:rand_bytes(16),
                       value3 = crypto:rand_bytes(16)},
        mnesia:dirty_write(store, Store)
      end,
  lists:foreach(F, lists:seq(Start, Stop)),
  crypto:stop(),
  ok.

説明省きまくり

ノード a@localhost (マスターもどき)

% erl
Erlang R13B04 (erts-5.7.5) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5  (abort with ^G)
1> test:a().
ok
(a@localhost)2> 
=INFO REPORT==== 20-Jun-2010::21:56:28 ===
    application: crypto
    exited: stopped
    type: temporary

(a@localhost)2> mnesia:info().
---> Processes holding locks <--- 
---> Processes waiting for locks <--- 
---> Participant transactions <--- 
---> Coordinator transactions <---
---> Uncertain transactions <--- 
---> Active tables <--- 
store          : with 10001    records occupying 251885   words of mem
schema         : with 2        records occupying 546      words of mem
===> System info in version "4.4.13", debug level = none <===
opt_disc. Directory "/tmp/Mnesia.a@localhost" is NOT used.
use fallback at restart = false
running db nodes   = [a@localhost]
stopped db nodes   = [] 
master node tables = []
remote             = []
ram_copies         = [schema,store]
disc_copies        = []
disc_only_copies   = []
[{a@localhost,ram_copies}] = [schema,store]
4 transactions committed, 0 aborted, 0 restarted, 0 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
ok
(a@localhost)3> 

ノード b@localhost

% erl
Erlang R13B04 (erts-5.7.5) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5  (abort with ^G)
1> test:b().
ok
(b@localhost)2> mnesia:info().
---> Processes holding locks <--- 
---> Processes waiting for locks <--- 
---> Participant transactions <--- 
---> Coordinator transactions <---
---> Uncertain transactions <--- 
---> Active tables <--- 
schema         : with 2        records occupying 557      words of mem
store          : with 10001    records occupying 251885   words of mem
===> System info in version "4.4.13", debug level = none <===
opt_disc. Directory "/tmp/Mnesia.b@localhost" is NOT used.
use fallback at restart = false
running db nodes   = [a@localhost,b@localhost]
stopped db nodes   = [] 
master node tables = []
remote             = []
ram_copies         = [schema,store]
disc_copies        = []
disc_only_copies   = []
[{a@localhost,ram_copies},{b@localhost,ram_copies}] = [store,schema]
5 transactions committed, 0 aborted, 0 restarted, 0 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
ok
(b@localhost)3> 

で、ノード a@localhost を落として、上げなおす。

(a@localhost)3> q().
ok
% erl
Erlang R13B04 (erts-5.7.5) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5  (abort with ^G)
1> test:a().
ok
(a@localhost)2> mnesia:info().
---> Processes holding locks <--- 
---> Processes waiting for locks <--- 
---> Participant transactions <--- 
---> Coordinator transactions <---
---> Uncertain transactions <--- 
---> Active tables <--- 
store          : with 10001    records occupying 251885   words of mem
schema         : with 2        records occupying 557      words of mem
===> System info in version "4.4.13", debug level = none <===
opt_disc. Directory "/tmp/Mnesia.a@localhost" is NOT used.
use fallback at restart = false
running db nodes   = [b@localhost,a@localhost]
stopped db nodes   = [] 
master node tables = []
remote             = []
ram_copies         = [schema,store]
disc_copies        = []
disc_only_copies   = []
[{a@localhost,ram_copies},{b@localhost,ram_copies}] = [schema,store]
5 transactions committed, 1 aborted, 0 restarted, 0 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
ok
(a@localhost)3> 

そして、ノード b@localhost を落として、上げなおす。

(b@localhost)3> q().
ok
% erl
Erlang R13B04 (erts-5.7.5) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5  (abort with ^G)
1> test:b().
ok
(b@localhost)2> mnesia:info().
---> Processes holding locks <--- 
---> Processes waiting for locks <--- 
---> Participant transactions <--- 
---> Coordinator transactions <---
---> Uncertain transactions <--- 
---> Active tables <--- 
schema         : with 2        records occupying 557      words of mem
store          : with 10001    records occupying 251885   words of mem
===> System info in version "4.4.13", debug level = none <===
opt_disc. Directory "/tmp/Mnesia.b@localhost" is NOT used.
use fallback at restart = false
running db nodes   = [a@localhost,b@localhost]
stopped db nodes   = [] 
master node tables = []
remote             = []
ram_copies         = [schema,store]
disc_copies        = []
disc_only_copies   = []
[{a@localhost,ram_copies},{b@localhost,ram_copies}] = [store,schema]
5 transactions committed, 0 aborted, 0 restarted, 0 logged to disc
0 held locks, 0 in queue; 0 local transactions, 0 remote
0 transactions waits for other nodes: []
ok

こんな感じで動きます。