snaplock: snaplock.h Source File

snaplock  1.7.14
The multi-computer lock service.
snaplock.h
Go to the documentation of this file.
1 /*
2  * Text:
3  * snaplock/src/snaplock.h
4  *
5  * Description:
6  * A daemon to synchronize processes between any number of computers
7  * by blocking all of them but one.
8  *
9  * License:
10  * Copyright (c) 2016-2019 Made to Order Software Corp. All Rights Reserved
11  *
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the
17  * "Software"), to deal in the Software without restriction, including
18  * without limitation the rights to use, copy, modify, merge, publish,
19  * distribute, sublicense, and/or sell copies of the Software, and to
20  * permit persons to whom the Software is furnished to do so, subject to
21  * the following conditions:
22  *
23  * The above copyright notice and this permission notice shall be included
24  * in all copies or substantial portions of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
29  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
30  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  */
34 
35 // our lib
36 //
37 #include <snapwebsites/snap_communicator.h>
38 #include <snapwebsites/snap_communicator_dispatcher.h>
39 #include <snapwebsites/snap_exception.h>
40 #include <snapwebsites/snap_lock.h>
41 #include <snapwebsites/snapwebsites.h>
42 
43 
44 namespace snaplock
45 {
46 
47 
48 class snaplock_exception : public snap::snap_exception
49 {
50 public:
51  explicit snaplock_exception(char const * what_msg) : snap_exception("snaplock", what_msg) {}
52  explicit snaplock_exception(std::string const & what_msg) : snap_exception("snaplock", what_msg) {}
53  explicit snaplock_exception(QString const & what_msg) : snap_exception("snaplock", what_msg) {}
54 };
55 
57 {
58 public:
59  explicit snaplock_exception_content_invalid_usage(char const * what_msg) : snaplock_exception(what_msg) {}
60  explicit snaplock_exception_content_invalid_usage(std::string const & what_msg) : snaplock_exception(what_msg) {}
61  explicit snaplock_exception_content_invalid_usage(QString const & what_msg) : snaplock_exception(what_msg) {}
62 };
63 
64 
65 class snaplock;
66 
67 
68 
70  : public snap::snap_communicator::snap_signal
71 {
72 public:
73  typedef std::shared_ptr<snaplock_interrupt> pointer_t;
74 
76  snaplock_interrupt(snaplock_interrupt const & rhs) = delete;
77  virtual ~snaplock_interrupt() override {}
78 
79  snaplock_interrupt & operator = (snaplock_interrupt const & rhs) = delete;
80 
81  // snap::snap_communicator::snap_signal implementation
82  virtual void process_signal() override;
83 
84 private:
85  snaplock * f_snaplock = nullptr;
86 };
87 
88 
89 
91  : public snap::snap_communicator::snap_timer
92 {
93 public:
94  typedef std::shared_ptr<snaplock_timer> pointer_t;
95 
97  snaplock_timer(snaplock_timer const & rhs) = delete;
98  virtual ~snaplock_timer() override {}
99 
100  snaplock_timer & operator = (snaplock_timer const & rhs) = delete;
101 
102  // snap::snap_communicator::snap_connection implementation
103  virtual void process_timeout() override;
104 
105 private:
106  snaplock * f_snaplock = nullptr;
107 };
108 
109 
110 
112  : public snap::snap_communicator::snap_signal
113 {
114 public:
115  typedef std::shared_ptr<snaplock_info> pointer_t;
116 
117  snaplock_info(snaplock * sl);
118  snaplock_info(snaplock_info const & rhs) = delete;
119  virtual ~snaplock_info() override {}
120 
121  snaplock_info const & operator = (snaplock_info const & rhs) = delete;
122 
123  // snap::snap_communicator::snap_signal implementation
124  virtual void process_signal() override;
125 
126 private:
127  snaplock * f_snaplock = nullptr;
128 };
129 
130 
131 
133  : public snap::snap_communicator::snap_signal
134 {
135 public:
136  typedef std::shared_ptr<snaplock_debug_info> pointer_t;
137 
139  snaplock_debug_info(snaplock_debug_info const & rhs) = delete;
140  virtual ~snaplock_debug_info() override {}
141 
142  snaplock_debug_info const & operator = (snaplock_debug_info const & rhs) = delete;
143 
144  // snap::snap_communicator::snap_signal implementation
145  virtual void process_signal() override;
146 
147 private:
148  snaplock * f_snaplock = nullptr;
149 };
150 
151 
152 
154  : public snap::snap_communicator::snap_tcp_client_permanent_message_connection
155 {
156 public:
157  typedef std::shared_ptr<snaplock_messenger> pointer_t;
158 
159  snaplock_messenger(snaplock * sl, std::string const & addr, int port);
160  snaplock_messenger(snaplock_messenger const & rhs) = delete;
161  virtual ~snaplock_messenger() override {}
162 
163  snaplock_messenger & operator = (snaplock_messenger const & rhs) = delete;
164 
165  // snap::snap_communicator::snap_tcp_client_permanent_message_connection implementation
166  virtual void process_connection_failed(std::string const & error_message) override;
167  virtual void process_connected() override;
168 
169 protected:
170  // this is owned by a snaplock function so no need for a smart pointer
171  // (and it would create a loop)
172  snaplock * f_snaplock = nullptr;
173 };
174 
175 
177  : public snaplock_messenger
178 {
179 public:
180  typedef std::shared_ptr<snaplock_tool> pointer_t;
181 
182  snaplock_tool(snaplock * sl, std::string const & addr, int port);
183  snaplock_tool(snaplock_tool const & rhs) = delete;
184  virtual ~snaplock_tool() override {}
185 
186  snaplock_tool & operator = (snaplock_tool const & rhs) = delete;
187 
188  // snap::snap_communicator::snap_tcp_client_permanent_message_connection implementation
189  virtual void process_message(snap::snap_communicator_message const & message);
190  virtual void process_connection_failed(std::string const & error_message);
191  virtual void process_connected();
192 };
193 
194 
196 {
197  int64_t f_number = 0;
198  int64_t f_timeout = 0;
199 };
200 
201 
202 
204  : public std::enable_shared_from_this<snaplock_ticket>
205 {
206 public:
207  typedef std::shared_ptr<snaplock_ticket> pointer_t;
208  typedef std::vector<pointer_t> vector_t;
209  typedef std::map<QString, pointer_t> key_map_t; // sorted by key
210  typedef std::map<QString, key_map_t> object_map_t; // sorted by object_name
211  typedef int32_t serial_t;
212  typedef uint32_t ticket_id_t;
213 
214  static serial_t const NO_SERIAL = -1;
215  static ticket_id_t const NO_TICKET = 0;
216 
218  snaplock * sl
220  , QString const & object_name
221  , QString const & entering_key
222  , time_t obtention_timeout
223  , snap::snap_lock::timeout_t lock_duration
224  , QString const & server_name
225  , QString const & service_name
226  );
227  snaplock_ticket(snaplock_ticket const & rhs) = delete;
228  snaplock_ticket & operator = (snaplock_ticket const & rhs) = delete;
229 
230  // message handling
231  //
232  bool send_message_to_leaders(snap::snap_communicator_message & message);
233  void entering();
234  void entered();
235  void max_ticket(int64_t new_max_ticket);
236  void add_ticket();
237  void ticket_added(snaplock_ticket::key_map_t const & entering);
238  void remove_entering(QString const & key);
239  void activate_lock();
240  void lock_activated();
241  void drop_ticket(); // this is called when we receive the UNLOCK event
242  void lock_failed();
243  void lock_tickets();
244 
245  // object handling
246  //
247  void set_owner(QString const & owner);
248  QString const & get_owner() const;
249  pid_t get_client_pid() const;
250  void set_serial(serial_t owner);
251  serial_t get_serial() const;
252  void set_unlock_duration(snap::snap_lock::timeout_t duration);
253  snap::snap_lock::timeout_t get_unlock_duration() const;
254  void set_ready();
255  void set_ticket_number(ticket_id_t number);
256  ticket_id_t get_ticket_number() const;
257  bool is_locked() const;
258  time_t get_obtention_timeout() const;
259  void set_alive_timeout(time_t timeout);
260  snap::snap_lock::timeout_t get_lock_duration() const;
261  time_t get_lock_timeout() const;
262  time_t get_current_timeout() const;
263  bool timed_out() const;
264  QString const & get_object_name() const;
265  QString const & get_server_name() const;
266  QString const & get_service_name() const;
267  QString const & get_entering_key() const;
268  QString const & get_ticket_key() const;
269  QString serialize() const;
270  void unserialize(QString const & data);
271 
272 private:
273  // this is owned by a snaplock function so no need for a smart pointer
274  // (and it would create a loop)
275  snaplock * f_snaplock = nullptr;
276 
277  // initialization
279  QString f_object_name = QString();
280  time_t f_obtention_timeout = 0;
281  time_t f_alive_timeout = 0;
282  snap::snap_lock::timeout_t f_lock_duration = 0;
283  snap::snap_lock::timeout_t f_unlock_duration = 0;
284  QString f_server_name = QString();
285  QString f_service_name = QString();
286  QString f_owner = QString();
287  serial_t f_serial = NO_SERIAL;
288 
289  // initialized, entering
290  QString f_entering_key = QString();
291  bool f_get_max_ticket = false;
292 
293  // entered, adding ticket
294  ticket_id_t f_our_ticket = NO_TICKET;
295  bool f_added_ticket = false;
296  QString f_ticket_key = QString();
297 
298  // ticket added, exiting
299  bool f_added_ticket_quorum = false;
301 
302  // exited, ticket ready
303  bool f_ticket_ready = false;
304 
305  // locked
306  bool f_locked = false;
307  time_t f_lock_timeout = 0;
308 
309  // the lock did not take (in most cases, this is because of a timeout)
310  bool f_lock_failed = false;
311 };
312 
313 
314 
315 #pragma GCC diagnostic push
316 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
317 class snaplock
318  : public snap::snap_communicator::connection_with_send_message
319  , public snap::dispatcher<snaplock>
320  , public std::enable_shared_from_this<snaplock>
321 {
322 public:
323  typedef std::shared_ptr<snaplock> pointer_t;
324 
326  {
327  public:
328  typedef int64_t priority_t;
329  typedef uint32_t random_t;
330  typedef std::shared_ptr<computer_t> pointer_t;
331  typedef std::map<QString, pointer_t> map_t;
332  typedef std::vector<pointer_t> vector_t;
333 
334  static priority_t const PRIORITY_UNDEFINED = -1;
335  static priority_t const PRIORITY_MIN = 0;
336  static priority_t const PRIORITY_LEADER = 0;
337  static priority_t const PRIORITY_USER_MIN = 1;
338  static priority_t const PRIORITY_DEFAULT = 14;
339  static priority_t const PRIORITY_OFF = 15;
340  static priority_t const PRIORITY_MAX = 15;
341 
342  computer_t();
343  computer_t(QString const & name, uint8_t priority);
344 
345  bool is_self() const;
346  void set_connected(bool connected);
347  bool get_connected() const;
348  bool set_id(QString const & id);
349  priority_t get_priority() const;
350  void set_start_time(time_t start_time);
351  time_t get_start_time() const;
352 
353  QString const & get_name() const;
354  QString const & get_id() const;
355  QString const & get_ip_address() const;
356 
357  private:
358  mutable QString f_id = QString();
359 
360  bool f_connected = true;
361  bool f_self = false;
362 
363  priority_t f_priority = PRIORITY_UNDEFINED;
364  random_t f_random_id = 0;
365  QString f_ip_address = QString();
366  pid_t f_pid = 0;
367  QString f_name = QString();
368 
369  time_t f_start_time = -1;
370  };
371 
372  static int64_t const DEFAULT_TIMEOUT = 5; // in seconds
373  static int64_t const MIN_TIMEOUT = 3; // in seconds
374 
375  snaplock(int argc, char * argv[]);
376  snaplock(snaplock const & rhs) = delete;
377  virtual ~snaplock();
378 
379  snaplock & operator = (snaplock const & rhs) = delete;
380 
381  void run();
382  //void process_message(snap::snap_communicator_message const & message);
383  void tool_message(snap::snap_communicator_message const & message);
384  void process_connection(int const s);
385 
386  // connection_with_send_message overloads
387  //
388  virtual bool send_message(snap::snap_communicator_message const & message, bool cache = false) override;
389 
390  int get_computer_count() const;
391  int quorum() const;
392  QString const & get_server_name() const;
393  bool is_ready() const;
394  computer_t::pointer_t is_leader(QString id = QString()) const;
395  computer_t::pointer_t get_leader_a() const;
396  computer_t::pointer_t get_leader_b() const;
397  void info();
398  void debug_info();
399  void cleanup();
400  snaplock_ticket::ticket_id_t get_last_ticket(QString const & object_name);
401  void set_ticket(QString const & object_name, QString const & key, snaplock_ticket::pointer_t ticket);
402  void lock_exiting(snap::snap_communicator_message & message);
403  snaplock_ticket::key_map_t const get_entering_tickets(QString const & object_name);
404  QString serialized_tickets();
405  snaplock_ticket::pointer_t find_first_lock(QString const & object_name);
406 
407  // implementation of snap::snapcommunicator::connection_with_send_message
408  //
409  // note: ready() is part of the understood messages, it has to be
410  // public for the snaplock_interrupt.cpp to call it
411  //
412  virtual void ready(snap::snap_communicator_message & message) override; // no "msg_" because that's in connection_with_send_message
413  virtual void stop(bool quitting) override; // no "msg_" because that's in connection_with_send_message
414 
415  static void sighandler(int sig);
416  static void sigloghandler(int sig);
417 
418 private:
420  {
421  typedef std::vector<message_cache> vector_t;
422 
423  time_t f_timeout = 0;
424  snap::snap_communicator_message f_message = snap::snap_communicator_message();
425  };
426 
427  void get_parameters(snap::snap_communicator_message const & message, QString * object_name, pid_t * client_pid, time_t * timeout, QString * key, QString * source);
428  void activate_first_lock(QString const & object_name);
429  void ticket_list(snap::snap_communicator_message const & message);
430  void send_lockstarted(snap::snap_communicator_message const * message);
431  void election_status();
432  void check_lock_status();
433  void synchronize_leaders();
434  void forward_message_to_leader(snap::snap_communicator_message & message);
435 
436  // messages handled by the dispatcher
437  // (see also ready() and stop() above)
438  //
439  void msg_absolutely(snap::snap_communicator_message & message);
440  void msg_activate_lock(snap::snap_communicator_message & message);
441  void msg_add_ticket(snap::snap_communicator_message & message);
442  void msg_cluster_up(snap::snap_communicator_message & message);
443  void msg_cluster_down(snap::snap_communicator_message & message);
444  void msg_server_gone(snap::snap_communicator_message & message);
445  void msg_drop_ticket(snap::snap_communicator_message & message);
446  void msg_get_max_ticket(snap::snap_communicator_message & message);
447  void msg_lock(snap::snap_communicator_message & message);
448  void msg_lock_activated(snap::snap_communicator_message & message);
449  void msg_lock_entered(snap::snap_communicator_message & message);
450  void msg_lock_entering(snap::snap_communicator_message & message);
451  void msg_lock_exiting(snap::snap_communicator_message & message);
452  void msg_lock_failed(snap::snap_communicator_message & message);
453  void msg_lock_leaders(snap::snap_communicator_message & message);
454  void msg_lock_started(snap::snap_communicator_message & message);
455  void msg_lock_status(snap::snap_communicator_message & message);
456  void msg_lock_tickets(snap::snap_communicator_message & message);
457  void msg_list_tickets(snap::snap_communicator_message & message);
458  void msg_max_ticket(snap::snap_communicator_message & message);
459  void msg_status(snap::snap_communicator_message & message);
460  void msg_ticket_added(snap::snap_communicator_message & message);
461  void msg_ticket_ready(snap::snap_communicator_message & message);
462  void msg_unlock(snap::snap_communicator_message & message);
463 
464  static snap::dispatcher<snaplock>::dispatcher_match::vector_t const g_snaplock_service_messages;
465 
466  advgetopt::getopt f_opt;
467  snap::snap_config f_config;
468  time_t f_start_time = -1;
469  QString f_log_conf = QString("/etc/snapwebsites/logger/snaplock.properties");
470  QString f_server_name = QString();
471  QString f_service_name = QString("snaplock");
472  QString f_communicator_addr = QString("localhost");
473  int f_communicator_port = 4040;
474  snap::snap_communicator::pointer_t f_communicator = snap::snap_communicator::pointer_t();
475  QString f_host_list = QString("localhost");
481  bool f_stop_received = false;
482  bool f_debug = false;
483  bool f_debug_lock_messages = false;
484  size_t f_neighbors_count = 0;
485  size_t f_neighbors_quorum = 0;
486  QString f_my_id = QString();
487  QString f_my_ip_address = QString();
488  QString f_lock_status = QString("NOLOCK");
489  computer_t::map_t f_computers = computer_t::map_t(); // key is the computer name
491  int f_next_leader = 0;
495  int64_t f_election_date = 0;
496  snaplock_ticket::serial_t f_ticket_serial = 0;
497  mutable time_t f_pace_lockstarted = 0;
498 };
499 #pragma GCC diagnostic pop
500 
501 
502 }
503 // snaplock namespace
504 // vim: ts=4 sw=4 et
std::shared_ptr< snaplock_timer > pointer_t
Definition: snaplock.h:94
std::shared_ptr< snaplock_interrupt > pointer_t
Definition: snaplock.h:73
std::shared_ptr< computer_t > pointer_t
Definition: snaplock.h:330
std::vector< message_cache > vector_t
Definition: snaplock.h:421
virtual ~snaplock_tool() override
Definition: snaplock.h:184
virtual ~snaplock_debug_info() override
Definition: snaplock.h:140
snaplock_exception_content_invalid_usage(QString const &what_msg)
Definition: snaplock.h:61
static snap::dispatcher< snaplock >::dispatcher_match::vector_t const g_snaplock_service_messages
List of snaplock commands.
Definition: snaplock.h:464
std::map< QString, key_map_t > object_map_t
Definition: snaplock.h:210
advgetopt::getopt f_opt
Definition: snaplock.h:466
virtual ~snaplock_info() override
Definition: snaplock.h:119
Handle the ticket messages.
Definition: snaplock.h:203
Handle the locks timeout.
Definition: snaplock.h:90
std::vector< pointer_t > vector_t
Definition: snaplock.h:332
std::vector< pointer_t > vector_t
Definition: snaplock.h:208
snaplock_exception_content_invalid_usage(char const *what_msg)
Definition: snaplock.h:59
virtual ~snaplock_interrupt() override
Definition: snaplock.h:77
Handle snaplock command line commands.
Definition: snaplock.h:176
std::shared_ptr< snaplock > pointer_t
Definition: snaplock.h:323
snap::snap_config f_config
Definition: snaplock.h:467
std::shared_ptr< snaplock_ticket > pointer_t
Definition: snaplock.h:207
std::shared_ptr< snaplock_tool > pointer_t
Definition: snaplock.h:180
std::shared_ptr< snaplock_messenger > pointer_t
Definition: snaplock.h:157
std::shared_ptr< snaplock_info > pointer_t
Definition: snaplock.h:115
snaplock_exception(QString const &what_msg)
Definition: snaplock.h:53
snaplock_exception(std::string const &what_msg)
Definition: snaplock.h:52
snaplock_exception(char const *what_msg)
Definition: snaplock.h:51
std::map< QString, pointer_t > map_t
Definition: snaplock.h:331
virtual ~snaplock_messenger() override
Definition: snaplock.h:161
Handle the SIGINT Unix signal.
Definition: snaplock.h:69
std::shared_ptr< snaplock_debug_info > pointer_t
Definition: snaplock.h:136
snaplock_exception_content_invalid_usage(std::string const &what_msg)
Definition: snaplock.h:60
Handle the SIGUSR2 Unix signal.
Definition: snaplock.h:132
Handle the SIGUSR1 Unix signal.
Definition: snaplock.h:111
std::map< QString, pointer_t > key_map_t
Definition: snaplock.h:209
virtual ~snaplock_timer() override
Definition: snaplock.h:98
Handle messages from the Snap Communicator server.
Definition: snaplock.h:153

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