Version: 1.0
Authors: Ulf Wiger (ulf.wiger@ericsson.com), Thomas Arts (thomas.arts@ituniv.se).
A leader election behaviour modeled after gen_server.This behaviour intends to make it reasonably straightforward to implement a fully distributed and fault-tolerant server with master-slave semantics.
The leader election algorithm used is designed to find a leader in constant time. A prerequisite is that all candidates are known from the beginning (but obviously, they do not all need to be alive.)
The gen_leader behaviour supports nearly everything that gen_server does (some functions, such as multicall() and the internal timeout, have been removed), and adds a few callbacks and API functions to support leader election etc.
Included is an example program, a global dictionary, gdict, based on the modules gen_leader and dict. The callback implementing the global dictionary is called 'test_cb', for no particularly logical reason.
gdict consists of 50 lines of code, essentially
emulating the interface of dict.erl. The "magic" in
gdict is performed by two macros:
-define(store(Dict,Expr,Legend),
gen_leader:leader_call(Dict, {store, fun(D) ->
Expr
end})).
-define(lookup(Dict, Expr, Legend),
gen_leader:call(Dict, {lookup, fun(D) ->
Expr
end})).
(Legend was a means to hook in some debugging info,
but is currently not used.)
Using these macros, the update functions in dict.erl
can be mapped to a set of gen_leader processes maintaining a
replicated dictionary:
store(Key, Value, Dict) ->
?store(Dict, dict:store(Key,Value,D), store).
fetch(Key, Dict) -> ?lookup(Dict, dict:fetch(Key,D), fetch).
... and so on.
Instantiating a global dictionary is done via
gdict:new/3:
new(Name, Candidates, Workers) ->
gen_leader:start(Name,Candidates, Workers, test_cb, dict:new(), []).
test_cb consists of 49 lines of code, and is the
gen_leader callback module supporting gdict. The "magic"
is performed by the following lines:
handle_leader_call({store,F}, From, Dict, E) ->
NewDict = F(Dict),
{reply, ok, {store, F}, NewDict};
...
from_leader({store,F}, Dict, E) ->
NewDict = F(Dict),
{ok, NewDict}.
handle_call({lookup, F}, From, Dict) ->
Reply = F(Dict),
{reply, Reply, Dict}.
Note that updates are served through the leader, using
gen_leader:leader_call/2 and
handle_leader_call/4 respectively, while lookups
are served locally, using gen_leader:call/2 and
handle_call/3. More details are found in test_cb.
Documentation of the required callbacks can be found in the example callback test_cb.
Generated by EDoc, Feb 18 2008, 06:50:12.