Browse Source

documentation improvements, convenient helper functions

git-svn-id: http://svn.ulf.wiger.net/gproc/branches/experimental-0906/gproc@36 f3948e33-8234-0410-8a80-a07eae3b6c4d
uwiger 15 years ago
parent
commit
a59aa75dc9

+ 136 - 11
doc/gproc.html

@@ -58,13 +58,30 @@
                                  a = aggregate_counter</p>
 
 <h2><a name="index">Function Index</a></h2>
-<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#first-1">first/1</a></td><td>Behaves as ets:first(Tab) for a given type of registration object.</td></tr>
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#add_global_aggr_counter-1">add_global_aggr_counter/1</a></td><td>Registers a global (unique) aggregated counter.</td></tr>
+<tr><td valign="top"><a href="#add_global_counter-2">add_global_counter/2</a></td><td>Registers a global (non-unique) counter.</td></tr>
+<tr><td valign="top"><a href="#add_global_name-1">add_global_name/1</a></td><td>Registers a global (unique) name.</td></tr>
+<tr><td valign="top"><a href="#add_global_property-2">add_global_property/2</a></td><td>Registers a global (non-unique) property.</td></tr>
+<tr><td valign="top"><a href="#add_local_aggr_counter-1">add_local_aggr_counter/1</a></td><td>Registers a local (unique) aggregated counter.</td></tr>
+<tr><td valign="top"><a href="#add_local_counter-2">add_local_counter/2</a></td><td>Registers a local (non-unique) counter.</td></tr>
+<tr><td valign="top"><a href="#add_local_name-1">add_local_name/1</a></td><td>Registers a local (unique) name.</td></tr>
+<tr><td valign="top"><a href="#add_local_property-2">add_local_property/2</a></td><td>Registers a local (non-unique) property.</td></tr>
+<tr><td valign="top"><a href="#first-1">first/1</a></td><td>Behaves as ets:first(Tab) for a given type of registration object.</td></tr>
 <tr><td valign="top"><a href="#get_value-1">get_value/1</a></td><td>Read the value stored with a key registered to the current process.</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_values-1">lookup_values/1</a></td><td></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="#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>
@@ -77,9 +94,10 @@
 <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="#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_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></td></tr>
-<tr><td valign="top"><a href="#table-1">table/1</a></td><td></td></tr>
-<tr><td valign="top"><a href="#table-2">table/2</a></td><td></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-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="#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="#where-1">where/1</a></td><td>Returns the pid registered as Key.</td></tr>
@@ -87,6 +105,48 @@
 
 <h2><a name="functions">Function Details</a></h2>
 
