Browse Source

Add groups partial netsplit support.

Roberto Ostinelli 5 years ago
parent
commit
299c9c9c19
5 changed files with 290 additions and 40 deletions
  1. 9 1
      src/syn.hrl
  2. 56 0
      src/syn_groups.erl
  3. 7 7
      src/syn_registry.erl
  4. 187 1
      test/syn_groups_SUITE.erl
  5. 31 31
      test/syn_registry_SUITE.erl

+ 9 - 1
src/syn.hrl

@@ -45,4 +45,12 @@
     Pid :: pid(),
     Pid :: pid(),
     Meta :: any()
     Meta :: any()
 }.
 }.
--export_type([syn_registry_tuple/0]).
+-type syn_group_tuple() :: {
+    Name :: any(),
+    Pid :: pid(),
+    Meta :: any()
+}.
+-export_type([
+    syn_registry_tuple/0,
+    syn_group_tuple/0
+]).

+ 56 - 0
src/syn_groups.erl

@@ -37,6 +37,7 @@
 
 
 %% sync API
 %% sync API
 -export([sync_join/3, sync_leave/2]).
 -export([sync_join/3, sync_leave/2]).
+-export([sync_get_local_group_tuples/1]).
 
 
 %% gen_server callbacks
 %% gen_server callbacks
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
@@ -139,6 +140,16 @@ sync_join(GroupName, Pid, Meta) ->
 sync_leave(GroupName, Pid) ->
 sync_leave(GroupName, Pid) ->
     gen_server:cast(?MODULE, {sync_leave, GroupName, Pid}).
     gen_server:cast(?MODULE, {sync_leave, GroupName, Pid}).
 
 
+-spec sync_get_local_group_tuples(FromNode :: node()) -> list(syn_group_tuple()).
+sync_get_local_group_tuples(FromNode) ->
+    error_logger:info_msg("Syn(~p): Received request of local group tuples from remote node: ~p~n", [node(), FromNode]),
+    %% build match specs
+    MatchHead = #syn_groups_table{name = '$1', pid = '$2', node = '$3', meta = '$4', _ = '_'},
+    Guard = {'=:=', '$3', node()},
+    GroupTupleFormat = {{'$1', '$2', '$4'}},
+    %% select
+    mnesia:dirty_select(syn_groups_table, [{MatchHead, [Guard], [GroupTupleFormat]}]).
+
 %% ===================================================================
 %% ===================================================================
 %% Callbacks
 %% Callbacks
 %% ===================================================================
 %% ===================================================================
@@ -256,6 +267,30 @@ handle_info({'DOWN', _MonitorRef, process, Pid, Reason}, State) ->
     %% return
     %% return
     {noreply, State};
     {noreply, State};
 
 
+handle_info({nodeup, RemoteNode}, State) ->
+    error_logger:info_msg("Syn(~p): Node ~p has joined the cluster~n", [node(), RemoteNode]),
+    global:trans({{?MODULE, auto_merge_groups}, self()},
+        fun() ->
+            error_logger:warning_msg("Syn(~p): GROUPS AUTOMERGE ----> Initiating for remote node ~p~n", [node(), RemoteNode]),
+            %% get group tuples from remote node
+            GroupTuples = rpc:call(RemoteNode, ?MODULE, sync_get_local_group_tuples, [node()]),
+            error_logger:warning_msg(
+                "Syn(~p): Received ~p group entrie(s) from remote node ~p, writing to local~n",
+                [node(), length(GroupTuples), RemoteNode]
+            ),
+            sync_group_tuples(RemoteNode, GroupTuples),
+            %% exit
+            error_logger:warning_msg("Syn(~p): GROUPS AUTOMERGE <---- Done for remote node ~p~n", [node(), RemoteNode])
+        end
+    ),
+    %% resume
+    {noreply, State};
+
+handle_info({nodedown, RemoteNode}, State) ->
+    error_logger:warning_msg("Syn(~p): Node ~p has left the cluster, removing group entries on local~n", [node(), RemoteNode]),
+    purge_group_entries_for_remote_node(RemoteNode),
+    {noreply, State};
+
 handle_info(Info, State) ->
 handle_info(Info, State) ->
     error_logger:warning_msg("Syn(~p): Received an unknown info message: ~p~n", [node(), Info]),
     error_logger:warning_msg("Syn(~p): Received an unknown info message: ~p~n", [node(), Info]),
     {noreply, State}.
     {noreply, State}.
