Browse Source

added rebar support

Ulf Wiger 14 years ago
parent
commit
98ba2d9bfa

+ 12 - 15
Makefile

@@ -20,24 +20,21 @@
 ## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 ## DEALINGS IN THE SOFTWARE.
 
+.PHONY: all compile clean eunit test eqc
+
 DIRS=src 
 
-all:
-	for D in $(DIRS) ; do \
-	(cd $$D; ${MAKE}) ; \
-	done
+all: compile eunit test
+
+compile:
+	./rebar compile
+
 
 clean:
-	for D in $(DIRS) ; do \
-	(cd $$D; ${MAKE} clean) ; \
-	done
+	./rebar clean
 
 eunit:
-	for D in $(DIRS) ; do \
-	(cd $$D; ${MAKE} eunit) ; \
-	done
-
-test:
-	for D in $(DIRS) ; do \
-	(cd $$D; ${MAKE} test) ; \
-	done
+	./rebar eunit
+
+test: eunit
+

+ 18 - 0
README.md

@@ -0,0 +1,18 @@
+Gproc - Extended Process Dictionary for Erlang
+==============================================
+
+Gproc is a process dictionary for Erlang, which provides a number of useful features beyond what the built-in dictionary has:
+
+* Use any term as a process alias
+* Register a process under several aliases
+* Non-unique properties can be registered simultaneously by many processes
+* QLC and match specification interface for efficient queries on the 
+  dictionary
+* Await registration, let's you wait until a process registers itself
+* Counters, and aggregated counters, which automatically maintain the 
+  total of all counters with a given name.
+* Global registry, with all the above functions applied to a network of nodes.
+
+Gproc has a QuickCheck test suite, covering a fairly large part of the local gproc functionality, although none of the global registry. It requires a commercial EQC license, but rebar is smart enough to detect whether EQC is available, and if it isn't, the code in gproc_eqc.erl will be "defined away".
+
+There is also an eunit suite in gproc.erl, but it covers only some of the most basic functions (local only). Lots more tests need to be written... some day. Contributions are most welcome.

+ 20 - 2
doc/gproc.html

@@ -67,6 +67,9 @@
 <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="#audit_process-1">audit_process/1</a></td><td></td></tr>
+<tr><td valign="top"><a href="#await-1">await/1</a></td><td>Equivalent to <a href="#await-2"><tt>await(Key, infinity)</tt></a>.
+</td></tr>
 <tr><td valign="top"><a href="#await-2">await/2</a></td><td>Wait for a local name to be registered.</td></tr>
 <tr><td valign="top"><a href="#cancel_wait-2">cancel_wait/2</a></td><td></td></tr>
 <tr><td valign="top"><a href="#default-1">default/1</a></td><td></td></tr>
@@ -152,6 +155,17 @@
 <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="audit_process-1">audit_process/1</a></h3>
+<div class="spec">
+<p><tt>audit_process(Pid) -&gt; any()</tt></p>
+</div>
+
+<h3 class="function"><a name="await-1">await/1</a></h3>
+<div class="spec">
+<p><tt>await(Key::<a href="#type-key">key()</a>) -&gt; {pid(), Value}</tt></p>
+</div><p>Equivalent to <a href="#await-2"><tt>await(Key, infinity)</tt></a>.</p>
+
+
 <h3 class="function"><a name="await-2">await/2</a></h3>
 <div class="spec">
 <p><tt>await(Key::<a href="#type-key">key()</a>, Timeout) -&gt; {pid(), Value}</tt>
@@ -159,7 +173,11 @@
 </ul></p>
 </div><p>Wait for a local name to be registered.
   The function raises an exception if the timeout expires. Timeout must be
-  either an interger &gt; 0 or 'infinity'.</p>
+  either an interger &gt; 0 or 'infinity'.
+  A small optimization: we first perform a lookup, to see if the name
+  is already registered. This way, the cost of the operation will be
+  roughly the same as of where/1 in the case where the name is already
+  registered (the difference: await/2 also returns the value).</p>
 
 <h3 class="function"><a name="cancel_wait-2">cancel_wait/2</a></h3>
 <div class="spec">