+<h3 class="function"><a name="add_global_aggr_counter-1">add_global_aggr_counter/1</a></h3>
+<div class="spec">
+<p><tt>add_global_aggr_counter(Name) -&gt; any()</tt></p>
+</div><p>Equivalent to <a href="#reg-1"><tt>reg({a, l, Name})</tt></a>.</p>
+<p>Registers a global (unique) aggregated counter.</p>
+
+<h3 class="function"><a name="add_global_counter-2">add_global_counter/2</a></h3>
+<div class="spec">
+<p><tt>add_global_counter(Name, Initial) -&gt; any()</tt></p>
+</div><p>Registers a global (non-unique) counter. @equiv reg({c,g,Name},Value)</p>
+
+<h3 class="function"><a name="add_global_name-1">add_global_name/1</a></h3>
+<div class="spec">
+<p><tt>add_global_name(Name) -&gt; any()</tt></p>
+</div><p>Registers a global (unique) name. @equiv reg({n,g,Name})</p>
+
+<h3 class="function"><a name="add_global_property-2">add_global_property/2</a></h3>
+<div class="spec">
+<p><tt>add_global_property(Name, Value) -&gt; any()</tt></p>
+</div><p>Registers a global (non-unique) property. @equiv reg({p,g,Name},Value)</p>
+
+<h3 class="function"><a name="add_local_aggr_counter-1">add_local_aggr_counter/1</a></h3>
+<div class="spec">
+<p><tt>add_local_aggr_counter(Name) -&gt; any()</tt></p>
+</div><p>Equivalent to <a href="#reg-1"><tt>reg({a, l, Name})</tt></a>.</p>
+<p>Registers a local (unique) aggregated counter.</p>
+
+<h3 class="function"><a name="add_local_counter-2">add_local_counter/2</a></h3>
+<div class="spec">
+<p><tt>add_local_counter(Name, Initial) -&gt; any()</tt></p>
+</div><p>Registers a local (non-unique) counter. @equiv reg({c,l,Name},Value)</p>
+
+<h3 class="function"><a name="add_local_name-1">add_local_name/1</a></h3>
+<div class="spec">
+<p><tt>add_local_name(Name) -&gt; any()</tt></p>
+</div><p>Registers a local (unique) name. @equiv reg({n,l,Name})</p>
+
+<h3 class="function"><a name="add_local_property-2">add_local_property/2</a></h3>
+<div class="spec">
+<p><tt>add_local_property(Name, Value) -&gt; any()</tt></p>
+</div><p>Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)</p>
+
 <h3 class="function"><a name="first-1">first/1</a></h3>
 <div class="spec">
 <p><tt>first(Type::<a href="#type-type">type()</a>) -&gt; <a href="#type-key">key()</a> | '$end_of_table'</tt></p>
@@ -130,6 +190,60 @@
   See <a href="http://www.erlang.org/doc/man/ets.html#last-1" target="_top"><tt>http://www.erlang.org/doc/man/ets.html#last-1</tt></a>.
   The registry behaves as an ordered_set table.</p>
 
+<h3 class="function"><a name="lookup_global_aggr_counter-1">lookup_global_aggr_counter/1</a></h3>
+<div class="spec">
+<p><tt>lookup_global_aggr_counter(Name::any()) -&gt; integer()</tt></p>
+</div><p>Equivalent to <a href="#where-1"><tt>where({a, g, Name})</tt></a>.</p>
+<p>Lookup a global (unique) aggregated counter and returns its value.
+  Fails if there is no such object.</p>
+
+<h3 class="function"><a name="lookup_global_counters-1">lookup_global_counters/1</a></h3>
+<div class="spec">
+<p><tt>lookup_global_counters(Counter::any()) -&gt; [{pid(), Value::integer()}]</tt></p>
+</div><p>Equivalent to <a href="#lookup_values-1"><tt>lookup_values({c, l, Counter})</tt></a>.</p>
+<p>Look up all global (non-unique) instances of a given Counter.
+  Returns a list of {Pid, Value} tuples for all matching objects.</p>
+
+<h3 class="function"><a name="lookup_global_name-1">lookup_global_name/1</a></h3>
+<div class="spec">
+<p><tt>lookup_global_name(Name::any()) -&gt; pid()</tt></p>
+</div><p>Equivalent to <a href="#where-1"><tt>where({n, g, Name})</tt></a>.</p>
+<p>Lookup a global unique name. Fails if there is no such name.</p>
+
+<h3 class="function"><a name="lookup_global_properties-1">lookup_global_properties/1</a></h3>
+<div class="spec">
+<p><tt>lookup_global_properties(Property::any()) -&gt; [{pid(), Value}]</tt></p>
+</div><p>Equivalent to <a href="#lookup_values-1"><tt>lookup_values({p, g, Property})</tt></a>.</p>
+<p>Look up all global (non-unique) instances of a given Property.
+  Returns a list of {Pid, Value} tuples for all matching objects.</p>
+
+<h3 class="function"><a name="lookup_local_aggr_counter-1">lookup_local_aggr_counter/1</a></h3>
+<div class="spec">
+<p><tt>lookup_local_aggr_counter(Name::any()) -&gt; integer()</tt></p>
+</div><p>Equivalent to <a href="#where-1"><tt>where({a, l, Name})</tt></a>.</p>
+<p>Lookup a local (unique) aggregated counter and returns its value.
+  Fails if there is no such object.</p>
+
+<h3 class="function"><a name="lookup_local_counters-1">lookup_local_counters/1</a></h3>
+<div class="spec">
+<p><tt>lookup_local_counters(Counter::any()) -&gt; [{pid(), Value::integer()}]</tt></p>
+</div><p>Equivalent to <a href="#lookup_values-1"><tt>lookup_values({c, l, Counter})</tt></a>.</p>
+<p>Look up all local (non-unique) instances of a given Counter.
+  Returns a list of {Pid, Value} tuples for all matching objects.</p>
+
+<h3 class="function"><a name="lookup_local_name-1">lookup_local_name/1</a></h3>
+<div class="spec">
+<p><tt>lookup_local_name(Name::any()) -&gt; pid()</tt></p>
+</div><p>Equivalent to <a href="#where-1"><tt>where({n, l, Name})</tt></a>.</p>
+<p>Lookup a local unique name. Fails if there is no such name.</p>
+
+<h3 class="function"><a name="lookup_local_properties-1">lookup_local_properties/1</a></h3>
+<div class="spec">
+<p><tt>lookup_local_properties(Property::any()) -&gt; [{pid(), Value}]</tt></p>
+</div><p>Equivalent to <a href="#lookup_values-1"><tt>lookup_values({p, l, Property})</tt></a>.</p>
+<p>Look up all local (non-unique) instances of a given Property.
+  Returns a list of {Pid, Value} tuples for all matching objects.</p>
+
 <h3 class="function"><a name="lookup_pid-1">lookup_pid/1</a></h3>
 <div class="spec">
 <p><tt>lookup_pid(Key) -&gt; Pid</tt></p>
