Browse Source

Create ETS tables based on scopes.

Roberto Ostinelli 3 years ago
parent
commit
8fd9d3f4b4
4 changed files with 48 additions and 29 deletions
  1. 40 21
      src/syn_backbone.erl
  2. 0 6
      src/syn_registry.erl
  3. 6 0
      src/syn_scopes_sup.erl
  4. 2 2
      src/syn_sup.erl

+ 40 - 21
src/syn_backbone.erl

@@ -28,6 +28,8 @@
 
 %% API
 -export([start_link/0]).
+-export([create_tables_for_scope/1]).
+-export([get_table_name/2]).
 
 %% gen_server callbacks
 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
@@ -46,6 +48,16 @@ start_link() ->
     Options = [],
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], Options).
 
+-spec create_tables_for_scope(Scope :: atom()) -> ok.
+create_tables_for_scope(Scope) ->
+    gen_server:call(?MODULE, {create_tables_for_scope, Scope}).
+
+-spec get_table_name(TableName :: atom(), Scope :: atom()) -> atom().
+get_table_name(TableName, Scope) ->
+    TableNameBin = atom_to_binary(TableName),
+    ScopeBin = atom_to_binary(Scope),
+    binary_to_atom(<<TableNameBin/binary, "_", ScopeBin/binary>>).
+
 %% ===================================================================
 %% Callbacks
 %% ===================================================================
@@ -59,16 +71,6 @@ start_link() ->
     ignore |
     {stop, Reason :: any()}.
 init([]) ->
