snaplock: snaplock::snaplock_ticket Class Reference

Handle the ticket messages. More...

#include <snaplock.h>

Inheritance diagram for snaplock::snaplock_ticket:
Collaboration diagram for snaplock::snaplock_ticket:
Public Types typedef std::map< QString, pointer_tkey_map_t   typedef std::map< QString, key_map_tobject_map_t   typedef std::shared_ptr< snaplock_ticketpointer_t   typedef int32_t serial_t   typedef uint32_t ticket_id_t   typedef std::vector< pointer_tvector_t   Public Member Functions  snaplock_ticket (snaplock *sl, snaplock_messenger::pointer_t messenger, QString const &object_name, QString const &entering_key, time_t obtention_timeout, snap::snap_lock::timeout_t lock_duration, QString const &server_name, QString const &service_name)    snaplock_ticket (snaplock_ticket const &rhs)=delete   void activate_lock ()  Check whether this ticket can be activated and do so if so. More...
  void add_ticket ()  Send the ADDTICKET message. More...
  void drop_ticket ()  We are done with the ticket. More...
  void entered ()  Tell this entering that we received a LOCKENTERED message. More...
  void entering ()  Enter the mode that lets us retrieve our ticket number. More...
  pid_t get_client_pid () const  Retrieve the client process identifier. More...
  time_t get_current_timeout () const  Get the current lock timeout date. More...
  QString const & get_entering_key () const  Retrieve a reference to the entering key of this ticket. More...
  snap::snap_lock::timeout_t get_lock_duration () const  Retrieve the lock duration. More...
  time_t get_lock_timeout () const  Get the lock timeout date. More...
  QString const & get_object_name () const  Retrieve the object name of this ticket. More...
  time_t get_obtention_timeout () const  Get the obtention timeout date. More...
  QString const & get_owner () const  Return the name of this ticket's owner. More...
  serial_t get_serial () const  Return the serial number of this ticket. More...
  QString const & get_server_name () const  Retrieve the server name of this ticket. More...
  QString const & get_service_name () const  Retrieve the service name of this ticket. More...
  QString const & get_ticket_key () const  Retrieve a reference to the ticket key. More...
  ticket_id_t get_ticket_number () const  Return the ticket number of this ticket. More...
  snap::snap_lock::timeout_t get_unlock_duration () const  Get unlock duration. More...
  bool is_locked () const  Check whether this ticket is locked or not. More...
  void lock_activated ()  Check whether this ticket can be activated and do so if so. More...
  void lock_failed ()  Let the service that wanted this lock know that it failed. More...
  void lock_tickets ()   void max_ticket (int64_t new_max_ticket)  Called whenever a MAXTICKET is received. More...
  snaplock_ticketoperator= (snaplock_ticket const &rhs)=delete   void remove_entering (QString const &key)  Call any time time an entering flag is reset. More...
  bool send_message_to_leaders (snap::snap_communicator_message &message)  Send a message to the other two leaders. More...
  QString serialize () const  Serialize a ticket to send it over to another leader. More...
  void set_alive_timeout (time_t timeout)  Define a time when the ticket times out while waiting. More...
  void set_owner (QString const &owner)  Define whether this ticket is the owner of that lock. More...
  void set_ready ()  Mark the ticket as being ready. More...
  void set_serial (serial_t owner)  Give the lock a serial number for some form of unicity. More...
  void set_ticket_number (ticket_id_t number)  Set the ticket number. More...
  void set_unlock_duration (snap::snap_lock::timeout_t duration)  Change the lock duration to the specified value. More...
  void ticket_added (snaplock_ticket::key_map_t const &entering)  Called whenever a TICKETADDED is received. More...
  bool timed_out () const  Check whether this ticket timed out. More...
  void unserialize (QString const &data)  Unserialize a ticket string back to a ticket object. More...
  Static Public Attributes static serial_t const NO_SERIAL = -1   static ticket_id_t const NO_TICKET = 0   Private Attributes bool f_added_ticket = false   bool f_added_ticket_quorum = false   time_t f_alive_timeout = 0   QString f_entering_key = QString()   bool f_get_max_ticket = false   snap::snap_lock::timeout_t f_lock_duration = 0   bool f_lock_failed = false   time_t f_lock_timeout = 0   bool f_locked = false   snaplock_messenger::pointer_t f_messenger = snaplock_messenger::pointer_t()   QString f_object_name = QString()   time_t f_obtention_timeout = 0   ticket_id_t f_our_ticket = NO_TICKET   QString f_owner = QString()   serial_t f_serial = NO_SERIAL   QString f_server_name = QString()   QString f_service_name = QString()   snaplockf_snaplock = nullptr   snaplock_ticket::key_map_t f_still_entering = snaplock_ticket::key_map_t()   QString f_ticket_key = QString()   bool f_ticket_ready = false   snap::snap_lock::timeout_t f_unlock_duration = 0   Detailed Description