@@ -145,6 +259,11 @@
   this function will return either an empty list, or a list of one pid.
   For non-unique types, the return value can be a list of any length.</p>
 
+<h3 class="function"><a name="lookup_values-1">lookup_values/1</a></h3>
+<div class="spec">
+<p><tt>lookup_values(Key) -&gt; any()</tt></p>
+</div>
+
 <h3 class="function"><a name="mreg-3">mreg/3</a></h3>
 <div class="spec">
 <p><tt>mreg(T::<a href="#type-type">type()</a>, X2::<a href="#type-scope">scope()</a>, KVL::[{Key::any(), Value::any()}]) -&gt; true</tt></p>
@@ -225,18 +344,24 @@ If it doesn't, this function will exit.</p>
 
 <h3 class="function"><a name="start_link-0">start_link/0</a></h3>
 <div class="spec">
-<p><tt>start_link() -&gt; any()</tt></p>
-</div>
+<p><tt>start_link() -&gt; {ok, pid()}</tt></p>
+</div><p><p>Starts the gproc server.</p>
+ 
+  This function is intended to be called from gproc_sup, as part of
+  starting the gproc application.</p>
 
 <h3 class="function"><a name="table-1">table/1</a></h3>
 <div class="spec">
-<p><tt>table(Type) -&gt; any()</tt></p>
-</div>
+<p><tt>table(Context::<a href="#type-context">context()</a>) -&gt; any()</tt></p>
+</div><p>Equivalent to <a href="#table-2"><tt>table(Context, [])</tt></a>.</p>
+
 
 <h3 class="function"><a name="table-2">table/2</a></h3>
 <div class="spec">
-<p><tt>table(T, Opts) -&gt; any()</tt></p>
-</div>
+<p><tt>table(Context::<a href="#type-context">context()</a>, Opts) -&gt; any()</tt></p>
+</div><p>QLC table generator for the gproc registry.
+  Context specifies which subset of the registry should be queried.
+  See <a href="http://www.erlang.org/doc/man/qlc.html" target="_top"><tt>http://www.erlang.org/doc/man/qlc.html</tt></a>.</p>
 
 <h3 class="function"><a name="unreg-1">unreg/1</a></h3>
 <div class="spec">