@@ -423,6 +441,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, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</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, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
 </body>
 </html>

+ 32 - 8
doc/gproc_dist.html

@@ -20,15 +20,19 @@
 <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="#code_change-4">code_change/4</a></td><td></td></tr>
 <tr><td valign="top"><a href="#elected-2">elected/2</a></td><td></td></tr>
+<tr><td valign="top"><a href="#elected-3">elected/3</a></td><td></td></tr>
 <tr><td valign="top"><a href="#from_leader-3">from_leader/3</a></td><td></td></tr>
 <tr><td valign="top"><a href="#handle_DOWN-3">handle_DOWN/3</a></td><td></td></tr>
-<tr><td valign="top"><a href="#handle_call-3">handle_call/3</a></td><td></td></tr>
-<tr><td valign="top"><a href="#handle_cast-2">handle_cast/2</a></td><td></td></tr>
+<tr><td valign="top"><a href="#handle_call-4">handle_call/4</a></td><td></td></tr>
+<tr><td valign="top"><a href="#handle_cast-3">handle_cast/3</a></td><td></td></tr>
 <tr><td valign="top"><a href="#handle_info-2">handle_info/2</a></td><td></td></tr>
 <tr><td valign="top"><a href="#handle_leader_call-4">handle_leader_call/4</a></td><td></td></tr>
 <tr><td valign="top"><a href="#handle_leader_cast-3">handle_leader_cast/3</a></td><td></td></tr>
 <tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
+<tr><td valign="top"><a href="#leader_call-1">leader_call/1</a></td><td></td></tr>
+<tr><td valign="top"><a href="#leader_cast-1">leader_cast/1</a></td><td></td></tr>
 <tr><td valign="top"><a href="#mreg-2">mreg/2</a></td><td></td></tr>
+<tr><td valign="top"><a href="#reg-1">reg/1</a></td><td></td></tr>
 <tr><td valign="top"><a href="#reg-2">reg/2</a></td><td>
       Class = n  - unique name
             | p  - non-unique property
@@ -56,6 +60,11 @@
 <p><tt>elected(S, E) -&gt; any()</tt></p>
 </div>
 
+<h3 class="function"><a name="elected-3">elected/3</a></h3>
+<div class="spec">
+<p><tt>elected(S, E, Node) -&gt; any()</tt></p>
+</div>
+
 <h3 class="function"><a name="from_leader-3">from_leader/3</a></h3>
 <div class="spec">
 <p><tt>from_leader(Ops, S, E) -&gt; any()</tt></p>
@@ -66,14 +75,14 @@
 <p><tt>handle_DOWN(Node, S, E) -&gt; any()</tt></p>
 </div>
 
-<h3 class="function"><a name="handle_call-3">handle_call/3</a></h3>
+<h3 class="function"><a name="handle_call-4">handle_call/4</a></h3>
 <div class="spec">
-<p><tt>handle_call(X1, X2, S) -&gt; any()</tt></p>
+<p><tt>handle_call(X1, X2, S, X4) -&gt; any()</tt></p>
 </div>
 
-<h3 class="function"><a name="handle_cast-2">handle_cast/2</a></h3>
+<h3 class="function"><a name="handle_cast-3">handle_cast/3</a></h3>
 <div class="spec">
-<p><tt>handle_cast(Msg, S) -&gt; any()</tt></p>
+<p><tt>handle_cast(Msg, S, X3) -&gt; any()</tt></p>
 </div>
 
 <h3 class="function"><a name="handle_info-2">handle_info/2</a></h3>
@@ -93,7 +102,17 @@
 
 <h3 class="function"><a name="init-1">init/1</a></h3>
 <div class="spec">
