Browse Source

Allow to attach metadata to a process.

Roberto Ostinelli 9 years ago
parent
commit
c67c7908c8
5 changed files with 209 additions and 18 deletions
  1. 35 0
      README.md
  2. 2 1
      include/syn.hrl
  3. 16 2
      src/syn.erl
  4. 57 15
      src/syn_backbone.erl
  5. 99 0
      test/syn_register_processes_SUITE.erl

+ 35 - 0
README.md

@@ -91,6 +91,18 @@ Types:
 	Error = taken
 ```
 
+To register a process and attach metadata to it:
+
+```erlang
+syn:register(Key, Pid, Meta) -> ok | {error, Error}.
+
+Types:
+	Key = any()
+	Pid = pid()
+	Meta = any()
+	Error = taken
+```
+
 To retrieve a Pid from a Key:
 
 ```erlang
@@ -101,6 +113,17 @@ Types:
 	Pid = pid()
 ```
 
+To retrieve a Pid from a Key with its metadata:
+
+```erlang
+syn:find_by_key(Key, with_meta) -> {Pid, Meta} | undefined.
+
+Types:
+	Key = any()
+	Pid = pid()
+	Meta = any()
+```
+
 To retrieve a Key from a Pid:
 
 ```erlang
@@ -111,6 +134,18 @@ Types:
 	Key = any()
 ```
 
+
+To retrieve a Key from a Pid with its metadata:
+
+```erlang
+syn:find_by_pid(Pid, with_meta) -> {Key, Meta} | undefined.
+
+Types:
+	Pid = pid()
+	Key = any()
+	Meta = any()
+```
+
 To unregister a previously registered Key:
 
 ```erlang

+ 2 - 1
include/syn.hrl

@@ -30,5 +30,6 @@
 -record(syn_processes_table, {
     key = undefined :: undefined | any(),
     pid = undefined :: undefined | pid() | atom(),
-    node = undefined :: atom()
+    node = undefined :: atom(),
+    meta = undefined :: any()
 }).

+ 16 - 2
src/syn.erl

@@ -31,8 +31,10 @@
 %% API
 -export([start/0, stop/0]).
 -export([init/0]).
--export([register/2, unregister/1]).
--export([find_by_key/1, find_by_pid/1]).
+-export([register/2, register/3]).
+-export([unregister/1]).
+-export([find_by_key/1, find_by_key/2]).
+-export([find_by_pid/1, find_by_pid/2]).
 -export([count/0, count/1]).
 
 
@@ -57,6 +59,10 @@ init() ->
 register(Key, Pid) ->
     syn_backbone:register(Key, Pid).
 
+-spec register(Key :: any(), Pid :: pid(), Meta :: any()) -> ok | {error, taken}.
+register(Key, Pid, Meta) ->
+    syn_backbone:register(Key, Pid, Meta).
+
 -spec unregister(Key :: any()) -> ok | {error, undefined}.
 unregister(Key) ->
     syn_backbone:unregister(Key).
@@ -65,10 +71,18 @@ unregister(Key) ->
 find_by_key(Key) ->
     syn_backbone:find_by_key(Key).
 
+-spec find_by_key(Key :: any(), with_meta) -> {pid(), Meta :: any()} | undefined.
+find_by_key(Key, with_meta) ->
+    syn_backbone:find_by_key(Key, with_meta).
+
 -spec find_by_pid(Pid :: pid()) -> Key :: any() | undefined.
 find_by_pid(Pid) ->
     syn_backbone:find_by_pid(Pid).
 
+-spec find_by_pid(Pid :: pid(), with_meta) -> {Key :: any(), Meta :: any()} | undefined.
+find_by_pid(Pid, with_meta) ->
+    syn_backbone:find_by_pid(Pid, with_meta).
+
 -spec count() -> non_neg_integer().
 count() ->
     syn_backbone:count().

+ 57 - 15
src/syn_backbone.erl

@@ -32,8 +32,10 @@
 %% API
 -export([start_link/0]).
 -export([initdb/0]).
