Browse Source

Merge pull request #69 from geometerio/member-count

Add member_count/2 for getting counts of process groups by group name
Roberto Ostinelli 3 years ago
parent
commit
85ab8a46ad
3 changed files with 37 additions and 0 deletions
  1. 18 0
      src/syn.erl
  2. 15 0
      src/syn_pg.erl
  3. 4 0
      test/syn_pg_SUITE.erl

+ 18 - 0
src/syn.erl

@@ -68,6 +68,7 @@
 -export([register_name/2, unregister_name/1, whereis_name/1, send/2]).
 %% groups
 -export([members/2, member/3, is_member/3, update_member/4]).
+-export([member_count/2]).
 -export([local_members/2, is_local_member/3]).
 -export([join/3, join/4]).
 -export([leave/3]).
@@ -450,6 +451,23 @@ members(Scope, GroupName) ->
 member(Scope, GroupName, Pid) ->
     syn_pg:member(Scope, GroupName, Pid).
 
+%% @doc Returns the count of all members for the specified Scope and GroupName.
+%%
+%% <h2>Examples</h2>
+%% <h3>Elixir</h3>
+%% ```
+%% iex> :syn.member_count(:devices, "abc123")
+%% 512473
+%% '''
+%% <h3>Erlang</h3>
+%% ```
+%% 1> syn:member_count(devices, "abc123").
+%% 512473
+%% '''
+-spec member_count(Scope :: atom(), GroupName :: term()) -> non_neg_integer().
+member_count(Scope, GroupName) ->
+    syn_pg:member_count(Scope, GroupName).
+
 %% @doc Returns whether a `pid()' is a member of GroupName in the specified Scope.
 -spec is_member(Scope :: atom(), GroupName :: term(), Pid :: pid()) -> boolean().
 is_member(Scope, GroupName, Pid) ->

+ 15 - 0
src/syn_pg.erl

@@ -34,6 +34,7 @@
 -export([leave/3]).
 -export([members/2]).
 -export([member/3]).
+-export([member_count/2]).
 -export([is_member/3]).
 -export([update_member/4]).
 -export([local_members/2]).
@@ -108,6 +109,20 @@ is_member(Scope, GroupName, Pid) ->
 local_members(Scope, GroupName) ->
     do_get_members(Scope, GroupName, undefined, node()).
 
+-spec member_count(Scope :: atom(), GroupName :: term()) -> non_neg_integer().
+member_count(Scope, GroupName) ->
+    case syn_backbone:get_table_name(syn_pg_by_name, Scope) of
+        undefined ->
+            error({invalid_scope, Scope});
+
+        TableByName ->
+            ets:select_count(TableByName, [{
+                {{GroupName, '$1'}, '_', '_', '_', '_'},
+                [],
+                [true]
+            }])
+    end.
+
 -spec do_get_members(Scope :: atom(), GroupName :: term(), pid() | undefined, Node :: node() | undefined) ->
     [{pid(), Meta :: term()}].
 do_get_members(Scope, GroupName, Pid, Node) ->

+ 4 - 0
test/syn_pg_SUITE.erl

@@ -331,6 +331,7 @@ three_nodes_join_leave_and_monitor(Config) ->
     false = rpc:call(SlaveNode1, syn, is_member, [scope_ab, {group, "one"}, PidWithMeta]),
     false = rpc:call(SlaveNode1, syn, is_member, [scope_ab, {group, "one"}, PidRemoteOn1]),
     {badrpc, {'EXIT', {{invalid_scope, scope_ab}, _}}} = (catch rpc:call(SlaveNode2, syn, is_member, [scope_ab, {group, "one"}, Pid])),
+    0 = syn:member_count(scope_ab, {group, "one"}),
 
     [] = syn:local_members(scope_ab, {group, "one"}),
     [] = rpc:call(SlaveNode1, syn, local_members, [scope_ab, {group, "one"}]),
@@ -385,8 +386,11 @@ three_nodes_join_leave_and_monitor(Config) ->
     ok = syn:join(scope_ab, {group, "one"}, Pid),
     ok = syn:join(scope_ab, {group, "one"}, PidWithMeta, <<"with meta">>),
     ok = rpc:call(SlaveNode1, syn, join, [scope_bc, {group, "two"}, PidRemoteOn1]),
+    2 = syn:member_count(scope_ab, {group, "one"}),
+    0 = syn:member_count(scope_ab, {group, "two"}),
     ok = syn:join(scope_ab, {group, "two"}, Pid),
     ok = syn:join(scope_ab, {group, "two"}, PidWithMeta, "with-meta-2"),
+    2 = syn:member_count(scope_ab, {group, "two"}),
 
     %% errors
     {error, not_alive} = syn:join(scope_ab, {"pid not alive"}, list_to_pid("<0.9999.0>")),