cluck 1.0.1
The cluster lock service.
Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
cluck_daemon::cluckd Class Reference

Class handling intercomputer locking. More...

#include <cluckd.h>

Public Types

typedef std::shared_ptr< cluckdpointer_t
 

Public Member Functions

 cluckd (cluckd const &rhs)=delete
 
 cluckd (int argc, char *argv[])
 Initializes a cluckd object.
 
virtual ~cluckd ()
 Do some clean ups.
 
void add_connections ()
 Finish the cluck daemon initialization.
 
void cleanup ()
 Clean timed out entries if any.
 
void election_status ()
 Check the status of the election.
 
ticket::pointer_t find_first_lock (std::string const &lock_name)
 
int get_computer_count () const
 Return the number of known computers running cluckd.
 
ticket::key_map_t const get_entering_tickets (std::string const &lock_name)
 Get a reference to the list of entering tickets.
 
ticket::ticket_id_t get_last_ticket (std::string const &lock_name)
 Determine the last ticket defined in this cluck daemon.
 
computer::pointer_t get_leader_a () const
 Get pointer to leader A.
 
computer::pointer_t get_leader_b () const
 Get pointer to leader B.
 
std::string const & get_server_name () const
 Get the name of the server we are running on.
 
bool is_daemon_ready () const
 Check whether the cluck daemon is ready to process lock requests.
 
computer::pointer_t is_leader (std::string id=std::string()) const
 Search for a leader.
 
void lock_exiting (ed::message &msg)
 Used to simulate a LOCK_EXITING message.
 
void msg_absolutely (ed::message &msg)
 Lock the resource after confirmation that client is alive.
 
void msg_activate_lock (ed::message &msg)
 Acknowledge the ACTIVATE_LOCK with what we think is our first lock.
 
void msg_add_ticket (ed::message &msg)
 Add a ticket from another cluckd.
 
void msg_clock_stable (ed::message &msg)
 Message telling us whether the clock is stable.
 
void msg_cluster_down (ed::message &msg)
 The communicatord lost too many connections.
 
void msg_cluster_up (ed::message &msg)
 Cluster is ready, send the LOCK_STARTED message.
 
void msg_drop_ticket (ed::message &msg)
 One of the cluckd processes asked for a ticket to be dropped.
 
void msg_get_max_ticket (ed::message &msg)
 Search for the largest ticket.
 
void msg_info (ed::message &msg)
 Return a JSON with the state of this cluckd object.
 
void msg_list_tickets (ed::message &msg)
 Reply to the LIST_TICKETS message with the TICKET_LIST.
 
void msg_lock (ed::message &msg)
 Lock the named resource.
 
void msg_lock_activated (ed::message &msg)
 Acknowledgement of the lock to activate.
 
void msg_lock_entered (ed::message &msg)
 Tell the specified ticket LOCK_ENTERED was received.
 
void msg_lock_entering (ed::message &msg)
 Create an entering ticket.
 
void msg_lock_exiting (ed::message &msg)
 Exit a ticket.
 
void msg_lock_failed (ed::message &msg)
 Acknowledge a lock failure.
 
void msg_lock_leaders (ed::message &msg)
 The list of leaders.
 
void msg_lock_started (ed::message &msg)
 Called whenever a cluck computer is acknowledging itself.
 
void msg_lock_status (ed::message &msg)
 A service asked about the lock status.
 
void msg_lock_tickets (ed::message &msg)
 Another cluckd is sending us its list of tickets.
 
void msg_max_ticket (ed::message &msg)
 Got the largest ticket from another leader.
 
void msg_server_gone (ed::message &msg)
 Called whenever a remote connection is disconnected.
 
void msg_status (ed::message &msg)
 With the STATUS message we know of new communicatord services.
 
void msg_ticket_added (ed::message &msg)
 Acknowledgement that the ticket was properly added.
 
void msg_ticket_ready (ed::message &msg)
 Let other leaders know that the ticket is ready.
 
void msg_unlock (ed::message &msg)
 Unlock the resource.
 
cluckdoperator= (cluckd const &rhs)=delete
 
void run ()
 Run the cluck daemon.
 
void send_lock_started (ed::message const *msg)
 
std::string serialized_tickets ()
 
void set_my_ip_address (addr::addr const &a)
 
void set_ticket (std::string const &object_name, std::string const &key, ticket::pointer_t ticket)
 Set the ticket.
 
void stop (bool quitting)
 Called whenever we receive the STOP command or equivalent.
 
std::string ticket_list () const
 Generate the output for "cluck-status --list".
 

Private Member Functions

void activate_first_lock (std::string const &object_name)
 Make sure the very first ticket is marked as LOCKED.
 
void check_lock_status ()
 
void forward_message_to_leader (ed::message &message)
 Forward a user message to a leader.
 
bool get_parameters (ed::message const &message, std::string *object_name, ed::dispatcher_match::tag_t *tag, pid_t *client_pid, cluck::timeout_t *timeout, std::string *key, std::string *source)
 Try to get a set of parameters.
 
void synchronize_leaders ()
 Synchronize leaders.
 

Private Attributes

ed::communicator::pointer_t f_communicator = ed::communicator::pointer_t()
 
computer::map_t f_computers = computer::map_t()
 
snapdev::timespec_ex f_election_date = snapdev::timespec_ex()
 
ticket::object_map_t f_entering_tickets = ticket::object_map_t()
 
interrupt::pointer_t f_interrupt = interrupt::pointer_t()
 
computer::vector_t f_leaders = computer::vector_t()
 
bool f_lock_status = false
 
message_cache::list_t f_message_cache = message_cache::list_t()
 
messenger::pointer_t f_messenger = messenger::pointer_t()
 
