Skip to content

Commit

Permalink
gproc:reg_or_locate/3, spawns a regged process
Browse files Browse the repository at this point in the history
  • Loading branch information
uwiger authored and RJ committed Jul 9, 2012
1 parent 6e03fb6 commit a1b0f25
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 30 deletions.
25 changes: 23 additions & 2 deletions doc/gproc.md
Expand Up @@ -212,7 +212,7 @@ This function is the reverse of monitor/1.</td></tr><tr><td valign="top"><a href
to forget about the calling process.</td></tr><tr><td valign="top"><a href="#i-0">i/0</a></td><td>Similar to the built-in shell command <code>i()</code> but inserts information
about names and properties registered in Gproc, where applicable.</td></tr><tr><td valign="top"><a href="#info-1">info/1</a></td><td>Similar to <code>process_info(Pid)</code> but with additional gproc info.</td></tr><tr><td valign="top"><a href="#info-2">info/2</a></td><td>Similar to process_info(Pid, Item), but with additional gproc info.</td></tr><tr><td valign="top"><a href="#last-1">last/1</a></td><td>Behaves as ets:last(Tab) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#lookup_global_aggr_counter-1">lookup_global_aggr_counter/1</a></td><td>Lookup a global (unique) aggregated counter and returns its value.</td></tr><tr><td valign="top"><a href="#lookup_global_counters-1">lookup_global_counters/1</a></td><td>Look up all global (non-unique) instances of a given Counter.</td></tr><tr><td valign="top"><a href="#lookup_global_name-1">lookup_global_name/1</a></td><td>Lookup a global unique name.</td></tr><tr><td valign="top"><a href="#lookup_global_properties-1">lookup_global_properties/1</a></td><td>Look up all global (non-unique) instances of a given Property.</td></tr><tr><td valign="top"><a href="#lookup_local_aggr_counter-1">lookup_local_aggr_counter/1</a></td><td>Lookup a local (unique) aggregated counter and returns its value.</td></tr><tr><td valign="top"><a href="#lookup_local_counters-1">lookup_local_counters/1</a></td><td>Look up all local (non-unique) instances of a given Counter.</td></tr><tr><td valign="top"><a href="#lookup_local_name-1">lookup_local_name/1</a></td><td>Lookup a local unique name.</td></tr><tr><td valign="top"><a href="#lookup_local_properties-1">lookup_local_properties/1</a></td><td>Look up all local (non-unique) instances of a given Property.</td></tr><tr><td valign="top"><a href="#lookup_pid-1">lookup_pid/1</a></td><td>Lookup the Pid stored with a key.</td></tr><tr><td valign="top"><a href="#lookup_pids-1">lookup_pids/1</a></td><td>Returns a list of pids with the published key Key.</td></tr><tr><td valign="top"><a href="#lookup_value-1">lookup_value/1</a></td><td>Lookup the value stored with a key.</td></tr><tr><td valign="top"><a href="#lookup_values-1">lookup_values/1</a></td><td>Retrieve the <code>{Pid,Value}</code> pairs corresponding to Key.</td></tr><tr><td valign="top"><a href="#monitor-1">monitor/1</a></td><td>monitor a registered name
This function works much like erlang:monitor(process, Pid), but monitors
a unique name registered via gproc.</td></tr><tr><td valign="top"><a href="#mreg-3">mreg/3</a></td><td>Register multiple {Key,Value} pairs of a given type and scope.</td></tr><tr><td valign="top"><a href="#munreg-3">munreg/3</a></td><td>Unregister multiple Key items of a given type and scope.</td></tr><tr><td valign="top"><a href="#nb_wait-1">nb_wait/1</a></td><td>Wait for a local name to be registered.</td></tr><tr><td valign="top"><a href="#nb_wait-2">nb_wait/2</a></td><td>Wait for a local name to be registered on <code>Node</code>.</td></tr><tr><td valign="top"><a href="#next-2">next/2</a></td><td>Behaves as ets:next(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#prev-2">prev/2</a></td><td>Behaves as ets:prev(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#reg-1">reg/1</a></td><td>Equivalent to <a href="#reg-2"><tt>reg(Key, default(Key))</tt></a>.</td></tr><tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>Register a name or property for the current process.</td></tr><tr><td valign="top"><a href="#reg_or_locate-1">reg_or_locate/1</a></td><td>Equivalent to <a href="#reg_or_locate-2"><tt>reg_or_locate(Key, default(Key))</tt></a>.</td></tr><tr><td valign="top"><a href="#reg_or_locate-2">reg_or_locate/2</a></td><td>Try registering a unique name, or return existing registration.</td></tr><tr><td valign="top"><a href="#reg_shared-1">reg_shared/1</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#register_name-2">register_name/2</a></td><td>Behaviour support callback.</td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td>Reads and resets a counter in a "thread-safe" way.</td></tr><tr><td valign="top"><a href="#select-1">select/1</a></td><td>Perform a select operation on the process registry.</td></tr><tr><td valign="top"><a href="#select-2">select/2</a></td><td>Perform a select operation with limited context on the process registry.</td></tr><tr><td valign="top"><a href="#select-3">select/3</a></td><td>Like <a href="#select-2"><code>select/2</code></a> but returns Limit objects at a time.</td></tr><tr><td valign="top"><a href="#select_count-1">select_count/1</a></td><td>Equivalent to <a href="#select_count-2"><tt>select_count(all, Pat)</tt></a>.</td></tr><tr><td valign="top"><a href="#select_count-2">select_count/2</a></td><td>Perform a select_count operation on the process registry.</td></tr><tr><td valign="top"><a href="#send-2">send/2</a></td><td>Sends a message to the process, or processes, corresponding to Key.</td></tr><tr><td valign="top"><a href="#set_env-5">set_env/5</a></td><td>Updates the cached value as well as underlying environment.</td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td>Sets the value of the registeration entry given by Key.</td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td>Starts the gproc server.</td></tr><tr><td valign="top"><a href="#table-0">table/0</a></td><td>Equivalent to <a href="#table-1"><tt>table({all, all})</tt></a>.</td></tr><tr><td valign="top"><a href="#table-1">table/1</a></td><td>Equivalent to <a href="#table-2"><tt>table(Context, [])</tt></a>.</td></tr><tr><td valign="top"><a href="#table-2">table/2</a></td><td>QLC table generator for the gproc registry.</td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td>Unregister a name or property.</td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td>Unregister a shared resource.</td></tr><tr><td valign="top"><a href="#unregister_name-1">unregister_name/1</a></td><td>Equivalent to <tt>unreg / 1</tt>.</td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td>Updates the counter registered as Key for the current process.</td></tr><tr><td valign="top"><a href="#update_counters-2">update_counters/2</a></td><td>Update a list of counters.</td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td>Updates the shared counter registered as Key.</td></tr><tr><td valign="top"><a href="#where-1">where/1</a></td><td>Returns the pid registered as Key.</td></tr><tr><td valign="top"><a href="#whereis_name-1">whereis_name/1</a></td><td>Equivalent to <tt>where / 1</tt>.</td></tr><tr><td valign="top"><a href="#wide_await-3">wide_await/3</a></td><td>Wait for a local name to be registered on any of <code>Nodes</code>.</td></tr></table>
a unique name registered via gproc.</td></tr><tr><td valign="top"><a href="#mreg-3">mreg/3</a></td><td>Register multiple {Key,Value} pairs of a given type and scope.</td></tr><tr><td valign="top"><a href="#munreg-3">munreg/3</a></td><td>Unregister multiple Key items of a given type and scope.</td></tr><tr><td valign="top"><a href="#nb_wait-1">nb_wait/1</a></td><td>Wait for a local name to be registered.</td></tr><tr><td valign="top"><a href="#nb_wait-2">nb_wait/2</a></td><td>Wait for a local name to be registered on <code>Node</code>.</td></tr><tr><td valign="top"><a href="#next-2">next/2</a></td><td>Behaves as ets:next(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#prev-2">prev/2</a></td><td>Behaves as ets:prev(Tab,Key) for a given type of registration object.</td></tr><tr><td valign="top"><a href="#reg-1">reg/1</a></td><td>Equivalent to <a href="#reg-2"><tt>reg(Key, default(Key))</tt></a>.</td></tr><tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>Register a name or property for the current process.</td></tr><tr><td valign="top"><a href="#reg_or_locate-1">reg_or_locate/1</a></td><td>Equivalent to <a href="#reg_or_locate-2"><tt>reg_or_locate(Key, default(Key))</tt></a>.</td></tr><tr><td valign="top"><a href="#reg_or_locate-2">reg_or_locate/2</a></td><td>Try registering a unique name, or return existing registration.</td></tr><tr><td valign="top"><a href="#reg_or_locate-3">reg_or_locate/3</a></td><td>Spawn a process with a registered name, or return existing registration.</td></tr><tr><td valign="top"><a href="#reg_shared-1">reg_shared/1</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td>Register a resource, but don't tie it to a particular process.</td></tr><tr><td valign="top"><a href="#register_name-2">register_name/2</a></td><td>Behaviour support callback.</td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td>Reads and resets a counter in a "thread-safe" way.</td></tr><tr><td valign="top"><a href="#select-1">select/1</a></td><td>Perform a select operation on the process registry.</td></tr><tr><td valign="top"><a href="#select-2">select/2</a></td><td>Perform a select operation with limited context on the process registry.</td></tr><tr><td valign="top"><a href="#select-3">select/3</a></td><td>Like <a href="#select-2"><code>select/2</code></a> but returns Limit objects at a time.</td></tr><tr><td valign="top"><a href="#select_count-1">select_count/1</a></td><td>Equivalent to <a href="#select_count-2"><tt>select_count(all, Pat)</tt></a>.</td></tr><tr><td valign="top"><a href="#select_count-2">select_count/2</a></td><td>Perform a select_count operation on the process registry.</td></tr><tr><td valign="top"><a href="#send-2">send/2</a></td><td>Sends a message to the process, or processes, corresponding to Key.</td></tr><tr><td valign="top"><a href="#set_env-5">set_env/5</a></td><td>Updates the cached value as well as underlying environment.</td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td>Sets the value of the registeration entry given by Key.</td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td>Starts the gproc server.</td></tr><tr><td valign="top"><a href="#table-0">table/0</a></td><td>Equivalent to <a href="#table-1"><tt>table({all, all})</tt></a>.</td></tr><tr><td valign="top"><a href="#table-1">table/1</a></td><td>Equivalent to <a href="#table-2"><tt>table(Context, [])</tt></a>.</td></tr><tr><td valign="top"><a href="#table-2">table/2</a></td><td>QLC table generator for the gproc registry.</td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td>Unregister a name or property.</td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td>Unregister a shared resource.</td></tr><tr><td valign="top"><a href="#unregister_name-1">unregister_name/1</a></td><td>Equivalent to <tt>unreg / 1</tt>.</td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td>Updates the counter registered as Key for the current process.</td></tr><tr><td valign="top"><a href="#update_counters-2">update_counters/2</a></td><td>Update a list of counters.</td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td>Updates the shared counter registered as Key.</td></tr><tr><td valign="top"><a href="#where-1">where/1</a></td><td>Returns the pid registered as Key.</td></tr><tr><td valign="top"><a href="#whereis_name-1">whereis_name/1</a></td><td>Equivalent to <tt>where / 1</tt>.</td></tr><tr><td valign="top"><a href="#wide_await-3">wide_await/3</a></td><td>Wait for a local name to be registered on any of <code>Nodes</code>.</td></tr></table>


<a name="functions"></a>
Expand Down Expand Up @@ -929,7 +929,28 @@ Try registering a unique name, or return existing registration.

This function tries to register the name `Key`, if available.
If such a registration already exists, the pid and value of
the current registration is returned instead.<a name="reg_shared-1"></a>
the current registration is returned instead.<a name="reg_or_locate-3"></a>

###reg_or_locate/3##


<pre>reg_or_locate(Key::<a href="#type-key">key()</a>, Value, Fun::function()) -> {pid(), NewValue}</pre>
<br></br>




Spawn a process with a registered name, or return existing registration.



This function checks whether a local name is registered; if not, it spawns
a new process (with `spawn(Fun)`) and gives it the name.
The pid and value of the resulting registration is returned.

This function is only available for local registration. While it could
theoretically be done in the global case, the spawning of a new process
on a remote node by the leader instance is more problematic.<a name="reg_shared-1"></a>

###reg_shared/1##

Expand Down
8 changes: 4 additions & 4 deletions doc/gproc_dist.md
Expand Up @@ -28,7 +28,7 @@ Class = n - unique name
| p - non-unique property
| c - counter
| a - aggregated counter
Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#reg_or_locate-2">reg_or_locate/2</a></td><td></td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td></td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td></td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-1">start_link/1</a></td><td></td></tr><tr><td valign="top"><a href="#surrendered-3">surrendered/3</a></td><td></td></tr><tr><td valign="top"><a href="#sync-0">sync/0</a></td><td>Synchronize with the gproc leader.</td></tr><tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td></td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td></td></tr><tr><td valign="top"><a href="#update_counters-1">update_counters/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td></td></tr></table>
Scope = l | g (global or local).</td></tr><tr><td valign="top"><a href="#reg_or_locate-3">reg_or_locate/3</a></td><td></td></tr><tr><td valign="top"><a href="#reg_shared-2">reg_shared/2</a></td><td></td></tr><tr><td valign="top"><a href="#reset_counter-1">reset_counter/1</a></td><td></td></tr><tr><td valign="top"><a href="#set_value-2">set_value/2</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-0">start_link/0</a></td><td></td></tr><tr><td valign="top"><a href="#start_link-1">start_link/1</a></td><td></td></tr><tr><td valign="top"><a href="#surrendered-3">surrendered/3</a></td><td></td></tr><tr><td valign="top"><a href="#sync-0">sync/0</a></td><td>Synchronize with the gproc leader.</td></tr><tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr><tr><td valign="top"><a href="#unreg-1">unreg/1</a></td><td></td></tr><tr><td valign="top"><a href="#unreg_shared-1">unreg_shared/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_counter-2">update_counter/2</a></td><td></td></tr><tr><td valign="top"><a href="#update_counters-1">update_counters/1</a></td><td></td></tr><tr><td valign="top"><a href="#update_shared_counter-2">update_shared_counter/2</a></td><td></td></tr></table>


<a name="functions"></a>
Expand Down Expand Up @@ -175,12 +175,12 @@ Class = n - unique name
| p - non-unique property
| c - counter
| a - aggregated counter
Scope = l | g (global or local)<a name="reg_or_locate-2"></a>
Scope = l | g (global or local)<a name="reg_or_locate-3"></a>

###reg_or_locate/2##
###reg_or_locate/3##


`reg_or_locate(Key, Value) -> any()`
`reg_or_locate(Key, Value, Pid) -> any()`

<a name="reg_shared-2"></a>

Expand Down
53 changes: 34 additions & 19 deletions src/gproc.erl
Expand Up @@ -72,7 +72,7 @@

-export([start_link/0,
reg/1, reg/2, unreg/1,
reg_or_locate/1, reg_or_locate/2,
reg_or_locate/1, reg_or_locate/2, reg_or_locate/3,
reg_shared/1, reg_shared/2, unreg_shared/1,
mreg/3,
munreg/3,
Expand Down Expand Up @@ -614,7 +614,7 @@ reg_or_locate(Key) ->
?CATCH_GPROC_ERROR(reg_or_locate1(Key), [Key]).

reg_or_locate1(Key) ->
reg_or_locate1(Key, default(Key)).
reg_or_locate1(Key, default(Key), self()).

default({T,_,_}) when T==c -> 0;
default(_) -> undefined.
Expand Down Expand Up @@ -945,14 +945,29 @@ reg1(_, _) ->
%% the current registration is returned instead.
%% @end
reg_or_locate(Key, Value) ->
?CATCH_GPROC_ERROR(reg_or_locate1(Key, Value), [Key, Value]).
?CATCH_GPROC_ERROR(reg_or_locate1(Key, Value, self()), [Key, Value]).

reg_or_locate1({_,g,_} = Key, Value) ->
%% @spec reg_or_locate(Key::key(), Value, Fun::fun()) -> {pid(), NewValue}
%%
%% @doc Spawn a process with a registered name, or return existing registration.
%%
%% This function checks whether a local name is registered; if not, it spawns
%% a new process (with `spawn(Fun)') and gives it the name.
%% The pid and value of the resulting registration is returned.
%%
%% This function is only available for local registration. While it could
%% theoretically be done in the global case, the spawning of a new process
%% on a remote node by the leader instance is more problematic.
%% @end
reg_or_locate({_,l,_} = Key, Value, F) when is_function(F, 0) ->
?CATCH_GPROC_ERROR(reg_or_locate1(Key, Value, F), [Key, Value, F]).

reg_or_locate1({_,g,_} = Key, Value, P) ->
?CHK_DIST,
gproc_dist:reg_or_locate(Key, Value);
reg_or_locate1({n,l,_} = Key, Value) ->
call({reg_or_locate, Key, Value});
reg_or_locate1(_, _) ->
gproc_dist:reg_or_locate(Key, Value, P);
reg_or_locate1({n,l,_} = Key, Value, P) ->
call({reg_or_locate, Key, Value, P});
reg_or_locate1(_, _, _) ->
?THROW_GPROC_ERROR(badarg).

%% @spec reg_shared(Key::key()) -> true
Expand Down Expand Up @@ -1801,19 +1816,19 @@ handle_call({reg, {_T,l,_} = Key, Val}, {Pid,_}, S) ->
false ->
{reply, badarg, S}
end;
handle_call({reg_or_locate, {T,l,_} = Key, Val}, {Pid,_}, S) ->
case try_insert_reg(Key, Val, Pid) of
true ->
handle_call({reg_or_locate, {T,l,_} = Key, Val, P}, _, S) ->
case ets:lookup(?TAB, {Key, T}) of
[] ->
Pid = if is_function(P, 0) ->
spawn(P);
is_pid(P) ->
P
end,
true = gproc_lib:insert_reg(Key, Val, Pid, l),
_ = gproc_lib:ensure_monitor(Pid, l),
{reply, {Pid, Val}, S};
false ->
case ets:lookup(?TAB, {Key, T}) of
[{_, OtherPid, OtherValue}] ->
{reply, {OtherPid, OtherValue}, S};
_ ->
%% ?? - shouldn't be possible, but don't let the server crash
{reply, badarg, S}
end
[{_, OtherPid, OtherValue}] ->
{reply, {OtherPid, OtherValue}, S}
end;
handle_call({monitor, {T,l,_} = Key, Pid}, _From, S)
when T==n; T==a ->
Expand Down
10 changes: 5 additions & 5 deletions src/gproc_dist.erl
Expand Up @@ -24,7 +24,7 @@

-export([start_link/0, start_link/1,
reg/1, reg/2, unreg/1,
reg_or_locate/2,
reg_or_locate/3,
reg_shared/2, unreg_shared/1,
mreg/2,
munreg/2,
Expand Down Expand Up @@ -90,9 +90,9 @@ reg(Key) ->

%% {@see gproc:reg_or_locate/2}
%%
reg_or_locate({n,g,_} = Key, Value) ->
leader_call({reg_or_locate, Key, Value, self()});
reg_or_locate(_, _) ->
reg_or_locate({n,g,_} = Key, Value, Pid) when is_pid(Pid) ->
leader_call({reg_or_locate, Key, Value, Pid});
reg_or_locate(_, _, _) ->
?THROW_GPROC_ERROR(badarg).


Expand Down Expand Up @@ -294,7 +294,7 @@ handle_leader_call({reg, {C,g,Name} = K, Value, Pid}, _From, S, _E) ->
end,
{reply, true, [{insert, Vals}], S}
end;
handle_leader_call({reg_or_locate, {n,g,Name} = K, Value, Pid}, _From, S, _E) ->
handle_leader_call({reg_or_locate, {n,g,_} = K, Value, Pid}, _From, S, _E) ->
case gproc_lib:insert_reg(K, Value, Pid, g) of
false ->
case ets:lookup(?TAB, {K,n}) of
Expand Down

0 comments on commit a1b0f25

Please sign in to comment.