-<p><tt>init(X1) -&gt; any()</tt></p>
+<p><tt>init(Opts) -&gt; any()</tt></p>
+</div>
+
+<h3 class="function"><a name="leader_call-1">leader_call/1</a></h3>
+<div class="spec">
+<p><tt>leader_call(Req) -&gt; any()</tt></p>
+</div>
+
+<h3 class="function"><a name="leader_cast-1">leader_cast/1</a></h3>
+<div class="spec">
+<p><tt>leader_cast(Msg) -&gt; any()</tt></p>
 </div>
 
 <h3 class="function"><a name="mreg-2">mreg/2</a></h3>
@@ -101,6 +120,11 @@
 <p><tt>mreg(T, KVL) -&gt; any()</tt></p>
 </div>
 
+<h3 class="function"><a name="reg-1">reg/1</a></h3>
+<div class="spec">
+<p><tt>reg(Key) -&gt; any()</tt></p>
+</div>
+
 <h3 class="function"><a name="reg-2">reg/2</a></h3>
 <div class="spec">
 <p><tt>reg(Key, Value) -&gt; any()</tt></p>
@@ -149,6 +173,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, Feb 11 2010, 05:33:38.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</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, Feb 11 2010, 05:33:38.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</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, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</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, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
 </body>
 </html>

+ 1 - 1
doc/overview-summary.html

@@ -35,6 +35,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, Feb 11 2010, 05:33:39.</i></p>
+<p><i>Generated by EDoc, Sep 11 2010, 18:22:25.</i></p>
 </body>
 </html>

+ 9 - 19
ebin/gproc.app

@@ -1,19 +1,9 @@
-%%% -*- mode: erlang -*-
-%%% $Id$
-%%%
-
-{application, gproc,
- [
-  {description, "GPROC"},
-  {vsn, "0.01"},
-  {id, "GPROC"},
-  {modules, [
-	     %% TODO: fill in this list, perhaps
-            ]
-  },
-  {registered, [ ] },
-  %% NOTE: do not list applications which are load-only!
-  {applications, [ kernel, stdlib ] },
-  {mod, {gproc_app, []} }
- ]
-}.
+{application,gproc,
+             [{description,"GPROC"},
+              {vsn,"0.01"},
+              {id,"GPROC"},
+              {registered,[]},
+              {applications,[kernel,stdlib]},
+              {mod,{gproc_app,[]}},
+              {modules,[gproc,gproc_app,gproc_dist,gproc_eqc,gproc_init,
+                        gproc_lib,gproc_sup]}]}.

BIN
rebar


+ 1 - 0
rebar.config

@@ -0,0 +1 @@
+{erl_opts, [debug_info]}.

BIN
reference/erlang07-wiger.pdf


+ 2 - 2
src/Makefile

@@ -33,7 +33,7 @@ ERLC += +debug_info
 
 #EQC ?= /host/dev/eqc-1.16
 
-EQC_ERLC = $(ERLC) -pa $(EQC)/ebin
+EQC_ERLC = $(ERLC) -pa $(EQC)/ebin -I ../include
 EQC_ERL = erl -pz ../ebin -pz $(EQC)/ebin -pz ./Unit-Quick-Files -kernel error_logger silent -sasl errlog_type error
 
 SOURCES = $(wildcard *.erl)
@@ -68,7 +68,7 @@ eunit: all
 	erl -noshell -boot start_clean -sasl errlog_type error \
 	-pa ../ebin -eval 'eunit:test("../ebin", [verbose])' -s init stop
 
-test : all ./Unit-Quick-Files/gproc_eqc.beam
+eqc : all ./Unit-Quick-Files/gproc_eqc.beam
 	$(EQC_ERL) -s gproc_eqc run -s erlang halt
 
 itest : all ./Unit-Quick-Files/gproc_eqc.beam

+ 17 - 2
src/Unit-Quick-Files/gproc_eqc.erl