@@ -373,3 +408,24 @@ log_process_exit(GroupName, Pid, Reason) ->
                     )
                     )
             end
             end
     end.
     end.
+
+-spec sync_group_tuples(RemoteNode :: node(), GroupTuples :: [syn_registry_tuple()]) -> ok.
+sync_group_tuples(RemoteNode, GroupTuples) ->
+    %% ensure that groups doesn't have any joining node's entries (here again for race conditions)
+    purge_group_entries_for_remote_node(RemoteNode),
+    %% loop
+    F = fun({Name, RemotePid, RemoteMeta}) ->
+        join_on_node(Name, RemotePid, RemoteMeta)
+    end,
+    %% add to table
+    lists:foreach(F, GroupTuples).
+
+-spec purge_group_entries_for_remote_node(Node :: atom()) -> ok.
+purge_group_entries_for_remote_node(Node) when Node =/= node() ->
+    %% NB: no demonitoring is done, hence why this needs to run for a remote node
+    %% build match specs
+    Pattern = #syn_groups_table{node = Node, _ = '_'},
+    ObjectsToDelete = mnesia:dirty_match_object(syn_groups_table, Pattern),
+    %% delete
+    DelF = fun(Record) -> mnesia:dirty_delete_object(syn_groups_table, Record) end,
+    lists:foreach(DelF, ObjectsToDelete).

+ 7 - 7
src/syn_registry.erl

@@ -254,10 +254,10 @@ handle_info({'DOWN', _MonitorRef, process, Pid, Reason}, State) ->
 
 
 handle_info({nodeup, RemoteNode}, State) ->
 handle_info({nodeup, RemoteNode}, State) ->
     error_logger:info_msg("Syn(~p): Node ~p has joined the cluster~n", [node(), RemoteNode]),
     error_logger:info_msg("Syn(~p): Node ~p has joined the cluster~n", [node(), RemoteNode]),
-    global:trans({{?MODULE, auto_merge_node_up}, self()},
+    global:trans({{?MODULE, auto_merge_registry}, self()},
         fun() ->
         fun() ->
-            error_logger:warning_msg("Syn(~p): AUTOMERGE ----> Initiating for remote node ~p~n", [node(), RemoteNode]),
-            %% get processes info from remote node
+            error_logger:warning_msg("Syn(~p): REGISTRY AUTOMERGE ----> Initiating for remote node ~p~n", [node(), RemoteNode]),
+            %% get registry tuples from remote node
             RegistryTuples = rpc:call(RemoteNode, ?MODULE, sync_get_local_registry_tuples, [node()]),
             RegistryTuples = rpc:call(RemoteNode, ?MODULE, sync_get_local_registry_tuples, [node()]),
             error_logger:warning_msg(
             error_logger:warning_msg(
                 "Syn(~p): Received ~p registry entrie(s) from remote node ~p, writing to local~n",
                 "Syn(~p): Received ~p registry entrie(s) from remote node ~p, writing to local~n",
@@ -265,14 +265,14 @@ handle_info({nodeup, RemoteNode}, State) ->
             ),
             ),
             sync_registry_tuples(RemoteNode, RegistryTuples),
             sync_registry_tuples(RemoteNode, RegistryTuples),
             %% exit
             %% exit
-            error_logger:warning_msg("Syn(~p): AUTOMERGE <---- Done for remote node ~p~n", [node(), RemoteNode])
+            error_logger:warning_msg("Syn(~p): REGISTRY AUTOMERGE <---- Done for remote node ~p~n", [node(), RemoteNode])
         end
         end
     ),
     ),
     %% resume
     %% resume
     {noreply, State};
     {noreply, State};
 
 
 handle_info({nodedown, RemoteNode}, State) ->
 handle_info({nodedown, RemoteNode}, State) ->
-    error_logger:warning_msg("Syn(~p): Node ~p has left the cluster, removing its entries on local~n", [node(), RemoteNode]),
+    error_logger:warning_msg("Syn(~p): Node ~p has left the cluster, removing registry entries on local~n", [node(), RemoteNode]),
     purge_registry_entries_for_remote_node(RemoteNode),
     purge_registry_entries_for_remote_node(RemoteNode),
     {noreply, State};
     {noreply, State};
 
 
@@ -407,8 +407,8 @@ purge_registry_entries_for_remote_node(Node) when Node =/= node() ->
     %% build match specs
     %% build match specs
     MatchHead = #syn_registry_table{name = '$1', node = '$2', _ = '_'},
     MatchHead = #syn_registry_table{name = '$1', node = '$2', _ = '_'},
     Guard = {'=:=', '$2', Node},
     Guard = {'=:=', '$2', Node},
