Browse Source

Add groups count.

Roberto Ostinelli 5 years ago
parent
commit
65dc15493f
4 changed files with 107 additions and 3 deletions
  1. 16 3
      README.md
  2. 9 0
      src/syn.erl
  3. 21 0
      src/syn_groups.erl
  4. 61 0
      test/syn_groups_SUITE.erl

+ 16 - 3
README.md

@@ -178,13 +178,13 @@ Types:
 
 
 > Force registering is specifically useful if you are force registering a process on a different node from where the process currently registered with `Name` is running on, as `force_register/2,3` will ensure that the registration succeeds and propagates properly. You may otherwise experience a `{error, taken}` response to the registration call if you were to sequentially `unregister/1` and `register/2,3` a process, due to race conditions. Note that the previously registered process will not be killed and will be demonitored, so that the `on_process_exit/4` callback will _not_ be called (even if implemented) when the process dies.
 > Force registering is specifically useful if you are force registering a process on a different node from where the process currently registered with `Name` is running on, as `force_register/2,3` will ensure that the registration succeeds and propagates properly. You may otherwise experience a `{error, taken}` response to the registration call if you were to sequentially `unregister/1` and `register/2,3` a process, due to race conditions. Note that the previously registered process will not be killed and will be demonitored, so that the `on_process_exit/4` callback will _not_ be called (even if implemented) when the process dies.
 
 
-To retrieve the count of total registered processes running in the cluster:
+To retrieve the total count of registered processes running in the cluster:
 
 
 ```erlang
 ```erlang
 syn:registry_count() -> non_neg_integer().
 syn:registry_count() -> non_neg_integer().
 ```
 ```
 
 
-To retrieve the count of total registered processes running on a specific node:
+To retrieve the total count of registered processes running on a specific node:
 
 
 ```erlang
 ```erlang
 syn:registry_count(Node) -> non_neg_integer().
 syn:registry_count(Node) -> non_neg_integer().
@@ -193,7 +193,6 @@ Types:
     Node = atom()
     Node = atom()
 ```
 ```
 
 
-
 ### Process Groups
 ### Process Groups
 
 
 > There's no need to manually create / delete Process Groups, Syn will take care of managing those for you.
 > There's no need to manually create / delete Process Groups, Syn will take care of managing those for you.
@@ -361,6 +360,20 @@ Types:
 
 
 > `RecipientCount` is the count of the intended recipients.
 > `RecipientCount` is the count of the intended recipients.
 
 
+To retrieve the total count of groups in the cluster:
+
+```erlang
+syn:groups_count() -> non_neg_integer().
+```
+
+To retrieve the count of groups that have at least 1 process running on a specific node:
+
+```erlang
+syn:groups_count(Node) -> non_neg_integer().
+
+Types:
+    Node = atom()
+```
 
 
 ## Callbacks
 ## Callbacks
 In Syn you can specify a custom callback module if you want to:
 In Syn you can specify a custom callback module if you want to:

+ 9 - 0
src/syn.erl

@@ -38,6 +38,7 @@
 -export([member/2]).
 -export([member/2]).
 -export([get_local_members/1, get_local_members/2]).
 -export([get_local_members/1, get_local_members/2]).
 -export([local_member/2]).
 -export([local_member/2]).
+-export([groups_count/0, groups_count/1]).
 -export([publish/2]).
 -export([publish/2]).
 -export([publish_to_local/2]).
 -export([publish_to_local/2]).
 -export([multi_call/2, multi_call/3, multi_call_reply/2]).
 -export([multi_call/2, multi_call/3, multi_call_reply/2]).
@@ -161,6 +162,14 @@ get_local_members(GroupName, with_meta) ->
 local_member(GroupName, Pid) ->
 local_member(GroupName, Pid) ->
     syn_groups:local_member(GroupName, Pid).
     syn_groups:local_member(GroupName, Pid).
 
 
