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, Dec 25 2007, 02:41:20.