@@ -7,12 +7,13 @@
 
 -module(gproc_eqc).
 
+-ifdef(EQC).
+
 -include_lib("eqc/include/eqc.hrl").
 -include_lib("eqc/include/eqc_statem.hrl").
 
 -compile(export_all).
 
-
 %%
 %% QUESTIONS:
 %%
@@ -55,6 +56,18 @@
 %% external API
 
 %% UW: renamed to avoid confusion with eunit
+
+gproc_test_() ->
+    {timeout, 60, [fun() -> run(3000) end]}.
+
+%% When run from eunit, we need to set the group leader so that EQC
+%% reporting (the dots) are made visible - that is, if that's what we want.
+verbose_run(N) ->
+    erlang:group_leader(whereis(user), self()),
+    run(N).
+
+%% 3000 tests seems like a large number, but this seems to be needed
+%% to reach enough variation in the tests.
 all_tests() ->
     eqc:module({numtests, 3000}, ?MODULE).
 
@@ -456,7 +469,7 @@ postcondition(S,{call,_,lookup_pids,[#key{class=Class}=Key]},Res)
     Pids = [ Pid1 || #reg{pid=Pid1,key=Key1} <- S#state.regs
                          , Key==Key1 ],
     lists:sort(Res) == lists:sort(Pids);
-postcondition(S,{call,_,await_new,[#key{}]}, Pid) ->
+postcondition(_S, {call,_,await_new,[#key{}]}, Pid) ->
     is_pid(Pid);
 postcondition(S,{call,_,await_existing,[#reg{key=Key}]}, {P1,V1}) ->
     case lists:keyfind(Key, #reg.key, S#state.regs) of
@@ -652,3 +665,5 @@ check_waiter(WPid, Pid, _Key, Value) ->
     after 1000 ->
             erlang:error(timeout)
     end.
+
+-endif.

+ 15 - 0
src/gproc.app.src

@@ -0,0 +1,15 @@
+%%% -*- mode: erlang -*-
+%%% $Id$
+%%%
+
+{application, gproc,
+ [
+  {description, "GPROC"},
+  {vsn, "0.01"},
+  {id, "GPROC"},
+  {registered, [ ] },
+  %% NOTE: do not list applications which are load-only!
+  {applications, [ kernel, stdlib ] },
+  {mod, {gproc_app, []} }
+ ]
+}.

+ 5 - 5
src/gproc.erl

@@ -270,6 +270,11 @@ reg(Key) ->
 default({T,_,_}) when T==c -> 0;
 default(_) -> undefined.
 
+%% @spec await(Key::key()) -> {pid(),Value}
+%% @equiv await(Key,infinity)
+%%
+await(Key) ->
+    await(Key, infinity).
 
 %% @spec await(Key::key(), Timeout) -> {pid(),Value}
 %%   Timeout = integer() | infinity
@@ -283,9 +288,6 @@ default(_) -> undefined.
 %% registered (the difference: await/2 also returns the value).
 %% @end
 %%
-await(Key) ->
-    await(Key, infinity).
-
 await({n,g,_} = Key, Timeout) ->
     ?CHK_DIST,
     request_wait(Key, Timeout);
@@ -1284,7 +1286,6 @@ reg_test_() ->
      ]}.
 
 t_simple_reg() ->
-    ?debugFmt("self() = ~p~n", [self()]),
     ?assert(gproc:reg({n,l,name}) =:= true),
     ?assert(gproc:where({n,l,name}) =:= self()),
     ?assert(gproc:unreg({n,l,name}) =:= true),
@@ -1300,7 +1301,6 @@ t_simple_prop() ->
     ?assert(gproc:unreg({p,l,prop}) =:= true).
 
 t_other_proc(F) ->
-    ?debugFmt("self() = ~p~n", [self()]),
     {_Pid,Ref} = spawn_monitor(fun() -> exit(F()) end),
     receive
         {'DOWN',Ref,_,_,R} ->