@@ -263,6 +388,6 @@ If it doesn't, this function will exit.</p>
 <hr>
 
 <div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Sep 20 2009, 09:15:40.</i></p>
+<p><i>Generated by EDoc, Sep 21 2009, 10:14:31.</i></p>
 </body>
 </html>

+ 1 - 1
doc/gproc_app.html

@@ -38,6 +38,6 @@
 <hr>
 
 <div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Sep 20 2009, 09:15:40.</i></p>
+<p><i>Generated by EDoc, Sep 21 2009, 10:14:30.</i></p>
 </body>
 </html>

+ 1 - 1
doc/gproc_dist.html

@@ -149,6 +149,6 @@
 <hr>
 
 <div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Sep 20 2009, 09:15:40.</i></p>
+<p><i>Generated by EDoc, Sep 21 2009, 10:14:30.</i></p>
 </body>
 </html>

+ 1 - 1
doc/gproc_init.html

@@ -31,6 +31,6 @@
 <hr>
 
 <div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Sep 20 2009, 09:15:40.</i></p>
+<p><i>Generated by EDoc, Sep 21 2009, 10:14:30.</i></p>
 </body>
 </html>

+ 1 - 1
doc/gproc_lib.html

@@ -18,6 +18,6 @@
   <p>For a detailed description, see gproc/doc/erlang07-wiger.pdf.</p><hr>
 
 <div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Sep 20 2009, 09:15:40.</i></p>
+<p><i>Generated by EDoc, Sep 21 2009, 10:14:31.</i></p>
 </body>
 </html>

+ 1 - 1
doc/gproc_sup.html

@@ -32,6 +32,6 @@
 <hr>
 
 <div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Sep 20 2009, 09:15:40.</i></p>
+<p><i>Generated by EDoc, Sep 21 2009, 10:14:31.</i></p>
 </body>
 </html>

+ 1 - 1
doc/overview-summary.html

@@ -32,6 +32,6 @@ express a strong urge to use this functionality.</em>
 
 <hr>
 <div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
-<p><i>Generated by EDoc, Sep 20 2009, 09:15:40.</i></p>
+<p><i>Generated by EDoc, Sep 21 2009, 10:14:31.</i></p>
 </body>
 </html>

+ 1 - 1
src/Makefile

@@ -34,7 +34,7 @@ ERLC += +debug_info
 EQC ?= /host/dev/eqc-1.16
 
 EQC_ERLC = $(ERLC) -I $(EQC)/include
-EQC_ERL = erl -pz ../ebin -pz $(EQC)/ebin -pz ./Unit-Quick-Files -kernel error_logger silent
+EQC_ERL = erl -pz ../ebin -pz $(EQC)/ebin -pz ./Unit-Quick-Files -kernel error_logger silent -sasl errlog_type error
 
 SOURCES = $(wildcard *.erl)
 

+ 5 - 3
src/Unit-Quick-Files/gproc_eqc.erl

@@ -318,6 +318,8 @@ postcondition(S,{call,_,set_value,[Pid,Key,_Value]},Res) ->
             is_registered_and_alive(S,Pid,Key);
         {'EXIT', {badarg, _}} ->
             not is_registered_and_alive(S,Pid,Key)