+-spec groups_count() -> non_neg_integer().
+groups_count() ->
+    syn_groups:count().
+
+-spec groups_count(Node :: atom()) -> non_neg_integer().
+groups_count(Node) ->
+    syn_groups:count(Node).
+
 -spec publish(GroupName :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 -spec publish(GroupName :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 publish(GroupName, Message) ->
 publish(GroupName, Message) ->
     syn_groups:publish(GroupName, Message).
     syn_groups:publish(GroupName, Message).

+ 21 - 0
src/syn_groups.erl

@@ -34,6 +34,7 @@
 -export([member/2]).
 -export([member/2]).
 -export([get_local_members/1, get_local_members/2]).
 -export([get_local_members/1, get_local_members/2]).
 -export([local_member/2]).
 -export([local_member/2]).
+-export([count/0, count/1]).
 -export([publish/2]).
 -export([publish/2]).
 -export([publish_to_local/2]).
 -export([publish_to_local/2]).
 -export([multi_call/2, multi_call/3, multi_call_reply/2]).
 -export([multi_call/2, multi_call/3, multi_call_reply/2]).
@@ -146,6 +147,26 @@ local_member(Pid, GroupName) ->
             false
             false
     end.
     end.
 
 
+-spec count() -> non_neg_integer().
+count() ->
+    Entries = ets:select(syn_groups_by_name, [{
+        {{'$1', '_'}, '_', '_',  '_'},
+        [],
+        ['$1']
+    }]),
+    Set = sets:from_list(Entries),
+    sets:size(Set).
+
+-spec count(Node :: node()) -> non_neg_integer().
+count(Node) ->
+    Entries = ets:select(syn_groups_by_name, [{
+        {{'$1', '_'}, '_', '_',  Node},
+        [],
+        ['$1']
+    }]),
+    Set = sets:from_list(Entries),
+    sets:size(Set).
+
 -spec publish(GroupName :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 -spec publish(GroupName :: any(), Message :: any()) -> {ok, RecipientCount :: non_neg_integer()}.
 publish(GroupName, Message) ->
 publish(GroupName, Message) ->
     MemberPids = get_members(GroupName),
     MemberPids = get_members(GroupName),

+ 61 - 0
test/syn_groups_SUITE.erl

@@ -36,6 +36,7 @@
     single_node_join_and_monitor/1,
     single_node_join_and_monitor/1,
     single_node_join_and_leave/1,
     single_node_join_and_leave/1,
     single_node_join_errors/1,
     single_node_join_errors/1,
+    single_node_groups_count/1,
     single_node_publish/1,
     single_node_publish/1,
     single_node_multicall/1,
     single_node_multicall/1,
     single_node_multicall_with_custom_timeout/1,
     single_node_multicall_with_custom_timeout/1,
@@ -45,6 +46,7 @@
 -export([
 -export([
     two_nodes_join_monitor_and_unregister/1,
     two_nodes_join_monitor_and_unregister/1,
     two_nodes_local_members/1,
     two_nodes_local_members/1,
+    two_nodes_groups_count/1,
     two_nodes_publish/1,
     two_nodes_publish/1,
     two_nodes_local_publish/1,
     two_nodes_local_publish/1,
     two_nodes_multicall/1,
     two_nodes_multicall/1,
@@ -94,8 +96,10 @@ all() ->
 groups() ->
 groups() ->
     [
     [
         {single_node_groups, [shuffle], [
         {single_node_groups, [shuffle], [
+            single_node_join_and_monitor,
             single_node_join_and_leave,
             single_node_join_and_leave,
             single_node_join_errors,
             single_node_join_errors,
+            single_node_groups_count,
             single_node_publish,
             single_node_publish,
             single_node_multicall,
             single_node_multicall,
             single_node_multicall_with_custom_timeout,
             single_node_multicall_with_custom_timeout,
@@ -105,6 +109,7 @@ 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,
+            two_nodes_groups_count,
             two_nodes_publish,
             two_nodes_publish,
             two_nodes_local_publish,
             two_nodes_local_publish,
             two_nodes_multicall,
             two_nodes_multicall,
@@ -297,6 +302,31 @@ single_node_join_errors(_Config) ->
     {error, not_in_group} = syn:leave(GroupName, Pid2),
     {error, not_in_group} = syn:leave(GroupName, Pid2),
     {error, not_alive} = syn:join(GroupName, Pid2).
     {error, not_alive} = syn:join(GroupName, Pid2).
 
 
+single_node_groups_count(_Config) ->
+    %% start
+    ok = syn:start(),
+    %% start processes
+    Pid = syn_test_suite_helper:start_process(),
+    Pid2 = syn_test_suite_helper:start_process(),
+    Pid3 = syn_test_suite_helper:start_process(),
+    PidUnjoined = syn_test_suite_helper:start_process(),
+    %% join
+    ok = syn:join({"group-1"}, Pid),
+    ok = syn:join({"group-1"}, Pid2),
+    ok = syn:join({"group-1"}, Pid3),
+    ok = syn:join({"group-2"}, Pid2),
+    %% count
+    2 = syn:groups_count(),
+    2 = syn:groups_count(node()),
+    %% kill & unregister
+    ok = syn:leave({"group-1"}, Pid),
+    syn_test_suite_helper:kill_process(Pid2),
+    syn_test_suite_helper:kill_process(Pid3),
+    timer:sleep(100),
+    %% count
+    0 = syn:groups_count(),
+    0 = syn:groups_count(node()).
+
 single_node_publish(_Config) ->
 single_node_publish(_Config) ->
     GroupName = "my group",
     GroupName = "my group",
     Message = {test, message},
     Message = {test, message},
@@ -586,6 +616,37 @@ two_nodes_local_members(Config) ->
     [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
     [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName]),
     [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]).
     [] = rpc:call(SlaveNode, syn, get_local_members, [GroupName, with_meta]).
 
 
+two_nodes_groups_count(Config) ->
+    %% get slave
+    SlaveNode = proplists:get_value(slave_node, Config),
+    %% start
+    ok = syn:start(),
+    ok = rpc:call(SlaveNode, syn, start, []),
+    timer:sleep(100),
+    %% start processes
+    LocalPid = syn_test_suite_helper:start_process(),
+    RemotePid = syn_test_suite_helper:start_process(SlaveNode),
+    RemotePidRegRemote = syn_test_suite_helper:start_process(SlaveNode),
+    _PidUnjoined = syn_test_suite_helper:start_process(),
+    %% join
+    ok = syn:join(<<"local group">>, LocalPid),
+    ok = syn:join(<<"remote group">>, RemotePid),
+    ok = rpc:call(SlaveNode, syn, join, [<<"remote group join_remote">>, RemotePidRegRemote]),
+    timer:sleep(500),
+    %% count
+    3 = syn:groups_count(),
+    1 = syn:groups_count(node()),
+    2 = syn:groups_count(SlaveNode),
+    %% kill & unregister processes
+    syn_test_suite_helper:kill_process(LocalPid),
+    ok = syn:leave(<<"remote group">>, RemotePid),
+    syn_test_suite_helper:kill_process(RemotePidRegRemote),
+    timer:sleep(100),
+    %% count
+    0 = syn:groups_count(),
+    0 = syn:groups_count(node()),
+    0 = syn:groups_count(SlaveNode).
+
 two_nodes_publish(Config) ->
 two_nodes_publish(Config) ->
     GroupName = "my group",
     GroupName = "my group",
     Message = {test, message},
     Message = {test, message},