-    NameFormat = '$1',
+    IdFormat = '$1',
     %% delete
     %% delete
-    NodePids = mnesia:dirty_select(syn_registry_table, [{MatchHead, [Guard], [NameFormat]}]),
+    NodePids = mnesia:dirty_select(syn_registry_table, [{MatchHead, [Guard], [IdFormat]}]),
     DelF = fun(Id) -> mnesia:dirty_delete({syn_registry_table, Id}) end,
     DelF = fun(Id) -> mnesia:dirty_delete({syn_registry_table, Id}) end,
     lists:foreach(DelF, NodePids).
     lists:foreach(DelF, NodePids).

+ 187 - 1
test/syn_groups_SUITE.erl

@@ -41,6 +41,9 @@
     two_nodes_join_monitor_and_unregister/1,
     two_nodes_join_monitor_and_unregister/1,
     two_nodes_local_members/1
     two_nodes_local_members/1
 ]).
 ]).
+-export([
+    three_nodes_partial_netsplit_consistency/1
+]).
 
 
 %% include
 %% include
 -include_lib("common_test/include/ct.hrl").
 -include_lib("common_test/include/ct.hrl").
@@ -60,7 +63,8 @@
 all() ->
 all() ->
     [
     [
         {group, single_node_groups},
         {group, single_node_groups},
-        {group, two_nodes_groups}
+        {group, two_nodes_groups},
+        {group, three_nodes_groups}
     ].
     ].
 
 
 %% -------------------------------------------------------------------
 %% -------------------------------------------------------------------
@@ -85,6 +89,9 @@ groups() ->
         {two_nodes_groups, [shuffle], [
         {two_nodes_groups, [shuffle], [
             two_nodes_join_monitor_and_unregister,
             two_nodes_join_monitor_and_unregister,
             two_nodes_local_members
             two_nodes_local_members
+        ]},
+        {three_nodes_groups, [shuffle], [
+            three_nodes_partial_netsplit_consistency
         ]}
         ]}
     ].
     ].
 %% -------------------------------------------------------------------
 %% -------------------------------------------------------------------
@@ -408,3 +415,182 @@ two_nodes_local_members(Config) ->
     %% kill processes
     %% kill processes
     syn_test_suite_helper:kill_process(LocalPid),
     syn_test_suite_helper:kill_process(LocalPid),
     syn_test_suite_helper:kill_process(RemotePid).
     syn_test_suite_helper:kill_process(RemotePid).
