1 /* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
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
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /**
24 @file clone_handler.h
25 Clone handler interface to access clone plugin
26 */
27 
28 #ifndef CLONE_HANDLER_INCLUDED
29 #define CLONE_HANDLER_INCLUDED
30 
31 #include <atomic>
32 #include <string>
33 
34 #include "my_io.h"
35 #include "mysql.h"
36 #include "sql/sql_plugin_ref.h"  // plugin_ref
37 
38 class THD;
39 class Srv_session;
40 struct Mysql_clone;
41 struct MYSQL_SOCKET;
42 
43 /**
44   Number of PSI_statement_info instruments
45   for clone statements.
46 */
47 
48 #define CLONE_PSI_STATEMENT_COUNT 5
49 
50 /**
51   Clone plugin handler to convenient way to. Takes
52 */
53 class Clone_handler {
54  public:
55   /** Constructor: Initialize plugin name */
Clone_handler(const char * plugin_name_arg)56   Clone_handler(const char *plugin_name_arg) : m_plugin_handle(nullptr) {
57     m_plugin_name.assign(plugin_name_arg);
58   }
59 
60   /** Initialize plugin handle
61   @return error code */
62   int init();
63 
64   /** Clone handler interface for local clone.
65   @param[in]	thd		server thread handle
66   @param[in]	data_dir	cloned data directory
67   @return error code */
68   int clone_local(THD *thd, const char *data_dir);
69 
70   /** Clone handler interface for remote clone client.
71   @param[in]	thd		server thread handle
72   @param[in]	remote_host	remote host IP address
73   @param[in]	remote_port	remote server port
74   @param[in]	remote_user	remote user name
75   @param[in]	remote_passwd	remote user's password
76   @param[in]	data_dir	cloned data directory
77   @param[in]	ssl_mode	remote connection ssl mode
78   @return error code */
79   int clone_remote_client(THD *thd, const char *remote_host, uint remote_port,
80                           const char *remote_user, const char *remote_passwd,
81                           const char *data_dir, enum mysql_ssl_mode ssl_mode);
82 
83   /** Clone handler interface for remote clone server.
84   @param[in]	thd	server thread handle
85   @param[in]	socket	network socket to remote client
86   @return error code */
87   int clone_remote_server(THD *thd, MYSQL_SOCKET socket);
88 
89   /** Get donor error and message for ER_CLONE_DONOR error.
90   @param[in]	session	server session
91   @param[out]	error	donor error number
92   @param[out]	message	error message
93   @return true, iff successful. */
94   static bool get_donor_error(Srv_session *session, int &error,
95                               const char *&message);
96 
97   /** @return false only if no user data is dropped yet. */
is_data_dropped()98   static bool is_data_dropped() { return (s_is_data_dropped); }
99 
100   /** Must set before dropping any user data. */
set_drop_data()101   static void set_drop_data() { s_is_data_dropped.store(true); }
102 
103   /** @return true, if clone provisioning in progress. */
is_provisioning()104   static bool is_provisioning() { return (s_provision_in_progress > 0); }
105 
106   /** @return true, if ordered commit should be forced. Currently
107   clone would force ordered commit at end while blocking XA operations */
need_commit_order()108   static bool need_commit_order() { return (s_xa_block_op.load()); }
109 
110   /* Initialize XA counters and mutex. */
111   static void init_xa();
112 
113   /* Destroy XA mutex. */
114   static void uninit_xa();
115 
116   /* RAII guard for XA operation synchronization with clone. */
117   struct XA_Operation {
118     /** Constructor: mark XA operation begin.
119     @param[in]	thd	session thread */
120     explicit XA_Operation(THD *thd);
121 
122     /** Destructor: mark XA operation end. */
123     ~XA_Operation();
124 
125     /** Disable copy construction */
126     XA_Operation(XA_Operation const &) = delete;
127 
128     /** Disable assignment */
129     XA_Operation &operator=(XA_Operation const &) = delete;
130 
131    private:
132     /** Session thread holding the guard. */
133     THD *m_thd;
134   };
135 
136   /* RAII guard for blocking and unblocking XA operations. */
137   struct XA_Block {
138     /** Constructor: Block all XA operations.
139     @param[in]	thd	session thread */
140     explicit XA_Block(THD *thd);
141 
142     /** Destructor: unblock XA operations. */
143     ~XA_Block();
144 
145     /** Disable copy construction */
146     XA_Block(XA_Block const &) = delete;
147 
148     /** Disable assignment */
149     XA_Block &operator=(XA_Block const &) = delete;
150 
151     /** @return true, if XA blocking is unsuccessful. */
152     bool failed() const;
153 
154    private:
155     /** If blocking is successful and there is no XA operations. */
156     bool m_success;
157   };
158 
159  private:
160   /** Block new active XA operations and wait for existing ones to complete.
161   @param[in]	thd	session thread */
162   static bool block_xa_operation(THD *thd);
163 
164   /** Unblock waiting XA operations. */
165   static void unblock_xa_operation();
166 
167   /** Increment XA operation count and wait if blocked by clone.
168   @param[in]	thd	session thread */
169   static void begin_xa_operation(THD *thd);
170 
171   /** Decrement XA operation count. */
172   static void end_xa_operation();
173 
174   /** Validate clone data directory and convert to os format
175   @param[in]	in_dir	user specified clone directory
176   @param[out]	out_dir	data directory in native os format
177   @return error code */
178   int validate_dir(const char *in_dir, char *out_dir);
179 
180  private:
181   /** Number of XA operations (prepare/commit/rollback) in progress. */
182   static std::atomic<int> s_xa_counter;
183 
184   /** Set when clone blocks XA operations. XA operations currently are
185   not ordered between binlog and SE and needs to be synchronized for clone. */
186   static std::atomic<bool> s_xa_block_op;
187 
188   /** True if clone provisioning in progress. */
189   static std::atomic<int> s_provision_in_progress;
190 
191   /** True, if any user data is dropped by clone. */
192   static std::atomic<bool> s_is_data_dropped;
193 
194   /** Mutex to synchronize blocking XA operation. */
195   static mysql_mutex_t s_xa_mutex;
196 
197   /** Clone plugin name */
198   std::string m_plugin_name;
199 
200   /** Clone plugin handle */
201   Mysql_clone *m_plugin_handle;
202 };
203 
204 /** Check if the clone plugin is installed and lock. If the plugin is ready,
205 return the handler to caller.
206 @param[in]	thd	server thread handle
207 @param[out]	plugin	plugin reference
208 @return clone handler on success otherwise NULL */
209 Clone_handler *clone_plugin_lock(THD *thd, plugin_ref *plugin);
210 
211 /** Unlock the clone plugin.
212 @param[in]	thd	server thread handle
213 @param[out]	plugin	plugin reference */
214 void clone_plugin_unlock(THD *thd, plugin_ref plugin);
215 
216 #endif /* CLONE_HANDLER_INCLUDED */
217