forked from uwiger/unsplit
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ulf Wiger
committed
Feb 4, 2010
0 parents
commit 649ad0b
Showing
6 changed files
with
424 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
unsplit - Resolve conflicts in Mnesia tables after network split | ||
|
||
Author: Ulf Wiger, Erlang Solutions Ltd | ||
|
||
|
||
NOTE: This application is currently a fairly crude prototype, | ||
and is not intended for mission-critical tasks (yet). | ||
|
||
Documentation will follow, as soon as the approach has been | ||
verified to work. So far, no Mnesia patches are used, but | ||
for it to work really well, some added functionality in | ||
Mnesia may well be needed. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
erl -boot start_sasl -kernel dist_auto_connect once -sname n1 -pa ~/src/unsplit-0.1/ebin -mnesia debug trace | ||
erl -boot start_sasl -kernel dist_auto_connect once -sname n2 -pa ~/src/unsplit-0.1/ebin -mnesia debug trace | ||
|
||
mnesia:start(). | ||
application:start(unsplit). | ||
rd(test,{key,modified=erlang:now(),value}). | ||
|
||
On n2@debian: | ||
|
||
mnesia:create_schema([n1@debian,n2@debian]). | ||
|
||
mnesia:delete_table(test). | ||
mnesia:create_table(test,[{ram_copies,[n1@debian,n2@debian]},{attributes,[key,modified,value]},{user_properties,[{unsplit_method,{unsplit_lib,last_modified,[]}}]}]). | ||
|
||
mnesia:transaction(fun() -> mnesia:write(#test{key=1,value=a}) end). | ||
mnesia:transaction(fun() -> mnesia:write(#test{key=2,value=a}) end). | ||
|
||
ets:tab2list(test). | ||
|
||
|
||
On n1@debian: | ||
|
||
disconnect_node(n2@debian). | ||
mnesia:transaction(fun() -> mnesia:write(#test{key=2,value=b}) end). | ||
timer:sleep(3000). | ||
net_kernel:connect_node(n2@debian). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{application, unsplit, | ||
[{vsn, "0.1"}, | ||
{description, "Merges mnesia tables after net split"}, | ||
{applications, [mnesia]}, | ||
{mod, {unsplit, []}}, | ||
{env, []} | ||
]}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
-module(unsplit). | ||
|
||
-behaviour(application). | ||
-behaviour(supervisor). | ||
|
||
-export([start/2, stop/1]). | ||
|
||
|
||
-export([init/1]). | ||
|
||
start(_, _) -> | ||
supervisor:start_link({local,?MODULE}, ?MODULE, []). | ||
|
||
stop(_) -> | ||
ok. | ||
|
||
%% Supervisor callback: | ||
|
||
init([]) -> | ||
Children = [{unsplit_server, {unsplit_server, start_link, []}, | ||
permanent, 3000, worker, [unsplit_server]}], | ||
{ok, {{one_for_one, 3, 10}, Children}}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
-module(unsplit_lib). | ||
-export([no_action/2, | ||
last_modified/2, | ||
last_version/2]). | ||
|
||
|
||
|
||
no_action(start, [Tab|_]) -> | ||
error_logger:format("Will not merge table ~p~n", [Tab]), | ||
stop. | ||
|
||
|
||
last_modified(init, S0) -> | ||
last_version(init, S0 ++ [modified]); | ||
last_modified(Other, S) -> | ||
last_version(Other, S). | ||
|
||
last_version(init, [Tab, Attrs, Attr]) -> | ||
case lists:member(Attr, Attrs) of | ||
false -> | ||
error_logger:format("Cannot merge table ~p." | ||
"Missing ~p attribute~n", [Tab, Attr]), | ||
stop; | ||
true -> | ||
io:fwrite("Starting merge of ~p (~p)~n", [Tab, Attrs]), | ||
{ok, {Tab, pos(Attr, Tab, Attrs)}} | ||
end; | ||
last_version(done, _) -> | ||
ok; | ||
last_version(Objs, {T, P} = S) when is_list(Objs) -> | ||
Actions = lists:map(fun(Obj) -> | ||
last_version_entry(Obj, T, P) | ||
end, Objs), | ||
{ok, Actions, same, S}. | ||
|
||
|
||
last_version_entry(Obj, T, P) -> | ||
io:fwrite("last_version_entry(~p)~n", [Obj]), | ||
case Obj of | ||
{A, []} -> {write, A}; | ||
{[], B} -> {write, B}; | ||
{[A], [B]} -> | ||
ModA = element(P, A), | ||
ModB = element(P, B), | ||
io:fwrite("ModA = ~p, ModB = ~p~n", [ModA, ModB]), | ||
if ModA < ModB -> | ||
{write, B}; | ||
ModA > ModB -> | ||
{write, A}; | ||
ModA == ModB -> | ||
if A =/= B -> | ||
mnesia:abort({undecided,T,A,B}); | ||
true -> | ||
{write, A} | ||
end | ||
end | ||
end. | ||
|
||
|
||
|
||
pos(A, T, L) -> | ||
pos(A, T, L, 2). % record tag is the 1st element in the tuple | ||
|
||
pos(H, _, [H|_], P) -> | ||
P; | ||
pos(H, Tab, [_|T], P) -> | ||
pos(H, Tab, T, P+1); | ||
pos(A, Tab, [], _) -> | ||
mnesia:abort({missing_attribute, Tab, A}). |
Oops, something went wrong.