--export([register/2, unregister/1]).
--export([find_by_key/1, find_by_pid/1]).
+-export([register/2, register/3]).
+-export([unregister/1]).
+-export([find_by_key/1, find_by_key/2]).
+-export([find_by_pid/1, find_by_pid/2]).
 -export([count/0, count/1]).
 
 %% gen_server callbacks
@@ -63,16 +65,30 @@ initdb() ->
 
 -spec find_by_key(Key :: any()) -> pid() | undefined.
 find_by_key(Key) ->
-    case mnesia:dirty_read(syn_processes_table, Key) of
-        [Process] -> return_pid_if_on_connected_node(Process);
-        _ -> undefined
+    case i_find_by_key(Key) of
+        undefined -> undefined;
+        Process -> Process#syn_processes_table.pid
+    end.
+
+-spec find_by_key(Key :: any(), with_meta) -> {pid(), Meta :: any()} | undefined.
+find_by_key(Key, with_meta) ->
+    case i_find_by_key(Key) of
+        undefined -> undefined;
+        Process -> {Process#syn_processes_table.pid, Process#syn_processes_table.meta}
     end.
 
 -spec find_by_pid(Pid :: pid()) -> Key :: any() | undefined.
 find_by_pid(Pid) ->
-    case mnesia:dirty_index_read(syn_processes_table, Pid, #syn_processes_table.pid) of
-        [Process] -> return_key_if_on_connected_node(Process);
-        _ -> undefined
+    case i_find_by_pid(Pid) of
+        undefined -> undefined;
+        Process -> Process#syn_processes_table.key
+    end.
+
+-spec find_by_pid(Pid :: pid(), with_meta) -> {Key :: any(), Meta :: any()} | undefined.
+find_by_pid(Pid, with_meta) ->
+    case i_find_by_pid(Pid) of
+        undefined -> undefined;
+        Process -> {Process#syn_processes_table.key, Process#syn_processes_table.meta}
     end.
 
 -spec register(Key :: any(), Pid :: pid()) -> ok | {error, taken}.
@@ -93,6 +109,25 @@ register(Key, Pid) ->
             {error, taken}
     end.
 
+-spec register(Key :: any(), Pid :: pid(), Meta :: any()) -> ok | {error, taken}.
+register(Key, Pid, Meta) ->
+    case find_by_key(Key) of
+        undefined ->
+            %% get processes's node
+            Node = node(Pid),
+            %% add to table
+            mnesia:dirty_write(#syn_processes_table{
+                key = Key,
+                pid = Pid,
+                node = Node,
+                meta = Meta
+            }),
+            %% link
+            gen_server:call({?MODULE, Node}, {link_process, Pid});
+        _ ->
+            {error, taken}
+    end.
+
 -spec unregister(Key :: any()) -> ok | {error, undefined}.
 unregister(Key) ->
     case find_by_key(Key) of
@@ -296,17 +331,24 @@ add_table_copy_to_current_node() ->
             {error, Reason}
     end.
 
--spec return_pid_if_on_connected_node(Process :: #syn_processes_table{}) -> pid() | undefined.
-return_pid_if_on_connected_node(Process) ->
-    case lists:member(Process#syn_processes_table.node, [node() | nodes()]) of
-        true -> Process#syn_processes_table.pid;
+-spec i_find_by_key(Key :: any()) -> Process :: #syn_processes_table{} | undefined.
+i_find_by_key(Key) ->
+    case mnesia:dirty_read(syn_processes_table, Key) of
+        [Process] -> return_if_on_connected_node(Process);
+        _ -> undefined
+    end.
+
+-spec i_find_by_pid(Pid :: pid()) -> Process :: #syn_processes_table{} | undefined.
+i_find_by_pid(Pid) ->
+    case mnesia:dirty_index_read(syn_processes_table, Pid, #syn_processes_table.pid) of
+        [Process] -> return_if_on_connected_node(Process);
         _ -> undefined
     end.
 
--spec return_key_if_on_connected_node(Process :: #syn_processes_table{}) -> pid() | undefined.
-return_key_if_on_connected_node(Process) ->
+-spec return_if_on_connected_node(Process :: #syn_processes_table{}) -> boolean().
+return_if_on_connected_node(Process) ->
     case lists:member(Process#syn_processes_table.node, [node() | nodes()]) of
-        true -> Process#syn_processes_table.key;
+        true -> Process;
         _ -> undefined
     end.
 

+ 99 - 0
test/syn_register_processes_SUITE.erl

@@ -37,7 +37,9 @@
 %% tests
 -export([
     single_node_when_mnesia_is_ram_find_by_key/1,
+    single_node_when_mnesia_is_ram_find_by_key_with_meta/1,
     single_node_when_mnesia_is_ram_find_by_pid/1,
+    single_node_when_mnesia_is_ram_find_by_pid_with_meta/1,
     single_node_when_mnesia_is_ram_re_register_error/1,
     single_node_when_mnesia_is_ram_unregister/1,
     single_node_when_mnesia_is_ram_process_count/1,
@@ -46,6 +48,7 @@
 ]).
 -export([
     two_nodes_when_mnesia_is_ram_find_by_key/1,
+    two_nodes_when_mnesia_is_ram_find_by_key_with_meta/1,
     two_nodes_when_mnesia_is_ram_process_count/1,
     two_nodes_when_mnesia_is_ram_callback_on_process_exit/1,
     two_nodes_when_mnesia_is_disc_find_by_pid/1
@@ -91,7 +94,9 @@ groups() ->
     [
         {single_node_process_registration, [shuffle], [
             single_node_when_mnesia_is_ram_find_by_key,
+            single_node_when_mnesia_is_ram_find_by_key_with_meta,
             single_node_when_mnesia_is_ram_find_by_pid,
+            single_node_when_mnesia_is_ram_find_by_pid_with_meta,
             single_node_when_mnesia_is_ram_re_register_error,
             single_node_when_mnesia_is_ram_unregister,
             single_node_when_mnesia_is_ram_process_count,
@@ -100,6 +105,7 @@ groups() ->
         ]},
         {two_nodes_process_registration, [shuffle], [
             two_nodes_when_mnesia_is_ram_find_by_key,
+            two_nodes_when_mnesia_is_ram_find_by_key_with_meta,
             two_nodes_when_mnesia_is_ram_process_count,
             two_nodes_when_mnesia_is_ram_callback_on_process_exit,
             two_nodes_when_mnesia_is_disc_find_by_pid
@@ -203,6 +209,33 @@ single_node_when_mnesia_is_ram_find_by_key(_Config) ->
     %% retrieve
     undefined = syn:find_by_key(<<"my proc">>).
 
+single_node_when_mnesia_is_ram_find_by_key_with_meta(_Config) ->
+    %% set schema location
+    application:set_env(mnesia, schema_location, ram),
+    %% start
+    ok = syn:start(),
+    ok = syn:init(),
+    %% start process
+    Pid1 = syn_test_suite_helper:start_process(),
+    Pid2 = syn_test_suite_helper:start_process(),
+    %% retrieve
+    undefined = syn:find_by_key(<<"my proc 1">>, with_meta),
+    undefined = syn:find_by_key(<<"my proc 2">>, with_meta),
+    %% register
+    Meta = [{some, 1}, {meta, <<"data">>}],
+    ok = syn:register(<<"my proc 1">>, Pid1, Meta),
+    ok = syn:register(<<"my proc 2">>, Pid2),
+    %% retrieve
+    {Pid1, Meta} = syn:find_by_key(<<"my proc 1">>, with_meta),
+    {Pid2, undefined} = syn:find_by_key(<<"my proc 2">>, with_meta),
+    %% kill process
+    syn_test_suite_helper:kill_process(Pid1),
+    syn_test_suite_helper:kill_process(Pid2),
+    timer:sleep(100),
+    %% retrieve
+    undefined = syn:find_by_key(<<"my proc 1">>, with_meta),
+    undefined = syn:find_by_key(<<"my proc 2">>, with_meta).
+
 single_node_when_mnesia_is_ram_find_by_pid(_Config) ->
     %% set schema location
     application:set_env(mnesia, schema_location, ram),
@@ -221,6 +254,33 @@ single_node_when_mnesia_is_ram_find_by_pid(_Config) ->
     %% retrieve
     undefined = syn:find_by_pid(Pid).
 
+single_node_when_mnesia_is_ram_find_by_pid_with_meta(_Config) ->
+    %% set schema location
+    application:set_env(mnesia, schema_location, ram),
+    %% start
+    ok = syn:start(),
+    ok = syn:init(),
+    %% start process
+    Pid1 = syn_test_suite_helper:start_process(),
+    Pid2 = syn_test_suite_helper:start_process(),
+    %% retrieve
+    undefined = syn:find_by_pid(Pid1, with_meta),
+    undefined = syn:find_by_pid(Pid2, with_meta),
+    %% register
+    Meta = [{some, 1}, {meta, <<"data">>}],
+    ok = syn:register(<<"my proc 1">>, Pid1, Meta),
+    ok = syn:register(<<"my proc 2">>, Pid2),
+    %% retrieve
+    {<<"my proc 1">>, Meta} = syn:find_by_pid(Pid1, with_meta),
+    {<<"my proc 2">>, undefined} = syn:find_by_pid(Pid2, with_meta),
+    %% kill process
+    syn_test_suite_helper:kill_process(Pid1),
+    syn_test_suite_helper:kill_process(Pid2),
+    timer:sleep(100),
+    %% retrieve
+    undefined = syn:find_by_pid(Pid1, with_meta),
+    undefined = syn:find_by_pid(Pid2, with_meta).
+
 single_node_when_mnesia_is_ram_re_register_error(_Config) ->
     %% set schema location
     application:set_env(mnesia, schema_location, ram),
@@ -374,6 +434,45 @@ two_nodes_when_mnesia_is_ram_find_by_key(Config) ->
     undefined = syn:find_by_key(<<"my proc">>),
     undefined = rpc:call(SlaveNode, syn, find_by_key, [<<"my proc">>]).
 
+two_nodes_when_mnesia_is_ram_find_by_key_with_meta(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 process
+    Pid1 = syn_test_suite_helper:start_process(),
+    Pid2 = syn_test_suite_helper:start_process(),
+    %% retrieve
+    undefined = syn:find_by_key(<<"my proc 1">>),
+    undefined = rpc:call(SlaveNode, syn, find_by_key, [<<"my proc 1">>]),
+    undefined = syn:find_by_key(<<"my proc 2">>),
+    undefined = rpc:call(SlaveNode, syn, find_by_key, [<<"my proc 2">>]),
+    %% register
+    Meta = [{some, 1}, {meta, <<"data">>}],
+    ok = syn:register(<<"my proc 1">>, Pid1, Meta),
+    ok = syn:register(<<"my proc 2">>, Pid2),
+    %% retrieve
+    {Pid1, Meta} = syn:find_by_key(<<"my proc 1">>, with_meta),
+    {Pid1, Meta} = rpc:call(SlaveNode, syn, find_by_key, [<<"my proc 1">>, with_meta]),
+    {Pid2, undefined} = syn:find_by_key(<<"my proc 2">>, with_meta),
+    {Pid2, undefined} = rpc:call(SlaveNode, syn, find_by_key, [<<"my proc 2">>, with_meta]),
+    %% kill process
+    syn_test_suite_helper:kill_process(Pid1),
+    syn_test_suite_helper:kill_process(Pid2),
+    timer:sleep(100),
+    %% retrieve
+    undefined = syn:find_by_key(<<"my proc 1">>),
+    undefined = rpc:call(SlaveNode, syn, find_by_key, [<<"my proc 1">>]),
+    undefined = syn:find_by_key(<<"my proc 2">>),
+    undefined = rpc:call(SlaveNode, syn, find_by_key, [<<"my proc 2">>]).
+
 two_nodes_when_mnesia_is_ram_process_count(Config) ->
     %% get slave
     SlaveNode = proplists:get_value(slave_node, Config),