snaplock: snaplock_ticket.cpp Source File

snaplock  1.7.14
The multi-computer lock service.
snaplock_ticket.cpp
Go to the documentation of this file.
1 /*
2  * Text:
3  * snaplock/src/snaplock_ticket.cpp
4  *
5  * Description:
6  * A daemon to synchronize processes between any number of computers
7  * by blocking all of them but one.
8  *
9  * The ticket class is used to know which computer is next. All
10  * computers are given a number. The computer with the smallest
11  * number has priority in case multiple computers are assigned
12  * the same ticket number.
13  *
14  * This algorithm is called the Lamport's Bakery Algorithm.
15  *
16  * License:
17  * Copyright (c) 2016-2019 Made to Order Software Corp. All Rights Reserved
18  *
21  *
22  * Permission is hereby granted, free of charge, to any person obtaining a
23  * copy of this software and associated documentation files (the
24  * "Software"), to deal in the Software without restriction, including
25  * without limitation the rights to use, copy, modify, merge, publish,
26  * distribute, sublicense, and/or sell copies of the Software, and to
27  * permit persons to whom the Software is furnished to do so, subject to
28  * the following conditions:
29  *
30  * The above copyright notice and this permission notice shall be included
31  * in all copies or substantial portions of the Software.
32  *
33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
34  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
36  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
37  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
38  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40  */
41 
42 
43 // ourselves
44 //
45 #include "snaplock.h"
46 
47 
48 // our lib
49 //
50 #include <snapwebsites/log.h>
51 
52 
53 // last include
54 //
55 #include <snapdev/poison.h>
56 
57 
58 
59 namespace snaplock
60 {
61 
396  snaplock * sl
398  , QString const & object_name
399  , QString const & entering_key
400  , time_t obtention_timeout
401  , int32_t lock_duration
402  , QString const & server_name
403  , QString const & service_name)
404  : f_snaplock(sl)
405  , f_messenger(messenger)
406  , f_object_name(object_name)
407  , f_obtention_timeout(obtention_timeout)
408  , f_lock_duration(lock_duration)
409  , f_server_name(server_name)
410  , f_service_name(service_name)
411  , f_owner(f_snaplock->get_server_name())
412  , f_entering_key(entering_key)
413 {
414  // clamp the lock duration
415  //
416  if(f_lock_duration < snap::snap_lock::SNAP_UNLOCK_MINIMUM_TIMEOUT)
417  {
418  f_lock_duration = snap::snap_lock::SNAP_UNLOCK_MINIMUM_TIMEOUT;
419  }
420  else if(f_lock_duration > snap::snap_lock::SNAP_MAXIMUM_TIMEOUT)
421  {
422  f_lock_duration = snap::snap_lock::SNAP_MAXIMUM_TIMEOUT;
423  }
424 
425  set_unlock_duration(f_lock_duration);
426 
427  SNAP_LOG_TRACE("Attempting to lock \"")
428  (f_object_name)
429  ("\" on \"")
430  (f_entering_key)
431  ("\" for \"")
432  (f_server_name)
433  ("/")
434  (f_service_name)
435  ("\" (timeout: ")
436  (f_obtention_timeout)
437  (").");
438 }
439 
440 
456 bool snaplock_ticket::send_message_to_leaders(snap::snap_communicator_message & message)
457 {
458  // finish the message initialization
459  //
460  message.set_service("snaplock");
461  message.add_parameter("object_name", f_object_name);
462 
464  if(leader != nullptr)
465  {
466  // there are at least two leaders
467  //
468  message.set_server(leader->get_name());
469  f_messenger->send_message(message);
470 
471  // check for a third leader
472  //
473  leader = f_snaplock->get_leader_b();
474  if(leader != nullptr)
475  {
476  message.set_server(leader->get_name());
477  f_messenger->send_message(message);
478  }
479 
480  // we have to wait for at least one reply
481  //
482  return true;
483  }
484 
485  // there is only one leader (ourselves)
486  //
487  // verify that this is correct otherwise we would mess up the algorithm
488  //
489  return f_snaplock->get_computer_count() != 1;
490 }
491 
492 
501 {
502  // TODO implement the special case when there is only 1 leader
503  // (on the other hand, that should be rather rare)
504  //snaplock::computer_t::pointer_t leader(f_snaplock->get_leader_a());
505  //if(leader == nullptr)
506  //{
507  // -- do the necessary to obtain the lock --
508  // return;
509  //}
510 
511  snap::snap_communicator_message entering_message;
512  entering_message.set_command("LOCKENTERING");
513  entering_message.add_parameter("key", f_entering_key);
514  entering_message.add_parameter("timeout", f_obtention_timeout);
515  entering_message.add_parameter("duration", f_lock_duration);
516  if(f_lock_duration != f_unlock_duration)
517  {
518  entering_message.add_parameter("unlock_duration", f_unlock_duration);
519  }
520  entering_message.add_parameter("source", f_server_name + "/" + f_service_name);
521  entering_message.add_parameter("serial", f_serial);
522  if(!send_message_to_leaders(entering_message))
523  {
524  // there are no other leaders, make sure the algorithm progresses
525  //
526  entered();
527  }
528 }
529 
530 
548 {
549  // is this ticket concerned?
550  //
551  if(!f_get_max_ticket)
552  {
553  // with 2 or 3 leaders, quorum is obtain with one
554  // single acknowledgement
555  //
556  f_get_max_ticket = true;
557 
558  // calculate this instance max. ticket number
559  //
560  f_our_ticket = f_snaplock->get_last_ticket(f_object_name);
561 
562  snap::snap_communicator_message get_max_ticket_message;
563  get_max_ticket_message.set_command("GETMAXTICKET");
564  get_max_ticket_message.add_parameter("key", f_entering_key);
565  if(!send_message_to_leaders(get_max_ticket_message))
566  {
567  // there are no other leaders, make sure the algorithm progresses
568  //
569  max_ticket(f_our_ticket);
570  }
571  }
572 }
573 
574 
583 void snaplock_ticket::max_ticket(int64_t new_max_ticket)
584 {
585  if(!f_added_ticket)
586  {
587  if(new_max_ticket > f_our_ticket)
588  {
589  f_our_ticket = new_max_ticket;
590  }
591 
592  ++f_our_ticket;
593 
594  add_ticket();
595  }
596 }
597 
598 
605 {
606  // we expect exactly one call to this function
607  //
608  if(f_added_ticket)
609  {
610  throw std::logic_error("snaplock_ticket::add_ticket() called more than once.");
611  }
612  f_added_ticket = true;
613 
614  //
615  // WARNING: the ticket key MUST be properly sorted by:
616  //
617  // ticket number
618  // server name
619  // client pid
620  //
621  // The client PID does not need to be sorted numerically, just be sorted
622  // so one client is before the other.
623  //
624  // However, the ticket number MUST be numerically sorted. For this reason,
625  // since the key is a string, we must add introducing zeroes.
626  //
627  f_ticket_key = QString("%1/%2").arg(f_our_ticket, 8, 16, QChar('0')).arg(f_entering_key);
628 
629  f_snaplock->set_ticket(f_object_name, f_ticket_key, shared_from_this());
630 
631  snap::snap_communicator_message add_ticket_message;
632  add_ticket_message.set_command("ADDTICKET");
633  add_ticket_message.add_parameter("key", f_ticket_key);
634  add_ticket_message.add_parameter("timeout", f_obtention_timeout);
635  if(!send_message_to_leaders(add_ticket_message))
636  {
637  ticket_added(f_snaplock->get_entering_tickets(f_object_name));
638  }
639 }
640 
641 
656 {
657  if(!f_added_ticket_quorum)
658  {
659  // when we have 2 or 3 leaders, quorum is obtain with one
660  // single acknowledgement
661  //
662  f_added_ticket_quorum = true;
663 
664  f_still_entering = still_entering;
665 
666  // okay, the ticket was added on all snaplock
667  // now we can forget about the entering flag
668  // (equivalent to setting it to false)
669  //
670  snap::snap_communicator_message exiting_message;
671  exiting_message.set_command("LOCKEXITING");
672  exiting_message.add_parameter("key", f_entering_key);
673  snap::NOTUSED(send_message_to_leaders(exiting_message));
674 
675  f_snaplock->lock_exiting(exiting_message);
676  }
677 }
678 
679 
690 void snaplock_ticket::remove_entering(QString const & key)
691 {
692  if(f_added_ticket_quorum
693  && !f_ticket_ready)
694  {
695  auto it(f_still_entering.find(key));
696  if(it != f_still_entering.end())
697  {
698  f_still_entering.erase(it);
699 
700  // just like the quorum computation, we compute the
701  // remaining list of entering tickets dynamically at
702  // the time we check the value
703  //
704  for(auto key_entering(f_still_entering.begin()); key_entering != f_still_entering.end(); )
705  {
706  if(key_entering->second->timed_out())
707  {
708  key_entering = f_still_entering.erase(key_entering);
709  }
710  else
711  {
712  ++key_entering;
713  }
714  }
715 
716  // once all removed, our ticket is ready!
717  //
718  if(f_still_entering.empty())
719  {
720  f_ticket_ready = true;
721 
722  // let the other two leaders know that the ticket is ready
723  //
724  snap::snap_communicator_message ticket_ready_message;
725  ticket_ready_message.set_command("TICKETREADY");
726  ticket_ready_message.add_parameter("key", f_ticket_key);
727  snap::NOTUSED(send_message_to_leaders(ticket_ready_message));
728  }
729  }
730  }
731 }
732 
733 
744 {
745  if(f_ticket_ready
746  && !f_locked
747  && !f_lock_failed)
748  {
749  snap::snap_communicator_message activate_lock_message;
750  activate_lock_message.set_command("ACTIVATELOCK");
751  activate_lock_message.add_parameter("key", f_ticket_key);
752  if(!send_message_to_leaders(activate_lock_message))
753  {
754  lock_activated();
755  }
756  }
757 }
758 
759 
770 {
771  if(f_ticket_ready
772  && !f_locked
773  && !f_lock_failed)
774  {
775  f_locked = true;
776  f_lock_timeout = f_lock_duration + time(nullptr);
777 
778  if(f_owner == f_snaplock->get_server_name())
779  {
780  snap::snap_communicator_message locked_message;
781  locked_message.set_command("LOCKED");
782  locked_message.set_server(f_server_name);
783  locked_message.set_service(f_service_name);
784  locked_message.add_parameter("object_name", f_object_name);
785  locked_message.add_parameter("timeout_date", f_lock_timeout);
786  f_messenger->send_message(locked_message);
787  }
788  }
789 }
790 
791 
801 {
802  SNAP_LOG_TRACE("Unlock on \"")(f_object_name)("\" with key \"")(f_entering_key)("\".");
803 
804  snap::snap_communicator_message drop_ticket_message;
805  drop_ticket_message.set_command("DROPTICKET");
806  drop_ticket_message.add_parameter("key", f_ticket_key.isEmpty() ? f_entering_key : f_ticket_key);
807  send_message_to_leaders(drop_ticket_message);
808 
809  if(!f_lock_failed)
810  {
811  f_lock_failed = true;
812 
813  //if(f_owner == f_snaplock->get_server_name()) -- this can happen with any leader so we have to send the UNLOCKED
814  // the other leaders won't call this function they receive DROPTICKET
815  // instead and as mentioned in the TODO below, we should get a QUORUM
816  // instead...
817  {
818  // we can immediately say it got unlocked...
819  //
820  // TODO: this is true ONLY if you lock the same object no more than
821  // once within a session, which is not unlikely false (it is
822  // true for what I can remember of Snap!, but long term this
823  // is not safe.) Like the LOCK, we need a quorum and then
824  // send the UNLOCK... At this point, I'm not too sure how
825  // we implement such because the drop_ticket function ends
826  // up deleting the ticket from memory and thus no counting
827  // can happen after that... (i.e. we need a special case
828  // of the receiver for the UNLOCK, argh!)
829  //
830  snap::snap_communicator_message unlocked_message;
831  unlocked_message.set_command("UNLOCKED");
832  unlocked_message.set_server(f_server_name);
833  unlocked_message.set_service(f_service_name);
834  unlocked_message.add_parameter("object_name", f_object_name);
835  f_messenger->send_message(unlocked_message);
836  }
837  }
838 }
839 
840 
871 {
872  if(!f_lock_failed)
873  {
874  // send that message at most once
875  //
876  f_lock_failed = true;
877 
878  if(f_locked)
879  {
880  // now we have to extend the lock timeout to make sure that
881  // the UNLOCKED has a chance to be acknowledged
882  //
883  f_lock_timeout += f_unlock_duration;
884  }
885 
886  if(f_owner == f_snaplock->get_server_name())
887  {
888  if(f_locked)
889  {
890  // if we were locked and reach here, then the lock
891  // timed out while locked
892  //
893  SNAP_LOG_INFO("Lock on \"")(f_object_name)("\" with key \"")(f_entering_key)("\" timed out.");
894 
895  snap::snap_communicator_message lock_failed_message;
896  lock_failed_message.set_command("UNLOCKED");
897  lock_failed_message.set_server(f_server_name);
898  lock_failed_message.set_service(f_service_name);
899  lock_failed_message.add_parameter("object_name", f_object_name);
900  lock_failed_message.add_parameter("error", "timedout");
901  f_messenger->send_message(lock_failed_message);
902  }
903  else
904  {
905  SNAP_LOG_INFO("Lock on \"")(f_object_name)("\" with key \"")(f_entering_key)("\" failed.");
906 
907  snap::snap_communicator_message lock_failed_message;
908  lock_failed_message.set_command("LOCKFAILED");
909  lock_failed_message.set_server(f_server_name);
910  lock_failed_message.set_service(f_service_name);
911  lock_failed_message.add_parameter("object_name", f_object_name);
912  lock_failed_message.add_parameter("error", "failed");
913  f_messenger->send_message(lock_failed_message);
914  }
915  }
916  }
917 }
918 
919 
931 void snaplock_ticket::set_owner(QString const & owner)
932 {
933  f_owner = owner;
934 }
935 
936 
945 QString const & snaplock_ticket::get_owner() const
946 {
947  return f_owner;
948 }
949 
950 
964 {
965  snap::snap_string_list const segments(f_entering_key.split('/'));
966  if(segments.size() != 2)
967  {
969  "snaplock_ticket::get_owner() split f_entering_key "
970  + f_entering_key
971  + " and did not get exactly two segments.");
972  }
973  bool ok(false);
974  return segments[1].toInt(&ok, 10);
975 }
976 
977 
996 {
997  f_serial = serial;
998 }
999 
1000 
1009 {
1010  return f_serial;
1011 }
1012 
1013 
1038 {
1039  if(duration == snap::snap_lock::SNAP_UNLOCK_USES_LOCK_TIMEOUT)
1040  {
1041  duration = f_lock_duration;
1042  }
1043 
1044  if(duration < snap::snap_lock::SNAP_UNLOCK_MINIMUM_TIMEOUT)
1045  {
1046  f_unlock_duration = snap::snap_lock::SNAP_UNLOCK_MINIMUM_TIMEOUT;
1047  }
1048  else if(duration > snap::snap_lock::SNAP_MAXIMUM_TIMEOUT)
1049  {
1050  f_unlock_duration = snap::snap_lock::SNAP_MAXIMUM_TIMEOUT;
1051  }
1052  else
1053  {
1054  f_unlock_duration = duration;
1055  }
1056 }
1057 
1058 
1067 snap::snap_lock::timeout_t snaplock_ticket::get_unlock_duration() const
1068 {
1069  return f_unlock_duration;
1070 }
1071 
1072 
1087 {
1088  if(f_our_ticket != 0)
1089  {
1090  throw std::logic_error("snaplock_ticket::set_ticket_number() called with "
1091  + std::to_string(number)
1092  + " when f_our_ticket is already set to "
1093  + std::to_string(f_our_ticket)
1094  + ".");
1095  }
1096  if(f_added_ticket)
1097  {
1098  throw std::logic_error("snaplock_ticket::set_ticket_number() called when f_added_ticket is already true.");
1099  }
1100  f_added_ticket = true;
1101 
1102  f_our_ticket = number;
1103  f_ticket_key = QString("%1/%2").arg(f_our_ticket, 8, 16, QChar('0')).arg(f_entering_key);
1104 }
1105 
1106 
1116 {
1117  f_ticket_ready = true;
1118 }
1119 
1120 
1134 {
1135  return f_our_ticket;
1136 }
1137 
1138 
1146 {
1147  return f_locked;
1148 }
1149 
1150 
1160 {
1161  return f_obtention_timeout;
1162 }
1163 
1164 
1193 {
1194  if(timeout < 0)
1195  {
1196  timeout = 0;
1197  }
1198 
1199  if(timeout < f_obtention_timeout)
1200  {
1201  f_alive_timeout = timeout;
1202  }
1203  else
1204  {
1205  // use the obtension timeout if smaller because that was the
1206  // first premise that the client asked about
1207  //
1208  f_alive_timeout = f_obtention_timeout;
1209  }
1210 }
1211 
1212 
1220 snap::snap_lock::timeout_t snaplock_ticket::get_lock_duration() const
1221 {
1222  return f_lock_duration;
1223 }
1224 
1225 
1238 {
1239  return f_lock_timeout;
1240 }
1241 
1242 
1260 {
1261  if(f_alive_timeout > 0)
1262  {
1263  return f_alive_timeout;
1264  }
1265 
1266  if(f_locked)
1267  {
1268  return f_lock_timeout;
1269  }
1270 
1271  return f_obtention_timeout;
1272 }
1273 
1274 
1288 {
1289  // Note: as long as f_locked is false, the f_lock_timeout value is zero
1290  //
1291  return get_current_timeout() <= time(nullptr);
1292 }
1293 
1294 
1302 QString const & snaplock_ticket::get_object_name() const
1303 {
1304  return f_object_name;
1305 }
1306 
1307 
1319 QString const & snaplock_ticket::get_server_name() const
1320 {
1321  return f_server_name;
1322 }
1323 
1324 
1336 QString const & snaplock_ticket::get_service_name() const
1337 {
1338  return f_service_name;
1339 }
1340 
1341 
1353 QString const & snaplock_ticket::get_entering_key() const
1354 {
1355  return f_entering_key;
1356 }
1357 
1358 
1374 QString const & snaplock_ticket::get_ticket_key() const
1375 {
1376  return f_ticket_key;
1377 }
1378 
1379 
1397 {
1398  std::map<QString, QString> data;
1399 
1400  data["object_name"] = f_object_name;
1401  data["obtention_timeout"] = QString("%1").arg(f_obtention_timeout);
1402  //data["alive_timeout"] = QString("%1").arg(f_alive_timeout); -- we do not want to transfer this one
1403  data["lock_duration"] = QString("%1").arg(f_lock_duration);
1404  data["unlock_duration"] = QString("%1").arg(f_unlock_duration);
1405  data["server_name"] = f_server_name;
1406  data["service_name"] = f_service_name;
1407  data["owner"] = f_owner;
1408  if(f_serial != NO_SERIAL)
1409  {
1410  data["serial"] = QString("%1").arg(f_serial);
1411  }
1412  data["entering_key"] = f_entering_key;
1413  data["get_max_ticket"] = f_get_max_ticket ? "true" : "false";
1414  data["our_ticket"] = QString("%1").arg(f_our_ticket);
1415  data["added_ticket"] = f_added_ticket ? "true" : "false";
1416  data["ticket_key"] = f_ticket_key;
1417  data["added_ticket_quorum"] = f_added_ticket_quorum ? "true" : "false";
1418 
1419  // this is a map
1420  //names["still_entering"] = f_still_entering;
1421  //snaplock_ticket::key_map_t f_still_entering = snaplock_ticket::key_map_t();
1422 
1423  data["ticket_ready"] = f_ticket_ready ? "true" : "false";
1424  data["locked"] = f_locked ? "true" : "false";
1425  data["lock_timeout"] = QString("%1").arg(f_lock_timeout);
1426  data["lock_failed"] = f_lock_failed ? "true" : "false";
1427 
1428  QString result;
1429  for(auto & it : data)
1430  {
1431  result += it.first;
1432  result += QChar('=');
1433  it.second.replace("|", "%7C"); // make sure the value does not include any ';'
1434  result += it.second;
1435  result += QChar('|');
1436  }
1437 
1438  return result;
1439 }
1440 
1441 
1455 void snaplock_ticket::unserialize(QString const & data)
1456 {
1457  bool ok(false);
1458  snap::snap_string_list const vars(data.split('|'));
1459  for(auto const & d : vars)
1460  {
1461  int const pos(d.indexOf('='));
1462  QString const name(d.mid(0, pos));
1463  QString const value(d.mid(pos + 1));
1464  if(name == "object_name")
1465  {
1466 #ifdef _DEBUG
1467  if(f_object_name != value)
1468  {
1469  throw std::logic_error(
1470  "snaplock_ticket::unserialize() not unserializing object name \""
1471  + std::string(value.toUtf8().data())
1472  + "\" over itself \""
1473  + std::string(f_object_name.toUtf8().data())
1474  + "\" (object name mismatch)."
1475  );
1476  }
1477 #endif
1478  f_object_name = value;
1479  }
1480  else if(name == "obtention_timeout")
1481  {
1482  f_obtention_timeout = value.toLong(&ok, 10);
1483  }
1484  //else if(name == "alive_timeout") -- we do not transfer this one (not required, and could actually cause problems)
1485  //{
1486  // f_alive_timeout = value.toLong(&ok, 10);
1487  //}
1488  else if(name == "lock_duration")
1489  {
1490  f_lock_duration = value.toLong(&ok, 10);
1491  }
1492  else if(name == "unlock_duration")
1493  {
1494  f_unlock_duration = value.toLong(&ok, 10);
1495  }
1496  else if(name == "server_name")
1497  {
1498  f_server_name = value;
1499  }
1500  else if(name == "service_name")
1501  {
1502  f_service_name = value;
1503  }
1504  else if(name == "owner")
1505  {
1506  f_owner = value;
1507  }
1508  else if(name == "serial")
1509  {
1510  f_serial = value.toLong(&ok, 10);
1511  }
1512  else if(name == "entering_key")
1513  {
1514 #ifdef _DEBUG
1515  if(f_entering_key != value)
1516  {
1517  throw std::logic_error(
1518  "snaplock_ticket::unserialize() not unserializing entering key \""
1519  + std::string(value.toUtf8().data())
1520  + "\" over itself \""
1521  + std::string(f_entering_key.toUtf8().data())
1522  + "\" (entering key mismatch)."
1523  );
1524  }
1525 #endif
1526  f_entering_key = value;
1527  }
1528  else if(name == "get_max_ticket")
1529  {
1530  f_get_max_ticket = f_get_max_ticket || value == "true";
1531  }
1532  else if(name == "our_ticket")
1533  {
1534  f_our_ticket = value.toLong(&ok, 10);
1535  }
1536  else if(name == "added_ticket")
1537  {
1538  f_added_ticket = f_added_ticket || value == "true";
1539  }
1540  else if(name == "ticket_key")
1541  {
1542  f_ticket_key = value;
1543  }
1544  else if(name == "added_ticket_quorum")
1545  {
1546  f_added_ticket_quorum = f_added_ticket_quorum || value == "true";
1547  }
1548 
1549  // this is a map
1550  //names["still_entering"] = f_still_entering;
1551  //snaplock_ticket::key_map_t f_still_entering = snaplock_ticket::key_map_t();
1552 
1553  else if(name == "ticket_ready")
1554  {
1555  f_ticket_ready = f_ticket_ready || value == "true";
1556  }
1557  else if(name == "locked")
1558  {
1559  f_locked = f_locked || value == "true";
1560  }
1561  else if(name == "lock_timeout")
1562  {
1563  // the time may be larger because of an UNLOCK so we keep
1564  // the largest value
1565  //
1566  time_t const timeout(value.toLong(&ok, 10));
1567  if(timeout > f_lock_timeout)
1568  {
1569  f_lock_timeout = timeout;
1570  }
1571  }
1572  else if(name == "lock_failed")
1573  {
1574  f_lock_failed = f_lock_failed || value == "true";
1575  }
1576  }
1577 }
1578 
1579 
1580 }
1581 // snaplock namespace
1582 // vim: ts=4 sw=4 et
void lock_exiting(snap::snap_communicator_message &message)
Used to simulate a LOCKEXITING message.
Definition: snaplock.cpp:4139
serial_t get_serial() const
Return the serial number of this ticket.
computer_t::pointer_t get_leader_a() const
Definition: snaplock.cpp:1182
void lock_failed()
Let the service that wanted this lock know that it failed.
computer_t::pointer_t get_leader_b() const
Definition: snaplock.cpp:1208
std::shared_ptr< computer_t > pointer_t
Definition: snaplock.h:330
void set_owner(QString const &owner)
Define whether this ticket is the owner of that lock.
void entered()
Tell this entering that we received a LOCKENTERED message.
time_t get_current_timeout() const
Get the current lock timeout date.
void add_ticket()
Send the ADDTICKET message.
void set_serial(serial_t owner)
Give the lock a serial number for some form of unicity.
void ticket_added(snaplock_ticket::key_map_t const &entering)
Called whenever a TICKETADDED is received.
void max_ticket(int64_t new_max_ticket)
Called whenever a MAXTICKET is received.
void activate_lock()
Check whether this ticket can be activated and do so if so.
ticket_id_t get_ticket_number() const
Return the ticket number of this ticket.
int get_computer_count() const
Return the number of known computers running snaplock.
Definition: snaplock.cpp:973
QString const & get_object_name() const
Retrieve the object name of this ticket.
void drop_ticket()
We are done with the ticket.
QString const & get_owner() const
Return the name of this ticket&#39;s owner.
QString serialize() const
Serialize a ticket to send it over to another leader.
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)
time_t get_obtention_timeout() const
Get the obtention timeout date.
snap::snap_lock::timeout_t get_lock_duration() const
Retrieve the lock duration.
void set_ticket_number(ticket_id_t number)
Set the ticket number.
snaplock_ticket::key_map_t const get_entering_tickets(QString const &object_name)
Get a reference to the list of entering tickets.
Definition: snaplock.cpp:4120
bool send_message_to_leaders(snap::snap_communicator_message &message)
Send a message to the other two leaders.
QString const & get_server_name() const
Get the name of the server we are running on.
Definition: snaplock.cpp:1019
QString const & get_ticket_key() const
Retrieve a reference to the ticket key.
std::shared_ptr< snaplock_messenger > pointer_t
Definition: snaplock.h:157
void set_ready()
Mark the ticket as being ready.
void entering()
Enter the mode that lets us retrieve our ticket number.
void unserialize(QString const &data)
Unserialize a ticket string back to a ticket object.
bool is_locked() const
Check whether this ticket is locked or not.
void set_alive_timeout(time_t timeout)
Define a time when the ticket times out while waiting.
void remove_entering(QString const &key)
Call any time time an entering flag is reset.
QString const & get_service_name() const
Retrieve the service name of this ticket.
void set_ticket(QString const &object_name, QString const &key, snaplock_ticket::pointer_t ticket)
Set the ticket.
Definition: snaplock.cpp:4103
pid_t get_client_pid() const
Retrieve the client process identifier.
bool timed_out() const
Check whether this ticket timed out.
QString const & get_server_name() const
Retrieve the server name of this ticket.
snap::snap_lock::timeout_t get_unlock_duration() const
Get unlock duration.
QString const & get_entering_key() const
Retrieve a reference to the entering key of this ticket.
time_t get_lock_timeout() const
Get the lock timeout date.
std::map< QString, pointer_t > key_map_t
Definition: snaplock.h:209
void set_unlock_duration(snap::snap_lock::timeout_t duration)
Change the lock duration to the specified value.
void lock_activated()
Check whether this ticket can be activated and do so if so.
snaplock_ticket::ticket_id_t get_last_ticket(QString const &object_name)
Determine the last ticket defined in this snaplock.
Definition: snaplock.cpp:4064

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