+                orelse (Key#key.class == c
+                        andalso is_registered_and_alive(S, Pid, Key))
     end;
 %% update_counter
 postcondition(S,{call,_,update_counter,[Pid,#key{class=Class}=Key,Incr]},Res)
@@ -354,12 +356,12 @@ postcondition(_S,{call,_,lookup_pid,[_Key]},Res) ->
     case Res of {'EXIT', {badarg, _}} -> true; _ -> false end;
 %% lookup_pids
 postcondition(S,{call,_,lookup_pids,[#key{class=Class}=Key]},Res)
-  when Class == n; Class == a; Class == c ->
+  when Class == n; Class == a; Class == c; Class == p ->
     Pids = [ Pid1 || #reg{pid=Pid1,key=Key1} <- S#state.regs
                          , Key==Key1 ],
     lists:sort(Res) == lists:sort(Pids);
-postcondition(_S,{call,_,lookup_pids,[_Key]},Res) ->
-    case Res of {'EXIT', {badarg, _}} -> true; _ -> false end;
+%% postcondition(_S,{call,_,lookup_pids,[_Key]},Res) ->
+%%     case Res of {'EXIT', {badarg, _}} -> true; _ -> false end;
 %% otherwise
 postcondition(_S,{call,_,_,_},_Res) ->
     false.

+ 214 - 14
src/gproc.erl

@@ -13,7 +13,7 @@
 %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
 %% AB. All Rights Reserved.''
 %%
-%% @author Ulf Wiger <ulf.wiger@ericsson.com>
+%% @author Ulf Wiger <ulf.wiger@erlang-consulting.com>
 %%
 %% @doc Extended process registry
 %% <p>This module implements an extended process registry</p>
@@ -45,6 +45,7 @@
          where/1,
          lookup_pid/1,
          lookup_pids/1,
+         lookup_values/1,
          update_counter/2,
          send/2,
          info/1, info/2,
@@ -55,6 +56,24 @@
          last/1,
          table/1, table/2]).
 
+%% Convenience functions
+-export([add_local_name/1,
+         add_global_name/1,
+         add_local_property/2,
+         add_global_property/2,
+         add_local_counter/2,
+         add_global_counter/2,
+         add_local_aggr_counter/1,
+         add_global_aggr_counter/1,
+         lookup_local_name/1,
+         lookup_global_name/1,
+         lookup_local_properties/1,
+         lookup_global_properties/1,
+         lookup_local_counters/1,
+         lookup_global_counters/1,
+         lookup_local_aggr_counter/1,
+         lookup_global_aggr_counter/1]).
+
 %%% internal exports
 -export([init/1,
          handle_cast/2,
@@ -79,10 +98,155 @@
 
 -record(state, {}).
 
+%% @spec () -> {ok, pid()}
+%%
+%% @doc Starts the gproc server.
+%%
+%% This function is intended to be called from gproc_sup, as part of 
+%% starting the gproc application.
+%% @end
 start_link() ->
     create_tabs(),
     gen_server:start({local, ?SERVER}, ?MODULE, [], []).
 
+%% spec(Name::any()) -> true
+%%
+%% @doc Registers a local (unique) name. @equiv reg({n,l,Name})
+%% @end
+%%
+add_local_name(Name)  -> reg({n,l,Name}, undefined).
+
+
+%% spec(Name::any()) -> true
+%%
+%% @doc Registers a global (unique) name. @equiv reg({n,g,Name})
+%% @end
+%%
+add_global_name(Name) -> reg({n,g,Name}, undefined).
+
+
+%% spec(Name::any(), Value::any()) -> true
+%%
+%% @doc Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)
+%% @end
+%%
+add_local_property(Name , Value) -> reg({p,l,Name}, Value).
+
+%% spec(Name::any(), Value::any()) -> true
+%%
+%% @doc Registers a global (non-unique) property. @equiv reg({p,g,Name},Value)
+%% @end
+%%
+add_global_property(Name, Value) -> reg({p,g,Name}, Value).
+
+%% spec(Name::any(), Initial::integer()) -> true
+%%
+%% @doc Registers a local (non-unique) counter. @equiv reg({c,l,Name},Value)
+%% @end
+%%
+add_local_counter(Name, Initial) when is_integer(Initial) ->
+    reg({c,l,Name}, Initial).
+
+
+%% spec(Name::any(), Initial::integer()) -> true
+%%
+%% @doc Registers a global (non-unique) counter. @equiv reg({c,g,Name},Value)
+%% @end
+%%
+add_global_counter(Name, Initial) when is_integer(Initial) ->
+    reg({n,g,Name}, Initial).
+
+%% spec(Name::any()) -> true
+%%
+%% @doc Registers a local (unique) aggregated counter.
+%% @equiv reg({a,l,Name})
+%% @end
+%%
+add_local_aggr_counter(Name)  -> reg({a,l,Name}).
+
+%% spec(Name::any()) -> true
+%%
+%% @doc Registers a global (unique) aggregated counter.
+%% @equiv reg({a,l,Name})
+%% @end
+%%
+add_global_aggr_counter(Name) -> reg({a,g,Name}).
+    
+
+%% @spec (Name::any()) -> pid()
+%%
+%% @doc Lookup a local unique name. Fails if there is no such name.
+%% @equiv where({n,l,Name})
+%% @end
+%%
+lookup_local_name(Name)   -> where({n,l,Name}).
+
+%% @spec (Name::any()) -> pid()
+%%
+%% @doc Lookup a global unique name. Fails if there is no such name.
+%% @equiv where({n,g,Name})
+%% @end
+%%
+lookup_global_name(Name)  -> where({g,l,Name}).
+
+%% @spec (Name::any()) -> integer()
+%%
+%% @doc Lookup a local (unique) aggregated counter and returns its value.
+%% Fails if there is no such object.
+%% @equiv where({a,l,Name})
+%% @end
+%%
+lookup_local_aggr_counter(Name)  -> lookup_value({a,l,Name}).
+
+%% @spec (Name::any()) -> integer()
+%%
+%% @doc Lookup a global (unique) aggregated counter and returns its value.
+%% Fails if there is no such object.
+%% @equiv where({a,g,Name})
+%% @end
+%%
+lookup_global_aggr_counter(Name) -> lookup_value({a,g,Name}).
+    
+
+%% @spec (Property::any()) -> [{pid(), Value}]
+%%
+%% @doc Look up all local (non-unique) instances of a given Property.
+%% Returns a list of {Pid, Value} tuples for all matching objects.
+%% @equiv lookup_values({p, l, Property})
+%% @end
+%%
+lookup_local_properties(P)  -> lookup_values({p,l,P}).
+
+%% @spec (Property::any()) -> [{pid(), Value}]
+%%
+%% @doc Look up all global (non-unique) instances of a given Property.
+%% Returns a list of {Pid, Value} tuples for all matching objects.
+%% @equiv lookup_values({p, g, Property})
+%% @end
+%%
+lookup_global_properties(P) -> lookup_values({p,g,P}).
+
+
+%% @spec (Counter::any()) -> [{pid(), Value::integer()}]
+%%
+%% @doc Look up all local (non-unique) instances of a given Counter.
+%% Returns a list of {Pid, Value} tuples for all matching objects.
+%% @equiv lookup_values({c, l, Counter})
+%% @end
+%%
+lookup_local_counters(P)    -> lookup_values({c,l,P}).
+
+
+%% @spec (Counter::any()) -> [{pid(), Value::integer()}]
+%%
+%% @doc Look up all global (non-unique) instances of a given Counter.
+%% Returns a list of {Pid, Value} tuples for all matching objects.
+%% @equiv lookup_values({c, l, Counter})
+%% @end
+%%
+lookup_global_counters(P)   -> lookup_values({c,g,P}).
+
+
 
 %% @spec reg(Key::key()) -> true
 %%
@@ -269,6 +433,13 @@ lookup_pid({_T,_,_} = Key) ->
         P -> P
     end.
 
+lookup_value({T,_,_} = Key) ->
+    if T==n orelse T==a ->
+            ets:lookup_element(?TAB, {Key,T}, 3);
+       true ->
+            erlang:error(badarg)
+    end.
+
 %% @spec (Key::key()) -> pid()
 %%
 %% @doc Returns the pid registered as Key
@@ -302,12 +473,29 @@ where({T,_,_}=Key) ->
 lookup_pids({T,_,_} = Key) ->
     if T==n orelse T==a ->
             ets:select(?TAB, [{{{Key,T}, '$1', '_'},[],['$1']}]);
-       T==c ->
-            ets:select(?TAB, [{{{Key,'_'}, '$1', '_'},[],['$1']}]);
        true ->
-            erlang:error(badarg)
+            ets:select(?TAB, [{{{Key,'_'}, '$1', '_'},[],['$1']}])
+%%%        true ->
+%%%             erlang:error(badarg)
+    end.
+
+%% @spec (Key::key()) -> [{pid(), Value}]
+%%
+%% @doc Retrieve the `{Pid,Value}' pairs corresponding to Key.
+%%
+%% Key refer to any type of registry object. If it refers to a unique
+%% object, the list will be of length 0 or 1. If it refers to a non-unique
+%% object, the return value can be a list of any length.
+%% @end
+%%
+lookup_values({T,_,_} = Key) ->
+    if T==n orelse T==a ->
+            ets:select(?TAB, [{{{Key,T}, '$1', '$2'},[],[{{'$1','$2'}}]}]);
+       true ->
+            ets:select(?TAB, [{{{Key,'_'}, '$1', '$2'},[],[{{'$1','$2'}}]}])
     end.
 
+
 %% @spec (Key::key(), Incr::integer()) -> integer()
 %%
 %% @doc Updates the counter registered as Key for the current process.
@@ -763,25 +951,37 @@ rewrite1(Expr, _) ->
     Expr.
 
 
-table(Type) ->
-    table(Type, []).
+%% @spec (Context::context()) -> any()
+%%
+%% @doc
+%% @equiv table(Context, [])
+%% @end
+%%
+table(Context) ->
+    table(Context, []).
 
-table(T, Opts) ->
+%% @spec (Context::context(), Opts) -> any()
+%%
+%% @doc QLC table generator for the gproc registry.
+%% Context specifies which subset of the registry should be queried.
+%% See [http://www.erlang.org/doc/man/qlc.html].
+%% @end
+table(Ctxt, Opts) ->
     [Traverse, NObjs] = [proplists:get_value(K,Opts,Def) ||
                             {K,Def} <- [{traverse,select}, {n_objects,100}]],
     TF = case Traverse of
              first_next ->
-                 fun() -> qlc_next(T, first(T)) end;
-             last_prev -> fun() -> qlc_prev(T, last(T)) end;
+                 fun() -> qlc_next(Ctxt, first(Ctxt)) end;
+             last_prev -> fun() -> qlc_prev(Ctxt, last(Ctxt)) end;
              select ->
-                 fun(MS) -> qlc_select(select(T, MS, NObjs)) end;
+                 fun(MS) -> qlc_select(select(Ctxt, MS, NObjs)) end;
              {select,MS} ->
-                 fun() -> qlc_select(select(T, MS, NObjs)) end;
+                 fun() -> qlc_select(select(Ctxt, MS, NObjs)) end;
              _ ->
-                 erlang:error(badarg, [T,Opts])
+                 erlang:error(badarg, [Ctxt,Opts])
          end,
     InfoFun = fun(indices) -> [2];
-                 (is_unique_objects) -> is_unique(T);
+                 (is_unique_objects) -> is_unique(Ctxt);
                  (keypos) -> 1;
                  (is_sorted_key) -> true;
                  (num_of_objects) ->
@@ -791,7 +991,7 @@ table(T, Opts) ->
     LookupFun =
         case Traverse of
             {select, _MS} -> undefined;
-            _ -> fun(Pos, Ks) -> qlc_lookup(T, Pos, Ks) end
+            _ -> fun(Pos, Ks) -> qlc_lookup(Ctxt, Pos, Ks) end
         end,
     qlc:table(TF, [{info_fun, InfoFun},
                    {lookup_fun, LookupFun}] ++ [{K,V} || {K,V} <- Opts,