+
+three_nodes_partial_netsplit_consistency(Config) ->
+    GroupName = "my group",
+    %% get slaves
+    SlaveNode1 = proplists:get_value(slave_node_1, Config),
+    SlaveNode2 = proplists:get_value(slave_node_2, Config),
+    %% start syn on nodes
+    ok = syn:start(),
+    ok = rpc:call(SlaveNode1, syn, start, []),
+    ok = rpc:call(SlaveNode2, syn, start, []),
+    timer:sleep(100),
+    %% start processes
+    Pid0 = syn_test_suite_helper:start_process(),
+    Pid0Changed = syn_test_suite_helper:start_process(),
+    Pid1 = syn_test_suite_helper:start_process(SlaveNode1),
+    Pid2 = syn_test_suite_helper:start_process(SlaveNode2),
+    OtherPid = syn_test_suite_helper:start_process(),
+    timer:sleep(100),
+    %% retrieve local
+    [] = syn:get_members("group-1"),
+    [] = syn:get_members(GroupName),
+    [] = syn:get_members(GroupName, with_meta),
+    false = syn:member(Pid0, GroupName),
+    false = syn:member(Pid0Changed, GroupName),
+    false = syn:member(Pid1, GroupName),
+    false = syn:member(Pid2, GroupName),
+    %% retrieve slave 1
+    [] = rpc:call(SlaveNode1, syn, get_members, [GroupName]),
+    [] = rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta]),
+    false = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
+    false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
+    false = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
+    false = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
+    %% retrieve slave 2
+    [] = rpc:call(SlaveNode2, syn, get_members, [GroupName]),
+    [] = rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta]),
+    false = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
+    false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
+    false = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
+    false = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
+    %% join
+    ok = syn:join(GroupName, Pid0),
+    ok = syn:join(GroupName, Pid0Changed, {meta, changed}),
+    ok = rpc:call(SlaveNode1, syn, join, [GroupName, Pid1]),
+    ok = rpc:call(SlaveNode2, syn, join, [GroupName, Pid2, {meta, 2}]),
+    ok = syn:join("other-group", OtherPid),
+    timer:sleep(200),
+    %% retrieve local
+    true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid0Changed, {meta, changed}},
+        {Pid1, undefined},
+        {Pid2, {meta, 2}}
+    ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
+    true = syn:member(Pid0, GroupName),
+    true = syn:member(Pid0Changed, GroupName),
+    true = syn:member(Pid1, GroupName),
+    true = syn:member(Pid2, GroupName),
+    false = syn:member(OtherPid, GroupName),
+    %% retrieve slave 1
+    true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
+        =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid0Changed, {meta, changed}},
+        {Pid1, undefined},
+        {Pid2, {meta, 2}}
+    ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
+    true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
+    false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
+    %% retrieve slave 2
+    true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
+        =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid0Changed, {meta, changed}},
+        {Pid1, undefined},
+        {Pid2, {meta, 2}}
+    ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
+    true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
+    true = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
+    true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
+    true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
+    false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
+    %% disconnect slave 2 from main (slave 1 can still see slave 2)
+    syn_test_suite_helper:disconnect_node(SlaveNode2),
+    timer:sleep(500),
+    %% retrieve local
+    true = lists:sort([Pid0, Pid0Changed, Pid1]) =:= lists:sort(syn:get_members(GroupName)),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid0Changed, {meta, changed}},
+        {Pid1, undefined}
+    ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
+    true = syn:member(Pid0, GroupName),
+    true = syn:member(Pid0Changed, GroupName),
+    true = syn:member(Pid1, GroupName),
+    false = syn:member(Pid2, GroupName),
+    false = syn:member(OtherPid, GroupName),
+    %% retrieve slave 1
+    true = lists:sort([Pid0, Pid0Changed, Pid1, Pid2])
+        =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid0Changed, {meta, changed}},
+        {Pid1, undefined},
+        {Pid2, {meta, 2}}
+    ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
+    true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
+    false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
+    %% disconnect slave 1
+    syn_test_suite_helper:disconnect_node(SlaveNode1),
+    timer:sleep(500),
+    %% unregister 0Changed
+    ok = syn:leave(GroupName, Pid0Changed),
+    %% retrieve local
+    true = lists:sort([Pid0]) =:= lists:sort(syn:get_members(GroupName)),
+    true = lists:sort([
+        {Pid0, undefined}
+    ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
+    true = syn:member(Pid0, GroupName),
+    false = syn:member(Pid0Changed, GroupName),
+    false = syn:member(Pid1, GroupName),
+    false = syn:member(Pid2, GroupName),
+    false = syn:member(OtherPid, GroupName),
+    %% reconnect all
+    syn_test_suite_helper:connect_node(SlaveNode1),
+    syn_test_suite_helper:connect_node(SlaveNode2),
+    timer:sleep(5000),
+    %% retrieve local
+    true = lists:sort([Pid0, Pid1, Pid2]) =:= lists:sort(syn:get_members(GroupName)),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid1, undefined},
+        {Pid2, {meta, 2}}
+    ]) =:= lists:sort(syn:get_members(GroupName, with_meta)),
+    true = syn:member(Pid0, GroupName),
+    false = syn:member(Pid0Changed, GroupName),
+    true = syn:member(Pid1, GroupName),
+    true = syn:member(Pid2, GroupName),
+    false = syn:member(OtherPid, GroupName),
+    %% retrieve slave 1
+    true = lists:sort([Pid0, Pid1, Pid2])
+        =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName])),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid1, undefined},
+        {Pid2, {meta, 2}}
+    ]) =:= lists:sort(rpc:call(SlaveNode1, syn, get_members, [GroupName, with_meta])),
+    true = rpc:call(SlaveNode1, syn, member, [Pid0, GroupName]),
+    false = rpc:call(SlaveNode1, syn, member, [Pid0Changed, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid1, GroupName]),
+    true = rpc:call(SlaveNode1, syn, member, [Pid2, GroupName]),
+    false = rpc:call(SlaveNode1, syn, member, [OtherPid, GroupName]),
+    %% retrieve slave 2
+    true = lists:sort([Pid0,  Pid1, Pid2])
+        =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName])),
+    true = lists:sort([
+        {Pid0, undefined},
+        {Pid1, undefined},
+        {Pid2, {meta, 2}}
+    ]) =:= lists:sort(rpc:call(SlaveNode2, syn, get_members, [GroupName, with_meta])),
+    true = rpc:call(SlaveNode2, syn, member, [Pid0, GroupName]),
+    false = rpc:call(SlaveNode2, syn, member, [Pid0Changed, GroupName]),
+    true = rpc:call(SlaveNode2, syn, member, [Pid1, GroupName]),
+    true = rpc:call(SlaveNode2, syn, member, [Pid2, GroupName]),
+    false = rpc:call(SlaveNode2, syn, member, [OtherPid, GroupName]),
+    %% kill processes
+    syn_test_suite_helper:kill_process(Pid0),
+    syn_test_suite_helper:kill_process(Pid0Changed),
+    syn_test_suite_helper:kill_process(Pid1),
+    syn_test_suite_helper:kill_process(Pid2).