std::string f_my_id = std::string()
 
addr::addr f_my_ip_address = addr::addr()
 
std::size_t f_neighbors_count = 0
 
std::size_t f_neighbors_quorum = 0
 
int f_next_leader = 0
 
advgetopt::getopt f_opts
 
time_t f_pace_lockstarted = 0
 
std::string f_server_name = std::string()
 
bool f_stable_clock = false
 
cluck::timeout_t f_start_time = cluck::timeout_t()
 
ticket::serial_t f_ticket_serial = 0
 
ticket::object_map_t f_tickets = ticket::object_map_t()
 
timer::pointer_t f_timer = timer::pointer_t()
 

Detailed Description

This class is used in order to create intercomputer locks on request.

The class uses Snap! Communicator messages and implements the LOCK and UNLOCK commands and sends the LOCKED and UNLOCKED commands to its senders.

The system makes use of the Lamport's Bakery Algorithm. This is explained in the ticket class.

Note
At this time, there is one potential problem that can arise: the lock may fail to concretize because the computer to which you first sent the LOCK message goes down in some way. The other cluck computers will have no clue by which computer the lock was being worked on and whether one of them should take over. One way to remediate is to run one instance of cluck on each computer on which a lock is likely to happen. Then the LOCK message will be proxied to the proper destination (a leader).
Warning
The LOCK mechanism uses the system clock of each computer to know when a lock times out. You are responsible for making sure that all those computers have a synchronized clocked (i.e. run a timed daemon such as ntpd). The difference in time should be as small as possible. The precision required by cluck is around 1 second.

The following shows the messages used to promote 3 leaders, in other words it shows how the election process happens. The election itself is done on the computer that is part of the cluster considered to be up and which has the smallest IP address. That's the one computer that will send the LOCKLEADERS. As soon as that happens all the other nodes on the cluster know the leaders and inform new nodes through the LOCKSTARTED message.

msc_inline_mscgraph_3
See also
ticket

Definition at line 47 of file cluckd.h.

Member Typedef Documentation

◆ pointer_t

typedef std::shared_ptr<cluckd> cluck_daemon::cluckd::pointer_t

Definition at line 50 of file cluckd.h.

Constructor & Destructor Documentation

◆ cluckd() [1/2]

cluck_daemon::cluckd::cluckd ( int  argc,
char *  argv[] 
)

This function parses the command line arguments, reads configuration files, setups the logger.

It also immediately executes a –help or a –version command line option and exits the process if these are present.

Parameters
[in]argcThe number of arguments in the argv array.
[in]argvThe array of argument strings.

Definition at line 323 of file cluckd.cpp.

References f_messenger, f_opts, f_server_name, and f_start_time.

◆ cluckd() [2/2]

cluck_daemon::cluckd::cluckd ( cluckd const &  rhs)
delete

◆ ~cluckd()

cluck_daemon::cluckd::~cluckd ( )
virtual

At this point, the destructor is present mainly because we have some virtual functions.

Definition at line 366 of file cluckd.cpp.

Member Function Documentation

◆ activate_first_lock()

void cluck_daemon::cluckd::activate_first_lock ( std::string const &  object_name)
private

This function is called whenever the f_tickets map changes (more specifically, one of its children) to make sure that the first ticket is clearly marked as being locked. Most of the time this happens when we add and when we remove tickets.

Note that the function may be called many times even though the first ticket does not actually change. Generally this is fine although each time it sends an ACTIVATE_LOCK message so we want to limit the number of calls to make sure we do not send too many possibly confusing messages.

Note
We need the ACTIVATE_LOCK and LOCK_ACTIVATED messages to make sure that we only activate the very first lock which we cannot be sure of on our own because all the previous messages are using the QUORUM as expected and thus our table of locks may not be complete at any one time.
Parameters
[in]object_nameThe name of the object which very first ticket may have changed.

Definition at line 1328 of file cluckd.cpp.

References cluck_daemon::ticket::activate_lock(), and find_first_lock().

Referenced by cleanup(), msg_drop_ticket(), msg_lock_exiting(), msg_lock_failed(), and msg_unlock().

◆ add_connections()

void cluck_daemon::cluckd::add_connections ( )

This function creates all the connections used by the cluck daemon.

Note
This is separate from the run() function so we can run unit tests against the cluck daemon.
See also
run()

Definition at line 381 of file cluckd.cpp.

References f_communicator, f_interrupt, f_messenger, and f_timer.

◆ check_lock_status()

void cluck_daemon::cluckd::check_lock_status ( )
private

◆ cleanup()

void cluck_daemon::cluckd::cleanup ( )

This function goes through the list of tickets and entering entries and removes any one of them that timed out. This is important if a process dies and does not properly remove its locks.

When the timer gets its process_timeout() function called, it ends up calling this function to clean up any lock that has timed out.

Definition at line 1688 of file cluckd.cpp.

References activate_first_lock(), f_entering_tickets, f_message_cache, f_messenger, f_tickets, f_timer, and get_parameters().

Referenced by msg_activate_lock(), msg_drop_ticket(), msg_get_max_ticket(), msg_lock(), msg_lock_entering(), msg_lock_exiting(), msg_lock_failed(), msg_lock_tickets(), msg_unlock(), and cluck_daemon::timer::process_timeout().

◆ election_status()

void cluck_daemon::cluckd::election_status ( )

This function checks whether the leaders were already elected. If so, then nothing happens.

