GHS
Leader Election Based on GHS Minimum Spanning Tree
|
The main state machine for the GHS algorithm More...
#include <ghs.h>
Public Member Functions | |
GhsState (agent_t my_id, Edge *edges, size_t num_edges) | |
le::Errno | start_round (StaticQueue< Msg, MSG_Q_SIZE > &outgoing_msgs, size_t &) |
le::Errno | process (const Msg &msg, StaticQueue< Msg, MSG_Q_SIZE > &outgoing_buffer, size_t &sz) |
bool | is_converged () const |
size_t | get_n_peers () const |
le::Errno | get_edge (const agent_t &to, Edge &out) const |
bool | has_edge (const agent_t to) const |
le::Errno | get_edge_status (const agent_t &to, status_t &out) const |
le::Errno | get_edge_metric (const agent_t &to, metric_t &m) const |
le::Errno | is_waiting_for (const agent_t &who, bool &out_waiting_for) |
le::Errno | is_response_required (const agent_t &who, bool &response_required) |
le::Errno | get_response_prompt (const agent_t &who, msg::InPartPayload &m) |
agent_t | get_id () const |
agent_t | get_parent_id () const |
agent_t | get_leader_id () const |
level_t | get_level () const |
size_t | waiting_count () const |
size_t | delayed_count () const |
Edge | mwoe () const |
le::Errno | checked_index_of (const agent_t &, size_t &) const |
le::Errno | mst_broadcast (const msg::Type, const msg::Data &, StaticQueue< Msg, MSG_Q_SIZE > &buf, size_t &) const |
le::Errno | mst_convergecast (const msg::Type, const msg::Data &, StaticQueue< Msg, MSG_Q_SIZE > &buf, size_t &) const |
le::Errno | typecast (const status_t status, const msg::Type, const msg::Data &, StaticQueue< Msg, MSG_Q_SIZE > &buf, size_t &) const |
The main state machine for the GHS algorithm
GhsState is the message-driven state machine that executes the GHS algorithm. It receives incoming messages from a communication layer, and returns the next batch of messages to send. When completed, is_converged() will return true.
You are responsible for describing the communication graph by calling, probably, set_edge() and then starting the algorithm by calling start_round() on at least one node (the root), but most likely just call it on all nodes, which will generate the first set of messages to send.
Then, as response messages come in from other nodes, just feed them into process() until is_converged() is true.
GhsState::GhsState | ( | agent_t | my_id, |
Edge * | edges, | ||
size_t | num_edges | ||
) |
Initializes the state of the GHS algorithm for this particular node.
Requires a agent_t to represent the node id, which will be used in all incoming and outgoing mesasages (unique among all agents).
Requires a list of le::ghs::Edge structures that represent the communication links to other agents that will not be modified during execution.
The edge list may contain any number of edges (up to NUM_AGENTS). This class will ignore (not copy in) any edge that:
The following conditions will produce undefined behavior:
After the construction, you can verify the number of copied edges with get_n_peers().
my_id | of type agent_t that tells the class which edges to consider |
edges | a set of le::ghs::Edge structures, which are filtered and stored internally to determine message destinations. |
num_edges | the length of the edge set |
le::Errno GhsState::checked_index_of | ( | const agent_t & | who, |
size_t & | idx | ||
) | const |
A much-called function that returns the index of the given agent. The index corresponds to a number 0 to N-1 for N agents, such that all data about that agent can be stored in consecutive memory. This is not a hash function! It simply searches as an O(n) operation, the memory for the matching ID.
size_t GhsState::delayed_count | ( | ) | const |
Returns the number of agents from which we have received an IN_PART message that we have not responded to.
le::Errno GhsState::get_edge | ( | const agent_t & | to, |
Edge & | out | ||
) | const |
Populates the given edge with any stored edge that connects this agent to another agent. If we are unaware of that agent or do not have an edge, return error code.
to | an agent_t to look up |
out | and Edge to populate as an out parameter |
agent_t GhsState::get_id | ( | ) | const |
Returns whatever was set (or initialized) as the agent_t for this state machine
Never fails to return
agent_t GhsState::get_leader_id | ( | ) | const |
Returns whatever I believe my leader is
level_t GhsState::get_level | ( | ) | const |
Returns whatever I believe this partition's level is
|
inline |
Returns the number of peers, which is a counter that is incremented every time you add_edge_to(id) (or variant), with a new id.
agent_t GhsState::get_parent_id | ( | ) | const |
Returns whatever I believe my parent is
le::Errno GhsState::get_response_prompt | ( | const agent_t & | who, |
msg::InPartPayload & | m | ||
) |
Returns the message that triggered a delay in response.
agent_t | who sent the message |
InPartPayload | the outgoing payload of the message that we cannot respond to yet |
bool GhsState::has_edge | ( | const agent_t | to | ) | const |
bool GhsState::is_converged | ( | ) | const |
le::Errno GhsState::is_response_required | ( | const agent_t & | who, |
bool & | response_required | ||
) |
returns the response-delayed status for the given agent.
agent_t | who |
bool | waiting to send (true) or not waiting (false) |
le::Errno GhsState::is_waiting_for | ( | const agent_t & | who, |
bool & | out_waiting_for | ||
) |
returns the waiting status for the given agent.
agent_t | who |
bool | waiting for response (true) or not waiting for response (false) |
le::Errno GhsState::mst_broadcast | ( | const msg::Type | , |
const msg::Data & | , | ||
StaticQueue< Msg, MSG_Q_SIZE > & | buf, | ||
size_t & | |||
) | const |
Sends messages to MST child links only. There are very good reasons for using MST links even for non-ghs messages, so this is public.
For example, this ensures each node only receives one copy, even if it is a "bottleneck" leading towards many agents.
Functionally equivalent to:
msg::Type | denoting what type of message to send |
msg::Data | denoting what message data to broadcast |
StaticQueue | in which to queue the outgoing messages |
size_t | denoting how many messages were enqueued only if OK is returned. |
le::Errno GhsState::mst_convergecast | ( | const msg::Type | , |
const msg::Data & | , | ||
StaticQueue< Msg, MSG_Q_SIZE > & | buf, | ||
size_t & | |||
) | const |
The opposite of mst_broadcast, will send messages "UP" the MST to the root.
useful for conducting "reduce" operations on an MST, assuming it is combined with a useful data reduction strategy.
In GHS, the reduction strategy is to compare msg::SrchRetPayload from all incoming MST links, and pass the minimum weight edge up to the parent.
Is actually implemented with a search across all edges for one of type MST and with peer matching our parent id.
msg::Type | denoting what type of message to send |
msg::Data | denoting what message data to broadcast |
StaticQueue | in which to queue the outgoing messages |
size_t | denoting how many messages were enqueued only if OK is returned. |
Edge GhsState::mwoe | ( | ) | const |
Returns the current minimum weight outgoing edge (MWOE).
This is the edge we would add to our partition if you forced us to chose from our minimum spanning tree rooted at ourself. To find the global MWOE, these are passed UP the MST using mst_convergecast(), with a msg::SrchRetPayload. At each node, the msg::SrchRetPayload is compared to our mwoe() to determine the actual best edge all the way up to the root of the MST for this partition. After that, a msg::JoinUsPayload is sent back from the root using mst_broadcast() to trigger the process of adding that edge to the MST
le::Errno GhsState::process | ( | const Msg & | msg, |
StaticQueue< Msg, MSG_Q_SIZE > & | outgoing_buffer, | ||
size_t & | sz | ||
) |
The main class entry point. It will puplate the outgoing_buffer with message that should be sent as a response to the passed-in message. You can execute the entire algorithm simply by calling process() with a msg::SrchPayload message properly constructed (but use start_round() for this), then feeding in all the response messages.
Msg | to process |
StaticQueue | into which to push the response messages |
sz | the size_t that will be set to the number of messages added to outgoing_buffer on success, or left unset otherwise |
le::Errno GhsState::start_round | ( | StaticQueue< Msg, MSG_Q_SIZE > & | outgoing_msgs, |
size_t & | |||
) |
ONLY IF this node is the root of an MST (even an MST with only itself as a member) THEN this function will enqueue the first set of messages to send to all peers, and set up the internal state of the algorithm to be ready to process the responses.
In short it:
Calling start_round() while in the middle of a round will essentially lose all state, such that incomign messages that are not a response to these outgoing messages will likely cause errors.
However, no edge statuses are changed, so executing start_round is safe if you already know of some MST links and have edited them in, or have somehow terminated a round and want to resume it.
StaticQeueue | in which to enque outgoing messages |
size_t | the number of messages enque'd |
Queue up the start of the round
le::Errno GhsState::typecast | ( | const status_t | status, |
const msg::Type | , | ||
const msg::Data & | , | ||
StaticQueue< Msg, MSG_Q_SIZE > & | buf, | ||
size_t & | |||
) | const |
Filters edges by msgtype
, and sends outgoing message along those that match.
status_t | the edge status along which to send messages. |
msg::Type | denoting what type of message to send |
msg::Data | denoting what message data to broadcast |
StaticQueue | in which to queue the outgoing messages |
size_t | denoting how many messages were enqueued only if OK is returned. |
size_t GhsState::waiting_count | ( | ) | const |
Returns the number of agents to which we have already sent IN_PART messages, but from which we have not yet received ACK_PART or NACK_PART messages.