Introduction

This class manages the Leslie Lamport's Bakery Algorithm (1974) lock mechanism (a critical section that we can get between any number of threads, processes, computers.) Details of this algorithm can be found here:

http://en.wikipedia.org/wiki/Lamport's_bakery_algorithm

The algorithm requires:

  • A unique name for each computer (server_name)
  • A unique number for the process attempting the lock (see gettid(2) manual)
  • A user supplied object name (the name of the lock)
  • A ticket number (use the largest existing ticket number + 1)

We also include a timeout on any one lock so we can forfeit the lock from happening if it cannot be obtained in a minimal amount of time. The timeout is specified as an absolute time in the future (now + X seconds.) The timeout is given in seconds (a standard time_t value).

This class sends various messages to manage the locks.

The Bakery Algorithm Explained

The bakery algorithm is based on the basic idea that a large number of customers go to one bakery to buy bread. In order to make sure they all are served in the order they come in, they are given a ticket with a number. The ticket numbers increase by one for each new customer. The person still in line with the smallest ticket number is served next. Once served, the ticket is destroyed.

Note
The ticket numbers can restart at one whenever the queue of customers goes empty. Otherwise it only increases. From our usage in Snap, it is really rare that the ticket numbers would not quickly be reset, especially because we have such numbers on a per object_name basis and thus many times the number will actually be one.

On a computer without any synchronization mechanism available (our case) two customers may enter the bakery simultaneously (especially since we are working with processes that may run on different computers.) This means two customers may end up with the exact same ticket number and there are no real means to avoid that problem. However, each customer is also assigned two unique numbers on creation: its "host number" (its server name, we use a string to simplify things) and its process number (we actually use gettid() so each thread gets a unique number which is an equivalent to a pid_t number for every single thread.) These two numbers are used to further order processes and make sure we can tell who will get the lock first.

So, the basic bakery algorithm looks like this in C++. This algorithm expects memory to be guarded (shared or "volatile"; always visible by all threads.) In our case, we send the data over the network to all the snaplock processes. This is definitely guarded.

