1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software Foundation,
21    51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 #ifndef RECOVERY_INCLUDE
24 #define RECOVERY_INCLUDE
25 
26 #include <list>
27 #include <string>
28 
29 #include "applier.h"
30 #include "channel_observation_manager.h"
31 #include "recovery_state_transfer.h"
32 #include <mysql/gcs/gcs_communication_interface.h>
33 #include <mysql/gcs/gcs_control_interface.h>
34 #include <mysql/group_replication_priv.h>
35 
36 /* The possible policies used on recovery when applying cached transactions */
37 enum enum_recovery_completion_policies
38 {
39   RECOVERY_POLICY_WAIT_CERTIFIED= 0, // Wait for the certification of transactions
40   RECOVERY_POLICY_WAIT_EXECUTED,     // Wait for the execution of transactions
41 };
42 
43 class Recovery_module
44 {
45 
46 public:
47 /**
48   Recovery_module constructor
49 
50   @param applier
51             reference to the applier
52   @param channel_obsr_mngr
53             reference to the channel hooks observation manager
54   @param components_stop_timeout
55             timeout value for the recovery module during shutdown.
56  */
57   Recovery_module(Applier_module_interface *applier,
58                   Channel_observation_manager *channel_obsr_mngr,
59                   ulong components_stop_timeout);
60 
61   ~Recovery_module();
62 
set_applier_module(Applier_module_interface * applier)63   void set_applier_module(Applier_module_interface *applier)
64   {
65     applier_module= applier;
66   }
67 
68   /**
69     Starts the recovery process, initializing the recovery thread.
70     This method is designed to be as light as possible, as if it involved any
71     major computation or wait process that would block the view change process
72     delaying the group.
73 
74     @note this method only returns when the recovery thread is already running
75 
76     @param group_name          the joiner's group name
77     @param rec_view_id         the new view id
78 
79     @return the operation status
80       @retval 0      OK
81       @retval !=0    Error
82   */
83   int start_recovery(const std::string& group_name,
84                      const std::string& rec_view_id);
85 
86   /**
87     Recovery thread main execution method.
88 
89     Here, the donor is selected, the connection to the donor is established,
90     and several safe keeping assurances are guaranteed, such as the applier
91     being suspended.
92   */
93   int recovery_thread_handle();
94 
95   /**
96     Set retrieved certification info from a group replication channel extracted
97     from a given View_change event.
98 
99     @param info  the given view_change_event
100 
101     @return the operation status
102       @retval 0      OK
103       @retval !=0    Error
104   */
105   int set_retrieved_cert_info(void* info);
106 
107   /**
108     Stops the recovery process, shutting down the recovery thread.
109     If the thread does not stop in a user designated time interval, a timeout
110     is issued.
111 
112     @note this method only returns when the thread is stopped or on timeout
113 
114     @return the operation status
115       @retval 0      OK
116       @retval !=0    Timeout
117   */
118   int stop_recovery();
119 
120   /**
121     This method decides what action to take when a member exits the group and
122     executes it.
123     It can for the joiner:
124       If it exited, then terminate the recovery process.
125       If the donor left, and the state transfer is still ongoing, then pick a
126       new one and restart the transfer.
127 
128     @param did_members_left states if members left the view
129     @param is_leaving true if the member is leaving the group
130 
131     @return the operation status
132       @retval 0      OK
133       @retval !=0    Error
134    */
135   int update_recovery_process(bool did_members_left, bool is_leaving);
136 
137   //Methods for variable updates
138 
139   /** Sets the number of times recovery tries to connect to a given donor. */
set_recovery_donor_retry_count(ulong retry_count)140   void set_recovery_donor_retry_count(ulong retry_count)
141   {
142     recovery_state_transfer.set_recovery_donor_retry_count(retry_count);
143   }
144 
145   /** Sets the sleep time between connection attempts to all possible donors */
set_recovery_donor_reconnect_interval(ulong reconnect_interval)146   void set_recovery_donor_reconnect_interval(ulong reconnect_interval)
147   {
148     recovery_state_transfer.
149         set_recovery_donor_reconnect_interval(reconnect_interval);
150   }
151 
152   /**
153     Sets all the SSL option to use on recovery.
154 
155      @param use_ssl                 force the use of SSL on recovery connections
156      @param ssl_ca                  SSL trusted certificate authorities file
157      @param ssl_capath              a directory with trusted CA files
158      @param ssl_cert                the certificate file for secure connections
159      @param ssl_cipher              the list of ciphers to use
160      @param ssl_key                 the SSL key file
161      @param ssl_crl                 SSL revocation list file
162      @param ssl_crlpath             path with revocation list files
163      @param ssl_verify_server_cert  verify the hostname against the certificate
164   */
set_recovery_ssl_options(bool use_ssl,const char * ssl_ca,const char * ssl_capath,const char * ssl_cert,const char * ssl_cipher,const char * ssl_key,const char * ssl_crl,const char * ssl_crlpath,bool ssl_verify_server_cert)165   void set_recovery_ssl_options(bool use_ssl,
166                                 const char *ssl_ca,
167                                 const char *ssl_capath,
168                                 const char *ssl_cert,
169                                 const char *ssl_cipher,
170                                 const char *ssl_key,
171                                 const char *ssl_crl,
172                                 const char *ssl_crlpath,
173                                 bool ssl_verify_server_cert)
174   {
175     recovery_state_transfer.set_recovery_use_ssl(use_ssl);
176     if (ssl_ca != NULL)
177       recovery_state_transfer.set_recovery_ssl_ca(ssl_ca);
178     if (ssl_capath != NULL)
179       recovery_state_transfer.set_recovery_ssl_capath(ssl_capath);
180     if (ssl_cert != NULL)
181       recovery_state_transfer.set_recovery_ssl_cert(ssl_cert);
182     if (ssl_cipher != NULL)
183       recovery_state_transfer.set_recovery_ssl_cipher(ssl_cipher);
184     if (ssl_key != NULL)
185       recovery_state_transfer.set_recovery_ssl_key(ssl_key);
186     if (ssl_crl != NULL)
187       recovery_state_transfer.set_recovery_ssl_crl(ssl_crl);
188     if (ssl_crlpath != NULL)
189       recovery_state_transfer.set_recovery_ssl_crlpath(ssl_crlpath);
190     recovery_state_transfer.
191         set_recovery_ssl_verify_server_cert(ssl_verify_server_cert);
192   }
193 
194   /** Set the option that forces the use of SSL on recovery connections */
set_recovery_use_ssl(char use_ssl)195   void set_recovery_use_ssl(char use_ssl)
196   {
197     recovery_state_transfer.set_recovery_use_ssl(use_ssl);
198   }
199 
200   /** Set a SSL trusted certificate authorities file */
set_recovery_ssl_ca(const char * ssl_ca)201   void set_recovery_ssl_ca(const char* ssl_ca)
202   {
203     recovery_state_transfer.set_recovery_ssl_ca(ssl_ca);
204   }
205 
206   /** Set a folder with SSL trusted CA files */
set_recovery_ssl_capath(const char * ssl_capath)207   void set_recovery_ssl_capath(const char* ssl_capath)
208   {
209     recovery_state_transfer.set_recovery_ssl_capath(ssl_capath);
210   }
211 
212   /** Set a SSL certificate for connection */
set_recovery_ssl_cert(const char * ssl_cert)213   void set_recovery_ssl_cert(const char* ssl_cert)
214   {
215     recovery_state_transfer.set_recovery_ssl_cert(ssl_cert);
216   }
217 
218   /** Set a SSL ciphers to be used */
set_recovery_ssl_cipher(const char * ssl_cipher)219   void set_recovery_ssl_cipher(const char* ssl_cipher)
220   {
221     recovery_state_transfer.set_recovery_ssl_cipher(ssl_cipher);
222   }
223 
224   /** Set a SSL key for connections */
set_recovery_ssl_key(const char * ssl_key)225   void set_recovery_ssl_key(const char* ssl_key)
226   {
227     recovery_state_transfer.set_recovery_ssl_key(ssl_key);
228   }
229 
230   /** Set a SSL revocation list file*/
set_recovery_ssl_crl(const char * ssl_crl)231   void set_recovery_ssl_crl(const char* ssl_crl)
232   {
233     recovery_state_transfer.set_recovery_ssl_crl(ssl_crl);
234   }
235 
236   /** Set a folder with SSL revocation list files*/
set_recovery_ssl_crlpath(const char * ssl_crlpath)237   void set_recovery_ssl_crlpath(const char* ssl_crlpath)
238   {
239     recovery_state_transfer.set_recovery_ssl_crlpath(ssl_crlpath);
240   }
241 
242   /** Set if recovery shall compare the used hostname against the certificate */
set_recovery_ssl_verify_server_cert(char ssl_verify_server_cert)243   void set_recovery_ssl_verify_server_cert(char ssl_verify_server_cert)
244   {
245     recovery_state_transfer.set_recovery_ssl_verify_server_cert(ssl_verify_server_cert);
246   }
247 
248   /**
249     Sets the recovery shutdown timeout.
250 
251     @param[in]  timeout      the timeout
252   */
set_stop_wait_timeout(ulong timeout)253   void set_stop_wait_timeout (ulong timeout){
254     stop_wait_timeout= timeout;
255     recovery_state_transfer.set_stop_wait_timeout(timeout);
256   }
257 
258   /**
259     Sets recovery threshold policy on what to wait when handling transactions
260     @param completion_policy  if recovery shall wait for execution
261                               or certification
262   */
263   void
set_recovery_completion_policy(enum_recovery_completion_policies completion_policy)264   set_recovery_completion_policy(enum_recovery_completion_policies completion_policy)
265   {
266     this->recovery_completion_policy= completion_policy;
267   }
268 
269   /**
270     Checks if the given id matches the recovery applier thread
271     @param id  the thread id
272 
273     @return if it belongs to a thread
274       @retval true   the id matches a SQL or worker thread
275       @retval false  the id doesn't match any thread
276   */
277   bool is_own_event_channel(my_thread_id id);
278 
279 private:
280 
281   /** Sets the thread context */
282   void set_recovery_thread_context();
283 
284   /**
285     Handles code for removing the member in case of a failure during
286     recovery.
287   */
288   void leave_group_on_recovery_failure();
289 
290   /** Cleans the recovery thread related options/structures. */
291   void clean_recovery_thread_context();
292 
293   /**
294     Starts a wait process until the applier fulfills the necessary condition for
295     the member to be acknowledge as being online.
296 
297     @return the operation status
298       @retval 0      OK
299       @retval !=0    Error
300   */
301   int  wait_for_applier_module_recovery();
302 
303   /**
304     Sends a message throughout the group stating the member as online.
305   */
306   void notify_group_recovery_end();
307 
308   //recovery thread variables
309   my_thread_handle recovery_pthd;
310   THD *recovery_thd;
311 
312   /* The plugin's applier module interface*/
313   Applier_module_interface *applier_module;
314 
315   /* The group to which the recovering member belongs */
316   std::string group_name;
317 
318   /* The recovery state transfer class */
319   Recovery_state_transfer recovery_state_transfer;
320 
321   /* Recovery running flag */
322   bool recovery_running;
323   /* Recovery abort flag */
324   bool recovery_aborted;
325   /* Recovery starting flag */
326   bool recovery_starting;
327 
328   //run conditions and locks
329   mysql_mutex_t run_lock;
330   mysql_cond_t  run_cond;
331 
332   /* Recovery strategy when waiting for the cache transaction handling*/
333   enum_recovery_completion_policies recovery_completion_policy;
334 
335   /* Recovery module's timeout on shutdown */
336   ulong stop_wait_timeout;
337 };
338 
339 #endif /* RECOVERY_INCLUDE */
340