+ 31 - 31
test/syn_registry_SUITE.erl

@@ -405,34 +405,34 @@ three_nodes_partial_netsplit_consistency(Config) ->
     timer:sleep(100),
     timer:sleep(100),
     %% retrieve
     %% retrieve
     undefined = syn:whereis(<<"proc0">>),
     undefined = syn:whereis(<<"proc0">>),
-    undefined = syn:whereis(<<"proc0b-changed">>),
+    undefined = syn:whereis(<<"proc0-changed">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc2">>),
     undefined = syn:whereis(<<"proc2">>),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     %% register (mix nodes)
     %% register (mix nodes)
     ok = rpc:call(SlaveNode2, syn, register, [<<"proc0">>, Pid0]),
     ok = rpc:call(SlaveNode2, syn, register, [<<"proc0">>, Pid0]),
     ok = syn:register(<<"proc1">>, Pid1),
     ok = syn:register(<<"proc1">>, Pid1),
     ok = rpc:call(SlaveNode1, syn, register, [<<"proc2">>, Pid2]),
     ok = rpc:call(SlaveNode1, syn, register, [<<"proc2">>, Pid2]),
-    ok = rpc:call(SlaveNode1, syn, register, [<<"proc0b-changed">>, Pid0Changed]),
+    ok = rpc:call(SlaveNode1, syn, register, [<<"proc0-changed">>, Pid0Changed]),
     timer:sleep(200),
     timer:sleep(200),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    Pid0Changed = syn:whereis(<<"proc0b-changed">>),
+    Pid0Changed = syn:whereis(<<"proc0-changed">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
-    Pid0Changed = rpc:call(SlaveNode2, syn, whereis, [<<"proc0b-changed">>]),
+    Pid0Changed = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     %% disconnect slave 2 from main (slave 1 can still see slave 2)
     %% disconnect slave 2 from main (slave 1 can still see slave 2)
@@ -440,21 +440,21 @@ three_nodes_partial_netsplit_consistency(Config) ->
     timer:sleep(500),
     timer:sleep(500),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    Pid0Changed = syn:whereis(<<"proc0b-changed">>),
+    Pid0Changed = syn:whereis(<<"proc0-changed">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid1 = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
     undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]), %% slave 1 still has slave 2 so 'proc2' is still there
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]), %% slave 1 still has slave 2 so 'proc2' is still there
     %% disconnect slave 1
     %% disconnect slave 1
     syn_test_suite_helper:disconnect_node(SlaveNode1),
     syn_test_suite_helper:disconnect_node(SlaveNode1),
     timer:sleep(500),
     timer:sleep(500),