Otherwise, it checks the state of the election:

  • leaders are not already elected
  • this cluckd received its own IP address
  • we do not yet know how many neighbors there are in our cluster
  • the cluster as a sufficient (quorum) number of computers to support the lock mechanism properly (2 of the 3 leaders or a cluster quorum when the cluster has 4 or more computers)
  • we have the lowest IP address (only the cluck daemon with the lowest IP can decide which computers are the leaders
  • not too many of the cluckd are opt out of leadership

Definition at line 972 of file cluckd.cpp.

References f_computers, f_election_date, f_leaders, f_messenger, f_my_ip_address, f_neighbors_count, f_neighbors_quorum, cluck_daemon::computer::PRIORITY_OFF, and synchronize_leaders().

Referenced by msg_cluster_up(), msg_lock_started(), and msg_server_gone().

◆ find_first_lock()

ticket::pointer_t cluck_daemon::cluckd::find_first_lock ( std::string const &  lock_name)

Definition at line 1343 of file cluckd.cpp.

References f_tickets.

Referenced by activate_first_lock(), and msg_activate_lock().

◆ forward_message_to_leader()

void cluck_daemon::cluckd::forward_message_to_leader ( ed::message &  msg)
private

The user may send a LOCK or an UNLOCK command to the cluck daemon. Those messages need to be forwarded to a leader to work as expected. If we are not a leader, then we need to call this function to forward the message (this daemon acts as a proxy).

Note that we do not make a copy of the message because we do not expect it to be used any further after this call so we may as well update that message. It should not be destructive at all anyway.

Parameters
[in,out]msgThe message being forwarded to a leader.

Definition at line 1648 of file cluckd.cpp.

References f_leaders, f_messenger, and f_next_leader.

Referenced by msg_lock(), and msg_unlock().

◆ get_computer_count()

int cluck_daemon::cluckd::get_computer_count ( ) const

This function is used by the ticket objects to calculate the quorum so as to know how many computers need to reply to our messages before we can be sure we got the correct results.

Returns
The number of instances of cluckd running and connected.

Definition at line 445 of file cluckd.cpp.

References f_computers.

Referenced by cluck_daemon::ticket::one_leader().

◆ get_entering_tickets()

ticket::key_map_t const cluck_daemon::cluckd::get_entering_tickets ( std::string const &  object_name)

This function returns a constant reference to the list of entering tickets. This is used by the ticket::add_ticket() function in order to know once all entering tickets are done so the algorithm can move forward.

Parameters
[in]object_nameThe name of the object being locked.
Returns
A constant copy of the list of entering tickets.

Definition at line 1930 of file cluckd.cpp.

References f_entering_tickets.

Referenced by cluck_daemon::ticket::add_ticket().

◆ get_last_ticket()

ticket::ticket_id_t cluck_daemon::cluckd::get_last_ticket ( std::string const &  object_name)

This function loops through the existing tickets and returns the largest ticket number it finds.

Note that the number returned is the last ticket. At some point, the caller needs to add one to this number before assigning the result to a new ticket.

If no ticket were defined for object_name or we are dealing with that object very first ticket, then the function returns NO_TICKET (which is 0).

Parameters
[in]object_nameThe name of the object for which the last ticket number is being sought.
Returns
The last ticket number or NO_TICKET.

Definition at line 1871 of file cluckd.cpp.

References f_tickets, and cluck_daemon::ticket::NO_TICKET.

Referenced by cluck_daemon::ticket::entered(), and msg_get_max_ticket().

◆ get_leader_a()

computer::pointer_t cluck_daemon::cluckd::get_leader_a ( ) const

We have 1 to 3 leaders in each cluck daemon. There is "self", leader A, and leader B. This function returns leader A or a null pointer if there is only one leader.

Leader A is either f_leaders[0] or f_leaders[1]. If "self" is f_leaders[0] then the function returns f_leaders[1], If "self" is f_leaders[1], then the function returns f_leaders[0].

Note
In a setup where you have only 1 computer total, this function always returns a null pointer.
If the elections have not yet happened, this function always returns a null pionter.
Returns
A pointer to the leader A computer or nullptr if there is no such computer.

Definition at line 701 of file cluckd.cpp.

References f_leaders, and is_leader().

Referenced by cluck_daemon::ticket::send_message_to_leaders(), and synchronize_leaders().

◆ get_leader_b()

computer::pointer_t cluck_daemon::cluckd::get_leader_b ( ) const

We have 1 to 3 leaders in each cluck daemon. There is "self", leader A, and leader B. This function returns leader B or a null pointer if there is only one leader.

Leader B is either f_leaders[1] or f_leaders[2]. If "self" is f_leaders[1] then the function returns f_leaders[2], If "self" is f_leaders[2], then the function returns f_leaders[1].

Note
In a setup where you have only 1 or 2 computers total, this function always returns a null pointer.
If the elections have not yet happened, this function always returns a null pionter.
Returns
A pointer to the leader B computer or nullptr if there is no such computer.

Definition at line 748 of file cluckd.cpp.

References f_leaders, and is_leader().

Referenced by cluck_daemon::ticket::send_message_to_leaders(), and synchronize_leaders().

◆ get_parameters()

bool cluck_daemon::cluckd::get_parameters ( ed::message const &  msg,
std::string *  object_name,
ed::dispatcher_match::tag_t *  tag,
pid_t *  client_pid,
cluck::timeout_t timeout,
std::string *  key,
std::string *  source 
)
private

This function attempts to get the specified set of parameters from the specified message.

The function throws if a parameter is missing or invalid (i.e. passed a string when an integer was expected).

When defined, the client_pid parameter is expected to be a positive integer. Any other number makes the function emit an error and return false.

Note
The timeout parameter is always viewed as optional. It is set to "now + cluck::CLUCK_LOCK_DEFAULT_TIMEOUT" if undefined in the message. If specified in the message, there is no minimum or maximum (i.e. it may already have timed out).
Parameters
[in]msgThe message from which we get parameters.
[out]object_nameA pointer to an std::string that receives the object name.
[out]tagA pointer to a tag_t that receives the tag number.
[out]client_pidA pointer to a pid_t that receives the client pid.
[out]timeoutA pointer to an cluck::timeout_t that receives the timeout date.
[out]keyA pointer to an std::string that receives the key parameter.
[out]sourceA pointer to an std::string that receives the source parameter.
Returns
true if all specified parameters could be retrieved as expected, false if parameters are either missing or invalid.

Definition at line 2017 of file cluckd.cpp.

References cluck::get_lock_obtention_timeout().

Referenced by cleanup(), msg_activate_lock(), msg_add_ticket(), msg_drop_ticket(), msg_get_max_ticket(), msg_lock(), msg_lock_activated(), msg_lock_entered(), msg_lock_entering(), msg_lock_exiting(), msg_lock_failed(), msg_max_ticket(), msg_ticket_added(), msg_ticket_ready(), and msg_unlock().

◆ get_server_name()

std::string const & cluck_daemon::cluckd::get_server_name ( ) const

This function returns the name of the server this instance of cluck is running. It is used by the ticket implementation to know whether to send a reply to the cluck object (i.e. at this time we can send messages to that object only from the server it was sent from).

Returns
The name of the server cluck is running on.

Definition at line 461 of file cluckd.cpp.

References f_server_name.

Referenced by cluck_daemon::ticket::lock_activated(), and cluck_daemon::ticket::lock_failed().

◆ is_daemon_ready()

bool cluck_daemon::cluckd::is_daemon_ready ( ) const

This function checks whether the cluck daemon is ready by looking at whether it has leaders and if so, whether each leader is connected.

Once both tests succeeds, this cluck daemon can forward the locks to the leaders. If it is a leader itself, it can enter a ticket in the selection and message both of the other leaders about it.

Returns
true once locks can be processed.

Definition at line 478 of file cluckd.cpp.

References f_computers, f_leaders, f_messenger, f_neighbors_count, f_neighbors_quorum, f_pace_lockstarted, f_stable_clock, and send_lock_started().

Referenced by check_lock_status(), msg_info(), msg_lock(), msg_lock_entering(), msg_lock_status(), and msg_unlock().

◆ is_leader()

computer::pointer_t cluck_daemon::cluckd::is_leader ( std::string  id = std::string()) const

This function goes through the list of leaders to determine whether the specified identifier represents a leader. If so it returns a pointer to that leader computer object.

When the function is called with an empty string as the computer identifier, this computer is checked to see whether it is a leader.

Warning
This function is considered slow since it goes through the list of leaders on each call. On the other hand, it's only 1 to 3 leaders. Yet, you should cache the result within your function if you need the result multiple times, as in:
if(leader != nullptr)
{
// ... use `leader` any number of times ...
}
computer::pointer_t is_leader(std::string id=std::string()) const
Search for a leader.
Definition cluckd.cpp:658
std::shared_ptr< computer > pointer_t
Definition computer.h:49
This is done that way because the function may return a different result over time (i.e. if a re-election happens). So you do not want to cache the results between calls to your function.
Parameters
[in]idThe identifier of the leader to search, if empty, default to f_my_id (i.e. whether this cluckd is a leader).
Returns
The leader computer::pointer_t or a null pointer.

Definition at line 658 of file cluckd.cpp.

References f_leaders, and f_my_id.

Referenced by get_leader_a(), get_leader_b(), msg_lock(), msg_lock_started(), msg_unlock(), and synchronize_leaders().

◆ lock_exiting()

void cluck_daemon::cluckd::lock_exiting ( ed::message &  msg)

This function is called to simulate sending a LOCK_EXITING to the cluckd object from the ticket object.

Parameters
[in]msgThe LOCK_EXITING message with proper object name, tag, and key.

Definition at line 1960 of file cluckd.cpp.

References msg_lock_exiting().

Referenced by cluck_daemon::ticket::ticket_added().

◆ msg_absolutely()

void cluck_daemon::cluckd::msg_absolutely ( ed::message &  msg)

This message is expected just after we sent an ALIVE message to the client.

Whenever a leader dies, we suspect that the client may have died with it so we send it an ALIVE message to know whether it is worth the trouble of entering that lock.

Parameters
[in]msgThe ABSOLUTELY message to handle.

Definition at line 2109 of file cluckd.cpp.

References f_entering_tickets, and f_messenger.

Referenced by cluck_daemon::messenger::messenger().

◆ msg_activate_lock()

void cluck_daemon::cluckd::msg_activate_lock ( ed::message &  msg)

This function replies to an ACTIVATE_LOCK request with what we think is the first lock for the specified object.

Right now, we disregard the specified key. There is nothing we can really do with it here.

If we do not have a ticket for the specified object (something that could happen if the ticket just timed out) then we still have to reply, only we let the other leader know that we have no clue what he is talking about.

Parameters
[in]msgThe ACTIVATE_LOCK message.

Definition at line 2193 of file cluckd.cpp.

References cleanup(), f_messenger, find_first_lock(), get_parameters(), cluck_daemon::ticket::get_ticket_key(), and cluck_daemon::ticket::lock_activated().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_add_ticket()

void cluck_daemon::cluckd::msg_add_ticket ( ed::message &  msg)

Tickets get duplicated on the cluckd leaders.

Note
Although we only need a QUORUM number of nodes to receive a copy of the data, the data still get broadcast to all the cluck leaders. After this message arrives any one of the cluck process can handle the unlock if the UNLOCK message gets sent to another process instead of the one which first created the ticket. This is the point of the implementation since we want to be fault tolerant (as in if one of the leaders goes down, the locking mechanism still works).
Parameters
[in]msgThe ADD_TICKET message being handled.

Definition at line 2254 of file cluckd.cpp.

References f_entering_tickets, f_messenger, f_tickets, get_parameters(), and set_ticket().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_clock_stable()

void cluck_daemon::cluckd::msg_clock_stable ( ed::message &  msg)

When rebooting, the NTP system takes a little time to get started. The communicator daemon checks the state of that NTP and sends messages to other services about the current state.

Once the clock is considered stable, the function sets the f_stable_clock flag to true and it remains true forever. This is done that way because at the moment I really don't have the time to consider changing the implementation to support a drop of the clock when it pretty much never happens.

Parameters
[in,out]msgThe CLOCK_STABLE message.

Definition at line 2472 of file cluckd.cpp.

References check_lock_status(), and f_stable_clock.

Referenced by cluck_daemon::messenger::messenger().

◆ msg_cluster_down()

void cluck_daemon::cluckd::msg_cluster_down ( ed::message &  msg)

When the cluster is not complete, the CLUSTER_DOWN message gets sent by the communicatord. We need to stop offering locks at that point. Locks that are up are fine, but new locks are not possible.

Parameters
[in]msgThe CLUSTER_DOWN message.

Definition at line 2492 of file cluckd.cpp.

References check_lock_status(), and f_leaders.

Referenced by cluck_daemon::messenger::messenger().

◆ msg_cluster_up()

void cluck_daemon::cluckd::msg_cluster_up ( ed::message &  msg)

Our cluster is finally ready, so we can send the LOCK_STARTED and work on a leader election if still required.

Parameters
[in]msgCLUSTER_UP message we are dealing with.

Definition at line 2521 of file cluckd.cpp.

References check_lock_status(), election_status(), f_computers, f_my_id, f_my_ip_address, f_neighbors_count, f_neighbors_quorum, f_opts, f_server_name, f_start_time, cluck_daemon::computer::PRIORITY_MAX, cluck_daemon::computer::PRIORITY_OFF, cluck_daemon::computer::PRIORITY_USER_MIN, and send_lock_started().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_drop_ticket()

void cluck_daemon::cluckd::msg_drop_ticket ( ed::message &  msg)

This function searches for the specified ticket and removes it from this cluckd.

If the specified ticket does not exist, nothing happens.

Warning
The DROP_TICKET event includes either the ticket key (if available) or the entering key (when the ticket key was not yet available). Note that the ticket key should always exists by the time a DROP_TICKET happens, but just in case this allows the dropping of a ticket at any time.
Parameters
[in]msgThe DROP_TICKET message.

Definition at line 2581 of file cluckd.cpp.

References activate_first_lock(), cleanup(), f_entering_tickets, f_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_get_max_ticket()

void cluck_daemon::cluckd::msg_get_max_ticket ( ed::message &  msg)

This function searches the list of tickets for the largest one and returns that number.

Note that this is specific to a given lock as defined by the object name of that lock. It is not the largest of all tickets across the entire set.

The function replies with the MAX_TICKET message.

Parameters
[in]msgThe message just received.

Definition at line 2671 of file cluckd.cpp.

References cleanup(), f_messenger, get_last_ticket(), and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_info()

void cluck_daemon::cluckd::msg_info ( ed::message &  msg)

This function generates a JSON string of the current state of this cluck daemon and replies with that message back to the caller.

This is primarily used to debug a cluckd instance and make sure that the state is how you would otherwise expect it to be.

Todo:
The list of tickets uses the internal serialization mechanism, which creates a much small array of tickets. At some point, we should transform that to output JSON instead.
Parameters
[in]msgThe INFO message.

Definition at line 790 of file cluckd.cpp.

References f_computers, f_leaders, f_message_cache, f_messenger, f_my_id, f_my_ip_address, f_neighbors_count, f_neighbors_quorum, is_daemon_ready(), and serialized_tickets().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_list_tickets()

void cluck_daemon::cluckd::msg_list_tickets ( ed::message &  msg)

This function gets called whenever the command line tool (cluckd) is run with the --list command line option. It generates a list of tickets and sends that back to the tool as a TICKET_LIST message.

Parameters
[in]msgThe LIST_TICKETS message.

Definition at line 2707 of file cluckd.cpp.

References f_messenger, and ticket_list().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock()

void cluck_daemon::cluckd::msg_lock ( ed::message &  msg)

This function locks the specified resource object_name. It returns when the resource is locked or when the lock timeout is reached.

See the ticket class for more details about the locking mechanisms (algorithm and MSC implementation).

Note that if lock() is called with an empty string then the function unlocks the lock and returns immediately with false. This is equivalent to calling unlock().

Note
The function reloads all the parameters (outside of the table) because we need to support a certain amount of dynamism. For example, an administrator may want to add a new host on the system. In that case, the list of host changes and it has to be detected here.
Attention
The function accepts a "serial" parameter in the message. This is only used internally when a leader is lost and a new one is assigned a lock which would otherwise fail.
Warning
The object name is left available in the lock table. Do not use any secure/secret name/word, etc. as the object name.
Bug:
At this point there is no proper protection to recover from errors that would happen while working on locking this entry. This means failures may result in a lock that never ends.
Parameters
[in]msgThe lock message.
See also
unlock()

Definition at line 2753 of file cluckd.cpp.

References cleanup(), cluck::CLUCK_DEFAULT_TIMEOUT, cluck::CLUCK_MAXIMUM_ENTERING_LOCKS, cluck::CLUCK_MINIMUM_TIMEOUT, cluck::CLUCK_UNLOCK_MINIMUM_TIMEOUT, cluck_daemon::ticket::entering(), f_entering_tickets, f_leaders, f_message_cache, f_messenger, f_my_id, f_ticket_serial, f_tickets, f_timer, forward_message_to_leader(), get_parameters(), is_daemon_ready(), is_leader(), cluck_daemon::ticket::set_alive_timeout(), cluck_daemon::ticket::set_serial(), and cluck_daemon::ticket::set_unlock_duration().

Referenced by cluck_daemon::messenger::messenger(), check_lock_status(), and synchronize_leaders().

◆ msg_lock_activated()

void cluck_daemon::cluckd::msg_lock_activated ( ed::message &  msg)

This function is an acknowledgement that the lock can now be activated. This is true only if the 'key' and 'other_key' are a match, though.

Parameters
[in]msgThe LOCK_ACTIVATED message.

Definition at line 3098 of file cluckd.cpp.

References f_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock_entered()

void cluck_daemon::cluckd::msg_lock_entered ( ed::message &  msg)

This function calls the specified ticket entered() function, which processes the LOCK_ENTERED message and sends the GET_MAX_TICKET message to the other leaders.

Parameters
[in]msgThe LOCK_ENTERED message.

Definition at line 3135 of file cluckd.cpp.

References f_entering_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock_entering()

void cluck_daemon::cluckd::msg_lock_entering ( ed::message &  msg)

When the cluck daemon receives a LOCK message, it sends a LOCK_ENTERING to the other leaders so that way of all them have a complete list of all the tickets.

This function creates an "entering ticket." This is a "real" ticket, but it is still in an "entering" state.

The function sends a LOCK_ENTERED as a reply to the LOCK_ENTERING message.

Note
Since a cluck daemon may receive this message multiple times, if it finds an existing entering ticket with the same parameters (object name and key), then it does not re-create yet another instance.
Parameters
[in]msgThe LOCK_ENTERING message.

Definition at line 3176 of file cluckd.cpp.

References cleanup(), cluck::CLUCK_DEFAULT_TIMEOUT, cluck::CLUCK_MINIMUM_TIMEOUT, cluck::CLUCK_UNLOCK_MINIMUM_TIMEOUT, f_entering_tickets, f_messenger, get_parameters(), is_daemon_ready(), cluck_daemon::ticket::set_owner(), cluck_daemon::ticket::set_serial(), and cluck_daemon::ticket::set_unlock_duration().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock_exiting()

void cluck_daemon::cluckd::msg_lock_exiting ( ed::message &  msg)

This command exits a ticket, which means we got the GET_MAX_TICKET result and thus can be sure that the ticket is properly sorted in the list of tickets.

Parameters
[in]msgThe LOCK_EXITING message.

Definition at line 3353 of file cluckd.cpp.

References activate_first_lock(), cleanup(), f_entering_tickets, f_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger(), and lock_exiting().

◆ msg_lock_failed()

void cluck_daemon::cluckd::msg_lock_failed ( ed::message &  msg)

This function handles the LOCK_FAILED event that another leader may send to us. In that case we have to stop the process.

LOCK_FAILED can happen mainly because of tainted data so we should never get here within a leader. However, with time we may add a few errors which could happen for other reasons than just tainted data.

When this function finds an entering ticket or a plain ticket to remove according to the object name and key found in the LOCK_FAILED message, it forwards the LOCK_FAILED message to the server and service found in the ticket.

Todo:
This function destroys a ticket even if it is already considered locked. Make double sure that this is okay with a LOCK_FAILED sent to the client.
Warning
Although this event should not occur, it is problematic since anyone can send a LOCK_FAILED message here and as a side effect destroy a perfectly valid ticket.
Parameters
[in]msgThe LOCK_FAILED message.

Definition at line 3468 of file cluckd.cpp.

References activate_first_lock(), cleanup(), f_entering_tickets, f_messenger, f_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock_leaders()

void cluck_daemon::cluckd::msg_lock_leaders ( ed::message &  msg)

This function receives the list of leaders after an election.

Parameters
[in]msgThe LOCK_LEADERS message.

Definition at line 3584 of file cluckd.cpp.

References check_lock_status(), f_computers, f_election_date, f_leaders, f_next_leader, and synchronize_leaders().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock_started()

void cluck_daemon::cluckd::msg_lock_started ( ed::message &  msg)

This function gets called on a LOCK_STARTED event which is sent whenever a cluck process is initialized on a computer.

The message is expected to include the computer name. At this time we cannot handle having more than one instance one the same computer.

Parameters
[in]msgThe LOCK_STARTED message.

Definition at line 3655 of file cluckd.cpp.

References check_lock_status(), election_status(), f_computers, f_election_date, f_leaders, f_server_name, cluck_daemon::computer::get_name(), is_leader(), send_lock_started(), cluck_daemon::computer::set_connected(), cluck_daemon::computer::set_id(), and cluck_daemon::computer::set_start_time().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock_status()

void cluck_daemon::cluckd::msg_lock_status ( ed::message &  msg)

The lock status is whether the cluck service is ready to receive LOCK messages (LOCK_READY) or is still waiting on a CLUSTER_UP and LOCK_LEADERS to happen (NO_LOCK).

Note that LOCK messages are accepted while the lock service is not yet ready, however, those are cached and it is more likely that they timeout before the system is ready to process the request.

Parameters
[in]msgThe message to reply to.

Definition at line 3801 of file cluckd.cpp.

References f_messenger, and is_daemon_ready().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_lock_tickets()

void cluck_daemon::cluckd::msg_lock_tickets ( ed::message &  msg)

Whenever a cluckd dies, a new one is quickly promoted as a leader and that new leader would have no idea about the existing tickets (locks) so the other two send it a LOCK_TICKETS message.

The tickets are defined in the parameter of the same name using the serialization function to transform the objects in a string. Here we can unserialize that string accordingly.

First we extract the object name and entering key to see whether we have that ticket already defined. If so, then we unserialize in that existing object. The extraction is additive so we can do it any number of times.

Parameters
[in]msgThe LOCK_TICKETS message.

Definition at line 3831 of file cluckd.cpp.

References cleanup(), cluck::CLUCK_DEFAULT_TIMEOUT, f_entering_tickets, f_leaders, f_messenger, f_server_name, and f_tickets.

Referenced by cluck_daemon::messenger::messenger().

◆ msg_max_ticket()

void cluck_daemon::cluckd::msg_max_ticket ( ed::message &  msg)

This function searches the list of entering tickets for the specified object name and key parameters found in the MAX_TICKET message.

On the first MAX_TICKET received for an entering ticket, that maximum + 1 gets saved in the ticket as its identifier. In other words, we place that ticket at the end of the list.

Note
Whenever a list of locks goes empty, its maximum ticket number returns to the default: NO_TICKET (0). In the unlikely case where the locks happen back to back and thus the list never becomes empty, the maximum ticket number could end up wrapping around. This is an error we can and it has the side effect of killing the cluck daemon.
Parameters
[in]msgThe MAX_TICKET message being handled.

Definition at line 3978 of file cluckd.cpp.

References f_entering_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_server_gone()

void cluck_daemon::cluckd::msg_server_gone ( ed::message &  msg)

This function is used to know that a remote connection was disconnected.

This function handles the HANGUP and DISCONNECTED nessages as required.

This allows us to manage the f_computers list of computers running cluckd services. If a cluckd was affected, we verify we still have enough leaders.

Note
The STATUS message does not directly call this function. Instead, it calls msg_status() which checks that (1) the status is in link with a communicator service and (2) the new service state is "down" and only if so, this function gets called.
Parameters
[in]msgThe DISCONNECTED, HANGUP, or STATUS message.

Definition at line 4021 of file cluckd.cpp.

References check_lock_status(), election_status(), f_computers, f_leaders, f_messenger, and f_server_name.

Referenced by cluck_daemon::messenger::messenger(), and msg_status().

◆ msg_status()

void cluck_daemon::cluckd::msg_status ( ed::message &  msg)

This function captures the STATUS message and if it sees that the name of the service is a remote communicator daemon then it sends a new LOCK_STARTED message to make sure that all cluck daemons are aware of us.

Parameters
[in]msgThe STATUS message.

Definition at line 4097 of file cluckd.cpp.

References msg_server_gone().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_ticket_added()

void cluck_daemon::cluckd::msg_ticket_added ( ed::message &  msg)

This function gets called whenever the ticket was added on another leader.

Parameters
[in]msgThe TICKET_ADDED message being handled.

Definition at line 4134 of file cluckd.cpp.

References f_entering_tickets, f_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_ticket_ready()

void cluck_daemon::cluckd::msg_ticket_ready ( ed::message &  msg)

This message is received when the owner of a ticket marks a ticket as ready. This means the ticket is available for locking.

Parameters
[in]msgThe TICKET_READY message.

Definition at line 4199 of file cluckd.cpp.

References f_tickets, and get_parameters().

Referenced by cluck_daemon::messenger::messenger().

◆ msg_unlock()

void cluck_daemon::cluckd::msg_unlock ( ed::message &  msg)

This function unlocks the resource specified in the call to lock().

Parameters
[in]msgThe unlock message.
See also
msg_lock()

Definition at line 4231 of file cluckd.cpp.

References activate_first_lock(), cleanup(), f_tickets, forward_message_to_leader(), get_parameters(), is_daemon_ready(), and is_leader().

Referenced by cluck_daemon::messenger::messenger().

◆ operator=()

cluckd & cluck_daemon::cluckd::operator= ( cluckd const &  rhs)
delete

◆ run()

void cluck_daemon::cluckd::run ( )

This function is the core function of the daemon. It runs the loop used to lock processes from any number of computers that have access to the cluck daemon network.

See also
add_connections()

Definition at line 421 of file cluckd.cpp.

References f_communicator.

◆ send_lock_started()

void cluck_daemon::cluckd::send_lock_started ( ed::message const *  msg)

◆ serialized_tickets()

std::string cluck_daemon::cluckd::serialized_tickets ( )

Definition at line 1970 of file cluckd.cpp.

References f_tickets.

Referenced by msg_info().

◆ set_my_ip_address()

void cluck_daemon::cluckd::set_my_ip_address ( addr::addr const &  a)

Definition at line 407 of file cluckd.cpp.

References f_my_ip_address.

Referenced by cluck_daemon::messenger::ready().

◆ set_ticket()

void cluck_daemon::cluckd::set_ticket ( std::string const &  object_name,
std::string const &  key,
ticket::pointer_t  ticket 
)

Once a ticket was assigned a valid identifier (see get_last_ticket()) it can be saved as a ticket. This function does that. Now this is an official ticket.

Parameters
[in]object_nameThe name of the object being locked.
[in]keyThe ticket key (3 segments).
[in]ticketThe ticket object being added.

Definition at line 1910 of file cluckd.cpp.

References f_tickets.

Referenced by cluck_daemon::ticket::add_ticket(), and msg_add_ticket().

◆ stop()

void cluck_daemon::cluckd::stop ( bool  quitting)

This function makes sure the cluck daemon exits as quickly as possible. This means unregistering all the daemon's connections from the communicator.

If possible, the function sends an UNREGISTER message to the communicator daemon.

Parameters
[in]quittingSet to true if we received a QUITTING message (false usually means we received a STOP message).

Definition at line 1284 of file cluckd.cpp.

References f_communicator, f_interrupt, f_messenger, and f_timer.

Referenced by cluck_daemon::interrupt::process_signal(), and cluck_daemon::messenger::stop().

◆ synchronize_leaders()

void cluck_daemon::cluckd::synchronize_leaders ( )
private

This function sends various events to the other two leaders in order to get them to synchronize the tickets this cluck daemon currently holds.

Only leaders make use of this function.

Synchronization is necessary whenever a leader dies and another gets elected as a replacement. The replacement would have no idea of the old tickets. This function makes sure that such doesn't occur.

Note
Our test checks the validity when ONE leader is lost. If TWO of the leaders are lost at once, the algorithm may not be 100% reliable. Especially, the remaining leader may not have all the necessary information to restore all the tickets as they were expected to be.
Warning
A ticket that just arrived to a leader and was not yet forwarded to the others with the LOCK_ENTERING message is going to be lost no matter what.

Definition at line 1419 of file cluckd.cpp.

References f_entering_tickets, f_leaders, f_messenger, f_my_id, f_tickets, get_leader_a(), get_leader_b(), is_leader(), and msg_lock().

Referenced by election_status(), and msg_lock_leaders().

◆ ticket_list()

std::string cluck_daemon::cluckd::ticket_list ( ) const

This function loops over the list of tickets and outputs a string that it sends back to the cluck-status --list tool for printing to the administrator.

Returns
A string with the list of all the tickets.

Definition at line 917 of file cluckd.cpp.

References f_tickets.

Referenced by msg_list_tickets().

Member Data Documentation

◆ f_communicator

ed::communicator::pointer_t cluck_daemon::cluckd::f_communicator = ed::communicator::pointer_t()
private

Definition at line 128 of file cluckd.h.

Referenced by add_connections(), run(), and stop().

◆ f_computers

computer::map_t cluck_daemon::cluckd::f_computers = computer::map_t()
private

◆ f_election_date

snapdev::timespec_ex cluck_daemon::cluckd::f_election_date = snapdev::timespec_ex()
private

Definition at line 144 of file cluckd.h.

Referenced by election_status(), msg_lock_leaders(), msg_lock_started(), and send_lock_started().

◆ f_entering_tickets

ticket::object_map_t cluck_daemon::cluckd::f_entering_tickets = ticket::object_map_t()
private

◆ f_interrupt

interrupt::pointer_t cluck_daemon::cluckd::f_interrupt = interrupt::pointer_t()
private

Definition at line 130 of file cluckd.h.

Referenced by add_connections(), and stop().

◆ f_leaders

computer::vector_t cluck_daemon::cluckd::f_leaders = computer::vector_t()
private

◆ f_lock_status

bool cluck_daemon::cluckd::f_lock_status = false
private

Definition at line 136 of file cluckd.h.

Referenced by check_lock_status().

◆ f_message_cache

message_cache::list_t cluck_daemon::cluckd::f_message_cache = message_cache::list_t()
private

Definition at line 141 of file cluckd.h.

Referenced by check_lock_status(), cleanup(), msg_info(), and msg_lock().

◆ f_messenger

messenger::pointer_t cluck_daemon::cluckd::f_messenger = messenger::pointer_t()
private

◆ f_my_id

std::string cluck_daemon::cluckd::f_my_id = std::string()
private

◆ f_my_ip_address

addr::addr cluck_daemon::cluckd::f_my_ip_address = addr::addr()
private

Definition at line 135 of file cluckd.h.

Referenced by election_status(), msg_cluster_up(), msg_info(), and set_my_ip_address().

◆ f_neighbors_count

std::size_t cluck_daemon::cluckd::f_neighbors_count = 0
private

Definition at line 132 of file cluckd.h.

Referenced by election_status(), is_daemon_ready(), msg_cluster_up(), and msg_info().

◆ f_neighbors_quorum

std::size_t cluck_daemon::cluckd::f_neighbors_quorum = 0
private

Definition at line 133 of file cluckd.h.

Referenced by election_status(), is_daemon_ready(), msg_cluster_up(), and msg_info().

◆ f_next_leader

int cluck_daemon::cluckd::f_next_leader = 0
private

Definition at line 140 of file cluckd.h.

Referenced by forward_message_to_leader(), and msg_lock_leaders().

◆ f_opts

advgetopt::getopt cluck_daemon::cluckd::f_opts
private

Definition at line 124 of file cluckd.h.

Referenced by cluckd(), and msg_cluster_up().

◆ f_pace_lockstarted

time_t cluck_daemon::cluckd::f_pace_lockstarted = 0
mutableprivate

Definition at line 146 of file cluckd.h.

Referenced by is_daemon_ready().

◆ f_server_name

std::string cluck_daemon::cluckd::f_server_name = std::string()
private

◆ f_stable_clock

bool cluck_daemon::cluckd::f_stable_clock = false
private

Definition at line 137 of file cluckd.h.

Referenced by is_daemon_ready(), and msg_clock_stable().

◆ f_start_time

cluck::timeout_t cluck_daemon::cluckd::f_start_time = cluck::timeout_t()
private

Definition at line 126 of file cluckd.h.

Referenced by cluckd(), msg_cluster_up(), and send_lock_started().

◆ f_ticket_serial

ticket::serial_t cluck_daemon::cluckd::f_ticket_serial = 0
private

Definition at line 145 of file cluckd.h.

Referenced by msg_lock().

◆ f_tickets

ticket::object_map_t cluck_daemon::cluckd::f_tickets = ticket::object_map_t()
private

◆ f_timer

timer::pointer_t cluck_daemon::cluckd::f_timer = timer::pointer_t()
private

Definition at line 131 of file cluckd.h.

Referenced by add_connections(), cleanup(), msg_lock(), and stop().


The documentation for this class was generated from the following files:

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.