You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1488 lines
39 KiB

compiler warnings (clang 4.0.1 on i386) extra/mariabackup/fil_cur.cc:361:42: warning: format specifies type 'unsigned long' but the argument has type 'ib_int64_t' (aka 'long long') [-Wformat] extra/mariabackup/fil_cur.cc:376:9: warning: format specifies type 'unsigned long' but the argument has type 'ib_int64_t' (aka 'long long') [-Wformat] sql/handler.cc:6196:45: warning: format specifies type 'unsigned long' but the argument has type 'wsrep_trx_id_t' (aka 'unsigned long long') [-Wformat] sql/log.cc:1681:16: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] sql/log.cc:1687:16: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] sql/wsrep_sst.cc:1388:86: warning: format specifies type 'long' but the argument has type 'wsrep_seqno_t' (aka 'long long') [-Wformat] sql/wsrep_sst.cc:232:86: warning: format specifies type 'long' but the argument has type 'wsrep_seqno_t' (aka 'long long') [-Wformat] storage/connect/filamdbf.cpp:450:47: warning: format specifies type 'short' but the argument has type 'int' [-Wformat] storage/connect/filamdbf.cpp:970:47: warning: format specifies type 'short' but the argument has type 'int' [-Wformat] storage/connect/inihandl.cpp:197:16: warning: address of array 'key->name' will always evaluate to 'true' [-Wpointer-bool-conversion] storage/innobase/btr/btr0scrub.cc:151:17: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/buf/buf0buf.cc:5085:8: warning: nonnull parameter 'bpage' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion] storage/innobase/fil/fil0crypt.cc:2454:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/handler/ha_innodb.cc:18685:7: warning: format specifies type 'unsigned long' but the argument has type 'wsrep_trx_id_t' (aka 'unsigned long long') [-Wformat] storage/innobase/row/row0mysql.cc:3319:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/row/row0mysql.cc:3327:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/maria/ma_norec.c:35:10: warning: implicit conversion from 'int' to 'my_bool' (aka 'char') changes value from 131 to -125 [-Wconstant-conversion] storage/maria/ma_norec.c:42:10: warning: implicit conversion from 'int' to 'my_bool' (aka 'char') changes value from 131 to -125 [-Wconstant-conversion] storage/maria/ma_test2.c:1009:12: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] storage/maria/ma_test2.c:1010:12: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] storage/mroonga/ha_mroonga.cpp:9189:44: warning: use of logical '&&' with constant operand [-Wconstant-logical-operand] storage/mroonga/vendor/groonga/lib/expr.c:4987:22: warning: comparison of constant -1 with expression of type 'grn_operator' is always false [-Wtautological-constant-out-of-range-compare] storage/xtradb/btr/btr0scrub.cc:151:17: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/buf/buf0buf.cc:5047:8: warning: nonnull parameter 'bpage' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion] storage/xtradb/fil/fil0crypt.cc:2454:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/row/row0mysql.cc:3324:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/row/row0mysql.cc:3332:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] unittest/sql/mf_iocache-t.cc:120:35: warning: format specifies type 'unsigned long' but the argument has type 'int' [-Wformat] unittest/sql/mf_iocache-t.cc:96:35: note: expanded from macro 'INFO_TAIL'
7 years ago
compiler warnings (clang 4.0.1 on i386) extra/mariabackup/fil_cur.cc:361:42: warning: format specifies type 'unsigned long' but the argument has type 'ib_int64_t' (aka 'long long') [-Wformat] extra/mariabackup/fil_cur.cc:376:9: warning: format specifies type 'unsigned long' but the argument has type 'ib_int64_t' (aka 'long long') [-Wformat] sql/handler.cc:6196:45: warning: format specifies type 'unsigned long' but the argument has type 'wsrep_trx_id_t' (aka 'unsigned long long') [-Wformat] sql/log.cc:1681:16: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] sql/log.cc:1687:16: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] sql/wsrep_sst.cc:1388:86: warning: format specifies type 'long' but the argument has type 'wsrep_seqno_t' (aka 'long long') [-Wformat] sql/wsrep_sst.cc:232:86: warning: format specifies type 'long' but the argument has type 'wsrep_seqno_t' (aka 'long long') [-Wformat] storage/connect/filamdbf.cpp:450:47: warning: format specifies type 'short' but the argument has type 'int' [-Wformat] storage/connect/filamdbf.cpp:970:47: warning: format specifies type 'short' but the argument has type 'int' [-Wformat] storage/connect/inihandl.cpp:197:16: warning: address of array 'key->name' will always evaluate to 'true' [-Wpointer-bool-conversion] storage/innobase/btr/btr0scrub.cc:151:17: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/buf/buf0buf.cc:5085:8: warning: nonnull parameter 'bpage' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion] storage/innobase/fil/fil0crypt.cc:2454:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/handler/ha_innodb.cc:18685:7: warning: format specifies type 'unsigned long' but the argument has type 'wsrep_trx_id_t' (aka 'unsigned long long') [-Wformat] storage/innobase/row/row0mysql.cc:3319:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/row/row0mysql.cc:3327:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/maria/ma_norec.c:35:10: warning: implicit conversion from 'int' to 'my_bool' (aka 'char') changes value from 131 to -125 [-Wconstant-conversion] storage/maria/ma_norec.c:42:10: warning: implicit conversion from 'int' to 'my_bool' (aka 'char') changes value from 131 to -125 [-Wconstant-conversion] storage/maria/ma_test2.c:1009:12: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] storage/maria/ma_test2.c:1010:12: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] storage/mroonga/ha_mroonga.cpp:9189:44: warning: use of logical '&&' with constant operand [-Wconstant-logical-operand] storage/mroonga/vendor/groonga/lib/expr.c:4987:22: warning: comparison of constant -1 with expression of type 'grn_operator' is always false [-Wtautological-constant-out-of-range-compare] storage/xtradb/btr/btr0scrub.cc:151:17: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/buf/buf0buf.cc:5047:8: warning: nonnull parameter 'bpage' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion] storage/xtradb/fil/fil0crypt.cc:2454:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/row/row0mysql.cc:3324:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/row/row0mysql.cc:3332:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] unittest/sql/mf_iocache-t.cc:120:35: warning: format specifies type 'unsigned long' but the argument has type 'int' [-Wformat] unittest/sql/mf_iocache-t.cc:96:35: note: expanded from macro 'INFO_TAIL'
7 years ago
compiler warnings (clang 4.0.1 on i386) extra/mariabackup/fil_cur.cc:361:42: warning: format specifies type 'unsigned long' but the argument has type 'ib_int64_t' (aka 'long long') [-Wformat] extra/mariabackup/fil_cur.cc:376:9: warning: format specifies type 'unsigned long' but the argument has type 'ib_int64_t' (aka 'long long') [-Wformat] sql/handler.cc:6196:45: warning: format specifies type 'unsigned long' but the argument has type 'wsrep_trx_id_t' (aka 'unsigned long long') [-Wformat] sql/log.cc:1681:16: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] sql/log.cc:1687:16: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] sql/wsrep_sst.cc:1388:86: warning: format specifies type 'long' but the argument has type 'wsrep_seqno_t' (aka 'long long') [-Wformat] sql/wsrep_sst.cc:232:86: warning: format specifies type 'long' but the argument has type 'wsrep_seqno_t' (aka 'long long') [-Wformat] storage/connect/filamdbf.cpp:450:47: warning: format specifies type 'short' but the argument has type 'int' [-Wformat] storage/connect/filamdbf.cpp:970:47: warning: format specifies type 'short' but the argument has type 'int' [-Wformat] storage/connect/inihandl.cpp:197:16: warning: address of array 'key->name' will always evaluate to 'true' [-Wpointer-bool-conversion] storage/innobase/btr/btr0scrub.cc:151:17: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/buf/buf0buf.cc:5085:8: warning: nonnull parameter 'bpage' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion] storage/innobase/fil/fil0crypt.cc:2454:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/handler/ha_innodb.cc:18685:7: warning: format specifies type 'unsigned long' but the argument has type 'wsrep_trx_id_t' (aka 'unsigned long long') [-Wformat] storage/innobase/row/row0mysql.cc:3319:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/innobase/row/row0mysql.cc:3327:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/maria/ma_norec.c:35:10: warning: implicit conversion from 'int' to 'my_bool' (aka 'char') changes value from 131 to -125 [-Wconstant-conversion] storage/maria/ma_norec.c:42:10: warning: implicit conversion from 'int' to 'my_bool' (aka 'char') changes value from 131 to -125 [-Wconstant-conversion] storage/maria/ma_test2.c:1009:12: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] storage/maria/ma_test2.c:1010:12: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] storage/mroonga/ha_mroonga.cpp:9189:44: warning: use of logical '&&' with constant operand [-Wconstant-logical-operand] storage/mroonga/vendor/groonga/lib/expr.c:4987:22: warning: comparison of constant -1 with expression of type 'grn_operator' is always false [-Wtautological-constant-out-of-range-compare] storage/xtradb/btr/btr0scrub.cc:151:17: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/buf/buf0buf.cc:5047:8: warning: nonnull parameter 'bpage' will evaluate to 'true' on first encounter [-Wpointer-bool-conversion] storage/xtradb/fil/fil0crypt.cc:2454:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/row/row0mysql.cc:3324:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] storage/xtradb/row/row0mysql.cc:3332:5: warning: format specifies type 'long' but the argument has type 'int' [-Wformat] unittest/sql/mf_iocache-t.cc:120:35: warning: format specifies type 'unsigned long' but the argument has type 'int' [-Wformat] unittest/sql/mf_iocache-t.cc:96:35: note: expanded from macro 'INFO_TAIL'
7 years ago
  1. /* Copyright 2008-2015 Codership Oy <http://www.codership.com>
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; version 2 of the License.
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program; if not, write to the Free Software
  11. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
  12. #include "wsrep_sst.h"
  13. #include <inttypes.h>
  14. #include <mysqld.h>
  15. #include <m_ctype.h>
  16. #include <my_sys.h>
  17. #include <strfunc.h>
  18. #include <sql_class.h>
  19. #include <set_var.h>
  20. #include <sql_acl.h>
  21. #include <sql_reload.h>
  22. #include <sql_parse.h>
  23. #include "wsrep_priv.h"
  24. #include "wsrep_utils.h"
  25. #include "wsrep_xid.h"
  26. #include <cstdio>
  27. #include <cstdlib>
  28. #include <my_service_manager.h>
  29. static char wsrep_defaults_file[FN_REFLEN * 2 + 10 + 30 +
  30. sizeof(WSREP_SST_OPT_CONF) +
  31. sizeof(WSREP_SST_OPT_CONF_SUFFIX) +
  32. sizeof(WSREP_SST_OPT_CONF_EXTRA)] = {0};
  33. const char* wsrep_sst_method = WSREP_SST_DEFAULT;
  34. const char* wsrep_sst_receive_address = WSREP_SST_ADDRESS_AUTO;
  35. const char* wsrep_sst_donor = "";
  36. const char* wsrep_sst_auth = NULL;
  37. // container for real auth string
  38. static const char* sst_auth_real = NULL;
  39. my_bool wsrep_sst_donor_rejects_queries = FALSE;
  40. bool wsrep_sst_method_check (sys_var *self, THD* thd, set_var* var)
  41. {
  42. if ((! var->save_result.string_value.str) ||
  43. (var->save_result.string_value.length == 0 ))
  44. {
  45. my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
  46. var->save_result.string_value.str ?
  47. var->save_result.string_value.str : "NULL");
  48. return 1;
  49. }
  50. return 0;
  51. }
  52. bool wsrep_sst_method_update (sys_var *self, THD* thd, enum_var_type type)
  53. {
  54. return 0;
  55. }
  56. static const char* data_home_dir = NULL;
  57. void wsrep_set_data_home_dir(const char *data_dir)
  58. {
  59. data_home_dir= (data_dir && *data_dir) ? data_dir : NULL;
  60. }
  61. static void make_wsrep_defaults_file()
  62. {
  63. if (!wsrep_defaults_file[0])
  64. {
  65. char *ptr= wsrep_defaults_file;
  66. char *end= ptr + sizeof(wsrep_defaults_file);
  67. if (my_defaults_file)
  68. ptr= strxnmov(ptr, end - ptr,
  69. WSREP_SST_OPT_CONF, " '", my_defaults_file, "' ", NULL);
  70. if (my_defaults_extra_file)
  71. ptr= strxnmov(ptr, end - ptr,
  72. WSREP_SST_OPT_CONF_EXTRA, " '", my_defaults_extra_file, "' ", NULL);
  73. if (my_defaults_group_suffix)
  74. ptr= strxnmov(ptr, end - ptr,
  75. WSREP_SST_OPT_CONF_SUFFIX, " '", my_defaults_group_suffix, "' ", NULL);
  76. }
  77. }
  78. bool wsrep_sst_receive_address_check (sys_var *self, THD* thd, set_var* var)
  79. {
  80. if ((! var->save_result.string_value.str) ||
  81. (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety
  82. {
  83. goto err;
  84. }
  85. return 0;
  86. err:
  87. my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str,
  88. var->save_result.string_value.str ?
  89. var->save_result.string_value.str : "NULL");
  90. return 1;
  91. }
  92. bool wsrep_sst_receive_address_update (sys_var *self, THD* thd,
  93. enum_var_type type)
  94. {
  95. return 0;
  96. }
  97. bool wsrep_sst_auth_check (sys_var *self, THD* thd, set_var* var)
  98. {
  99. return 0;
  100. }
  101. static bool sst_auth_real_set (const char* value)
  102. {
  103. const char* v= NULL;
  104. if (value)
  105. {
  106. v= my_strdup(value, MYF(0));
  107. }
  108. else // its NULL
  109. {
  110. wsrep_sst_auth_free();
  111. return 0;
  112. }
  113. if (v)
  114. {
  115. // set sst_auth_real
  116. if (sst_auth_real) { my_free((void *) sst_auth_real); }
  117. sst_auth_real = v;
  118. // mask wsrep_sst_auth
  119. if (strlen(sst_auth_real))
  120. {
  121. if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); }
  122. wsrep_sst_auth= my_strdup(WSREP_SST_AUTH_MASK, MYF(0));
  123. }
  124. return 0;
  125. }
  126. return 1;
  127. }
  128. void wsrep_sst_auth_free()
  129. {
  130. if (wsrep_sst_auth) { my_free((void *) wsrep_sst_auth); }
  131. if (sst_auth_real) { my_free((void *) sst_auth_real); }
  132. wsrep_sst_auth= NULL;
  133. sst_auth_real= NULL;
  134. }
  135. bool wsrep_sst_auth_update (sys_var *self, THD* thd, enum_var_type type)
  136. {
  137. return sst_auth_real_set (wsrep_sst_auth);
  138. }
  139. void wsrep_sst_auth_init ()
  140. {
  141. sst_auth_real_set(wsrep_sst_auth);
  142. }
  143. bool wsrep_sst_donor_check (sys_var *self, THD* thd, set_var* var)
  144. {
  145. return 0;
  146. }
  147. bool wsrep_sst_donor_update (sys_var *self, THD* thd, enum_var_type type)
  148. {
  149. return 0;
  150. }
  151. bool wsrep_before_SE()
  152. {
  153. return (wsrep_provider != NULL
  154. && strcmp (wsrep_provider, WSREP_NONE)
  155. && strcmp (wsrep_sst_method, WSREP_SST_SKIP)
  156. && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP));
  157. }
  158. static bool sst_complete = false;
  159. static bool sst_needed = false;
  160. #define WSREP_EXTEND_TIMEOUT_INTERVAL 30
  161. #define WSREP_TIMEDWAIT_SECONDS 10
  162. void wsrep_sst_grab ()
  163. {
  164. WSREP_INFO("wsrep_sst_grab()");
  165. if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort();
  166. sst_complete = false;
  167. mysql_mutex_unlock (&LOCK_wsrep_sst);
  168. }
  169. // Wait for end of SST
  170. bool wsrep_sst_wait ()
  171. {
  172. double total_wtime = 0;
  173. if (mysql_mutex_lock (&LOCK_wsrep_sst))
  174. abort();
  175. WSREP_INFO("Waiting for SST to complete.");
  176. while (!sst_complete)
  177. {
  178. struct timespec wtime;
  179. set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS);
  180. time_t start_time = time(NULL);
  181. mysql_cond_timedwait (&COND_wsrep_sst, &LOCK_wsrep_sst, &wtime);
  182. time_t end_time = time(NULL);
  183. if (!sst_complete)
  184. {
  185. total_wtime += difftime(end_time, start_time);
  186. WSREP_DEBUG("Waiting for SST to complete. current seqno: %" PRId64 " waited %f secs.", local_seqno, total_wtime);
  187. service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL,
  188. "WSREP state transfer ongoing, current seqno: %" PRId64 " waited %f secs", local_seqno, total_wtime);
  189. }
  190. }
  191. if (local_seqno >= 0)
  192. {
  193. WSREP_INFO("SST complete, seqno: %lld", (long long) local_seqno);
  194. }
  195. else
  196. {
  197. WSREP_ERROR("SST failed: %d (%s)",
  198. int(-local_seqno), strerror(-local_seqno));
  199. }
  200. mysql_mutex_unlock (&LOCK_wsrep_sst);
  201. return (local_seqno >= 0);
  202. }
  203. // Signal end of SST
  204. void wsrep_sst_complete (const wsrep_uuid_t* sst_uuid,
  205. wsrep_seqno_t sst_seqno,
  206. bool needed)
  207. {
  208. if (mysql_mutex_lock (&LOCK_wsrep_sst)) abort();
  209. if (!sst_complete)
  210. {
  211. sst_complete = true;
  212. sst_needed = needed;
  213. local_uuid = *sst_uuid;
  214. local_seqno = sst_seqno;
  215. mysql_cond_signal (&COND_wsrep_sst);
  216. }
  217. else
  218. {
  219. /* This can happen when called from wsrep_synced_cb().
  220. At the moment there is no way to check there
  221. if main thread is still waiting for signal,
  222. so wsrep_sst_complete() is called from there
  223. each time wsrep_ready changes from FALSE -> TRUE.
  224. */
  225. WSREP_DEBUG("Nobody is waiting for SST.");
  226. }
  227. mysql_mutex_unlock (&LOCK_wsrep_sst);
  228. }
  229. /*
  230. If wsrep provider is loaded, inform that the new state snapshot
  231. has been received. Also update the local checkpoint.
  232. @param wsrep [IN] wsrep handle
  233. @param uuid [IN] Initial state UUID
  234. @param seqno [IN] Initial state sequence number
  235. @param state [IN] Always NULL, also ignored by wsrep provider (?)
  236. @param state_len [IN] Always 0, also ignored by wsrep provider (?)
  237. @param implicit [IN] Whether invoked implicitly due to SST
  238. (true) or explicitly because if change
  239. in wsrep_start_position by user (false).
  240. @return false Success
  241. true Error
  242. */
  243. bool wsrep_sst_received (wsrep_t* const wsrep,
  244. const wsrep_uuid_t& uuid,
  245. const wsrep_seqno_t seqno,
  246. const void* const state,
  247. const size_t state_len,
  248. const bool implicit)
  249. {
  250. /*
  251. To keep track of whether the local uuid:seqno should be updated. Also, note
  252. that local state (uuid:seqno) is updated/checkpointed only after we get an
  253. OK from wsrep provider. By doing so, the values remain consistent across
  254. the server & wsrep provider.
  255. */
  256. bool do_update= false;
  257. // Get the locally stored uuid:seqno.
  258. if (wsrep_get_SE_checkpoint(local_uuid, local_seqno))
  259. {
  260. return true;
  261. }
  262. if (memcmp(&local_uuid, &uuid, sizeof(wsrep_uuid_t)) ||
  263. local_seqno < seqno || seqno < 0)
  264. {
  265. do_update= true;
  266. }
  267. else if (local_seqno > seqno)
  268. {
  269. WSREP_WARN("SST position can't be set in past. Requested: %lld, Current: "
  270. " %lld.", (long long)seqno, (long long)local_seqno);
  271. /*
  272. If we are here because of SET command, simply return true (error) instead of
  273. aborting.
  274. */
  275. if (implicit)
  276. {
  277. WSREP_WARN("Can't continue.");
  278. unireg_abort(1);
  279. }
  280. else
  281. {
  282. return true;
  283. }
  284. }
  285. #ifdef GTID_SUPPORT
  286. wsrep_init_sidno(uuid);
  287. #endif /* GTID_SUPPORT */
  288. if (wsrep)
  289. {
  290. int const rcode(seqno < 0 ? seqno : 0);
  291. wsrep_gtid_t const state_id= {uuid,
  292. (rcode ? WSREP_SEQNO_UNDEFINED : seqno)};
  293. wsrep_status_t ret= wsrep->sst_received(wsrep, &state_id, state,
  294. state_len, rcode);
  295. if (ret != WSREP_OK)
  296. {
  297. return true;
  298. }
  299. }
  300. // Now is the good time to update the local state and checkpoint.
  301. if (do_update)
  302. {
  303. if (wsrep_set_SE_checkpoint(uuid, seqno))
  304. {
  305. return true;
  306. }
  307. local_uuid= uuid;
  308. local_seqno= seqno;
  309. }
  310. return false;
  311. }
  312. // Let applier threads to continue
  313. bool wsrep_sst_continue ()
  314. {
  315. if (sst_needed)
  316. {
  317. WSREP_INFO("Signalling provider to continue.");
  318. return wsrep_sst_received (wsrep, local_uuid, local_seqno, NULL, 0, true);
  319. }
  320. return false;
  321. }
  322. struct sst_thread_arg
  323. {
  324. const char* cmd;
  325. char** env;
  326. char* ret_str;
  327. int err;
  328. mysql_mutex_t lock;
  329. mysql_cond_t cond;
  330. sst_thread_arg (const char* c, char** e)
  331. : cmd(c), env(e), ret_str(0), err(-1)
  332. {
  333. mysql_mutex_init(key_LOCK_wsrep_sst_thread, &lock, MY_MUTEX_INIT_FAST);
  334. mysql_cond_init(key_COND_wsrep_sst_thread, &cond, NULL);
  335. }
  336. ~sst_thread_arg()
  337. {
  338. mysql_cond_destroy (&cond);
  339. mysql_mutex_unlock (&lock);
  340. mysql_mutex_destroy (&lock);
  341. }
  342. };
  343. static int sst_scan_uuid_seqno (const char* str,
  344. wsrep_uuid_t* uuid, wsrep_seqno_t* seqno)
  345. {
  346. int offt = wsrep_uuid_scan (str, strlen(str), uuid);
  347. errno= 0; /* Reset the errno */
  348. if (offt > 0 && strlen(str) > (unsigned int)offt && ':' == str[offt])
  349. {
  350. *seqno = strtoll (str + offt + 1, NULL, 10);
  351. if (*seqno != LLONG_MAX || errno != ERANGE)
  352. {
  353. return 0;
  354. }
  355. }
  356. WSREP_ERROR("Failed to parse uuid:seqno pair: '%s'", str);
  357. return EINVAL;
  358. }
  359. // get rid of trailing \n
  360. static char* my_fgets (char* buf, size_t buf_len, FILE* stream)
  361. {
  362. char* ret= fgets (buf, buf_len, stream);
  363. if (ret)
  364. {
  365. size_t len = strlen(ret);
  366. if (len > 0 && ret[len - 1] == '\n') ret[len - 1] = '\0';
  367. }
  368. return ret;
  369. }
  370. /*
  371. Generate opt_binlog_opt_val for sst_donate_other(), sst_prepare_other().
  372. Returns zero on success, negative error code otherwise.
  373. String containing binlog name is stored in param ret if binlog is enabled
  374. and GTID mode is on, otherwise empty string. Returned string should be
  375. freed with my_free().
  376. */
  377. static int generate_binlog_opt_val(char** ret)
  378. {
  379. DBUG_ASSERT(ret);
  380. *ret= NULL;
  381. if (opt_bin_log)
  382. {
  383. assert(opt_bin_logname);
  384. *ret= strcmp(opt_bin_logname, "0") ?
  385. my_strdup(opt_bin_logname, MYF(0)) : my_strdup("", MYF(0));
  386. }
  387. else
  388. {
  389. *ret= my_strdup("", MYF(0));
  390. }
  391. if (!*ret) return -ENOMEM;
  392. return 0;
  393. }
  394. static int generate_binlog_index_opt_val(char** ret)
  395. {
  396. DBUG_ASSERT(ret);
  397. *ret= NULL;
  398. if (opt_binlog_index_name) {
  399. *ret= strcmp(opt_binlog_index_name, "0") ?
  400. my_strdup(opt_binlog_index_name, MYF(0)) : my_strdup("", MYF(0));
  401. }
  402. else
  403. {
  404. *ret= my_strdup("", MYF(0));
  405. }
  406. if (!*ret) return -ENOMEM;
  407. return 0;
  408. }
  409. static void* sst_joiner_thread (void* a)
  410. {
  411. sst_thread_arg* arg= (sst_thread_arg*) a;
  412. int err= 1;
  413. {
  414. const char magic[] = "ready";
  415. const size_t magic_len = sizeof(magic) - 1;
  416. const size_t out_len = 512;
  417. char out[out_len];
  418. WSREP_INFO("Running: '%s'", arg->cmd);
  419. wsp::process proc (arg->cmd, "r", arg->env);
  420. if (proc.pipe() && !proc.error())
  421. {
  422. const char* tmp= my_fgets (out, out_len, proc.pipe());
  423. if (!tmp || strlen(tmp) < (magic_len + 2) ||
  424. strncasecmp (tmp, magic, magic_len))
  425. {
  426. WSREP_ERROR("Failed to read '%s <addr>' from: %s\n\tRead: '%s'",
  427. magic, arg->cmd, tmp);
  428. proc.wait();
  429. if (proc.error()) err = proc.error();
  430. }
  431. else
  432. {
  433. err = 0;
  434. }
  435. }
  436. else
  437. {
  438. err = proc.error();
  439. WSREP_ERROR("Failed to execute: %s : %d (%s)",
  440. arg->cmd, err, strerror(err));
  441. }
  442. // signal sst_prepare thread with ret code,
  443. // it will go on sending SST request
  444. mysql_mutex_lock (&arg->lock);
  445. if (!err)
  446. {
  447. arg->ret_str = strdup (out + magic_len + 1);
  448. if (!arg->ret_str) err = ENOMEM;
  449. }
  450. arg->err = -err;
  451. mysql_cond_signal (&arg->cond);
  452. mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that.
  453. if (err) return NULL; /* lp:808417 - return immediately, don't signal
  454. * initializer thread to ensure single thread of
  455. * shutdown. */
  456. wsrep_uuid_t ret_uuid = WSREP_UUID_UNDEFINED;
  457. wsrep_seqno_t ret_seqno = WSREP_SEQNO_UNDEFINED;
  458. // in case of successfull receiver start, wait for SST completion/end
  459. char* tmp = my_fgets (out, out_len, proc.pipe());
  460. proc.wait();
  461. err= EINVAL;
  462. if (!tmp)
  463. {
  464. WSREP_ERROR("Failed to read uuid:seqno and wsrep_gtid_domain_id from "
  465. "joiner script.");
  466. if (proc.error()) err = proc.error();
  467. }
  468. else
  469. {
  470. // Read state ID (UUID:SEQNO) followed by wsrep_gtid_domain_id (if any).
  471. const char *pos= strchr(out, ' ');
  472. if (!pos) {
  473. // There is no wsrep_gtid_domain_id (some older version SST script?).
  474. err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno);
  475. } else {
  476. // Scan state ID first followed by wsrep_gtid_domain_id.
  477. unsigned long int domain_id;
  478. // Null-terminate the state-id.
  479. out[pos - out]= 0;
  480. err= sst_scan_uuid_seqno (out, &ret_uuid, &ret_seqno);
  481. if (err)
  482. {
  483. goto err;
  484. }
  485. else if (wsrep_gtid_mode)
  486. {
  487. errno= 0; /* Reset the errno */
  488. domain_id= strtoul(pos + 1, NULL, 10);
  489. err= errno;
  490. /* Check if we received a valid gtid_domain_id. */
  491. if (err == EINVAL || err == ERANGE)
  492. {
  493. WSREP_ERROR("Failed to get donor wsrep_gtid_domain_id.");
  494. err= EINVAL;
  495. goto err;
  496. } else {
  497. wsrep_gtid_domain_id= (uint32) domain_id;
  498. }
  499. }
  500. }
  501. }
  502. err:
  503. if (err)
  504. {
  505. ret_uuid= WSREP_UUID_UNDEFINED;
  506. ret_seqno= -err;
  507. }
  508. // Tell initializer thread that SST is complete
  509. wsrep_sst_complete (&ret_uuid, ret_seqno, true);
  510. }
  511. return NULL;
  512. }
  513. #define WSREP_SST_AUTH_ENV "WSREP_SST_OPT_AUTH"
  514. static int sst_append_auth_env(wsp::env& env, const char* sst_auth)
  515. {
  516. int const sst_auth_size= strlen(WSREP_SST_AUTH_ENV) + 1 /* = */
  517. + (sst_auth ? strlen(sst_auth) : 0) + 1 /* \0 */;
  518. wsp::string sst_auth_str(sst_auth_size); // for automatic cleanup on return
  519. if (!sst_auth_str()) return -ENOMEM;
  520. int ret= snprintf(sst_auth_str(), sst_auth_size, "%s=%s",
  521. WSREP_SST_AUTH_ENV, sst_auth ? sst_auth : "");
  522. if (ret < 0 || ret >= sst_auth_size)
  523. {
  524. WSREP_ERROR("sst_append_auth_env(): snprintf() failed: %d", ret);
  525. return (ret < 0 ? ret : -EMSGSIZE);
  526. }
  527. env.append(sst_auth_str());
  528. return -env.error();
  529. }
  530. #define DATA_HOME_DIR_ENV "INNODB_DATA_HOME_DIR"
  531. static int sst_append_data_dir(wsp::env& env, const char* data_dir)
  532. {
  533. int const data_dir_size= strlen(DATA_HOME_DIR_ENV) + 1 /* = */
  534. + (data_dir ? strlen(data_dir) : 0) + 1 /* \0 */;
  535. wsp::string data_dir_str(data_dir_size); // for automatic cleanup on return
  536. if (!data_dir_str()) return -ENOMEM;
  537. int ret= snprintf(data_dir_str(), data_dir_size, "%s=%s",
  538. DATA_HOME_DIR_ENV, data_dir ? data_dir : "");
  539. if (ret < 0 || ret >= data_dir_size)
  540. {
  541. WSREP_ERROR("sst_append_data_dir(): snprintf() failed: %d", ret);
  542. return (ret < 0 ? ret : -EMSGSIZE);
  543. }
  544. env.append(data_dir_str());
  545. return -env.error();
  546. }
  547. static ssize_t sst_prepare_other (const char* method,
  548. const char* sst_auth,
  549. const char* addr_in,
  550. const char** addr_out)
  551. {
  552. int const cmd_len= 4096;
  553. wsp::string cmd_str(cmd_len);
  554. if (!cmd_str())
  555. {
  556. WSREP_ERROR("sst_prepare_other(): could not allocate cmd buffer of %d bytes",
  557. cmd_len);
  558. return -ENOMEM;
  559. }
  560. const char* binlog_opt= "";
  561. const char* binlog_index_opt= "";
  562. char* binlog_opt_val= NULL;
  563. char* binlog_index_opt_val= NULL;
  564. int ret;
  565. if ((ret= generate_binlog_opt_val(&binlog_opt_val)))
  566. {
  567. WSREP_ERROR("sst_prepare_other(): generate_binlog_opt_val() failed: %d",
  568. ret);
  569. return ret;
  570. }
  571. if ((ret= generate_binlog_index_opt_val(&binlog_index_opt_val)))
  572. {
  573. WSREP_ERROR("sst_prepare_other(): generate_binlog_index_opt_val() failed %d",
  574. ret);
  575. }
  576. if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
  577. if (strlen(binlog_index_opt_val)) binlog_index_opt= WSREP_SST_OPT_BINLOG_INDEX;
  578. make_wsrep_defaults_file();
  579. ret= snprintf (cmd_str(), cmd_len,
  580. "wsrep_sst_%s "
  581. WSREP_SST_OPT_ROLE " 'joiner' "
  582. WSREP_SST_OPT_ADDR " '%s' "
  583. WSREP_SST_OPT_DATA " '%s' "
  584. " %s "
  585. WSREP_SST_OPT_PARENT " '%d'"
  586. " %s '%s'"
  587. " %s '%s'",
  588. method, addr_in, mysql_real_data_home,
  589. wsrep_defaults_file,
  590. (int)getpid(), binlog_opt, binlog_opt_val,
  591. binlog_index_opt, binlog_index_opt_val);
  592. my_free(binlog_opt_val);
  593. my_free(binlog_index_opt_val);
  594. if (ret < 0 || ret >= cmd_len)
  595. {
  596. WSREP_ERROR("sst_prepare_other(): snprintf() failed: %d", ret);
  597. return (ret < 0 ? ret : -EMSGSIZE);
  598. }
  599. wsp::env env(NULL);
  600. if (env.error())
  601. {
  602. WSREP_ERROR("sst_prepare_other(): env. var ctor failed: %d", -env.error());
  603. return -env.error();
  604. }
  605. if ((ret= sst_append_auth_env(env, sst_auth)))
  606. {
  607. WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret);
  608. return ret;
  609. }
  610. if (data_home_dir)
  611. {
  612. if ((ret= sst_append_data_dir(env, data_home_dir)))
  613. {
  614. WSREP_ERROR("sst_prepare_other(): appending data "
  615. "directory failed: %d", ret);
  616. return ret;
  617. }
  618. }
  619. pthread_t tmp;
  620. sst_thread_arg arg(cmd_str(), env());
  621. mysql_mutex_lock (&arg.lock);
  622. ret = pthread_create (&tmp, NULL, sst_joiner_thread, &arg);
  623. if (ret)
  624. {
  625. WSREP_ERROR("sst_prepare_other(): pthread_create() failed: %d (%s)",
  626. ret, strerror(ret));
  627. return -ret;
  628. }
  629. mysql_cond_wait (&arg.cond, &arg.lock);
  630. *addr_out= arg.ret_str;
  631. if (!arg.err)
  632. ret = strlen(*addr_out);
  633. else
  634. {
  635. assert (arg.err < 0);
  636. ret = arg.err;
  637. }
  638. pthread_detach (tmp);
  639. return ret;
  640. }
  641. extern uint mysqld_port;
  642. /*! Just tells donor where to send mysqldump */
  643. static ssize_t sst_prepare_mysqldump (const char* addr_in,
  644. const char** addr_out)
  645. {
  646. ssize_t ret = strlen (addr_in);
  647. if (!strrchr(addr_in, ':'))
  648. {
  649. ssize_t s = ret + 7;
  650. char* tmp = (char*) malloc (s);
  651. if (tmp)
  652. {
  653. ret= snprintf (tmp, s, "%s:%u", addr_in, mysqld_port);
  654. if (ret > 0 && ret < s)
  655. {
  656. *addr_out= tmp;
  657. return ret;
  658. }
  659. if (ret > 0) /* buffer too short */ ret = -EMSGSIZE;
  660. free (tmp);
  661. }
  662. else {
  663. ret= -ENOMEM;
  664. }
  665. WSREP_ERROR ("Could not prepare state transfer request: "
  666. "adding default port failed: %zd.", ret);
  667. }
  668. else {
  669. *addr_out= addr_in;
  670. }
  671. return ret;
  672. }
  673. static bool SE_initialized = false;
  674. ssize_t wsrep_sst_prepare (void** msg)
  675. {
  676. const char* addr_in= NULL;
  677. const char* addr_out= NULL;
  678. if (!strcmp(wsrep_sst_method, WSREP_SST_SKIP))
  679. {
  680. ssize_t ret = strlen(WSREP_STATE_TRANSFER_TRIVIAL) + 1;
  681. *msg = strdup(WSREP_STATE_TRANSFER_TRIVIAL);
  682. if (!msg)
  683. {
  684. WSREP_ERROR("Could not allocate %zd bytes for state request", ret);
  685. unireg_abort(1);
  686. }
  687. return ret;
  688. }
  689. /*
  690. Figure out SST receive address. Common for all SST methods.
  691. */
  692. char ip_buf[256];
  693. const ssize_t ip_max= sizeof(ip_buf);
  694. // Attempt 1: wsrep_sst_receive_address
  695. if (wsrep_sst_receive_address &&
  696. strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO))
  697. {
  698. addr_in= wsrep_sst_receive_address;
  699. }
  700. //Attempt 2: wsrep_node_address
  701. else if (wsrep_node_address && strlen(wsrep_node_address))
  702. {
  703. wsp::Address addr(wsrep_node_address);
  704. if (!addr.is_valid())
  705. {
  706. WSREP_ERROR("Could not parse wsrep_node_address : %s",
  707. wsrep_node_address);
  708. unireg_abort(1);
  709. }
  710. memcpy(ip_buf, addr.get_address(), addr.get_address_len());
  711. addr_in= ip_buf;
  712. }
  713. // Attempt 3: Try to get the IP from the list of available interfaces.
  714. else
  715. {
  716. ssize_t ret= wsrep_guess_ip (ip_buf, ip_max);
  717. if (ret && ret < ip_max)
  718. {
  719. addr_in= ip_buf;
  720. }
  721. else
  722. {
  723. WSREP_ERROR("Failed to guess address to accept state transfer. "
  724. "wsrep_sst_receive_address must be set manually.");
  725. unireg_abort(1);
  726. }
  727. }
  728. ssize_t addr_len= -ENOSYS;
  729. if (!strcmp(wsrep_sst_method, WSREP_SST_MYSQLDUMP))
  730. {
  731. addr_len= sst_prepare_mysqldump (addr_in, &addr_out);
  732. if (addr_len < 0) unireg_abort(1);
  733. }
  734. else
  735. {
  736. /*! A heuristic workaround until we learn how to stop and start engines */
  737. if (SE_initialized)
  738. {
  739. // we already did SST at initializaiton, now engines are running
  740. // sql_print_information() is here because the message is too long
  741. // for WSREP_INFO.
  742. sql_print_information ("WSREP: "
  743. "You have configured '%s' state snapshot transfer method "
  744. "which cannot be performed on a running server. "
  745. "Wsrep provider won't be able to fall back to it "
  746. "if other means of state transfer are unavailable. "
  747. "In that case you will need to restart the server.",
  748. wsrep_sst_method);
  749. *msg = 0;
  750. return 0;
  751. }
  752. addr_len = sst_prepare_other (wsrep_sst_method, sst_auth_real,
  753. addr_in, &addr_out);
  754. if (addr_len < 0)
  755. {
  756. WSREP_ERROR("Failed to prepare for '%s' SST. Unrecoverable.",
  757. wsrep_sst_method);
  758. unireg_abort(1);
  759. }
  760. }
  761. size_t const method_len(strlen(wsrep_sst_method));
  762. size_t const msg_len (method_len + addr_len + 2 /* + auth_len + 1*/);
  763. *msg = malloc (msg_len);
  764. if (NULL != *msg) {
  765. char* const method_ptr(reinterpret_cast<char*>(*msg));
  766. strcpy (method_ptr, wsrep_sst_method);
  767. char* const addr_ptr(method_ptr + method_len + 1);
  768. strcpy (addr_ptr, addr_out);
  769. WSREP_INFO ("Prepared SST request: %s|%s", method_ptr, addr_ptr);
  770. }
  771. else {
  772. WSREP_ERROR("Failed to allocate SST request of size %zu. Can't continue.",
  773. msg_len);
  774. unireg_abort(1);
  775. }
  776. if (addr_out != addr_in) /* malloc'ed */ free ((char*)addr_out);
  777. return msg_len;
  778. }
  779. // helper method for donors
  780. static int sst_run_shell (const char* cmd_str, char** env, int max_tries)
  781. {
  782. int ret = 0;
  783. for (int tries=1; tries <= max_tries; tries++)
  784. {
  785. wsp::process proc (cmd_str, "r", env);
  786. if (NULL != proc.pipe())
  787. {
  788. proc.wait();
  789. }
  790. if ((ret = proc.error()))
  791. {
  792. WSREP_ERROR("Try %d/%d: '%s' failed: %d (%s)",
  793. tries, max_tries, proc.cmd(), ret, strerror(ret));
  794. sleep (1);
  795. }
  796. else
  797. {
  798. WSREP_DEBUG("SST script successfully completed.");
  799. break;
  800. }
  801. }
  802. return -ret;
  803. }
  804. static void sst_reject_queries(my_bool close_conn)
  805. {
  806. wsrep_ready_set (FALSE); // this will be resotred when donor becomes synced
  807. WSREP_INFO("Rejecting client queries for the duration of SST.");
  808. if (TRUE == close_conn) wsrep_close_client_connections(FALSE);
  809. }
  810. static int sst_donate_mysqldump (const char* addr,
  811. const wsrep_uuid_t* uuid,
  812. const char* uuid_str,
  813. wsrep_seqno_t seqno,
  814. bool bypass,
  815. char** env) // carries auth info
  816. {
  817. char host[256];
  818. wsp::Address address(addr);
  819. if (!address.is_valid())
  820. {
  821. WSREP_ERROR("Could not parse SST address : %s", addr);
  822. return 0;
  823. }
  824. memcpy(host, address.get_address(), address.get_address_len());
  825. int port= address.get_port();
  826. int const cmd_len= 4096;
  827. wsp::string cmd_str(cmd_len);
  828. if (!cmd_str())
  829. {
  830. WSREP_ERROR("sst_donate_mysqldump(): "
  831. "could not allocate cmd buffer of %d bytes", cmd_len);
  832. return -ENOMEM;
  833. }
  834. if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(TRUE);
  835. make_wsrep_defaults_file();
  836. int ret= snprintf (cmd_str(), cmd_len,
  837. "wsrep_sst_mysqldump "
  838. WSREP_SST_OPT_ADDR " '%s' "
  839. WSREP_SST_OPT_PORT " '%d' "
  840. WSREP_SST_OPT_LPORT " '%u' "
  841. WSREP_SST_OPT_SOCKET " '%s' "
  842. " %s "
  843. WSREP_SST_OPT_GTID " '%s:%lld' "
  844. WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
  845. "%s",
  846. addr, port, mysqld_port, mysqld_unix_port,
  847. wsrep_defaults_file, uuid_str,
  848. (long long)seqno, wsrep_gtid_domain_id,
  849. bypass ? " " WSREP_SST_OPT_BYPASS : "");
  850. if (ret < 0 || ret >= cmd_len)
  851. {
  852. WSREP_ERROR("sst_donate_mysqldump(): snprintf() failed: %d", ret);
  853. return (ret < 0 ? ret : -EMSGSIZE);
  854. }
  855. WSREP_DEBUG("Running: '%s'", cmd_str());
  856. ret= sst_run_shell (cmd_str(), env, 3);
  857. wsrep_gtid_t const state_id = { *uuid, (ret ? WSREP_SEQNO_UNDEFINED : seqno)};
  858. wsrep->sst_sent (wsrep, &state_id, ret);
  859. return ret;
  860. }
  861. wsrep_seqno_t wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED;
  862. /*
  863. Create a file under data directory.
  864. */
  865. static int sst_create_file(const char *name, const char *content)
  866. {
  867. int err= 0;
  868. char *real_name;
  869. char *tmp_name;
  870. ssize_t len;
  871. FILE *file;
  872. len= strlen(mysql_real_data_home) + strlen(name) + 2;
  873. real_name= (char *) alloca(len);
  874. snprintf(real_name, (size_t) len, "%s/%s", mysql_real_data_home, name);
  875. tmp_name= (char *) alloca(len + 4);
  876. snprintf(tmp_name, (size_t) len + 4, "%s.tmp", real_name);
  877. file= fopen(tmp_name, "w+");
  878. if (0 == file)
  879. {
  880. err= errno;
  881. WSREP_ERROR("Failed to open '%s': %d (%s)", tmp_name, err, strerror(err));
  882. }
  883. else
  884. {
  885. // Write the specified content into the file.
  886. if (content != NULL)
  887. {
  888. fprintf(file, "%s\n", content);
  889. fsync(fileno(file));
  890. }
  891. fclose(file);
  892. if (rename(tmp_name, real_name) == -1)
  893. {
  894. err= errno;
  895. WSREP_ERROR("Failed to rename '%s' to '%s': %d (%s)", tmp_name,
  896. real_name, err, strerror(err));
  897. }
  898. }
  899. return err;
  900. }
  901. static int run_sql_command(THD *thd, const char *query)
  902. {
  903. thd->set_query((char *)query, strlen(query));
  904. Parser_state ps;
  905. if (ps.init(thd, thd->query(), thd->query_length()))
  906. {
  907. WSREP_ERROR("SST query: %s failed", query);
  908. return -1;
  909. }
  910. mysql_parse(thd, thd->query(), thd->query_length(), &ps, FALSE, FALSE);
  911. if (thd->is_error())
  912. {
  913. int const err= thd->get_stmt_da()->sql_errno();
  914. WSREP_WARN ("Error executing '%s': %d (%s)%s",
  915. query, err, thd->get_stmt_da()->message(),
  916. err == ER_UNKNOWN_SYSTEM_VARIABLE ?
  917. ". Was mysqld built with --with-innodb-disallow-writes ?" : "");
  918. thd->clear_error();
  919. return -1;
  920. }
  921. return 0;
  922. }
  923. static int sst_flush_tables(THD* thd)
  924. {
  925. WSREP_INFO("Flushing tables for SST...");
  926. int err= 0;
  927. int not_used;
  928. /*
  929. Files created to notify the SST script about the outcome of table flush
  930. operation.
  931. */
  932. const char *flush_success= "tables_flushed";
  933. const char *flush_error= "sst_error";
  934. CHARSET_INFO *current_charset= thd->variables.character_set_client;
  935. if (!is_supported_parser_charset(current_charset))
  936. {
  937. /* Do not use non-supported parser character sets */
  938. WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname);
  939. thd->variables.character_set_client = &my_charset_latin1;
  940. WSREP_WARN("For SST temporally setting character set to : %s",
  941. my_charset_latin1.csname);
  942. }
  943. if (run_sql_command(thd, "FLUSH TABLES WITH READ LOCK"))
  944. {
  945. err= -1;
  946. }
  947. else
  948. {
  949. /*
  950. Make sure logs are flushed after global read lock acquired. In case
  951. reload fails, we must also release the acquired FTWRL.
  952. */
  953. if (reload_acl_and_cache(thd, REFRESH_ENGINE_LOG | REFRESH_BINARY_LOG,
  954. (TABLE_LIST*) 0, &not_used))
  955. {
  956. thd->global_read_lock.unlock_global_read_lock(thd);
  957. err= -1;
  958. }
  959. }
  960. thd->variables.character_set_client = current_charset;
  961. if (err)
  962. {
  963. WSREP_ERROR("Failed to flush and lock tables");
  964. /*
  965. The SST must be aborted as the flush tables failed. Notify this to SST
  966. script by creating the error file.
  967. */
  968. int tmp;
  969. if ((tmp= sst_create_file(flush_error, NULL))) {
  970. err= tmp;
  971. }
  972. }
  973. else
  974. {
  975. WSREP_INFO("Tables flushed.");
  976. /*
  977. Tables have been flushed. Create a file with cluster state ID and
  978. wsrep_gtid_domain_id.
  979. */
  980. char content[100];
  981. snprintf(content, sizeof(content), "%s:%lld %d\n", wsrep_cluster_state_uuid,
  982. (long long)wsrep_locked_seqno, wsrep_gtid_domain_id);
  983. err= sst_create_file(flush_success, content);
  984. }
  985. return err;
  986. }
  987. static void sst_disallow_writes (THD* thd, bool yes)
  988. {
  989. char query_str[64] = { 0, };
  990. ssize_t const query_max = sizeof(query_str) - 1;
  991. CHARSET_INFO *current_charset;
  992. current_charset = thd->variables.character_set_client;
  993. if (!is_supported_parser_charset(current_charset))
  994. {
  995. /* Do not use non-supported parser character sets */
  996. WSREP_WARN("Current client character set is non-supported parser character set: %s", current_charset->csname);
  997. thd->variables.character_set_client = &my_charset_latin1;
  998. WSREP_WARN("For SST temporally setting character set to : %s",
  999. my_charset_latin1.csname);
  1000. }
  1001. snprintf (query_str, query_max, "SET GLOBAL innodb_disallow_writes=%d",
  1002. yes ? 1 : 0);
  1003. if (run_sql_command(thd, query_str))
  1004. {
  1005. WSREP_ERROR("Failed to disallow InnoDB writes");
  1006. }
  1007. thd->variables.character_set_client = current_charset;
  1008. }
  1009. static void* sst_donor_thread (void* a)
  1010. {
  1011. sst_thread_arg* arg= (sst_thread_arg*)a;
  1012. WSREP_INFO("Running: '%s'", arg->cmd);
  1013. int err= 1;
  1014. bool locked= false;
  1015. const char* out= NULL;
  1016. const size_t out_len= 128;
  1017. char out_buf[out_len];
  1018. wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED;
  1019. wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST
  1020. wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can
  1021. // operate with wsrep_ready == OFF
  1022. wsp::process proc(arg->cmd, "r", arg->env);
  1023. err= proc.error();
  1024. /* Inform server about SST script startup and release TO isolation */
  1025. mysql_mutex_lock (&arg->lock);
  1026. arg->err = -err;
  1027. mysql_cond_signal (&arg->cond);
  1028. mysql_mutex_unlock (&arg->lock); //! @note arg is unusable after that.
  1029. if (proc.pipe() && !err)
  1030. {
  1031. wait_signal:
  1032. out= my_fgets (out_buf, out_len, proc.pipe());
  1033. if (out)
  1034. {
  1035. const char magic_flush[]= "flush tables";
  1036. const char magic_cont[]= "continue";
  1037. const char magic_done[]= "done";
  1038. if (!strcasecmp (out, magic_flush))
  1039. {
  1040. err= sst_flush_tables (thd.ptr);
  1041. if (!err)
  1042. {
  1043. sst_disallow_writes (thd.ptr, true);
  1044. /*
  1045. Lets also keep statements that modify binary logs (like RESET LOGS,
  1046. RESET MASTER) from proceeding until the files have been transferred
  1047. to the joiner node.
  1048. */
  1049. if (mysql_bin_log.is_open())
  1050. {
  1051. mysql_mutex_lock(mysql_bin_log.get_log_lock());
  1052. }
  1053. locked= true;
  1054. goto wait_signal;
  1055. }
  1056. }
  1057. else if (!strcasecmp (out, magic_cont))
  1058. {
  1059. if (locked)
  1060. {
  1061. if (mysql_bin_log.is_open())
  1062. {
  1063. mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
  1064. mysql_mutex_unlock(mysql_bin_log.get_log_lock());
  1065. }
  1066. sst_disallow_writes (thd.ptr, false);
  1067. thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
  1068. locked= false;
  1069. }
  1070. err= 0;
  1071. goto wait_signal;
  1072. }
  1073. else if (!strncasecmp (out, magic_done, strlen(magic_done)))
  1074. {
  1075. err= sst_scan_uuid_seqno (out + strlen(magic_done) + 1,
  1076. &ret_uuid, &ret_seqno);
  1077. }
  1078. else
  1079. {
  1080. WSREP_WARN("Received unknown signal: '%s'", out);
  1081. }
  1082. }
  1083. else
  1084. {
  1085. WSREP_ERROR("Failed to read from: %s", proc.cmd());
  1086. proc.wait();
  1087. }
  1088. if (!err && proc.error()) err= proc.error();
  1089. }
  1090. else
  1091. {
  1092. WSREP_ERROR("Failed to execute: %s : %d (%s)",
  1093. proc.cmd(), err, strerror(err));
  1094. }
  1095. if (locked) // don't forget to unlock server before return
  1096. {
  1097. if (mysql_bin_log.is_open())
  1098. {
  1099. mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
  1100. mysql_mutex_unlock(mysql_bin_log.get_log_lock());
  1101. }
  1102. sst_disallow_writes (thd.ptr, false);
  1103. thd.ptr->global_read_lock.unlock_global_read_lock (thd.ptr);
  1104. }
  1105. // signal to donor that SST is over
  1106. struct wsrep_gtid const state_id = {
  1107. ret_uuid, err ? WSREP_SEQNO_UNDEFINED : ret_seqno
  1108. };
  1109. wsrep->sst_sent (wsrep, &state_id, -err);
  1110. proc.wait();
  1111. return NULL;
  1112. }
  1113. static int sst_donate_other (const char* method,
  1114. const char* addr,
  1115. const char* uuid,
  1116. wsrep_seqno_t seqno,
  1117. bool bypass,
  1118. char** env) // carries auth info
  1119. {
  1120. int const cmd_len= 4096;
  1121. wsp::string cmd_str(cmd_len);
  1122. if (!cmd_str())
  1123. {
  1124. WSREP_ERROR("sst_donate_other(): "
  1125. "could not allocate cmd buffer of %d bytes", cmd_len);
  1126. return -ENOMEM;
  1127. }
  1128. const char* binlog_opt= "";
  1129. char* binlog_opt_val= NULL;
  1130. int ret;
  1131. if ((ret= generate_binlog_opt_val(&binlog_opt_val)))
  1132. {
  1133. WSREP_ERROR("sst_donate_other(): generate_binlog_opt_val() failed: %d",ret);
  1134. return ret;
  1135. }
  1136. if (strlen(binlog_opt_val)) binlog_opt= WSREP_SST_OPT_BINLOG;
  1137. make_wsrep_defaults_file();
  1138. ret= snprintf (cmd_str(), cmd_len,
  1139. "wsrep_sst_%s "
  1140. WSREP_SST_OPT_ROLE " 'donor' "
  1141. WSREP_SST_OPT_ADDR " '%s' "
  1142. WSREP_SST_OPT_SOCKET " '%s' "
  1143. WSREP_SST_OPT_DATA " '%s' "
  1144. " %s "
  1145. " %s '%s' "
  1146. WSREP_SST_OPT_GTID " '%s:%lld' "
  1147. WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
  1148. "%s",
  1149. method, addr, mysqld_unix_port, mysql_real_data_home,
  1150. wsrep_defaults_file,
  1151. binlog_opt, binlog_opt_val,
  1152. uuid, (long long) seqno, wsrep_gtid_domain_id,
  1153. bypass ? " " WSREP_SST_OPT_BYPASS : "");
  1154. my_free(binlog_opt_val);
  1155. if (ret < 0 || ret >= cmd_len)
  1156. {
  1157. WSREP_ERROR("sst_donate_other(): snprintf() failed: %d", ret);
  1158. return (ret < 0 ? ret : -EMSGSIZE);
  1159. }
  1160. if (!bypass && wsrep_sst_donor_rejects_queries) sst_reject_queries(FALSE);
  1161. pthread_t tmp;
  1162. sst_thread_arg arg(cmd_str(), env);
  1163. mysql_mutex_lock (&arg.lock);
  1164. ret = pthread_create (&tmp, NULL, sst_donor_thread, &arg);
  1165. if (ret)
  1166. {
  1167. WSREP_ERROR("sst_donate_other(): pthread_create() failed: %d (%s)",
  1168. ret, strerror(ret));
  1169. return ret;
  1170. }
  1171. mysql_cond_wait (&arg.cond, &arg.lock);
  1172. WSREP_INFO("sst_donor_thread signaled with %d", arg.err);
  1173. return arg.err;
  1174. }
  1175. wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
  1176. const void* msg, size_t msg_len,
  1177. const wsrep_gtid_t* current_gtid,
  1178. const char* state, size_t state_len,
  1179. bool bypass)
  1180. {
  1181. /* This will be reset when sync callback is called.
  1182. * Should we set wsrep_ready to FALSE here too? */
  1183. wsrep_config_state->set(WSREP_MEMBER_DONOR);
  1184. const char* method = (char*)msg;
  1185. size_t method_len = strlen (method);
  1186. const char* data = method + method_len + 1;
  1187. char uuid_str[37];
  1188. wsrep_uuid_print (&current_gtid->uuid, uuid_str, sizeof(uuid_str));
  1189. wsp::env env(NULL);
  1190. if (env.error())
  1191. {
  1192. WSREP_ERROR("wsrep_sst_donate_cb(): env var ctor failed: %d", -env.error());
  1193. return WSREP_CB_FAILURE;
  1194. }
  1195. int ret;
  1196. if ((ret= sst_append_auth_env(env, sst_auth_real)))
  1197. {
  1198. WSREP_ERROR("wsrep_sst_donate_cb(): appending auth env failed: %d", ret);
  1199. return WSREP_CB_FAILURE;
  1200. }
  1201. if (data_home_dir)
  1202. {
  1203. if ((ret= sst_append_data_dir(env, data_home_dir)))
  1204. {
  1205. WSREP_ERROR("wsrep_sst_donate_cb(): appending data "
  1206. "directory failed: %d", ret);
  1207. return WSREP_CB_FAILURE;
  1208. }
  1209. }
  1210. if (!strcmp (WSREP_SST_MYSQLDUMP, method))
  1211. {
  1212. ret = sst_donate_mysqldump(data, &current_gtid->uuid, uuid_str,
  1213. current_gtid->seqno, bypass, env());
  1214. }
  1215. else
  1216. {
  1217. ret = sst_donate_other(method, data, uuid_str,
  1218. current_gtid->seqno, bypass, env());
  1219. }
  1220. return (ret >= 0 ? WSREP_CB_SUCCESS : WSREP_CB_FAILURE);
  1221. }
  1222. void wsrep_SE_init_grab()
  1223. {
  1224. if (mysql_mutex_lock (&LOCK_wsrep_sst_init)) abort();
  1225. }
  1226. void wsrep_SE_init_wait()
  1227. {
  1228. double total_wtime=0;
  1229. while (SE_initialized == false)
  1230. {
  1231. struct timespec wtime;
  1232. set_timespec(wtime, WSREP_TIMEDWAIT_SECONDS);
  1233. time_t start_time = time(NULL);
  1234. mysql_cond_timedwait (&COND_wsrep_sst_init, &LOCK_wsrep_sst_init, &wtime);
  1235. time_t end_time = time(NULL);
  1236. if (!SE_initialized)
  1237. {
  1238. total_wtime += difftime(end_time, start_time);
  1239. WSREP_DEBUG("Waiting for SST to complete. current seqno: %" PRId64 " waited %f secs.", local_seqno, total_wtime);
  1240. service_manager_extend_timeout(WSREP_EXTEND_TIMEOUT_INTERVAL,
  1241. "WSREP state transfer ongoing, current seqno: %" PRId64 " waited %f secs", local_seqno, total_wtime);
  1242. }
  1243. }
  1244. mysql_mutex_unlock (&LOCK_wsrep_sst_init);
  1245. }
  1246. void wsrep_SE_init_done()
  1247. {
  1248. mysql_cond_signal (&COND_wsrep_sst_init);
  1249. mysql_mutex_unlock (&LOCK_wsrep_sst_init);
  1250. }
  1251. void wsrep_SE_initialized()
  1252. {
  1253. SE_initialized = true;
  1254. }