-    %% unregister 0b
-    ok = syn:unregister(<<"proc0b-changed">>),
+    %% unregister proc0-changed
+    ok = syn:unregister(<<"proc0-changed">>),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    undefined = syn:whereis(<<"proc0b-changed">>),
+    undefined = syn:whereis(<<"proc0-changed">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc2">>),
     undefined = syn:whereis(<<"proc2">>),
     %% reconnect all
     %% reconnect all
@@ -463,15 +463,15 @@ three_nodes_partial_netsplit_consistency(Config) ->
     timer:sleep(5000),
     timer:sleep(5000),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    undefined = syn:whereis(<<"proc0b-changed">>),
+    undefined = syn:whereis(<<"proc0-changed">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     %% kill processes
     %% kill processes
@@ -496,34 +496,34 @@ three_nodes_full_netsplit_consistency(Config) ->
     timer:sleep(100),
     timer:sleep(100),
     %% retrieve
     %% retrieve
     undefined = syn:whereis(<<"proc0">>),
     undefined = syn:whereis(<<"proc0">>),
-    undefined = syn:whereis(<<"proc0b-changed">>),
+    undefined = syn:whereis(<<"proc0-changed">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc2">>),
     undefined = syn:whereis(<<"proc2">>),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     %% register (mix nodes)
     %% register (mix nodes)
     ok = rpc:call(SlaveNode2, syn, register, [<<"proc0">>, Pid0]),
     ok = rpc:call(SlaveNode2, syn, register, [<<"proc0">>, Pid0]),
-    ok = rpc:call(SlaveNode2, syn, register, [<<"proc0b-changed">>, Pid0Changed]),
+    ok = rpc:call(SlaveNode2, syn, register, [<<"proc0-changed">>, Pid0Changed]),
     ok = syn:register(<<"proc1">>, Pid1),
     ok = syn:register(<<"proc1">>, Pid1),
     ok = rpc:call(SlaveNode1, syn, register, [<<"proc2">>, Pid2]),
     ok = rpc:call(SlaveNode1, syn, register, [<<"proc2">>, Pid2]),
     timer:sleep(200),
     timer:sleep(200),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    Pid0Changed = syn:whereis(<<"proc0b-changed">>),
+    Pid0Changed = syn:whereis(<<"proc0-changed">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
-    Pid0Changed = rpc:call(SlaveNode2, syn, whereis, [<<"proc0b-changed">>]),
+    Pid0Changed = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     %% disconnect slave 2 from main (slave 1 can still see slave 2)
     %% disconnect slave 2 from main (slave 1 can still see slave 2)
@@ -531,11 +531,11 @@ three_nodes_full_netsplit_consistency(Config) ->
     timer:sleep(500),
     timer:sleep(500),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    Pid0Changed = syn:whereis(<<"proc0b-changed">>),
+    Pid0Changed = syn:whereis(<<"proc0-changed">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid1 = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
     undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]), %% slave 1 still has slave 2 so 'proc2' is still there
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]), %% slave 1 still has slave 2 so 'proc2' is still there
     %% disconnect slave 2 from slave 1
     %% disconnect slave 2 from slave 1
@@ -543,22 +543,22 @@ three_nodes_full_netsplit_consistency(Config) ->
     timer:sleep(500),
     timer:sleep(500),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    Pid0Changed = syn:whereis(<<"proc0b-changed">>),
+    Pid0Changed = syn:whereis(<<"proc0-changed">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid1 = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
     undefined = syn:whereis(<<"proc2">>), %% main has lost slave 2 so 'proc2' is removed
     undefined = syn:whereis(<<"proc2">>, with_meta),
     undefined = syn:whereis(<<"proc2">>, with_meta),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    Pid0Changed = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     %% disconnect slave 1
     %% disconnect slave 1
     syn_test_suite_helper:disconnect_node(SlaveNode1),
     syn_test_suite_helper:disconnect_node(SlaveNode1),
     timer:sleep(500),
     timer:sleep(500),
     %% unregister
     %% unregister
-    ok = syn:unregister(<<"proc0b-changed">>),
+    ok = syn:unregister(<<"proc0-changed">>),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    undefined = syn:whereis(<<"proc0b-changed">>),
+    undefined = syn:whereis(<<"proc0-changed">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc1">>),
     undefined = syn:whereis(<<"proc2">>),
     undefined = syn:whereis(<<"proc2">>),
     %% reconnect all
     %% reconnect all
@@ -568,15 +568,15 @@ three_nodes_full_netsplit_consistency(Config) ->
     timer:sleep(1500),
     timer:sleep(1500),
     %% retrieve
     %% retrieve
     Pid0 = syn:whereis(<<"proc0">>),
     Pid0 = syn:whereis(<<"proc0">>),
-    undefined = syn:whereis(<<"proc0b-changed">>),
+    undefined = syn:whereis(<<"proc0-changed">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid1 = syn:whereis(<<"proc1">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid2 = syn:whereis(<<"proc2">>),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode1, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode1, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode1, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode1, syn, whereis, [<<"proc2">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
     Pid0 = rpc:call(SlaveNode2, syn, whereis, [<<"proc0">>]),
-    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0b-changed">>]),
+    undefined = rpc:call(SlaveNode2, syn, whereis, [<<"proc0-changed">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid1 = rpc:call(SlaveNode2, syn, whereis, [<<"proc1">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     Pid2 = rpc:call(SlaveNode2, syn, whereis, [<<"proc2">>]),
     %% kill processes
     %% kill processes