// declaration and initial values of global variables
namespace {
int num_threads = 100;
std::vector<bool> entering;
std::vector<uint32_t> tickets;
}
// initialize the vectors
void init()
{
entering.reserve(num_threads);
tickets.reserve(num_threads);
}
// i is a thread "number" (0 to 99)
void lock(int i)
{
// get the next ticket
entering[i] = true;
int my_ticket(0);
for(int j(0); j < num_threads; ++j)
{
if(ticket[k] > my_ticket)
{
my_ticket = ticket[k];
}
}
++my_ticket; // add 1, we want the next ticket
entering[i] = false;
for(int j(0); j < num_threads; ++j)
{
// wait until thread j receives its ticket number
while(entering[j])
{
sleep();
}
// there are several cases:
//
// (1) tickets that are 0 are not assigned so we can just go
// through
//
// (2) smaller tickets win over us (have a higher priority,)
// so if there is another thread with a smaller ticket
// sleep a little and try again; that ticket must go to
// zero to let us through that guard
//
// (3) if tickets are equal, compare the thread numbers and
// like the tickets, the smallest thread wins
//
while(ticket[j] != 0 && (ticket[j] < ticket[i] || (ticket[j] == ticket[i] && j < i))
{
sleep();
}
}
}
// i is the thread number
void unlock(int i)
{
// release our ticket
ticket[i] = 0;
}
void SomeThread(int i)
{
while(true)
{
[...]
// non-critical section...
lock(i);
// The critical section code goes here...
unlock(i);
// non-critical section...
[...]
}
}

Note that there are two possible optimizations when actually implementing the algorithm:

  • You can enter (entering[i] = true), get your ticket, exit (entering[i] = false) and then get the list of still existing 'entering' processes. Once that list goes empty, we do not need to test the entering[j] anymore because any further entering[j] will be about processes with a larger ticket number and thus processes that will appear later in the list of tickets.
  • By sorting (and they are) our ticket requests by ticket, server name, and process pid, we do not have to search for the smallest ticket. The smallest ticket is automatically first in that list! So all we have to do is: if not first, sleep() some more.
Note
A Cassandra version is proposed on the following page. However, because Cassandra always manages its data with tombstones, you get a very large number of tombstones quickly in your database (at least the CF that manages the lock.) Hence, we have our own deamon which is much faster anyway because it only does work in memory and through the network.

http://wiki.apache.org/cassandra/Locking

Note
We also have our own Cassandra implementation in our libQtCassandra library which is fully functional (look at version 0.5.22).

https://snapwebsites.org/project/libqtcassandra

Our implementation in snaplock

Locks are given a name by our users. This is used to lock just one small thing for any amount of time as required by your implementation.

That name is used as an index to the f_tickets object in the snaplock class. Within such a ticket, you have one entry per process trying to obtain that lock.

For example, the users plugin generates a unique user identifier which is a number starting at 1. When a process needs to do this, we need a lock to prevent any other processes to do it at the same time. We also use a QUORUM consistency in Cassandra to load/increment/save the user number.

In this example, all we need to lock is an object named something like "user number". Actually, if the number is specific to a website, we can use the website URI. In this case, we can use a name like this: "http://www.example.com/user#number". This says we are managing an atomic "#number" at address "http://www.example.com/user". This also means we do not need to block anyone if the other people need to lock a completely different field (so process A can lock the user unique number while process B could lock an invoice unique number.)

As a result, the locking mechanism manages the locks on a per lock name basis. In other words, if only two processes request a lock simultaneously and the object_name parameter are not equal, they both get their lock instantaneously (at least very quickly.)

Message Sequence Chart
Any drawback? Timeouts

Note that our locks have a timeout, by default it is very small (5 seconds, which for a front end hit to a website is very long already!) If that timeout is too short (i.e. a backend does heavy lifting work on the data,) then you can make it larger. Our backends are given 4h by default.

Deadlock

Like with any lock, if you have two processes that both try two distinct locks each in the other order, you get a deadlock:

P1 tries to get L1, and gets it;

P2 tries to get L2, and gets it;

P1 tries to get L2, and has to wait on P2;

P2 tries to get L1, and creates a deadlock.

The deadlock itself will be resolved once the lock times out, but P2 will "never" have a chance to work on L1.

One lock at a time.

The process of obtaining a lock assumes that the process requesting a lock gets blocked between the time it sends the request and the time it receives the confirmation for that lock.

This is very important because we manage objects coming from a specific process as unique by using theid PID. If the same process could send more than one lock request, the PID would be the same and if trying to lock the same object twice, you would have a bug because this system does not have any way to distinguish two such requests if received simlutaneously.

The lock should look as follow, although we have two implementations one of which does no work in a local place like this because it will be asynchronous.

{
SnapLock lock("some name");
// do protected work here...
}

Definition at line 203 of file snaplock.h.

Member Typedef Documentation
typedef std::map<QString, pointer_t> snaplock::snaplock_ticket::key_map_t

Definition at line 209 of file snaplock.h.

typedef std::map<QString, key_map_t> snaplock::snaplock_ticket::object_map_t

Definition at line 210 of file snaplock.h.

typedef std::shared_ptr<snaplock_ticket> snaplock::snaplock_ticket::pointer_t

Definition at line 207 of file snaplock.h.

typedef int32_t snaplock::snaplock_ticket::serial_t

Definition at line 211 of file snaplock.h.

typedef uint32_t snaplock::snaplock_ticket::ticket_id_t

Definition at line 212 of file snaplock.h.

typedef std::vector<pointer_t> snaplock::snaplock_ticket::vector_t

Definition at line 208 of file snaplock.h.

Constructor & Destructor Documentation
snaplock::snaplock_ticket::snaplock_ticket ( snaplocksl, snaplock_messenger::pointer_t  messenger, QString const &  object_name, QString const &  entering_key, time_t  obtention_timeout, snap::snap_lock::timeout_t  lock_duration, QString const &  server_name, QString const &  service_name  )
snaplock::snaplock_ticket::snaplock_ticket ( snaplock_ticket const &  rhs) delete
Member Function Documentation
void snaplock::snaplock_ticket::activate_lock ( )

This function checks whether the ticket is ready to be activated. This means it got a ticket and the ticket is ready. If so, then it sends the LOCKED message back to the system that required it.

This function can be called multiple times. It will send the LOCKED message only once.

Definition at line 743 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::add_ticket ( )

This function sends the ADDTICKET message to all the snaplock instances currently known.

Definition at line 604 of file snaplock_ticket.cpp.

References snaplock::snaplock_messenger::f_snaplock, snaplock::snaplock::get_entering_tickets(), and snaplock::snaplock::set_ticket().

void snaplock::snaplock_ticket::drop_ticket ( )

This function sends the DROPTICKET message to get read of a ticket from another leader's list of tickets.

Another leader has a list of tickets as it receives LOCK and ADDTICKET messages.

Definition at line 800 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::entered ( )

This function gets called each time we receive a LOCKENTERED message with this ticket entering key.

Since we have 1 to 3 leaders, the quorum and thus consensus is reached as soon as we receive one LOCKENTERED message. So as a result this function sends GETMAXTICKET the first time it gets called. The GETMAXTICKET message allows us to determine the ticket number for the concerned object.

Note
The msg_lockentered() function first checked whether the LOCKENTERED message had anything to do with this ticket. If not, the message was just ignored.

Definition at line 547 of file snaplock_ticket.cpp.

References snaplock::snaplock_messenger::f_snaplock, and snaplock::snaplock::get_last_ticket().

void snaplock::snaplock_ticket::entering ( )

In order to make sure we can get the current largest ticket number in a unique enough way, snaplock has to enter the lock loop. This process starts by sending a LOCKENTERING message to all the other snaplock leaders.

Definition at line 500 of file snaplock_ticket.cpp.

pid_t snaplock::snaplock_ticket::get_client_pid ( ) const

This function splits the entering key and return the process identifier. This is primarily used to resend a LOCK message since in most cases this information should not be required.

Note
This is not really information that the ticket is supposed to know about but well... there is now a case where we need to know this.
Returns
The name of this ticket owner.

Definition at line 963 of file snaplock_ticket.cpp.

time_t snaplock::snaplock_ticket::get_current_timeout ( ) const

This function returns the current lock timeout.

If the lock is being re-requested (after the loss of a leader) then the ALIVE timeout may be returned for a short period of time.

If the lock was not yet obtained, this function returns the obtension timeout timestamp. Once the lock was obtained, the lock timeout gets defined and that one is returned instead.

Note
This is the date used in the timed_out() function.
Returns
The date when the ticket will timeout or zero.

Definition at line 1259 of file snaplock_ticket.cpp.

QString const & snaplock::snaplock_ticket::get_entering_key ( ) const

This function returns the entering key of this ticket. The entering key is defined on instantiation so it is always available.

Note
By contrast, the ticket key is not available up until the time the ticket number is marked as valid.
Returns
The entering key of this ticket.

Definition at line 1353 of file snaplock_ticket.cpp.

snap::snap_lock::timeout_t snaplock::snaplock_ticket::get_lock_duration ( ) const

This function returns the lock duration in seconds as defined with the constructor.

Returns
The lock duration in seconds.

Definition at line 1220 of file snaplock_ticket.cpp.

time_t snaplock::snaplock_ticket::get_lock_timeout ( ) const

This function returns the lock timeout. If not yet defined, the function will return zero.

Note
The ticket will immediately be assigned a timeout date when it gets activated.
Returns
The date when the ticket will timeout or zero.

Definition at line 1237 of file snaplock_ticket.cpp.

QString const & snaplock::snaplock_ticket::get_object_name ( ) const

This function returns the name of the object associated with this lock (i.e. what is being locked.)

Returns
The object name of the ticket.

Definition at line 1302 of file snaplock_ticket.cpp.

time_t snaplock::snaplock_ticket::get_obtention_timeout ( ) const

This function returns the obtention timeout. Note that if the lock was already obtained, then this date may be in the past. You can test that by checking the get_lock_timeout() function first.

Returns
The date when the obtention of the ticket timeouts.

Definition at line 1159 of file snaplock_ticket.cpp.

QString const & snaplock::snaplock_ticket::get_owner ( ) const

This function returns the name of the owner of this ticket. When a leader dies out, its name stick around until a new leader gets assigned to it.

Returns
The name of this ticket owner.

Definition at line 945 of file snaplock_ticket.cpp.

snaplock_ticket::serial_t snaplock::snaplock_ticket::get_serial ( ) const

This function returns the serial number of this ticket. See the set_serial() function for additional information about this number.

Returns
The serial number of the ticket.

Definition at line 1008 of file snaplock_ticket.cpp.

QString const & snaplock::snaplock_ticket::get_server_name ( ) const

This function returns the name of the server associated with this lock, i.e. the server to which the LOCKED and UNLOCKED commands are to be sent back to.

This name is also used in case of an error to send the LOCKFAILED back to the service that requested the lock.

Returns
The server name of the ticket.

Definition at line 1319 of file snaplock_ticket.cpp.

QString const & snaplock::snaplock_ticket::get_service_name ( ) const

This function returns the name of the service associated with this lock. This is the service to which the LOCKED and UNLOCKED messages are sent.

This name is also used in case of an error to send the LOCKFAILED back to the service that requested the lock.

Returns
The service name of the ticket.

Definition at line 1336 of file snaplock_ticket.cpp.

QString const & snaplock::snaplock_ticket::get_ticket_key ( ) const

This function returns the ticket key of this ticket. The ticket key is only defined at a later time when the ticket has properly entered the bakery. It includes three parameters:

  • Ticket number as an hexadecimal number of 8 digits,
  • Server name of the server asking for the lock,
  • Process Identifier (PID) of the service daemon asking for the lock.
Note
This function returns an empty string until the ticket key is available.
Returns
The ticket key.

Definition at line 1374 of file snaplock_ticket.cpp.

snaplock_ticket::ticket_id_t snaplock::snaplock_ticket::get_ticket_number ( ) const

This function returns the ticket number of this ticket. This is generally used to determine the largest ticket number currently in use in order to assign a new ticket number to a process.

By default the value is 0 meaning that no ticket number was yet assigned to that ticket object.

Returns
The current ticket number.

Definition at line 1133 of file snaplock_ticket.cpp.

snap::snap_lock::timeout_t snaplock::snaplock_ticket::get_unlock_duration ( ) const

The unlock duration is used in case the lock times out. It extends the lock duration for that much longer until the client acknowledge the locks or the lock really times out.

Returns
The unlock acknowledgement timeout duration.

Definition at line 1067 of file snaplock_ticket.cpp.

bool snaplock::snaplock_ticket::is_locked ( ) const

This function returns true if the ticket is currently locked.

Returns
true when the ticket was successfully locked at some point.

Definition at line 1145 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::lock_activated ( )

This function checks whether the ticket is ready to be activated. This means it got a ticket and the ticket is ready. If so, then it sends the LOCKED message back to the system that required it.

This function can be called multiple times. It will send the LOCKED message only once.

Definition at line 769 of file snaplock_ticket.cpp.

References snaplock::snaplock_messenger::f_snaplock, and snaplock::snaplock::get_server_name().

void snaplock::snaplock_ticket::lock_failed ( )

This function sends a reply to the server that requested the lock to let it know that it somehow failed.

The function replies with a LOCKFAILED when the lock was never obtained. In this case the origin server cannot access the resources.

The function rep[ies with UNLOCKED when the lock timed out. The server is expected to send an UNLOCK reply to acknowledge the failure and fully release the lock. The lock will remain in place until that acknowledgement is received or an amount of time equal to the lock duration by default with a minimum of 1 minute.

By default, the UNLOCKED acknowledgement timeout is set to the same amount as the LOCK duration with a minimum of 60 seconds. It can also be specified with the unlock_duration parameter in the LOCK message.

Note
The function may get called multiple times. The failure message is sent only on the first call.
If the ticket was created on another snaplock (not the one that received the LOCK event in the first place) then this ticket is not marked as being owned by this snaplock and as a result this function only marks the ticket as failed.

Definition at line 870 of file snaplock_ticket.cpp.

References snaplock::snaplock_messenger::f_snaplock, and snaplock::snaplock::get_server_name().

void snaplock::snaplock_ticket::lock_tickets ( )
void snaplock::snaplock_ticket::max_ticket ( int64_t  new_max_ticket)

This function registers the largest ticket number. Once we reach QUORUM, then we have the largest number and we can move on to the next stage, which is to add the ticket.

Parameters
[in]new_max_ticketAnother possibly larger ticket.

Definition at line 583 of file snaplock_ticket.cpp.

snaplock_ticket& snaplock::snaplock_ticket::operator= ( snaplock_ticket const &  rhs) delete
void snaplock::snaplock_ticket::remove_entering ( QString const &  key)

This function gets called whenever an entering flag gets set back to false (i.e. removed in our implementation.)

This function knows whether this ticket received its number and is not yet ready. In both of these circumstances, we are waiting for all entering flags that got created while we determined the largest ticket number to be removed.

Definition at line 690 of file snaplock_ticket.cpp.

bool snaplock::snaplock_ticket::send_message_to_leaders ( snap::snap_communicator_message &  message)

The send_message() is "broadcast" to the other two leaders.

This is a safe guard so if one of our three leaders fails, we have a backup of the lock status.

The locking system also works if there are only two or even just one computer. In those cases, special care has to be taken to get things to work as expected.

Parameters
[in]messageThe message to send to the other two leaders.
Returns
true if the message was forwarded at least once, false otherwise.

Definition at line 456 of file snaplock_ticket.cpp.

References snaplock::snaplock_messenger::f_snaplock, snaplock::snaplock::get_computer_count(), snaplock::snaplock::get_leader_a(), and snaplock::snaplock::get_leader_b().

QString snaplock::snaplock_ticket::serialize ( ) const

This function serialize a ticket to share it with the other leaders. This is important when a new leader gets elected as it would not otherwise have any idea of what the existing tickets are, although it is not 100% important, if another of the two snaplock was to go down, it becomes primordial for the tickets to be known in the other leaders.

This is used at the start before a leader starts accepting new lock requests.

Returns
This ticket as a serialized string.
See also
unserialize()

Definition at line 1396 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::set_alive_timeout ( time_t  timeout)

This function defines the time threshold when to timeout this ticket in case a service does not reply to an ALIVE message.

Whenever a leader dies, a ticket which is not locked yet may be transferred to another leader. To not attempt to lock a ticket for nothing, the new leader first checks that the service which requested that lock is indeed still alive by send an ALIVE message to it. In return it expects an ABSOLUTELY reply.

If the ABSOLUTELY reply does not make it in time (at this time we limit this to 5 seconds) then we consider that this service is not responsive and we cancel the lock altogether.

To cancel this timeout, call the function with 0 in timeout.

Note
Since that message should happen while the snap_lock object is wait for the LOCK event, the reply should be close to instantaneous. So 5 seconds is plenty until somehow your network is really busy or really large and the time for the message to travel is too long.
Parameters
[in]timeoutThe time when the ALIVE message times out.

Definition at line 1192 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::set_owner ( QString const &  owner)

Whenever comes time to send the LOCK, UNLOCK, or LOCKFAILED messages, only the owner is expected to send it. This flag tells us who the owner is and thus who is responsible for sending that message.

Todo:
The ownership has to travel to others whenever a leader disappears.
Parameters
[in]ownerThe name of this ticket owner.

Definition at line 931 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::set_ready ( )

This ticket is marked as being ready.

A ticket is ready when all the entering tickets were removed from it on the owning leader. On the other two leaders, the ticket gets marked as being ready once they receive the LOCKEXITING message.

Definition at line 1115 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::set_serial ( serial_t  serial)

When we lose a leader, the unicity of the ticket may be required as we start sharing the tickets between the surviving leaders. This is done for the RELOCK message which attempts to restart the an old LOCK. In that case, two leaders end up attempt a RELOCK on the same ticket. To make sure that we can easily ignore the second attempt, we use the serial number to see that the exact same message is getting there twice.

The snaplock daemon uses the leader number as part of the serial number (bits 24 and 25) so it is unique among all the instances, at least until a snaplock deamon dies and its unique numbers get mingled (and the old leaders may change their own number too...)

Parameters
[in]serialThe serial number of the ticket.

Definition at line 995 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::set_ticket_number ( ticket_id_t  number)

The other two leaders receive the ticket number in the ADDTICKET message. That number must be saved in the ticket, somehow. This is the function we use to do that.

It is very important to have the correct number (by default it is zero) since the algorithm asks for the maximum ticket number currently available and without that information that request cannot be answered properly.

Parameters
[in]numberThe ticket number to save in f_our_ticket.

Definition at line 1086 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::set_unlock_duration ( snap::snap_lock::timeout_t  duration)

If the service requesting a lock fails to acknowledge an unlock, then the lock still gets unlocked after this number of seconds.

By default, this parameter gets set to the same value as duration with a minimum of 60. When the message includes an unlock_duration parameter then that value is used instead.

Note
If duration is less than SNAP_UNLOCK_MINIMUM_TIMEOUT, then SNAP_UNLOCK_MINIMUM_TIMEOUT is used. At time of writing SNAP_UNLOCK_MINIMUM_TIMEOUT is 60 seconds or one minute.
Warning
It is important to understand that as soon as an UNLOCKED event arrives, you should acknowledge it if it includes an "error" parameter. Not doing so increases the risk that two or more processes access the same resource simultaneously.
Parameters
[in]durationThe number of seconds to acknowledge an UNLOCKED event; after that the lock is released no matter what.

Definition at line 1037 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::ticket_added ( snaplock_ticket::key_map_t const &  still_entering)

This function sends a LOCKEXITING if the ticket reached the total number of TICKETADDED required to get a quorum (which is just one with 1 to 3 leaders.)

The still_entering paramater defines the list of tickets that are still trying to enter the same object. This is very important. It needs to be completely drained before we can proceed and mark the ticket as assigned.

Parameters
[in]still_enteringThe list of still entering processes

Definition at line 655 of file snaplock_ticket.cpp.

References snaplock::snaplock_messenger::f_snaplock, and snaplock::snaplock::lock_exiting().

bool snaplock::snaplock_ticket::timed_out ( ) const

This function returns true if the ticket timed out and should be removed from the various lists where it is kept.

The function select the date to check the timeout depending on the current status of the lock. If the lock was successfully activated, the lock timeout date is used. If the lock was not yet activate, the obtention timeout date is used.

Returns
true if the ticket timed out.

Definition at line 1287 of file snaplock_ticket.cpp.

void snaplock::snaplock_ticket::unserialize ( QString const &  data)

This function unserialize a string that was generated using the serialize() function.

Note that unknown fields are ignored and none of the fields are considered mandatory. Actually the function generates no errors. This means it should be forward compatible.

The data gets unserialized in this object.

Parameters
[in]dataThe serialized data.

Definition at line 1455 of file snaplock_ticket.cpp.

Member Data Documentation
bool snaplock::snaplock_ticket::f_added_ticket = false private

Definition at line 295 of file snaplock.h.

bool snaplock::snaplock_ticket::f_added_ticket_quorum = false private

Definition at line 299 of file snaplock.h.

time_t snaplock::snaplock_ticket::f_alive_timeout = 0 private

Definition at line 281 of file snaplock.h.

QString snaplock::snaplock_ticket::f_entering_key = QString() private

Definition at line 290 of file snaplock.h.

bool snaplock::snaplock_ticket::f_get_max_ticket = false private

Definition at line 291 of file snaplock.h.

snap::snap_lock::timeout_t snaplock::snaplock_ticket::f_lock_duration = 0 private

Definition at line 282 of file snaplock.h.

bool snaplock::snaplock_ticket::f_lock_failed = false private

Definition at line 310 of file snaplock.h.

time_t snaplock::snaplock_ticket::f_lock_timeout = 0 private

Definition at line 307 of file snaplock.h.

bool snaplock::snaplock_ticket::f_locked = false private

Definition at line 306 of file snaplock.h.

snaplock_messenger::pointer_t snaplock::snaplock_ticket::f_messenger = snaplock_messenger::pointer_t() private

Definition at line 278 of file snaplock.h.

QString snaplock::snaplock_ticket::f_object_name = QString() private

Definition at line 279 of file snaplock.h.

time_t snaplock::snaplock_ticket::f_obtention_timeout = 0 private

Definition at line 280 of file snaplock.h.

ticket_id_t snaplock::snaplock_ticket::f_our_ticket = NO_TICKET private

Definition at line 294 of file snaplock.h.

QString snaplock::snaplock_ticket::f_owner = QString() private

Definition at line 286 of file snaplock.h.

serial_t snaplock::snaplock_ticket::f_serial = NO_SERIAL private

Definition at line 287 of file snaplock.h.

QString snaplock::snaplock_ticket::f_server_name = QString() private

Definition at line 284 of file snaplock.h.

QString snaplock::snaplock_ticket::f_service_name = QString() private

Definition at line 285 of file snaplock.h.

snaplock* snaplock::snaplock_ticket::f_snaplock = nullptr private

Definition at line 275 of file snaplock.h.

snaplock_ticket::key_map_t snaplock::snaplock_ticket::f_still_entering = snaplock_ticket::key_map_t() private

Definition at line 300 of file snaplock.h.

QString snaplock::snaplock_ticket::f_ticket_key = QString() private

Definition at line 296 of file snaplock.h.

bool snaplock::snaplock_ticket::f_ticket_ready = false private

Definition at line 303 of file snaplock.h.

snap::snap_lock::timeout_t snaplock::snaplock_ticket::f_unlock_duration = 0 private

Definition at line 283 of file snaplock.h.

serial_t const snaplock::snaplock_ticket::NO_SERIAL = -1 static

Definition at line 214 of file snaplock.h.

ticket_id_t const snaplock::snaplock_ticket::NO_TICKET = 0 static

Definition at line 215 of file snaplock.h.

Referenced by snaplock::snaplock::get_last_ticket().


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.

Syndicate content

Snap! Websites
An Open Source CMS System in C++

Contact Us Directly