Browse Source

Add get_local_members.

[ostinelli/syn#17]
Roberto Ostinelli 8 years ago
parent
commit
95ebfc9a41
3 changed files with 92 additions and 4 deletions
  1. 9 0
      src/syn.erl
  2. 39 0
      src/syn_groups.erl
  3. 44 4
      test/syn_groups_SUITE.erl

+ 9 - 0
src/syn.erl

@@ -47,6 +47,7 @@
 -export([leave/2]).
 -export([leave/2]).
 -export([member/2]).
 -export([member/2]).
 -export([get_members/1, get_members/2]).
 -export([get_members/1, get_members/2]).
+-export([get_local_members/1, get_local_members/2]).
 -export([publish/2]).
 -export([publish/2]).
 -export([multi_call/2, multi_call/3]).
 -export([multi_call/2, multi_call/3]).
 -export([multi_call_reply/2]).
 -export([multi_call_reply/2]).
@@ -154,6 +155,14 @@ get_members(Name) ->
 get_members(Name, with_meta) ->
 get_members(Name, with_meta) ->
     syn_groups:get_members(Name, with_meta).
     syn_groups:get_members(Name, with_meta).
 
 
+-spec get_local_members(Name :: any()) -> [pid()].
+get_local_members(Name) ->
+    syn_groups:get_local_members(Name).
+
+-spec get_local_members(Name :: any(), with_meta) -> [{pid(), Meta :: any()}].
+get_local_members(Name, with_meta) ->
+    syn_groups:get_local_members(Name, with_meta).
+
 -spec publish(Name :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 -spec publish(Name :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 publish(Name, Message) ->
 publish(Name, Message) ->
     syn_groups:publish(Name, Message).
     syn_groups:publish(Name, Message).

+ 39 - 0
src/syn_groups.erl

@@ -32,6 +32,7 @@
 -export([leave/2]).
 -export([leave/2]).
 -export([member/2]).
 -export([member/2]).
 -export([get_members/1, get_members/2]).
 -export([get_members/1, get_members/2]).
+-export([get_local_members/1, get_local_members/2]).
 -export([publish/2]).
 -export([publish/2]).
 -export([multi_call/2, multi_call/3]).
 -export([multi_call/2, multi_call/3]).
 -export([multi_call_reply/2]).
 -export([multi_call_reply/2]).
@@ -89,6 +90,14 @@ get_members(Name) ->
 get_members(Name, with_meta) ->
 get_members(Name, with_meta) ->
     i_get_members(Name, with_meta).
     i_get_members(Name, with_meta).
 
 
+-spec get_local_members(Name :: any()) -> [pid()].
+get_local_members(Name) ->
+    i_get_local_members(Name).
+
+-spec get_local_members(Name :: any(), with_meta) -> [{pid(), Meta :: any()}].
+get_local_members(Name, with_meta) ->
+    i_get_local_members(Name, with_meta).
+
 -spec publish(Name :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 -spec publish(Name :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 publish(Name, Message) ->
 publish(Name, Message) ->
     MemberPids = i_get_members(Name),
     MemberPids = i_get_members(Name),
@@ -325,6 +334,36 @@ i_get_members(Name, with_meta) ->
     end, Processes),
     end, Processes),
     lists:keysort(1, PidsWithMeta).
     lists:keysort(1, PidsWithMeta).
 
 
+-spec i_get_local_members(Name :: any()) -> [pid()].
+i_get_local_members(Name) ->
+    %% build name guard
+    NameGuard = case is_tuple(Name) of
+        true -> {'==', '$1', {Name}};
+        _ -> {'=:=', '$1', Name}
+    end,
+    %% build match specs
+    MatchHead = #syn_groups_table{name = '$1', node = '$2', pid = '$3', _ = '_'},
+    Guards = [NameGuard, {'=:=', '$2', node()}],
+    Result = '$3',
+    %% select
+    Pids = mnesia:dirty_select(syn_groups_table, [{MatchHead, Guards, [Result]}]),
+    lists:sort(Pids).
+
+-spec i_get_local_members(Name :: any(), with_meta) -> [{pid(), Meta :: any()}].
+i_get_local_members(Name, with_meta) ->
+    %% build name guard
+    NameGuard = case is_tuple(Name) of
+        true -> {'==', '$1', {Name}};
+        _ -> {'=:=', '$1', Name}
+    end,
+    %% build match specs
+    MatchHead = #syn_groups_table{name = '$1', node = '$2', pid = '$3', meta = '$4', _ = '_'},
+    Guards = [NameGuard, {'=:=', '$2', node()}],
+    Result = {{'$3', '$4'}},
+    %% select
+    PidsWithMeta = mnesia:dirty_select(syn_groups_table, [{MatchHead, Guards, [Result]}]),
+    lists:keysort(1, PidsWithMeta).
+
 -spec find_groups_by_pid(Pid :: pid()) -> [Process :: #syn_groups_table{}].
 -spec find_groups_by_pid(Pid :: pid()) -> [Process :: #syn_groups_table{}].
 find_groups_by_pid(Pid) ->
 find_groups_by_pid(Pid) ->
     mnesia:dirty_index_read(syn_groups_table, Pid, #syn_groups_table.pid).
     mnesia:dirty_index_read(syn_groups_table, Pid, #syn_groups_table.pid).

+ 44 - 4
test/syn_groups_SUITE.erl

@@ -46,7 +46,8 @@
 -export([
 -export([
     two_nodes_kill/1,
     two_nodes_kill/1,
     two_nodes_publish/1,
     two_nodes_publish/1,
-    two_nodes_multi_call/1
+    two_nodes_multi_call/1,
+    two_nodes_local_members/1
 ]).
 ]).
 
 
 %% internals
 %% internals
@@ -103,7 +104,8 @@ groups() ->
         {two_nodes_process_groups, [shuffle], [
         {two_nodes_process_groups, [shuffle], [
             two_nodes_kill,
             two_nodes_kill,
             two_nodes_publish,
             two_nodes_publish,
-            two_nodes_multi_call
+            two_nodes_multi_call,
+            two_nodes_local_members
         ]}
         ]}
     ].
     ].
 %% -------------------------------------------------------------------
 %% -------------------------------------------------------------------
@@ -441,7 +443,7 @@ single_node_callback_on_process_exit(_Config) ->
     end,
     end,
     %% unregister
     %% unregister
     global:unregister_name(syn_process_groups_SUITE_result).
     global:unregister_name(syn_process_groups_SUITE_result).
-    
+
 two_nodes_kill(Config) ->
 two_nodes_kill(Config) ->
     %% get slave
     %% get slave
     SlaveNode = proplists:get_value(slave_node, Config),
     SlaveNode = proplists:get_value(slave_node, Config),
@@ -535,7 +537,7 @@ two_nodes_multi_call(Config) ->
     PidLocal = syn_test_suite_helper:start_process(fun() -> called_loop(pid1) end),
     PidLocal = syn_test_suite_helper:start_process(fun() -> called_loop(pid1) end),
     PidSlave = syn_test_suite_helper:start_process(SlaveNode, fun() -> called_loop(pid2) end),
     PidSlave = syn_test_suite_helper:start_process(SlaveNode, fun() -> called_loop(pid2) end),
     PidUnresponsive = syn_test_suite_helper:start_process(),
     PidUnresponsive = syn_test_suite_helper:start_process(),
-    %% register
+    %% join
     ok = syn:join(<<"my group">>, PidLocal),
     ok = syn:join(<<"my group">>, PidLocal),
     ok = syn:join(<<"my group">>, PidSlave),
     ok = syn:join(<<"my group">>, PidSlave),
     ok = syn:join(<<"my group">>, PidUnresponsive),
     ok = syn:join(<<"my group">>, PidUnresponsive),
@@ -552,6 +554,44 @@ two_nodes_multi_call(Config) ->
     syn_test_suite_helper:kill_process(PidSlave),
     syn_test_suite_helper:kill_process(PidSlave),
     syn_test_suite_helper:kill_process(PidUnresponsive).
     syn_test_suite_helper:kill_process(PidUnresponsive).
 
 
+two_nodes_local_members(Config) ->
+    %% get slave
+    SlaveNode = proplists:get_value(slave_node, Config),
+    %% set schema location
+    application:set_env(mnesia, schema_location, ram),
+    rpc:call(SlaveNode, mnesia, schema_location, [ram]),
+    %% start
+    ok = syn:start(),
+    ok = syn:init(),
+    ok = rpc:call(SlaveNode, syn, start, []),
+    ok = rpc:call(SlaveNode, syn, init, []),
+    timer:sleep(100),
+    %% start processes
+    PidLocal1 = syn_test_suite_helper:start_process(),
+    PidLocal2 = syn_test_suite_helper:start_process(),
+    PidSlave = syn_test_suite_helper:start_process(SlaveNode),
+    %% join
+    ok = syn:join(<<"my group">>, PidLocal1, {meta, pid_local_1}),
+    ok = syn:join(<<"my group">>, PidLocal2, {meta, pid_local_2}),
+    ok = syn:join(<<"my group">>, PidSlave, {meta, pid_slave}),
+    timer:sleep(100),
+    %% retrieve, pid should have the same order in all nodes
+    [PidLocal1, PidLocal2] = syn:get_local_members(<<"my group">>),
+    [
+        {PidLocal1, {meta, pid_local_1}},
+        {PidLocal2, {meta, pid_local_2}}
+    ] = syn:get_local_members(<<"my group">>, with_meta),
+    %% local pids leave
+    ok = syn:leave(<<"my group">>, PidLocal1),
+    ok = syn:leave(<<"my group">>, PidLocal2),
+    %% retrieve, no more local pids
+    [] = syn:get_local_members(<<"my group">>),
+    %% kill processes
+    syn_test_suite_helper:kill_process(PidLocal1),
+    syn_test_suite_helper:kill_process(PidLocal2),
+    syn_test_suite_helper:kill_process(PidSlave).
+
+
 %% ===================================================================
 %% ===================================================================
 %% Internal
 %% Internal
 %% ===================================================================
 %% ===================================================================