-    %% create default ETS tables
-
-    %% entries have structure {{Name, Pid}, Meta, Clock, MonitorRef, Node}
-    ets:new(syn_registry_by_name_default, [ordered_set, public, named_table, {read_concurrency, true}, {write_concurrency, true}]),
-    %% entries have format {{Pid, Name}, Meta, Clock, MonitorRef, Node}
-    ets:new(syn_registry_by_pid_default, [ordered_set, public, named_table, {read_concurrency, true}, {write_concurrency, true}]),
-    %% entries have format {{GroupName, Pid}, Meta, MonitorRef, Node}
-    ets:new(syn_groups_by_name_default, [ordered_set, public, named_table, {read_concurrency, true}, {write_concurrency, true}]),
-    %% entries have format {{Pid, GroupName}, Meta, MonitorRef, Node}
-    ets:new(syn_groups_by_pid_default, [ordered_set, public, named_table, {read_concurrency, true}, {write_concurrency, true}]),
     %% init
     {ok, #state{}}.
 
@@ -82,9 +84,16 @@ init([]) ->
     {noreply, #state{}, Timeout :: non_neg_integer()} |
     {stop, Reason :: any(), Reply :: any(), #state{}} |
     {stop, Reason :: any(), #state{}}.
+handle_call({create_tables_for_scope, Scope}, _From, State) ->
+    error_logger:warning_msg("SYN[~p] Creating tables for scope: ~p~n", [node(), Scope]),
+    ensure_table_exists(get_table_name(syn_registry_by_name, Scope)),
+    ensure_table_exists(get_table_name(syn_registry_by_pid, Scope)),
+    ensure_table_exists(get_table_name(syn_groups_by_name, Scope)),
+    ensure_table_exists(get_table_name(syn_groups_by_pid, Scope)),
+    {reply, ok, State};
 
 handle_call(Request, From, State) ->
-    error_logger:warning_msg("Syn(~p): Received from ~p an unknown call message: ~p~n", [node(), Request, From]),
+    error_logger:warning_msg("SYN[~p] Received from ~p an unknown call message: ~p~n", [node(), Request, From]),
     {reply, undefined, State}.
 
 %% ----------------------------------------------------------------------------------------------------------
@@ -94,9 +103,8 @@ handle_call(Request, From, State) ->
     {noreply, #state{}} |
     {noreply, #state{}, Timeout :: non_neg_integer()} |
     {stop, Reason :: any(), #state{}}.
-
 handle_cast(Msg, State) ->
-    error_logger:warning_msg("Syn(~p): Received an unknown cast message: ~p~n", [node(), Msg]),
+    error_logger:warning_msg("SYN[~p] Received an unknown cast message: ~p~n", [node(), Msg]),
     {noreply, State}.
 
 %% ----------------------------------------------------------------------------------------------------------
@@ -106,9 +114,8 @@ handle_cast(Msg, State) ->
     {noreply, #state{}} |
     {noreply, #state{}, Timeout :: non_neg_integer()} |
     {stop, Reason :: any(), #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}.
 
 %% ----------------------------------------------------------------------------------------------------------
@@ -116,12 +123,7 @@ handle_info(Info, State) ->
 %% ----------------------------------------------------------------------------------------------------------
 -spec terminate(Reason :: any(), #state{}) -> terminated.
 terminate(Reason, _State) ->
-    error_logger:info_msg("Syn(~p): Terminating with reason: ~p~n", [node(), Reason]),
-    %% delete ETS tables
-    ets:delete(syn_registry_by_name_default),
-    ets:delete(syn_registry_by_pid_default),
-    ets:delete(syn_groups_by_name_default),
-    ets:delete(syn_groups_by_pid_default),
+    error_logger:info_msg("SYN[~p] Terminating with reason: ~p~n", [node(), Reason]),
     %% return
     terminated.
 
@@ -131,3 +133,20 @@ terminate(Reason, _State) ->
 -spec code_change(OldVsn :: any(), #state{}, Extra :: any()) -> {ok, #state{}}.
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
+
+%% ===================================================================
+%% Internal
+%% ===================================================================
+-spec ensure_table_exists(Name :: atom()) -> atom().
+ensure_table_exists(Name) ->
+    case ets:whereis(Name) of
+        undefined ->
+            %% regarding decentralized_counters: <https://blog.erlang.org/scalable-ets-counters/>
+            ets:new(Name, [
+                ordered_set, public, named_table,
+                {read_concurrency, true}, {write_concurrency, true}, {decentralized_counters, true}
+            ]);
+
+        _ ->
+            ok
+    end.

+ 0 - 6
src/syn_registry.erl

@@ -230,9 +230,3 @@ get_process_name_for(Scope) ->
     ModuleBin = atom_to_binary(?MODULE),
     ScopeBin = atom_to_binary(Scope),
     binary_to_atom(<<ModuleBin/binary, "_", ScopeBin/binary>>).
-
-%%-spec get_table_name(TableName :: atom(), Scope :: atom()) -> atom().
-%%get_table_name(TableName, Scope) ->
-%%    TableNameBin = atom_to_binary(TableName),
-%%    ScopeBin = atom_to_binary(Scope),
-%%    binary_to_atom(<<TableNameBin/binary, "_", ScopeBin/binary>>).

+ 6 - 0
src/syn_scopes_sup.erl

@@ -57,6 +57,8 @@ add_node_to_scope(Scope) ->
     end,
     CustomScopes = CustomScopes0#{Scope => #{}},
     application:set_env(syn, syn_custom_scopes, CustomScopes),
+    %% create ETS tables
+    syn_backbone:create_tables_for_scope(Scope),
     %% start children
     supervisor:start_child(?MODULE, scope_child_spec(syn_registry, Scope)),
     supervisor:start_child(?MODULE, scope_child_spec(syn_groups, Scope)),
@@ -68,7 +70,11 @@ add_node_to_scope(Scope) ->
 -spec init([]) ->
     {ok, {{supervisor:strategy(), non_neg_integer(), pos_integer()}, [supervisor:child_spec()]}}.
 init([]) ->
+    %% empty on application start, but populated if the supervisor is restarted
     Children = lists:foldl(fun(Scope, Acc) ->
+        %% create ETS tables
+        syn_backbone:create_tables_for_scope(Scope),
+        %% add to specs
         [
             scope_child_spec(syn_registry, Scope),
             scope_child_spec(syn_groups, Scope)

+ 2 - 2
src/syn_sup.erl

@@ -46,8 +46,8 @@ start_link() ->
     {ok, {{supervisor:strategy(), non_neg_integer(), pos_integer()}, [supervisor:child_spec()]}}.
 init([]) ->
     Children = [
-        child_spec(syn_scopes_sup, supervisor),
-        child_spec(syn_backbone, worker)
+        child_spec(syn_backbone, worker),
+        child_spec(syn_scopes_sup, supervisor)
     ],
     {ok, {{one_for_one, 10, 10}, Children}}.