Skip to content

Latest commit

 

History

History
417 lines (215 loc) · 12.3 KB

test_cb.md

File metadata and controls

417 lines (215 loc) · 12.3 KB

Module test_cb

Example callback module for the locks_leader behaviour. Behaviours: locks_leader.

Authors: Ulf Wiger (ulf.wiger@feuerlabs.com), Thomas Arts (thomas.arts@quviq.com).

Description

This particular callback module implements a global dictionary, and is the back-end for the gdict module.

Data Types


broadcast() = term()

Whatever the leader decides to broadcast to the candidates.


commonReply() = {ok, state()} | {ok, broadcast(), state()} | {stop, reason(), state()}

Common set of valid replies from most callback functions.


dictionary() = tuple()

Same as from dict:new(); used in this module as State.


info() = term()

Opaque state of the gen_leader behaviour.


reason() = term()

Error information.


state() = dictionary()

Internal server state; In the general case, it can be any term.

Function Index

code_change/4Similar to code_change/3 in a gen_server callback module, with the exception of the added argument.
elected/3Called by the leader when it is elected leader, and each time a candidate recognizes the leader.
from_leader/3Called by each candidate in response to a message from the leader.
handle_DOWN/3Called by the leader when it detects loss of a candidate.
handle_call/4Equivalent to Mod:handle_call/3 in a gen_server.
handle_cast/3Equivalent to Mod:handle_call/3 in a gen_server, except (NOTE) for the possible return values.
handle_info/3Equivalent to Mod:handle_info/3 in a gen_server, except (NOTE) for the possible return values.
handle_leader_call/4Called by the leader in response to a leader_call().
handle_leader_cast/3Called by the leader in response to a leader_cast().
init/1Equivalent to the init/1 function in a gen_server.
surrendered/3Called by each candidate when it recognizes another instance as leader.
terminate/2Equivalent to terminate/2 in a gen_server callback module.

Function Details

code_change/4


code_change(FromVsn::string(), OldState::term(), I::info(), Extra::term()) -> {ok, NState}

Similar to code_change/3 in a gen_server callback module, with the exception of the added argument.

elected/3


elected(State::state(), I::info(), Cand::pid() | undefined) -> {ok, Broadcast, NState} | {reply, Msg, NState} | {ok, AmLeaderMsg, FromLeaderMsg, NState} | {error, term()}

Called by the leader when it is elected leader, and each time a candidate recognizes the leader.

This function is only called in the leader instance, and Broadcast will be sent to all candidates (when the leader is first elected), or to the new candidate that has appeared.

Broadcast might be the same as NState, but doesn't have to be. This is up to the application.

If Cand == undefined, it is possible to obtain a list of all new candidates that we haven't synced with (in the normal case, this will be all known candidates, but if our instance is re-elected after a netsplit, the 'new' candidates will be the ones that haven't yet recognized us as leaders). This gives us a chance to talk to them before crafting our broadcast message.

We can also choose a different message for the new candidates and for the ones that already see us as master. This would be accomplished by returning {ok, AmLeaderMsg, FromLeaderMsg, NewState}, where AmLeaderMsg is sent to the new candidates (and processed in surrendered/3, and FromLeaderMsg is sent to the old (and processed in from_leader/3).

If Cand == Pid, a new candidate has connected. If this affects our state such that all candidates need to be informed, we can return {ok, Msg, NSt}. If, on the other hand, we only need to get the one candidate up to speed, we can return {reply, Msg, NSt}, and only the candidate will get the message. In either case, the candidate (Cand) will receive the message in surrendered/3. In the former case, the other candidates will receive the message in from_leader/3.

Example:

    elected(#st{dict = Dict} = St, _I, undefined) ->
        {ok, Dict, St};
    elected(#st{dict = Dict} = St, _I, Pid) when is_pid(Pid) ->
        %% reply only to Pid
        {reply, Dict, St}.

from_leader/3


from_leader(Msg::term(), State::state(), I::info()) -> {ok, NState}

Called by each candidate in response to a message from the leader.

In this particular module, the leader passes an update function to be applied to the candidate's state.

handle_DOWN/3


handle_DOWN(Candidate::pid(), State::state(), I::info()) -> {ok, NState} | {ok, Broadcast, NState}

Called by the leader when it detects loss of a candidate.

If the function returns a Broadcast object, this will be sent to all candidates, and they will receive it in the function from_leader/3.

handle_call/4


handle_call(Request::term(), From::callerRef(), State::state(), I::info()) -> {reply, Reply, NState} | {noreply, NState} | {stop, Reason, Reply, NState} | commonReply()



Equivalent to Mod:handle_call/3 in a gen_server.

Note the difference in allowed return values. {ok,NState} and {noreply,NState} are synonymous.

{noreply,NState} is allowed as a return value from handle_call/3, since it could arguably add some clarity, but mainly because people are used to it from gen_server.

handle_cast/3


handle_cast(Msg::term(), State::state(), I::info()) -> {noreply, NState} | commonReply()



Equivalent to Mod:handle_call/3 in a gen_server, except (NOTE) for the possible return values.

handle_info/3


handle_info(Msg::term(), State::state(), I::info()) -> {noreply, NState} | commonReply()



Equivalent to Mod:handle_info/3 in a gen_server, except (NOTE) for the possible return values.

This function will be called in response to any incoming message not recognized as a call, cast, leader_call, leader_cast, from_leader message, internal leader negotiation message or system message.

handle_leader_call/4


handle_leader_call(Msg::term(), From::callerRef(), State::state(), I::info()) -> {reply, Reply, NState} | {reply, Reply, Broadcast, NState} | {noreply, state()} | {stop, Reason, Reply, NState} | commonReply()

Called by the leader in response to a leader_call().

If the return value includes a Broadcast object, it will be sent to all candidates, and they will receive it in the function from_leader/3.

Example:

    handle_leader_call({store,F}, From, #st{dict = Dict} = S, E) ->
        NewDict = F(Dict),
        {reply, ok, {store, F}, S#st{dict = NewDict}};
    handle_leader_call({leader_lookup,F}, From, #st{dict = Dict} = S, E) ->
        Reply = F(Dict),
        {reply, Reply, S}.

In this particular example, leader_lookup is not actually supported from the gdict module, but would be useful during complex operations, involving a series of updates and lookups. Using leader_lookup, all dictionary operations are serialized through the leader; normally, lookups are served locally and updates by the leader, which can lead to race conditions.

handle_leader_cast/3


handle_leader_cast(Msg::term(), State::term(), I::info()) -> commonReply()



Called by the leader in response to a leader_cast().

init/1


init(Arg::term()) -> {ok, State}

Equivalent to the init/1 function in a gen_server.

surrendered/3


surrendered(State::state(), Synch::broadcast(), I::info()) -> {ok, NState}

Called by each candidate when it recognizes another instance as leader.

Strictly speaking, this function is called when the candidate acknowledges a leader and receives a Synch message in return.

Example:

   surrendered(_OurDict, LeaderDict, _I) ->
       {ok, LeaderDict}.

terminate/2


terminate(Reason::term(), State::state()) -> Void



Equivalent to terminate/2 in a gen_server callback module.