1 /******************************************************
2 XtraBackup: hot backup tool for InnoDB
3 (c) 2009-2020 Percona LLC and/or its affiliates
4 Originally Created 3/3/2009 Yasufumi Kinoshita
5 Written by Alexey Kopytov, Aleksandr Kuzminsky, Stewart Smith, Vadim Tkachenko,
6 Yasufumi Kinoshita, Ignacio Nin and Baron Schwartz.
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; version 2 of the License.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
20 
21 *******************************************************
22 
23 This file incorporates work covered by the following copyright and
24 permission notice:
25 
26 Copyright (c) 2000, 2011, MySQL AB & Innobase Oy. All Rights Reserved.
27 
28 This program is free software; you can redistribute it and/or modify it under
29 the terms of the GNU General Public License as published by the Free Software
30 Foundation; version 2 of the License.
31 
32 This program is distributed in the hope that it will be useful, but WITHOUT
33 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
34 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
35 
36 You should have received a copy of the GNU General Public License along with
37 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
38 Place, Suite 330, Boston, MA 02111-1307 USA
39 
40 *******************************************************/
41 
42 //#define XTRABACKUP_TARGET_IS_PLUGIN
43 
44 #include <mysql_version.h>
45 #include <my_base.h>
46 #include <my_getopt.h>
47 #include <mysql_com.h>
48 #include <my_default.h>
49 #include <mysqld.h>
50 #include <sql_bitmap.h>
51 
52 #include <signal.h>
53 #include <fcntl.h>
54 #include <string.h>
55 
56 #ifdef __linux__
57 # include <sys/prctl.h>
58 #endif
59 
60 #include <sys/resource.h>
61 
62 #include <btr0sea.h>
63 #include <dict0priv.h>
64 #include <dict0stats.h>
65 #include <lock0lock.h>
66 #include <log0recv.h>
67 #include <row0mysql.h>
68 #include <row0quiesce.h>
69 #include <srv0start.h>
70 #include <buf0dblwr.h>
71 #include <my_aes.h>
72 #include <sql_locale.h>
73 
74 #include <list>
75 #include <sstream>
76 #include <set>
77 #include <mysql.h>
78 
79 #define G_PTR uchar*
80 
81 #include "common.h"
82 #include "xtrabackup_version.h"
83 #include "datasink.h"
84 
85 #include "xb_regex.h"
86 #include "fil_cur.h"
87 #include "write_filt.h"
88 #include "xtrabackup.h"
89 #include "ds_buffer.h"
90 #include "ds_tmpfile.h"
91 #include "xbstream.h"
92 #include "changed_page_bitmap.h"
93 #include "read_filt.h"
94 #include "wsrep.h"
95 #include "innobackupex.h"
96 #include "backup_mysql.h"
97 #include "backup_copy.h"
98 #include "backup_mysql.h"
99 #include "keyring_plugins.h"
100 #include "xb0xb.h"
101 #include "ds_encrypt.h"
102 #include "xbcrypt_common.h"
103 #include "crc_glue.h"
104 #include "xtrabackup_config.h"
105 
106 /* TODO: replace with appropriate macros used in InnoDB 5.6 */
107 #define PAGE_ZIP_MIN_SIZE_SHIFT	10
108 #define DICT_TF_ZSSIZE_SHIFT	1
109 #define DICT_TF_FORMAT_ZIP	1
110 #define DICT_TF_FORMAT_SHIFT		5
111 
112 int sys_var_init();
113 
114 my_bool innodb_inited= 0;
115 
116 
117 /* This tablespace name is reserved by InnoDB for the system tablespace
118 which uses space_id 0 and stores extra types of system pages like UNDO
119 and doublewrite. */
120 const char reserved_system_space_name[] = "innodb_system";
121 
122 /* This tablespace name is reserved by InnoDB for the predefined temporary
123 tablespace. */
124 const char reserved_temporary_space_name[] = "innodb_temporary";
125 
126 /* === xtrabackup specific options === */
127 char xtrabackup_real_target_dir[FN_REFLEN] = "./xtrabackup_backupfiles/";
128 char *xtrabackup_target_dir= xtrabackup_real_target_dir;
129 my_bool xtrabackup_version = FALSE;
130 my_bool xtrabackup_backup = FALSE;
131 my_bool xtrabackup_stats = FALSE;
132 my_bool xtrabackup_prepare = FALSE;
133 my_bool xtrabackup_copy_back = FALSE;
134 my_bool xtrabackup_move_back = FALSE;
135 my_bool xtrabackup_decrypt_decompress = FALSE;
136 my_bool xtrabackup_print_param = FALSE;
137 
138 my_bool xtrabackup_export = FALSE;
139 my_bool xtrabackup_apply_log_only = FALSE;
140 
141 longlong xtrabackup_use_memory = 100*1024*1024L;
142 my_bool xtrabackup_create_ib_logfile = FALSE;
143 
144 long xtrabackup_throttle = 0; /* 0:unlimited */
145 lint io_ticket;
146 os_event_t wait_throttle = NULL;
147 os_event_t log_copying_stop = NULL;
148 
149 char *xtrabackup_incremental = NULL;
150 lsn_t incremental_lsn;
151 lsn_t incremental_to_lsn;
152 lsn_t incremental_last_lsn;
153 lsn_t incremental_flushed_lsn;
154 xb_page_bitmap *changed_page_bitmap = NULL;
155 
156 char *xtrabackup_incremental_basedir = NULL; /* for --backup */
157 char *xtrabackup_extra_lsndir = NULL; /* for --backup with --extra-lsndir */
158 char *xtrabackup_incremental_dir = NULL; /* for --prepare */
159 
160 char xtrabackup_real_incremental_basedir[FN_REFLEN];
161 char xtrabackup_real_extra_lsndir[FN_REFLEN];
162 char xtrabackup_real_incremental_dir[FN_REFLEN];
163 
164 lsn_t xtrabackup_archived_to_lsn = 0; /* for --archived-to-lsn */
165 
166 char *xtrabackup_tables = NULL;
167 char *xtrabackup_tables_file = NULL;
168 char *xtrabackup_tables_exclude = NULL;
169 
170 typedef std::list<xb_regex_t> regex_list_t;
171 static regex_list_t regex_include_list;
172 static regex_list_t regex_exclude_list;
173 
174 static hash_table_t* tables_include_hash = NULL;
175 static hash_table_t* tables_exclude_hash = NULL;
176 
177 char *xtrabackup_databases = NULL;
178 char *xtrabackup_databases_file = NULL;
179 char *xtrabackup_databases_exclude = NULL;
180 static hash_table_t* databases_include_hash = NULL;
181 static hash_table_t* databases_exclude_hash = NULL;
182 
183 static hash_table_t* inc_dir_tables_hash;
184 
185 struct xb_filter_entry_struct{
186 	char*		name;
187 	ibool		has_tables;
188 	hash_node_t	name_hash;
189 };
190 typedef struct xb_filter_entry_struct	xb_filter_entry_t;
191 
192 static ulint		thread_nr[SRV_MAX_N_IO_THREADS + 6];
193 static os_thread_id_t	thread_ids[SRV_MAX_N_IO_THREADS + 6];
194 
195 lsn_t checkpoint_lsn_start;
196 lsn_t checkpoint_no_start;
197 lsn_t log_copy_scanned_lsn;
198 ibool log_copying = TRUE;
199 ibool log_copying_running = FALSE;
200 ibool io_watching_thread_running = FALSE;
201 
202 ibool xtrabackup_logfile_is_renamed = FALSE;
203 
204 int xtrabackup_parallel;
205 
206 char *xtrabackup_stream_str = NULL;
207 xb_stream_fmt_t xtrabackup_stream_fmt = XB_STREAM_FMT_NONE;
208 ibool xtrabackup_stream = FALSE;
209 
210 const char *xtrabackup_compress_alg = NULL;
211 ibool xtrabackup_compress = FALSE;
212 uint xtrabackup_compress_threads;
213 ulonglong xtrabackup_compress_chunk_size = 0;
214 
215 const char *xtrabackup_encrypt_algo_names[] =
216 { "NONE", "AES128", "AES192", "AES256", NullS};
217 TYPELIB xtrabackup_encrypt_algo_typelib=
218 {array_elements(xtrabackup_encrypt_algo_names)-1,"",
219 	xtrabackup_encrypt_algo_names, NULL};
220 
221 ibool xtrabackup_encrypt = FALSE;
222 ulong xtrabackup_encrypt_algo;
223 char *xtrabackup_encrypt_key = NULL;
224 char *xtrabackup_encrypt_key_file = NULL;
225 uint xtrabackup_encrypt_threads;
226 ulonglong xtrabackup_encrypt_chunk_size = 0;
227 
228 ulint xtrabackup_rebuild_threads = 1;
229 
230 /* sleep interval beetween log copy iterations in log copying thread
231 in milliseconds (default is 1 second) */
232 ulint xtrabackup_log_copy_interval = 1000;
233 
234 /* Ignored option (--log) for MySQL option compatibility */
235 char*	log_ignored_opt				= NULL;
236 
237 /* === metadata of backup === */
238 #define XTRABACKUP_METADATA_FILENAME "xtrabackup_checkpoints"
239 char metadata_type[30] = ""; /*[full-backuped|log-applied|
240 			     full-prepared|incremental]*/
241 lsn_t metadata_from_lsn = 0;
242 lsn_t metadata_to_lsn = 0;
243 lsn_t metadata_last_lsn = 0;
244 
245 #define XB_LOG_FILENAME "xtrabackup_logfile"
246 
247 ds_file_t	*dst_log_file = NULL;
248 
249 static char mysql_data_home_buff[2];
250 
251 const char *defaults_group = "mysqld";
252 
253 /* === static parameters in ha_innodb.cc */
254 
255 #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
256 #define HA_INNOBASE_RANGE_COUNT	  100
257 
258 ulong 	innobase_large_page_size = 0;
259 
260 /* The default values for the following, type long or longlong, start-up
261 parameters are declared in mysqld.cc: */
262 
263 long innobase_buffer_pool_awe_mem_mb = 0;
264 long innobase_file_io_threads = 4;
265 long innobase_read_io_threads = 4;
266 long innobase_write_io_threads = 4;
267 long innobase_force_recovery = 0;
268 long innobase_log_buffer_size = 16*1024*1024L;
269 long innobase_log_files_in_group = 2;
270 long innobase_open_files = 300L;
271 
272 longlong innobase_page_size = (1LL << 14); /* 16KB */
273 static ulong innobase_log_block_size = 512;
274 my_bool innobase_fast_checksum = FALSE;
275 char*	innobase_doublewrite_file = NULL;
276 char*	innobase_buffer_pool_filename = NULL;
277 
278 longlong innobase_buffer_pool_size = 8*1024*1024L;
279 longlong innobase_log_file_size = 48*1024*1024L;
280 
281 /* The default values for the following char* start-up parameters
282 are determined in innobase_init below: */
283 
284 char*	innobase_ignored_opt			= NULL;
285 char*	innobase_data_home_dir			= NULL;
286 char*   innobase_data_file_path                 = NULL;
287 char*   innobase_temp_data_file_path            = NULL;
288 char*	innobase_log_arch_dir			= NULL;/* unused */
289 /* The following has a misleading name: starting from 4.0.5, this also
290 affects Windows: */
291 char*	innobase_unix_file_flush_method		= NULL;
292 
293 /* Below we have boolean-valued start-up parameters, and their default
294 values */
295 
296 ulong	innobase_fast_shutdown			= 1;
297 my_bool innobase_log_archive			= FALSE;/* unused */
298 my_bool innobase_use_doublewrite    = TRUE;
299 my_bool innobase_use_checksums      = TRUE;
300 my_bool innobase_use_large_pages    = FALSE;
301 my_bool	innobase_file_per_table			= FALSE;
302 my_bool innobase_locks_unsafe_for_binlog        = FALSE;
303 my_bool innobase_rollback_on_timeout		= FALSE;
304 my_bool innobase_create_status_file		= FALSE;
305 my_bool innobase_adaptive_hash_index		= TRUE;
306 
307 static char *internal_innobase_data_file_path	= NULL;
308 
309 char*	opt_transition_key			= NULL;
310 char*	opt_xtra_plugin_dir			= NULL;
311 
312 my_bool	opt_generate_new_master_key = FALSE;
313 my_bool	opt_generate_transition_key = FALSE;
314 
315 bool use_dumped_tablespace_keys = false;
316 
317 /* The following counter is used to convey information to InnoDB
318 about server activity: in selects it is not sensible to call
319 srv_active_wake_master_thread after each fetch or search, we only do
320 it every INNOBASE_WAKE_INTERVAL'th step. */
321 
322 #define INNOBASE_WAKE_INTERVAL	32
323 ulong	innobase_active_counter	= 0;
324 
325 ibool srv_compact_backup = FALSE;
326 ibool srv_rebuild_indexes = FALSE;
327 
328 static char *xtrabackup_debug_sync = NULL;
329 static const char* dbug_setting = NULL;
330 
331 my_bool xtrabackup_compact = FALSE;
332 my_bool xtrabackup_rebuild_indexes = FALSE;
333 
334 my_bool xtrabackup_incremental_force_scan = FALSE;
335 
336 /* The flushed lsn which is read from data files */
337 lsn_t	min_flushed_lsn= 0;
338 lsn_t	max_flushed_lsn= 0;
339 
340 /* The size of archived log file */
341 size_t xtrabackup_arch_file_size = 0ULL;
342 /* The minimal LSN of found archived log files */
343 lsn_t xtrabackup_arch_first_file_lsn = 0ULL;
344 /* The maximum LSN of found archived log files */
345 lsn_t xtrabackup_arch_last_file_lsn = 0ULL;
346 
347 ulong xb_open_files_limit= 0;
348 my_bool xb_close_files= FALSE;
349 
350 /* Datasinks */
351 ds_ctxt_t       *ds_data     = NULL;
352 ds_ctxt_t       *ds_meta     = NULL;
353 ds_ctxt_t       *ds_redo     = NULL;
354 
355 static bool	innobackupex_mode = false;
356 
357 static long	innobase_log_files_in_group_save;
358 static char	*srv_log_group_home_dir_save;
359 static longlong	innobase_log_file_size_save;
360 
361 /* set true if corresponding variable set as option config file or
362 command argument */
363 bool innodb_log_checksum_algorithm_specified = false;
364 
365 /* set true if corresponding variable set as option config file or
366 command argument */
367 bool innodb_checksum_algorithm_specified = false;
368 
369 /* String buffer used by --print-param to accumulate server options as they are
370 parsed from the defaults file */
371 static std::ostringstream print_param_str;
372 static std::ostringstream param_str;
373 
374 /* Set of specified parameters */
375 std::set<std::string> param_set;
376 
377 static ulonglong global_max_value;
378 
379 extern "C" void handle_fatal_signal(int sig);
380 
381 my_bool opt_galera_info = FALSE;
382 my_bool opt_slave_info = FALSE;
383 my_bool opt_no_lock = FALSE;
384 my_bool opt_safe_slave_backup = FALSE;
385 my_bool opt_rsync = FALSE;
386 my_bool opt_force_non_empty_dirs = FALSE;
387 #ifdef HAVE_VERSION_CHECK
388 my_bool opt_noversioncheck = FALSE;
389 #endif
390 my_bool opt_no_backup_locks = FALSE;
391 my_bool opt_decompress = FALSE;
392 my_bool opt_remove_original = FALSE;
393 my_bool opt_tables_compatibility_check = TRUE;
394 static my_bool opt_check_privileges = FALSE;
395 
396 static const char *binlog_info_values[] = {"off", "lockless", "on", "auto",
397 					   NullS};
398 static TYPELIB binlog_info_typelib = {array_elements(binlog_info_values)-1, "",
399 				      binlog_info_values, NULL};
400 ulong opt_binlog_info;
401 
402 char *opt_incremental_history_name = NULL;
403 char *opt_incremental_history_uuid = NULL;
404 
405 char *opt_user = NULL;
406 char *opt_password = NULL;
407 char *opt_host = NULL;
408 char *opt_defaults_group = NULL;
409 char *opt_socket = NULL;
410 uint opt_port = 0;
411 char *opt_login_path = NULL;
412 char *opt_log_bin = NULL;
413 
414 bool tty_password = false;
415 bool tty_transition_key = false;
416 
417 const char *query_type_names[] = { "ALL", "UPDATE", "SELECT", NullS};
418 
419 TYPELIB query_type_typelib= {array_elements(query_type_names) - 1, "",
420 	query_type_names, NULL};
421 
422 ulong opt_lock_wait_query_type;
423 ulong opt_kill_long_query_type;
424 
425 ulong opt_decrypt_algo = 0;
426 
427 uint opt_kill_long_queries_timeout = 0;
428 uint opt_lock_wait_timeout = 0;
429 uint opt_lock_wait_threshold = 0;
430 uint opt_debug_sleep_before_unlock = 0;
431 uint opt_safe_slave_backup_timeout = 0;
432 uint opt_dump_innodb_buffer_pool_timeout = 10;
433 uint opt_dump_innodb_buffer_pool_pct = 0;
434 my_bool opt_dump_innodb_buffer_pool = FALSE;
435 
436 my_bool opt_lock_ddl = FALSE;
437 my_bool opt_lock_ddl_per_table = FALSE;
438 uint opt_lock_ddl_timeout = 0;
439 uint opt_backup_lock_timeout = 0;
440 uint opt_backup_lock_retry_count = 0;
441 
442 const char *opt_history = NULL;
443 my_bool opt_decrypt = FALSE;
444 uint opt_read_buffer_size = 0;
445 
446 const char *ssl_mode_names_lib[] =
447   {"DISABLED", "PREFERRED", "REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY",
448    NullS };
449 TYPELIB ssl_mode_typelib = {array_elements(ssl_mode_names_lib) - 1, "",
450                             ssl_mode_names_lib, NULL};
451 
452 #if defined(HAVE_OPENSSL)
453 uint opt_ssl_mode     = SSL_MODE_PREFERRED;
454 my_bool opt_use_ssl_arg= TRUE;
455 my_bool opt_ssl_verify_server_cert_arg = FALSE;
456 my_bool ssl_mode_set_explicitly= FALSE;
457 #if !defined(HAVE_YASSL)
458 char *opt_server_public_key = NULL;
459 #endif
460 #endif
461 
462 static void
463 check_all_privileges();
464 
465 std::vector<ulint> invalid_encrypted_tablespace_ids;
466 
467 /* Whether xtrabackup_binlog_info should be created on recovery */
468 static bool recover_binlog_info;
469 
470 /* Redo log format version */
471 ulint redo_log_version = REDO_LOG_V1;
472 
473 /* New server-id to encrypt tablespace keys for */
474 ulint opt_encrypt_server_id = 0;
475 bool opt_encrypt_for_server_id_specified = false;
476 
477 bool mdl_taken = false;
478 #define CLIENT_WARN_DEPRECATED(opt, new_opt) \
479   msg("WARNING: " opt \
480       " is deprecated and will be removed in a future version. " \
481       "Use " new_opt " instead.\n")
482 
483 /* Simple datasink creation tracking...add datasinks in the reverse order you
484 want them destroyed. */
485 #define XTRABACKUP_MAX_DATASINKS	10
486 static	ds_ctxt_t	*datasinks[XTRABACKUP_MAX_DATASINKS];
487 static	uint		actual_datasinks = 0;
488 static inline
489 void
xtrabackup_add_datasink(ds_ctxt_t * ds)490 xtrabackup_add_datasink(ds_ctxt_t *ds)
491 {
492 	xb_ad(actual_datasinks < XTRABACKUP_MAX_DATASINKS);
493 	datasinks[actual_datasinks] = ds; actual_datasinks++;
494 }
495 
496 /* ======== Datafiles iterator ======== */
497 datafiles_iter_t *
datafiles_iter_new(fil_system_t * f_system)498 datafiles_iter_new(fil_system_t *f_system)
499 {
500 	datafiles_iter_t *it;
501 
502 	it = static_cast<datafiles_iter_t *>
503 		(ut_malloc_nokey(sizeof(datafiles_iter_t)));
504 	mutex_create(LATCH_ID_XTRA_DATAFILES_ITER_MUTEX, &it->mutex);
505 
506 	it->system = f_system;
507 	it->space = NULL;
508 	it->node = NULL;
509 	it->started = FALSE;
510 
511 	return it;
512 }
513 
514 fil_node_t *
datafiles_iter_next(datafiles_iter_t * it)515 datafiles_iter_next(datafiles_iter_t *it)
516 {
517 	fil_node_t *new_node;
518 
519 	mutex_enter(&it->mutex);
520 
521 	if (it->node == NULL) {
522 		if (it->started)
523 			goto end;
524 		it->started = TRUE;
525 	} else {
526 		it->node = UT_LIST_GET_NEXT(chain, it->node);
527 		if (it->node != NULL)
528 			goto end;
529 	}
530 
531 	it->space = (it->space == NULL) ?
532 		UT_LIST_GET_FIRST(it->system->space_list) :
533 		UT_LIST_GET_NEXT(space_list, it->space);
534 
535 	while (it->space != NULL &&
536 	       (it->space->purpose != FIL_TYPE_TABLESPACE ||
537 		UT_LIST_GET_LEN(it->space->chain) == 0))
538 		it->space = UT_LIST_GET_NEXT(space_list, it->space);
539 	if (it->space == NULL)
540 		goto end;
541 
542 	it->node = UT_LIST_GET_FIRST(it->space->chain);
543 end:
544 	new_node = it->node;
545 	mutex_exit(&it->mutex);
546 
547 	return new_node;
548 }
549 
550 void
datafiles_iter_free(datafiles_iter_t * it)551 datafiles_iter_free(datafiles_iter_t *it)
552 {
553 	mutex_free(&it->mutex);
554 	ut_free(it);
555 }
556 
557 /* ======== Date copying thread context ======== */
558 
559 typedef struct {
560 	datafiles_iter_t 	*it;
561 	uint			num;
562 	uint			*count;
563 	ib_mutex_t		*count_mutex;
564 	bool			*error;
565 	os_thread_id_t		id;
566 } data_thread_ctxt_t;
567 
568 /* ======== for option and variables ======== */
569 
570 enum options_xtrabackup
571 {
572   OPT_XTRA_TARGET_DIR = 1000,     /* make sure it is larger
573                                      than OPT_MAX_CLIENT_OPTION */
574   OPT_XTRA_BACKUP,
575   OPT_XTRA_STATS,
576   OPT_XTRA_PREPARE,
577   OPT_XTRA_EXPORT,
578   OPT_XTRA_APPLY_LOG_ONLY,
579   OPT_XTRA_PRINT_PARAM,
580   OPT_XTRA_USE_MEMORY,
581   OPT_XTRA_THROTTLE,
582   OPT_XTRA_LOG_COPY_INTERVAL,
583   OPT_XTRA_INCREMENTAL,
584   OPT_XTRA_INCREMENTAL_BASEDIR,
585   OPT_XTRA_EXTRA_LSNDIR,
586   OPT_XTRA_INCREMENTAL_DIR,
587   OPT_XTRA_ARCHIVED_TO_LSN,
588   OPT_XTRA_TABLES,
589   OPT_XTRA_TABLES_FILE,
590   OPT_XTRA_DATABASES,
591   OPT_XTRA_DATABASES_FILE,
592   OPT_XTRA_CREATE_IB_LOGFILE,
593   OPT_XTRA_PARALLEL,
594   OPT_XTRA_STREAM,
595   OPT_XTRA_COMPRESS,
596   OPT_XTRA_COMPRESS_THREADS,
597   OPT_XTRA_COMPRESS_CHUNK_SIZE,
598   OPT_XTRA_ENCRYPT,
599   OPT_XTRA_ENCRYPT_KEY,
600   OPT_XTRA_ENCRYPT_KEY_FILE,
601   OPT_XTRA_ENCRYPT_THREADS,
602   OPT_XTRA_ENCRYPT_CHUNK_SIZE,
603   OPT_XTRA_SERVER_ID,
604   OPT_XTRA_ENCRYPT_FOR_SERVER_ID,
605   OPT_LOG,
606   OPT_INNODB,
607   OPT_INNODB_CHECKSUMS,
608   OPT_INNODB_DATA_FILE_PATH,
609   OPT_INNODB_DATA_HOME_DIR,
610   OPT_INNODB_ADAPTIVE_HASH_INDEX,
611   OPT_INNODB_DOUBLEWRITE,
612   OPT_INNODB_FAST_SHUTDOWN,
613   OPT_INNODB_FILE_PER_TABLE,
614   OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
615   OPT_INNODB_FLUSH_METHOD,
616   OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG,
617   OPT_INNODB_LOG_ARCH_DIR,
618   OPT_INNODB_LOG_ARCHIVE,
619   OPT_INNODB_LOG_GROUP_HOME_DIR,
620   OPT_INNODB_MAX_DIRTY_PAGES_PCT,
621   OPT_INNODB_MAX_PURGE_LAG,
622   OPT_INNODB_ROLLBACK_ON_TIMEOUT,
623   OPT_INNODB_STATUS_FILE,
624   OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE,
625   OPT_INNODB_AUTOEXTEND_INCREMENT,
626   OPT_INNODB_BUFFER_POOL_SIZE,
627   OPT_INNODB_COMMIT_CONCURRENCY,
628   OPT_INNODB_CONCURRENCY_TICKETS,
629   OPT_INNODB_FILE_IO_THREADS,
630   OPT_INNODB_IO_CAPACITY,
631   OPT_INNODB_READ_IO_THREADS,
632   OPT_INNODB_WRITE_IO_THREADS,
633   OPT_INNODB_USE_NATIVE_AIO,
634   OPT_INNODB_PAGE_SIZE,
635   OPT_INNODB_LOG_BLOCK_SIZE,
636   OPT_INNODB_FAST_CHECKSUM,
637   OPT_INNODB_EXTRA_UNDOSLOTS,
638   OPT_INNODB_DOUBLEWRITE_FILE,
639   OPT_INNODB_BUFFER_POOL_FILENAME,
640   OPT_INNODB_FORCE_RECOVERY,
641   OPT_INNODB_LOCK_WAIT_TIMEOUT,
642   OPT_INNODB_LOG_BUFFER_SIZE,
643   OPT_INNODB_LOG_FILE_SIZE,
644   OPT_INNODB_LOG_FILES_IN_GROUP,
645   OPT_INNODB_MIRRORED_LOG_GROUPS,
646   OPT_INNODB_OPEN_FILES,
647   OPT_INNODB_SYNC_SPIN_LOOPS,
648   OPT_INNODB_THREAD_CONCURRENCY,
649   OPT_INNODB_THREAD_SLEEP_DELAY,
650   OPT_XTRA_DEBUG_SYNC,
651   OPT_XTRA_COMPACT,
652   OPT_XTRA_REBUILD_INDEXES,
653   OPT_XTRA_REBUILD_THREADS,
654   OPT_INNODB_CHECKSUM_ALGORITHM,
655   OPT_INNODB_UNDO_DIRECTORY,
656   OPT_INNODB_UNDO_TABLESPACES,
657   OPT_INNODB_LOG_CHECKSUM_ALGORITHM,
658   OPT_XTRA_INCREMENTAL_FORCE_SCAN,
659   OPT_DEFAULTS_GROUP,
660   OPT_OPEN_FILES_LIMIT,
661   OPT_CLOSE_FILES,
662   OPT_CORE_FILE,
663 
664   OPT_COPY_BACK,
665   OPT_MOVE_BACK,
666   OPT_GALERA_INFO,
667   OPT_SLAVE_INFO,
668   OPT_NO_LOCK,
669   OPT_LOCK_DDL,
670   OPT_LOCK_DDL_TIMEOUT,
671   OPT_LOCK_DDL_PER_TABLE,
672   OPT_BACKUP_LOCK_TIMEOUT,
673   OPT_BACKUP_LOCK_RETRY,
674   OPT_DUMP_INNODB_BUFFER,
675   OPT_DUMP_INNODB_BUFFER_TIMEOUT,
676   OPT_DUMP_INNODB_BUFFER_PCT,
677   OPT_SAFE_SLAVE_BACKUP,
678   OPT_RSYNC,
679   OPT_FORCE_NON_EMPTY_DIRS,
680 #ifdef HAVE_VERSION_CHECK
681   OPT_NO_VERSION_CHECK,
682 #endif
683   OPT_NO_BACKUP_LOCKS,
684   OPT_DECOMPRESS,
685   OPT_INCREMENTAL_HISTORY_NAME,
686   OPT_INCREMENTAL_HISTORY_UUID,
687   OPT_DECRYPT,
688   OPT_REMOVE_ORIGINAL,
689   OPT_LOCK_WAIT_QUERY_TYPE,
690   OPT_KILL_LONG_QUERY_TYPE,
691   OPT_HISTORY,
692   OPT_KILL_LONG_QUERIES_TIMEOUT,
693   OPT_LOCK_WAIT_TIMEOUT,
694   OPT_LOCK_WAIT_THRESHOLD,
695   OPT_DEBUG_SLEEP_BEFORE_UNLOCK,
696   OPT_SAFE_SLAVE_BACKUP_TIMEOUT,
697   OPT_BINLOG_INFO,
698   OPT_REDO_LOG_VERSION,
699   OPT_XB_SECURE_AUTH,
700   OPT_TRANSITION_KEY,
701   OPT_GENERATE_TRANSITION_KEY,
702   OPT_XTRA_PLUGIN_DIR,
703   OPT_GENERATE_NEW_MASTER_KEY,
704 
705   OPT_SSL_SSL,
706   OPT_SSL_MODE,
707   OPT_SSL_VERIFY_SERVER_CERT,
708   OPT_SERVER_PUBLIC_KEY,
709 
710   OPT_XTRA_TABLES_EXCLUDE,
711   OPT_XTRA_DATABASES_EXCLUDE,
712 
713   OPT_XTRA_TABLES_COMPATIBILITY_CHECK,
714   OPT_XTRA_CHECK_PRIVILEGES,
715   OPT_XTRA_READ_BUFFER_SIZE,
716 };
717 
718 struct my_option xb_client_options[] =
719 {
720   {"version", 'v', "print xtrabackup version information",
721    (G_PTR *) &xtrabackup_version, (G_PTR *) &xtrabackup_version, 0, GET_BOOL,
722    NO_ARG, 0, 0, 0, 0, 0, 0},
723   {"target-dir", OPT_XTRA_TARGET_DIR, "destination directory", (G_PTR*) &xtrabackup_target_dir,
724    (G_PTR*) &xtrabackup_target_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
725   {"backup", OPT_XTRA_BACKUP, "take backup to target-dir",
726    (G_PTR*) &xtrabackup_backup, (G_PTR*) &xtrabackup_backup,
727    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
728   {"stats", OPT_XTRA_STATS, "calc statistic of datadir (offline mysqld is recommended)",
729    (G_PTR*) &xtrabackup_stats, (G_PTR*) &xtrabackup_stats,
730    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
731   {"prepare", OPT_XTRA_PREPARE, "prepare a backup for starting mysql server on the backup.",
732    (G_PTR*) &xtrabackup_prepare, (G_PTR*) &xtrabackup_prepare,
733    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
734   {"export", OPT_XTRA_EXPORT, "create files to import to another database when prepare.",
735    (G_PTR*) &xtrabackup_export, (G_PTR*) &xtrabackup_export,
736    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
737   {"apply-log-only", OPT_XTRA_APPLY_LOG_ONLY,
738    "stop recovery process not to progress LSN after applying log when prepare.",
739    (G_PTR*) &xtrabackup_apply_log_only, (G_PTR*) &xtrabackup_apply_log_only,
740    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
741   {"print-param", OPT_XTRA_PRINT_PARAM, "print parameter of mysqld needed for copyback.",
742    (G_PTR*) &xtrabackup_print_param, (G_PTR*) &xtrabackup_print_param,
743    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
744   {"use-memory", OPT_XTRA_USE_MEMORY, "The value is used instead of buffer_pool_size",
745    (G_PTR*) &xtrabackup_use_memory, (G_PTR*) &xtrabackup_use_memory,
746    0, GET_LL, REQUIRED_ARG, 100*1024*1024L, 1024*1024L, LLONG_MAX, 0,
747    1024*1024L, 0},
748   {"throttle", OPT_XTRA_THROTTLE, "limit count of IO operations (pairs of read&write) per second to IOS values (for '--backup')",
749    (G_PTR*) &xtrabackup_throttle, (G_PTR*) &xtrabackup_throttle,
750    0, GET_LONG, REQUIRED_ARG, 0, 0, LONG_MAX, 0, 1, 0},
751   {"log", OPT_LOG, "Ignored option for MySQL option compatibility",
752    (G_PTR*) &log_ignored_opt, (G_PTR*) &log_ignored_opt, 0,
753    GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
754   {"log-copy-interval", OPT_XTRA_LOG_COPY_INTERVAL, "time interval between checks done by log copying thread in milliseconds (default is 1 second).",
755    (G_PTR*) &xtrabackup_log_copy_interval, (G_PTR*) &xtrabackup_log_copy_interval,
756    0, GET_LONG, REQUIRED_ARG, 1000, 0, LONG_MAX, 0, 1, 0},
757   {"extra-lsndir", OPT_XTRA_EXTRA_LSNDIR, "(for --backup): save an extra copy of the xtrabackup_checkpoints file in this directory.",
758    (G_PTR*) &xtrabackup_extra_lsndir, (G_PTR*) &xtrabackup_extra_lsndir,
759    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
760   {"incremental-lsn", OPT_XTRA_INCREMENTAL, "(for --backup): copy only .ibd pages newer than specified LSN 'high:low'. ##ATTENTION##: If a wrong LSN value is specified, it is impossible to diagnose this, causing the backup to be unusable. Be careful!",
761    (G_PTR*) &xtrabackup_incremental, (G_PTR*) &xtrabackup_incremental,
762    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
763   {"incremental-basedir", OPT_XTRA_INCREMENTAL_BASEDIR, "(for --backup): copy only .ibd pages newer than backup at specified directory.",
764    (G_PTR*) &xtrabackup_incremental_basedir, (G_PTR*) &xtrabackup_incremental_basedir,
765    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
766   {"incremental-dir", OPT_XTRA_INCREMENTAL_DIR, "(for --prepare): apply .delta files and logfile in the specified directory.",
767    (G_PTR*) &xtrabackup_incremental_dir, (G_PTR*) &xtrabackup_incremental_dir,
768    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
769  {"to-archived-lsn", OPT_XTRA_ARCHIVED_TO_LSN,
770    "Don't apply archived logs with bigger log sequence number.",
771    (G_PTR*) &xtrabackup_archived_to_lsn, (G_PTR*) &xtrabackup_archived_to_lsn, 0,
772    GET_LL, REQUIRED_ARG, 0, 0, LLONG_MAX, 0, 0, 0},
773   {"tables", OPT_XTRA_TABLES, "filtering by regexp for table names.",
774    (G_PTR*) &xtrabackup_tables, (G_PTR*) &xtrabackup_tables,
775    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
776   {"tables_file", OPT_XTRA_TABLES_FILE, "filtering by list of the exact database.table name in the file.",
777    (G_PTR*) &xtrabackup_tables_file, (G_PTR*) &xtrabackup_tables_file,
778    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
779   {"databases", OPT_XTRA_DATABASES, "filtering by list of databases.",
780    (G_PTR*) &xtrabackup_databases, (G_PTR*) &xtrabackup_databases,
781    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
782   {"databases_file", OPT_XTRA_TABLES_FILE,
783    "filtering by list of databases in the file.",
784    (G_PTR*) &xtrabackup_databases_file, (G_PTR*) &xtrabackup_databases_file,
785    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
786   {"tables-exclude", OPT_XTRA_TABLES_EXCLUDE, "filtering by regexp for table names. "
787   "Operates the same way as --tables, but matched names are excluded from backup. "
788   "Note that this option has a higher priority than --tables.",
789     (G_PTR*) &xtrabackup_tables_exclude, (G_PTR*) &xtrabackup_tables_exclude,
790     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
791   {"databases-exclude", OPT_XTRA_DATABASES_EXCLUDE, "Excluding databases based on name, "
792   "Operates the same way as --databases, but matched names are excluded from backup. "
793   "Note that this option has a higher priority than --databases.",
794     (G_PTR*) &xtrabackup_databases_exclude, (G_PTR*) &xtrabackup_databases_exclude,
795     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
796   {"create-ib-logfile", OPT_XTRA_CREATE_IB_LOGFILE, "** not work for now** creates ib_logfile* also after '--prepare'. ### If you want create ib_logfile*, only re-execute this command in same options. ###",
797    (G_PTR*) &xtrabackup_create_ib_logfile, (G_PTR*) &xtrabackup_create_ib_logfile,
798    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
799 
800   {"stream", OPT_XTRA_STREAM, "Stream all backup files to the standard output "
801    "in the specified format. Currently the only supported format is 'tar'.",
802    (G_PTR*) &xtrabackup_stream_str, (G_PTR*) &xtrabackup_stream_str, 0, GET_STR,
803    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
804 
805   {"compress", OPT_XTRA_COMPRESS, "Compress individual backup files using the "
806    "specified compression algorithm. Currently the only supported algorithm "
807    "is 'quicklz'. It is also the default algorithm, i.e. the one used when "
808    "--compress is used without an argument.",
809    (G_PTR*) &xtrabackup_compress_alg, (G_PTR*) &xtrabackup_compress_alg, 0,
810    GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
811 
812   {"compress-threads", OPT_XTRA_COMPRESS_THREADS,
813    "Number of threads for parallel data compression. The default value is 1.",
814    (G_PTR*) &xtrabackup_compress_threads, (G_PTR*) &xtrabackup_compress_threads,
815    0, GET_UINT, REQUIRED_ARG, 1, 1, UINT_MAX, 0, 0, 0},
816 
817   {"compress-chunk-size", OPT_XTRA_COMPRESS_CHUNK_SIZE,
818    "Size of working buffer(s) for compression threads in bytes. The default value is 64K.",
819    (G_PTR*) &xtrabackup_compress_chunk_size, (G_PTR*) &xtrabackup_compress_chunk_size,
820    0, GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULLONG_MAX, 0, 0, 0},
821 
822   {"encrypt", OPT_XTRA_ENCRYPT, "Encrypt individual backup files using the "
823    "specified encryption algorithm.",
824    &xtrabackup_encrypt_algo, &xtrabackup_encrypt_algo,
825    &xtrabackup_encrypt_algo_typelib, GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
826 
827   {"encrypt-key", OPT_XTRA_ENCRYPT_KEY, "Encryption key to use.",0, 0, 0,
828    GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
829 
830   {"encrypt-key-file", OPT_XTRA_ENCRYPT_KEY_FILE, "File which contains encryption key to use.",
831    (G_PTR*) &xtrabackup_encrypt_key_file, (G_PTR*) &xtrabackup_encrypt_key_file, 0,
832    GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
833 
834   {"encrypt-threads", OPT_XTRA_ENCRYPT_THREADS,
835    "Number of threads for parallel data encryption. The default value is 1.",
836    (G_PTR*) &xtrabackup_encrypt_threads, (G_PTR*) &xtrabackup_encrypt_threads,
837    0, GET_UINT, REQUIRED_ARG, 1, 1, UINT_MAX, 0, 0, 0},
838 
839   {"encrypt-chunk-size", OPT_XTRA_ENCRYPT_CHUNK_SIZE,
840    "Size of working buffer(S) for encryption threads in bytes. The default value is 64K.",
841    (G_PTR*) &xtrabackup_encrypt_chunk_size, (G_PTR*) &xtrabackup_encrypt_chunk_size,
842    0, GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULLONG_MAX, 0, 0, 0},
843 
844   {"compact", OPT_XTRA_COMPACT,
845    "Create a compact backup by skipping secondary index pages.",
846    (G_PTR*) &xtrabackup_compact, (G_PTR*) &xtrabackup_compact,
847    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
848 
849   {"rebuild_indexes", OPT_XTRA_REBUILD_INDEXES,
850    "Rebuild secondary indexes in InnoDB tables after applying the log. "
851    "Only has effect with --prepare.",
852    (G_PTR*) &xtrabackup_rebuild_indexes, (G_PTR*) &xtrabackup_rebuild_indexes,
853    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
854 
855   {"rebuild_threads", OPT_XTRA_REBUILD_THREADS,
856    "Use this number of threads to rebuild indexes in a compact backup. "
857    "Only has effect with --prepare and --rebuild-indexes.",
858    (G_PTR*) &xtrabackup_rebuild_threads, (G_PTR*) &xtrabackup_rebuild_threads,
859    0, GET_UINT, REQUIRED_ARG, 1, 1, UINT_MAX, 0, 0, 0},
860 
861   {"incremental-force-scan", OPT_XTRA_INCREMENTAL_FORCE_SCAN,
862    "Perform a full-scan incremental backup even in the presence of changed "
863    "page bitmap data",
864    (G_PTR*)&xtrabackup_incremental_force_scan,
865    (G_PTR*)&xtrabackup_incremental_force_scan, 0, GET_BOOL, NO_ARG,
866    0, 0, 0, 0, 0, 0},
867 
868 
869   {"close_files", OPT_CLOSE_FILES, "do not keep files opened. Use at your own "
870    "risk.", (G_PTR*) &xb_close_files, (G_PTR*) &xb_close_files, 0, GET_BOOL,
871    NO_ARG, 0, 0, 0, 0, 0, 0},
872 
873   {"core-file", OPT_CORE_FILE, "Write core on fatal signals", 0, 0, 0,
874    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
875 
876 
877   {"copy-back", OPT_COPY_BACK, "Copy all the files in a previously made "
878    "backup from the backup directory to their original locations.",
879    (uchar *) &xtrabackup_copy_back, (uchar *) &xtrabackup_copy_back, 0,
880    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
881 
882   {"move-back", OPT_MOVE_BACK, "Move all the files in a previously made "
883    "backup from the backup directory to the actual datadir location. "
884    "Use with caution, as it removes backup files.",
885    (uchar *) &xtrabackup_move_back, (uchar *) &xtrabackup_move_back, 0,
886    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
887 
888   {"galera-info", OPT_GALERA_INFO, "This options creates the "
889    "xtrabackup_galera_info file which contains the local node state at "
890    "the time of the backup. Option should be used when performing the "
891    "backup of Percona-XtraDB-Cluster. Has no effect when backup locks "
892    "are used to create the backup.",
893    (uchar *) &opt_galera_info, (uchar *) &opt_galera_info, 0,
894    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
895 
896   {"slave-info", OPT_SLAVE_INFO, "This option is useful when backing "
897    "up a replication slave server. It prints the binary log position "
898    "and name of the master server. It also writes this information to "
899    "the \"xtrabackup_slave_info\" file as a \"CHANGE MASTER\" command. "
900    "A new slave for this master can be set up by starting a slave server "
901    "on this backup and issuing a \"CHANGE MASTER\" command with the "
902    "binary log position saved in the \"xtrabackup_slave_info\" file.",
903    (uchar *) &opt_slave_info, (uchar *) &opt_slave_info, 0,
904    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
905 
906   {"no-lock", OPT_NO_LOCK, "Use this option to disable table lock "
907    "with \"FLUSH TABLES WITH READ LOCK\". Use it only if ALL your "
908    "tables are InnoDB and you DO NOT CARE about the binary log "
909    "position of the backup. This option shouldn't be used if there "
910    "are any DDL statements being executed or if any updates are "
911    "happening on non-InnoDB tables (this includes the system MyISAM "
912    "tables in the mysql database), otherwise it could lead to an "
913    "inconsistent backup. If you are considering to use --no-lock "
914    "because your backups are failing to acquire the lock, this could "
915    "be because of incoming replication events preventing the lock "
916    "from succeeding. Please try using --safe-slave-backup to "
917    "momentarily stop the replication slave thread, this may help "
918    "the backup to succeed and you then don't need to resort to "
919    "using this option.",
920    (uchar *) &opt_no_lock, (uchar *) &opt_no_lock, 0,
921    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
922 
923   {"lock-ddl", OPT_LOCK_DDL, "Issue LOCK TABLES FOR BACKUP if it is "
924    "supported by server at the beginning of the backup to block all DDL "
925    "operations.", (uchar*) &opt_lock_ddl, (uchar*) &opt_lock_ddl, 0,
926    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
927 
928   {"lock-ddl-timeout", OPT_LOCK_DDL_TIMEOUT,
929    "If LOCK TABLES FOR BACKUP does not return within given timeout, abort "
930    "the backup.",
931    (uchar*) &opt_lock_ddl_timeout,
932    (uchar*) &opt_lock_ddl_timeout, 0, GET_UINT,
933    REQUIRED_ARG, 31536000, 1, 31536000, 0, 1, 0},
934 
935   {"lock-ddl-per-table", OPT_LOCK_DDL_PER_TABLE, "Lock DDL for each table "
936    "before xtrabackup starts the copy phase and until the backup is completed.",
937    (uchar*) &opt_lock_ddl_per_table, (uchar*) &opt_lock_ddl_per_table, 0,
938    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
939 
940   {"backup-lock-timeout", OPT_BACKUP_LOCK_TIMEOUT,
941    "Timeout in seconds for attempts to acquire metadata locks.",
942    (uchar *)&opt_backup_lock_timeout, (uchar *)&opt_backup_lock_timeout, 0,
943    GET_UINT, REQUIRED_ARG, 31536000, 1, 31536000, 0, 1, 0},
944 
945   {"backup-lock-retry-count", OPT_BACKUP_LOCK_RETRY,
946    "Number of attempts to acquire metadata locks.",
947    (uchar *)&opt_backup_lock_retry_count,
948    (uchar *)&opt_backup_lock_retry_count, 0,
949    GET_UINT, REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0},
950 
951   {"dump-innodb-buffer-pool", OPT_DUMP_INNODB_BUFFER,
952    "Instruct MySQL server to dump innodb buffer pool by issuing a "
953    "SET GLOBAL innodb_buffer_pool_dump_now=ON ",
954    (uchar*) &opt_dump_innodb_buffer_pool,
955    (uchar*) &opt_dump_innodb_buffer_pool, 0,
956    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
957 
958   {"dump-innodb-buffer-pool-timeout", OPT_DUMP_INNODB_BUFFER_TIMEOUT,
959    "This option specifies the number of seconds xtrabackup waits "
960    "for innodb buffer pool dump to complete",
961    (uchar*) &opt_dump_innodb_buffer_pool_timeout,
962    (uchar*) &opt_dump_innodb_buffer_pool_timeout, 0, GET_UINT,
963    REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
964 
965   {"dump-innodb-buffer-pool-pct", OPT_DUMP_INNODB_BUFFER_PCT,
966    "This option specifies the percentage of buffer pool "
967    "to be dumped ",
968    (uchar*) &opt_dump_innodb_buffer_pool_pct,
969    (uchar*) &opt_dump_innodb_buffer_pool_pct, 0, GET_UINT,
970    REQUIRED_ARG, 0, 0, 100, 0, 1, 0},
971 
972   {"safe-slave-backup", OPT_SAFE_SLAVE_BACKUP, "Stop slave SQL thread "
973    "and wait to start backup until Slave_open_temp_tables in "
974    "\"SHOW STATUS\" is zero. If there are no open temporary tables, "
975    "the backup will take place, otherwise the SQL thread will be "
976    "started and stopped until there are no open temporary tables. "
977    "The backup will fail if Slave_open_temp_tables does not become "
978    "zero after --safe-slave-backup-timeout seconds. The slave SQL "
979    "thread will be restarted when the backup finishes.",
980    (uchar *) &opt_safe_slave_backup,
981    (uchar *) &opt_safe_slave_backup,
982    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
983 
984   {"rsync", OPT_RSYNC, "Uses the rsync utility to optimize local file "
985    "transfers. When this option is specified, innobackupex uses rsync "
986    "to copy all non-InnoDB files instead of spawning a separate cp for "
987    "each file, which can be much faster for servers with a large number "
988    "of databases or tables.  This option cannot be used together with "
989    "--stream.",
990    (uchar *) &opt_rsync, (uchar *) &opt_rsync,
991    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
992 
993   {"force-non-empty-directories", OPT_FORCE_NON_EMPTY_DIRS, "This "
994    "option, when specified, makes --copy-back or --move-back transfer "
995    "files to non-empty directories. Note that no existing files will be "
996    "overwritten. If --copy-back or --nove-back has to copy a file from "
997    "the backup directory which already exists in the destination "
998    "directory, it will still fail with an error.",
999    (uchar *) &opt_force_non_empty_dirs,
1000    (uchar *) &opt_force_non_empty_dirs,
1001    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1002 
1003 #ifdef HAVE_VERSION_CHECK
1004   {"no-version-check", OPT_NO_VERSION_CHECK, "This option disables the "
1005    "version check which is enabled by the --version-check option.",
1006    (uchar *) &opt_noversioncheck,
1007    (uchar *) &opt_noversioncheck,
1008    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1009 #endif
1010 
1011   {"tables-compatibility-check", OPT_XTRA_TABLES_COMPATIBILITY_CHECK,
1012    "This option enables engine compatibility warning.",
1013    (uchar *) & opt_tables_compatibility_check,
1014    (uchar *) & opt_tables_compatibility_check,
1015    0, GET_BOOL, NO_ARG, TRUE, 0, 0, 0, 0, 0},
1016 
1017 
1018   {"no-backup-locks", OPT_NO_BACKUP_LOCKS, "This option controls if "
1019    "backup locks should be used instead of FLUSH TABLES WITH READ LOCK "
1020    "on the backup stage. The option has no effect when backup locks are "
1021    "not supported by the server. This option is enabled by default, "
1022    "disable with --no-backup-locks.",
1023    (uchar *) &opt_no_backup_locks,
1024    (uchar *) &opt_no_backup_locks,
1025    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1026 
1027   {"decompress", OPT_DECOMPRESS, "Decompresses all files with the .qp "
1028    "extension in a backup previously made with the --compress option.",
1029    (uchar *) &opt_decompress,
1030    (uchar *) &opt_decompress,
1031    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1032 
1033   {"user", 'u', "This option specifies the MySQL username used "
1034    "when connecting to the server, if that's not the current user. "
1035    "The option accepts a string argument. See mysql --help for details.",
1036    (uchar*) &opt_user, (uchar*) &opt_user, 0, GET_STR,
1037    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1038 
1039   {"host", 'H', "This option specifies the host to use when "
1040    "connecting to the database server with TCP/IP.  The option accepts "
1041    "a string argument. See mysql --help for details.",
1042    (uchar*) &opt_host, (uchar*) &opt_host, 0, GET_STR,
1043    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1044 
1045   {"port", 'P', "This option specifies the port to use when "
1046    "connecting to the database server with TCP/IP.  The option accepts "
1047    "a string argument. See mysql --help for details.",
1048    &opt_port, &opt_port, 0, GET_UINT, REQUIRED_ARG,
1049    0, 0, 0, 0, 0, 0},
1050 
1051   {"password", 'p', "This option specifies the password to use "
1052    "when connecting to the database. It accepts a string argument.  "
1053    "See mysql --help for details.",
1054    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1055 
1056   {"socket", 'S', "This option specifies the socket to use when "
1057    "connecting to the local database server with a UNIX domain socket.  "
1058    "The option accepts a string argument. See mysql --help for details.",
1059    (uchar*) &opt_socket, (uchar*) &opt_socket, 0, GET_STR,
1060    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1061 
1062   {"incremental-history-name", OPT_INCREMENTAL_HISTORY_NAME,
1063    "This option specifies the name of the backup series stored in the "
1064    "PERCONA_SCHEMA.xtrabackup_history history record to base an "
1065    "incremental backup on. Xtrabackup will search the history table "
1066    "looking for the most recent (highest innodb_to_lsn), successful "
1067    "backup in the series and take the to_lsn value to use as the "
1068    "starting lsn for the incremental backup. This will be mutually "
1069    "exclusive with --incremental-history-uuid, --incremental-basedir "
1070    "and --incremental-lsn. If no valid lsn can be found (no series by "
1071    "that name, no successful backups by that name) xtrabackup will "
1072    "return with an error. It is used with the --incremental option.",
1073    (uchar*) &opt_incremental_history_name,
1074    (uchar*) &opt_incremental_history_name, 0, GET_STR,
1075    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1076 
1077   {"incremental-history-uuid", OPT_INCREMENTAL_HISTORY_UUID,
1078    "This option specifies the UUID of the specific history record "
1079    "stored in the PERCONA_SCHEMA.xtrabackup_history to base an "
1080    "incremental backup on. --incremental-history-name, "
1081    "--incremental-basedir and --incremental-lsn. If no valid lsn can be "
1082    "found (no success record with that uuid) xtrabackup will return "
1083    "with an error. It is used with the --incremental option.",
1084    (uchar*) &opt_incremental_history_uuid,
1085    (uchar*) &opt_incremental_history_uuid, 0, GET_STR,
1086    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1087 
1088   {"decrypt", OPT_DECRYPT, "Decrypts all files with the .xbcrypt "
1089    "extension in a backup previously made with --encrypt option.",
1090    &opt_decrypt_algo, &opt_decrypt_algo,
1091    &xtrabackup_encrypt_algo_typelib, GET_ENUM, REQUIRED_ARG,
1092    0, 0, 0, 0, 0, 0},
1093 
1094   {"remove-original", OPT_REMOVE_ORIGINAL, "Remove .qp and .xbcrypt files "
1095    "after decryption and decompression.",
1096    (uchar *) &opt_remove_original,
1097    (uchar *) &opt_remove_original,
1098    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1099 
1100   {"ftwrl-wait-query-type", OPT_LOCK_WAIT_QUERY_TYPE,
1101    "This option specifies which types of queries are allowed to complete "
1102    "before innobackupex will issue the global lock. Default is all.",
1103    (uchar*) &opt_lock_wait_query_type,
1104    (uchar*) &opt_lock_wait_query_type, &query_type_typelib,
1105    GET_ENUM, REQUIRED_ARG, QUERY_TYPE_ALL, 0, 0, 0, 0, 0},
1106 
1107   {"kill-long-query-type", OPT_KILL_LONG_QUERY_TYPE,
1108    "This option specifies which types of queries should be killed to "
1109    "unblock the global lock. Default is \"all\".",
1110    (uchar*) &opt_kill_long_query_type,
1111    (uchar*) &opt_kill_long_query_type, &query_type_typelib,
1112    GET_ENUM, REQUIRED_ARG, QUERY_TYPE_SELECT, 0, 0, 0, 0, 0},
1113 
1114   {"history", OPT_HISTORY,
1115    "This option enables the tracking of backup history in the "
1116    "PERCONA_SCHEMA.xtrabackup_history table. An optional history "
1117    "series name may be specified that will be placed with the history "
1118    "record for the current backup being taken.",
1119    NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1120 
1121   {"kill-long-queries-timeout", OPT_KILL_LONG_QUERIES_TIMEOUT,
1122    "This option specifies the number of seconds innobackupex waits "
1123    "between starting FLUSH TABLES WITH READ LOCK and killing those "
1124    "queries that block it. Default is 0 seconds, which means "
1125    "innobackupex will not attempt to kill any queries.",
1126    (uchar*) &opt_kill_long_queries_timeout,
1127    (uchar*) &opt_kill_long_queries_timeout, 0, GET_UINT,
1128    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1129 
1130   {"ftwrl-wait-timeout", OPT_LOCK_WAIT_TIMEOUT,
1131    "This option specifies time in seconds that innobackupex should wait "
1132    "for queries that would block FTWRL before running it. If there are "
1133    "still such queries when the timeout expires, innobackupex terminates "
1134    "with an error. Default is 0, in which case innobackupex does not "
1135    "wait for queries to complete and starts FTWRL immediately.",
1136    (uchar*) &opt_lock_wait_timeout,
1137    (uchar*) &opt_lock_wait_timeout, 0, GET_UINT,
1138    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1139 
1140   {"ftwrl-wait-threshold", OPT_LOCK_WAIT_THRESHOLD,
1141    "This option specifies the query run time threshold which is used by "
1142    "innobackupex to detect long-running queries with a non-zero value "
1143    "of --ftwrl-wait-timeout. FTWRL is not started until such "
1144    "long-running queries exist. This option has no effect if "
1145    "--ftwrl-wait-timeout is 0. Default value is 60 seconds.",
1146    (uchar*) &opt_lock_wait_threshold,
1147    (uchar*) &opt_lock_wait_threshold, 0, GET_UINT,
1148    REQUIRED_ARG, 60, 0, 0, 0, 0, 0},
1149 
1150   {"debug-sleep-before-unlock", OPT_DEBUG_SLEEP_BEFORE_UNLOCK,
1151    "This is a debug-only option used by the XtraBackup test suite.",
1152    (uchar*) &opt_debug_sleep_before_unlock,
1153    (uchar*) &opt_debug_sleep_before_unlock, 0, GET_UINT,
1154    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1155 
1156   {"safe-slave-backup-timeout", OPT_SAFE_SLAVE_BACKUP_TIMEOUT,
1157    "How many seconds --safe-slave-backup should wait for "
1158    "Slave_open_temp_tables to become zero. (default 300)",
1159    (uchar*) &opt_safe_slave_backup_timeout,
1160    (uchar*) &opt_safe_slave_backup_timeout, 0, GET_UINT,
1161    REQUIRED_ARG, 300, 0, 0, 0, 0, 0},
1162 
1163   {"binlog-info", OPT_BINLOG_INFO,
1164    "This option controls how XtraBackup should retrieve server's binary log "
1165    "coordinates corresponding to the backup. Possible values are OFF, ON, "
1166    "LOCKLESS and AUTO. See the XtraBackup manual for more information",
1167    &opt_binlog_info, &opt_binlog_info,
1168    &binlog_info_typelib, GET_ENUM, OPT_ARG, BINLOG_INFO_AUTO, 0, 0, 0, 0, 0},
1169 
1170   {"reencrypt-for-server-id", OPT_XTRA_ENCRYPT_FOR_SERVER_ID,
1171    "Re-encrypt tablespace keys for given server-id.",
1172    &opt_encrypt_server_id, &opt_encrypt_server_id, 0,
1173    GET_UINT, REQUIRED_ARG, 0, 0, UINT_MAX32,
1174    0, 0, 0},
1175 
1176   {"check-privileges", OPT_XTRA_CHECK_PRIVILEGES, "Check database user "
1177     "privileges before performing any query.", &opt_check_privileges,
1178    &opt_check_privileges, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1179 
1180   {"read_buffer_size",
1181    OPT_XTRA_READ_BUFFER_SIZE,
1182    "Set datafile read buffer size, given value is scaled up to page size."
1183    " Default is 10Mb.",
1184    &opt_read_buffer_size,
1185    &opt_read_buffer_size,
1186    0, GET_UINT, OPT_ARG, 10*1024*1024,
1187    UNIV_PAGE_SIZE_MAX, UINT_MAX, 0, UNIV_PAGE_SIZE_MAX, 0},
1188 
1189 #include "sslopt-longopts.h"
1190 
1191 #if !defined(HAVE_YASSL)
1192   {"server-public-key-path", OPT_SERVER_PUBLIC_KEY,
1193    "File path to the server public RSA key in PEM format.",
1194    &opt_server_public_key, &opt_server_public_key, 0,
1195    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1196 #endif
1197 
1198   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1199 };
1200 
1201 uint xb_client_options_count = array_elements(xb_client_options);
1202 
1203 struct my_option xb_server_options[] =
1204 {
1205   {"datadir", 'h', "Path to the database root.", (G_PTR*) &mysql_data_home,
1206    (G_PTR*) &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1207   {"tmpdir", 't',
1208    "Path for temporary files. Several paths may be specified, separated by a "
1209 #if defined(__WIN__) || defined(OS2) || defined(__NETWARE__)
1210    "semicolon (;)"
1211 #else
1212    "colon (:)"
1213 #endif
1214    ", in this case they are used in a round-robin fashion.",
1215    (G_PTR*) &opt_mysql_tmpdir,
1216    (G_PTR*) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1217   {"parallel", OPT_XTRA_PARALLEL,
1218    "Number of threads to use for parallel datafiles transfer. "
1219    "The default value is 1.",
1220    (G_PTR*) &xtrabackup_parallel, (G_PTR*) &xtrabackup_parallel, 0, GET_INT,
1221    REQUIRED_ARG, 1, 1, INT_MAX, 0, 0, 0},
1222 
1223    {"log", OPT_LOG, "Ignored option for MySQL option compatibility",
1224    (G_PTR*) &log_ignored_opt, (G_PTR*) &log_ignored_opt, 0,
1225    GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1226 
1227    {"log_bin", OPT_LOG, "Base name for the log sequence",
1228    &opt_log_bin, &opt_log_bin, 0, GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0},
1229 
1230    {"innodb", OPT_INNODB, "Ignored option for MySQL option compatibility",
1231    (G_PTR*) &innobase_ignored_opt, (G_PTR*) &innobase_ignored_opt, 0,
1232    GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1233 
1234   {"innodb_adaptive_hash_index", OPT_INNODB_ADAPTIVE_HASH_INDEX,
1235    "Enable InnoDB adaptive hash index (enabled by default).  "
1236    "Disable with --skip-innodb-adaptive-hash-index.",
1237    (G_PTR*) &innobase_adaptive_hash_index,
1238    (G_PTR*) &innobase_adaptive_hash_index,
1239    0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1240   {"innodb_autoextend_increment", OPT_INNODB_AUTOEXTEND_INCREMENT,
1241    "Data file autoextend increment in megabytes",
1242    (G_PTR*) &sys_tablespace_auto_extend_increment,
1243    (G_PTR*) &sys_tablespace_auto_extend_increment,
1244    0, GET_ULONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0},
1245   {"innodb_buffer_pool_size", OPT_INNODB_BUFFER_POOL_SIZE,
1246    "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
1247    (G_PTR*) &innobase_buffer_pool_size, (G_PTR*) &innobase_buffer_pool_size, 0,
1248    GET_LL, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, LLONG_MAX, 0,
1249    1024*1024L, 0},
1250   {"innodb_checksums", OPT_INNODB_CHECKSUMS, "Enable InnoDB checksums validation (enabled by default). \
1251 Disable with --skip-innodb-checksums.", (G_PTR*) &innobase_use_checksums,
1252    (G_PTR*) &innobase_use_checksums, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1253   {"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH,
1254    "Path to individual files and their sizes.", &innobase_data_file_path,
1255    &innobase_data_file_path, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1256   {"innodb_data_home_dir", OPT_INNODB_DATA_HOME_DIR,
1257    "The common part for InnoDB table spaces.", &innobase_data_home_dir,
1258    &innobase_data_home_dir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1259   {"innodb_doublewrite", OPT_INNODB_DOUBLEWRITE, "Enable InnoDB doublewrite buffer (enabled by default). \
1260 Disable with --skip-innodb-doublewrite.", (G_PTR*) &innobase_use_doublewrite,
1261    (G_PTR*) &innobase_use_doublewrite, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
1262   {"innodb_io_capacity", OPT_INNODB_IO_CAPACITY,
1263    "Number of IOPs the server can do. Tunes the background IO rate",
1264    (G_PTR*) &srv_io_capacity, (G_PTR*) &srv_io_capacity,
1265    0, GET_ULONG, OPT_ARG, 200, 100, ~0UL, 0, 0, 0},
1266   {"innodb_file_io_threads", OPT_INNODB_FILE_IO_THREADS,
1267    "Number of file I/O threads in InnoDB.", (G_PTR*) &innobase_file_io_threads,
1268    (G_PTR*) &innobase_file_io_threads, 0, GET_LONG, REQUIRED_ARG, 4, 4, 64, 0,
1269    1, 0},
1270   {"innodb_read_io_threads", OPT_INNODB_READ_IO_THREADS,
1271    "Number of background read I/O threads in InnoDB.", (G_PTR*) &innobase_read_io_threads,
1272    (G_PTR*) &innobase_read_io_threads, 0, GET_LONG, REQUIRED_ARG, 4, 1, 64, 0,
1273    1, 0},
1274   {"innodb_write_io_threads", OPT_INNODB_WRITE_IO_THREADS,
1275    "Number of background write I/O threads in InnoDB.", (G_PTR*) &innobase_write_io_threads,
1276    (G_PTR*) &innobase_write_io_threads, 0, GET_LONG, REQUIRED_ARG, 4, 1, 64, 0,
1277    1, 0},
1278   {"innodb_file_per_table", OPT_INNODB_FILE_PER_TABLE,
1279    "Stores each InnoDB table to an .ibd file in the database dir.",
1280    (G_PTR*) &innobase_file_per_table,
1281    (G_PTR*) &innobase_file_per_table, 0, GET_BOOL, NO_ARG,
1282    FALSE, 0, 0, 0, 0, 0},
1283   {"innodb_flush_log_at_trx_commit", OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
1284    "Set to 0 (write and flush once per second), 1 (write and flush at each commit) or 2 (write at commit, flush once per second).",
1285    (G_PTR*) &srv_flush_log_at_trx_commit,
1286    (G_PTR*) &srv_flush_log_at_trx_commit,
1287    0, GET_ULONG, OPT_ARG,  1, 0, 2, 0, 0, 0},
1288   {"innodb_flush_method", OPT_INNODB_FLUSH_METHOD,
1289    "With which method to flush data.", (G_PTR*) &innobase_unix_file_flush_method,
1290    (G_PTR*) &innobase_unix_file_flush_method, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
1291    0, 0, 0},
1292 
1293 /* ####### Should we use this option? ####### */
1294   {"innodb_force_recovery", OPT_INNODB_FORCE_RECOVERY,
1295    "Helps to save your data in case the disk image of the database becomes corrupt.",
1296    (G_PTR*) &innobase_force_recovery, (G_PTR*) &innobase_force_recovery, 0,
1297    GET_LONG, REQUIRED_ARG, 0, 0, 6, 0, 1, 0},
1298 
1299   {"innodb_log_arch_dir", OPT_INNODB_LOG_ARCH_DIR,
1300    "Where full logs should be archived.", (G_PTR*) &innobase_log_arch_dir,
1301    (G_PTR*) &innobase_log_arch_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1302   {"innodb_log_buffer_size", OPT_INNODB_LOG_BUFFER_SIZE,
1303    "The size of the buffer which InnoDB uses to write log to the log files on disk.",
1304    (G_PTR*) &innobase_log_buffer_size, (G_PTR*) &innobase_log_buffer_size, 0,
1305    GET_LONG, REQUIRED_ARG, 16*1024*1024L, 256*1024L, LONG_MAX, 0, 1024, 0},
1306   {"innodb_log_file_size", OPT_INNODB_LOG_FILE_SIZE,
1307    "Size of each log file in a log group.",
1308    (G_PTR*) &innobase_log_file_size, (G_PTR*) &innobase_log_file_size, 0,
1309    GET_LL, REQUIRED_ARG, 48*1024*1024L, 1*1024*1024L, LLONG_MAX, 0,
1310    1024*1024L, 0},
1311   {"innodb_log_files_in_group", OPT_INNODB_LOG_FILES_IN_GROUP,
1312    "Number of log files in the log group. InnoDB writes to the files in a "
1313    "circular fashion. Value 3 is recommended here.",
1314    &innobase_log_files_in_group, &innobase_log_files_in_group,
1315    0, GET_LONG, REQUIRED_ARG, 2, 2, 100, 0, 1, 0},
1316   {"innodb_log_group_home_dir", OPT_INNODB_LOG_GROUP_HOME_DIR,
1317    "Path to InnoDB log files.", &srv_log_group_home_dir,
1318    &srv_log_group_home_dir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1319   {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT,
1320    "Percentage of dirty pages allowed in bufferpool.",
1321    (G_PTR*) &srv_max_buf_pool_modified_pct,
1322    (G_PTR*) &srv_max_buf_pool_modified_pct, 0, GET_DOUBLE, REQUIRED_ARG,
1323    (longlong)getopt_double2ulonglong(75), (longlong)getopt_double2ulonglong(0),
1324    getopt_double2ulonglong(100), 0, 0, 0},
1325   {"innodb_open_files", OPT_INNODB_OPEN_FILES,
1326    "How many files at the maximum InnoDB keeps open at the same time.",
1327    (G_PTR*) &innobase_open_files, (G_PTR*) &innobase_open_files, 0,
1328    GET_LONG, REQUIRED_ARG, 300L, 10L, LONG_MAX, 0, 1L, 0},
1329   {"innodb_use_native_aio", OPT_INNODB_USE_NATIVE_AIO,
1330    "Use native AIO if supported on this platform.",
1331    (G_PTR*) &srv_use_native_aio,
1332    (G_PTR*) &srv_use_native_aio, 0, GET_BOOL, NO_ARG,
1333    FALSE, 0, 0, 0, 0, 0},
1334   {"innodb_page_size", OPT_INNODB_PAGE_SIZE,
1335    "The universal page size of the database.",
1336    (G_PTR*) &innobase_page_size, (G_PTR*) &innobase_page_size, 0,
1337    /* Use GET_LL to support numeric suffixes in 5.6 */
1338    GET_LL, REQUIRED_ARG,
1339    (1LL << 14), (1LL << 12), (1LL << UNIV_PAGE_SIZE_SHIFT_MAX), 0, 1L, 0},
1340   {"innodb_log_block_size", OPT_INNODB_LOG_BLOCK_SIZE,
1341   "The log block size of the transaction log file. "
1342    "Changing for created log file is not supported. Use on your own risk!",
1343    (G_PTR*) &innobase_log_block_size, (G_PTR*) &innobase_log_block_size, 0,
1344    GET_ULONG, REQUIRED_ARG, 512, 512, 1 << UNIV_PAGE_SIZE_SHIFT_MAX, 0, 1L, 0},
1345   {"innodb_fast_checksum", OPT_INNODB_FAST_CHECKSUM,
1346    "Change the algorithm of checksum for the whole of datapage to 4-bytes word based.",
1347    (G_PTR*) &innobase_fast_checksum,
1348    (G_PTR*) &innobase_fast_checksum, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
1349   {"innodb_doublewrite_file", OPT_INNODB_DOUBLEWRITE_FILE,
1350    "Path to special datafile for doublewrite buffer. (default is "": not used)",
1351    (G_PTR*) &innobase_doublewrite_file, (G_PTR*) &innobase_doublewrite_file,
1352    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1353   {"innodb_buffer_pool_filename", OPT_INNODB_BUFFER_POOL_FILENAME,
1354    "Filename to/from which to dump/load the InnoDB buffer pool",
1355    (G_PTR*) &innobase_buffer_pool_filename,
1356    (G_PTR*) &innobase_buffer_pool_filename,
1357    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1358 
1359 #ifndef __WIN__
1360   {"debug-sync", OPT_XTRA_DEBUG_SYNC,
1361    "Debug sync point. This is only used by the xtrabackup test suite",
1362    (G_PTR*) &xtrabackup_debug_sync,
1363    (G_PTR*) &xtrabackup_debug_sync,
1364    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1365 #endif
1366 
1367 #ifndef DBUG_OFF
1368   {"debug", '#', "Output debug log. Default all ib_log output to stderr."
1369    " To redirect all ib_log output to separate file, use "
1370    "--debug=d,ib_log:o,/tmp/xtrabackup.trace", &dbug_setting,
1371    &dbug_setting, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1372 #endif /* !DBUG_OFF */
1373 
1374   {"innodb_checksum_algorithm", OPT_INNODB_CHECKSUM_ALGORITHM,
1375   "The algorithm InnoDB uses for page checksumming. [CRC32, STRICT_CRC32, "
1376    "INNODB, STRICT_INNODB, NONE, STRICT_NONE]", &srv_checksum_algorithm,
1377    &srv_checksum_algorithm, &innodb_checksum_algorithm_typelib, GET_ENUM,
1378    REQUIRED_ARG, SRV_CHECKSUM_ALGORITHM_INNODB, 0, 0, 0, 0, 0},
1379   {"innodb_log_checksum_algorithm", OPT_INNODB_LOG_CHECKSUM_ALGORITHM,
1380   "The algorithm InnoDB uses for log checksumming. [CRC32, STRICT_CRC32, "
1381    "INNODB, STRICT_INNODB, NONE, STRICT_NONE]", &srv_log_checksum_algorithm,
1382    &srv_log_checksum_algorithm, &innodb_checksum_algorithm_typelib, GET_ENUM,
1383    REQUIRED_ARG, SRV_CHECKSUM_ALGORITHM_INNODB, 0, 0, 0, 0, 0},
1384   {"innodb_undo_directory", OPT_INNODB_UNDO_DIRECTORY,
1385    "Directory where undo tablespace files live, this path can be absolute.",
1386    &srv_undo_dir, &srv_undo_dir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0,
1387    0},
1388 
1389   {"innodb_undo_tablespaces", OPT_INNODB_UNDO_TABLESPACES,
1390    "Number of undo tablespaces to use.",
1391    (G_PTR*)&srv_undo_tablespaces, (G_PTR*)&srv_undo_tablespaces,
1392    0, GET_ULONG, REQUIRED_ARG, 0, 0, 126, 0, 1, 0},
1393 
1394   {"defaults_group", OPT_DEFAULTS_GROUP, "defaults group in config file (default \"mysqld\").",
1395    (G_PTR*) &defaults_group, (G_PTR*) &defaults_group,
1396    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1397 
1398   {"open_files_limit", OPT_OPEN_FILES_LIMIT, "the maximum number of file "
1399    "descriptors to reserve with setrlimit().",
1400    (G_PTR*) &xb_open_files_limit, (G_PTR*) &xb_open_files_limit, 0, GET_ULONG,
1401    REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0},
1402 
1403   {"redo-log-version", OPT_REDO_LOG_VERSION,
1404    "Redo log version of the backup. For --prepare only.",
1405    &redo_log_version, &redo_log_version, 0, GET_UINT,
1406    REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
1407 
1408   {"server-id", OPT_XTRA_SERVER_ID, "The server instance being backed up",
1409    &server_id, &server_id, 0, GET_UINT, REQUIRED_ARG, 0, 0, UINT_MAX32,
1410    0, 0, 0},
1411 
1412   {"transition-key", OPT_TRANSITION_KEY, "Transition key to encrypt "
1413    "tablespace keys with.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
1414 
1415   {"xtrabackup-plugin-dir", OPT_XTRA_PLUGIN_DIR,
1416    "Directory for xtrabackup plugins.",
1417    &opt_xtra_plugin_dir, &opt_xtra_plugin_dir,
1418    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
1419 
1420   {"generate-new-master-key", OPT_GENERATE_NEW_MASTER_KEY,
1421    "Generate new master key when doing copy-back.",
1422    &opt_generate_new_master_key, &opt_generate_new_master_key, 0, GET_BOOL,
1423    NO_ARG, 0, 0, 0, 0, 0, 0},
1424 
1425   {"generate-transition-key", OPT_GENERATE_TRANSITION_KEY,
1426    "Generate transition key and store it into keyring.",
1427    &opt_generate_transition_key, &opt_generate_transition_key, 0, GET_BOOL,
1428    NO_ARG, 0, 0, 0, 0, 0, 0},
1429 
1430   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
1431 };
1432 
1433 uint xb_server_options_count = array_elements(xb_server_options);
1434 
1435 #ifndef __WIN__
1436 static int debug_sync_resumed;
1437 
1438 static void sigcont_handler(int sig);
1439 
sigcont_handler(int sig)1440 static void sigcont_handler(int sig __attribute__((unused)))
1441 {
1442 	debug_sync_resumed= 1;
1443 }
1444 #endif
1445 
1446 static inline
1447 void
debug_sync_point(const char * name)1448 debug_sync_point(const char *name)
1449 {
1450 #ifndef __WIN__
1451 	FILE	*fp;
1452 	pid_t	pid;
1453 	char	pid_path[FN_REFLEN];
1454 
1455 	if (xtrabackup_debug_sync == NULL) {
1456 		return;
1457 	}
1458 
1459 	if (strcmp(xtrabackup_debug_sync, name)) {
1460 		return;
1461 	}
1462 
1463 	pid = getpid();
1464 
1465 	snprintf(pid_path, sizeof(pid_path), "%s/xtrabackup_debug_sync",
1466 		 xtrabackup_target_dir);
1467 	fp = fopen(pid_path, "w");
1468 	if (fp == NULL) {
1469 		msg("xtrabackup: Error: cannot open %s\n", pid_path);
1470 		exit(EXIT_FAILURE);
1471 	}
1472 	fprintf(fp, "%u\n", (uint) pid);
1473 	fclose(fp);
1474 
1475 	msg("xtrabackup: DEBUG: Suspending at debug sync point '%s'. "
1476 	    "Resume with 'kill -SIGCONT %u'.\n", name, (uint) pid);
1477 
1478 	debug_sync_resumed= 0;
1479 	kill(pid, SIGSTOP);
1480 	while (!debug_sync_resumed) {
1481 		sleep(1);
1482 	}
1483 
1484 	/* On resume */
1485 	msg("xtrabackup: DEBUG: removing the pid file.\n");
1486 	my_delete(pid_path, MYF(MY_WME));
1487 #endif
1488 }
1489 
1490 static const char *xb_client_default_groups[]=
1491 	{ "xtrabackup", "client", 0, 0, 0 };
1492 
1493 static const char *xb_server_default_groups[]=
1494 	{ "xtrabackup", "mysqld", 0, 0, 0 };
1495 
print_version(void)1496 static void print_version(void)
1497 {
1498   msg("%s version %s based on MySQL server %s %s (%s) (revision id: %s)\n",
1499       my_progname, XTRABACKUP_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE,
1500       MACHINE_TYPE, XTRABACKUP_REVISION);
1501 }
1502 
usage(void)1503 static void usage(void)
1504 {
1505   puts("Open source backup tool for InnoDB and XtraDB\n\
1506 \n\
1507 Copyright (C) 2009-2017 Percona LLC and/or its affiliates.\n\
1508 Portions Copyright (C) 2000, 2011, MySQL AB & Innobase Oy. All Rights Reserved.\n\
1509 \n\
1510 This program is free software; you can redistribute it and/or\n\
1511 modify it under the terms of the GNU General Public License\n\
1512 as published by the Free Software Foundation version 2\n\
1513 of the License.\n\
1514 \n\
1515 This program is distributed in the hope that it will be useful,\n\
1516 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
1517 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
1518 GNU General Public License for more details.\n\
1519 \n\
1520 You can download full text of the license on http://www.gnu.org/licenses/gpl-2.0.txt\n");
1521 
1522   printf("Usage: [%s [--defaults-file=#] --backup | %s [--defaults-file=#] --prepare] [OPTIONS]\n",my_progname,my_progname);
1523   print_defaults("my", xb_server_default_groups);
1524   my_print_help(xb_client_options);
1525   my_print_help(xb_server_options);
1526   my_print_variables(xb_server_options);
1527   my_print_variables(xb_client_options);
1528 }
1529 
1530 #define ADD_PRINT_PARAM_OPT(value)              \
1531   { \
1532     print_param_str << opt->name << "=" << value << "\n"; \
1533     param_set.insert(opt->name); \
1534   }
1535 
1536 /************************************************************************
1537 Check if parameter is set in defaults file or via command line argument
1538 @return true if parameter is set. */
1539 bool
check_if_param_set(const char * param)1540 check_if_param_set(const char *param)
1541 {
1542 	return param_set.find(param) != param_set.end();
1543 }
1544 
1545 my_bool
xb_get_one_option(int optid,const struct my_option * opt,char * argument)1546 xb_get_one_option(int optid,
1547 		  const struct my_option *opt,
1548 		  char *argument)
1549 {
1550   static const char* hide_value[]=
1551     { "password", "encrypt-key", "transition-key" };
1552 
1553   param_str << "--" << opt->name;
1554   if (argument) {
1555     bool param_handled = false;
1556     for (unsigned i=0; i<sizeof(hide_value)/sizeof(char*); ++i) {
1557       if (strcmp(opt->name, hide_value[i]) == 0) {
1558         param_handled = true;
1559         param_str << "=*";
1560         break;
1561       }
1562     }
1563     if(!param_handled) {
1564       param_str << "=" << argument;
1565     }
1566   }
1567   param_str << " ";
1568   switch(optid) {
1569   case '#':
1570     dbug_setting = argument ? argument : "d,ib_log";
1571     DBUG_SET_INITIAL(dbug_setting);
1572     break;
1573 
1574   case 'h':
1575     strmake(mysql_real_data_home,argument, FN_REFLEN - 1);
1576     mysql_data_home= mysql_real_data_home;
1577 
1578     ADD_PRINT_PARAM_OPT(mysql_real_data_home);
1579     break;
1580 
1581   case 't':
1582 
1583     ADD_PRINT_PARAM_OPT(opt_mysql_tmpdir);
1584     break;
1585 
1586   case OPT_INNODB_DATA_HOME_DIR:
1587 
1588     ADD_PRINT_PARAM_OPT(innobase_data_home_dir);
1589     break;
1590 
1591   case OPT_INNODB_DATA_FILE_PATH:
1592 
1593     ADD_PRINT_PARAM_OPT(innobase_data_file_path);
1594     break;
1595 
1596   case OPT_INNODB_LOG_GROUP_HOME_DIR:
1597 
1598     ADD_PRINT_PARAM_OPT(srv_log_group_home_dir);
1599     break;
1600 
1601   case OPT_INNODB_LOG_FILES_IN_GROUP:
1602 
1603     ADD_PRINT_PARAM_OPT(innobase_log_files_in_group);
1604     break;
1605 
1606   case OPT_INNODB_LOG_FILE_SIZE:
1607 
1608     ADD_PRINT_PARAM_OPT(innobase_log_file_size);
1609     break;
1610 
1611   case OPT_INNODB_FLUSH_METHOD:
1612 
1613     ADD_PRINT_PARAM_OPT(innobase_unix_file_flush_method);
1614     break;
1615 
1616   case OPT_INNODB_PAGE_SIZE:
1617 
1618     ADD_PRINT_PARAM_OPT(innobase_page_size);
1619     break;
1620 
1621   case OPT_INNODB_FAST_CHECKSUM:
1622 
1623     ADD_PRINT_PARAM_OPT(!!innobase_fast_checksum);
1624     break;
1625 
1626   case OPT_INNODB_LOG_BLOCK_SIZE:
1627 
1628     ADD_PRINT_PARAM_OPT(innobase_log_block_size);
1629     break;
1630 
1631   case OPT_INNODB_DOUBLEWRITE_FILE:
1632 
1633     ADD_PRINT_PARAM_OPT(innobase_doublewrite_file);
1634     break;
1635 
1636   case OPT_INNODB_UNDO_DIRECTORY:
1637 
1638     ADD_PRINT_PARAM_OPT(srv_undo_dir);
1639     break;
1640 
1641   case OPT_INNODB_UNDO_TABLESPACES:
1642 
1643     ADD_PRINT_PARAM_OPT(srv_undo_tablespaces);
1644     break;
1645 
1646   case OPT_INNODB_CHECKSUM_ALGORITHM:
1647 
1648     ut_a(srv_checksum_algorithm <= SRV_CHECKSUM_ALGORITHM_STRICT_NONE);
1649 
1650     ADD_PRINT_PARAM_OPT(innodb_checksum_algorithm_names[srv_checksum_algorithm]);
1651     innodb_checksum_algorithm_specified = true;
1652     break;
1653 
1654   case OPT_INNODB_LOG_CHECKSUM_ALGORITHM:
1655 
1656     ut_a(srv_log_checksum_algorithm <= SRV_CHECKSUM_ALGORITHM_STRICT_NONE);
1657 
1658     ADD_PRINT_PARAM_OPT(innodb_checksum_algorithm_names[srv_log_checksum_algorithm]);
1659     innodb_log_checksum_algorithm_specified = true;
1660     break;
1661 
1662   case OPT_INNODB_BUFFER_POOL_FILENAME:
1663 
1664     ADD_PRINT_PARAM_OPT(innobase_buffer_pool_filename);
1665     break;
1666 
1667   case OPT_XTRA_TARGET_DIR:
1668     strmake(xtrabackup_real_target_dir,argument, sizeof(xtrabackup_real_target_dir)-1);
1669     xtrabackup_target_dir= xtrabackup_real_target_dir;
1670     break;
1671   case OPT_XTRA_STREAM:
1672     if (!strcasecmp(argument, "tar"))
1673       xtrabackup_stream_fmt = XB_STREAM_FMT_TAR;
1674     else if (!strcasecmp(argument, "xbstream"))
1675       xtrabackup_stream_fmt = XB_STREAM_FMT_XBSTREAM;
1676     else
1677     {
1678       msg("Invalid --stream argument: %s\n", argument);
1679       return 1;
1680     }
1681     xtrabackup_stream = TRUE;
1682     break;
1683   case OPT_XTRA_COMPRESS:
1684     if (argument == NULL)
1685       xtrabackup_compress_alg = "quicklz";
1686     else if (strcasecmp(argument, "quicklz"))
1687     {
1688       msg("Invalid --compress argument: %s\n", argument);
1689       return 1;
1690     }
1691     xtrabackup_compress = TRUE;
1692     break;
1693   case OPT_XTRA_ENCRYPT:
1694     if (argument == NULL)
1695     {
1696       msg("Missing --encrypt argument, must specify a valid encryption "
1697           " algorithm.\n");
1698       return 1;
1699     }
1700     xtrabackup_encrypt = TRUE;
1701     break;
1702   case OPT_DECRYPT:
1703     if (argument == NULL) {
1704       msg("Missing --decrypt argument, must specify a "
1705           "valid encryption  algorithm.\n");
1706       return(1);
1707     }
1708     opt_decrypt = TRUE;
1709     xtrabackup_decrypt_decompress = true;
1710     break;
1711   case OPT_DECOMPRESS:
1712     opt_decompress = TRUE;
1713     xtrabackup_decrypt_decompress = true;
1714     break;
1715   case (int) OPT_CORE_FILE:
1716     test_flags |= TEST_CORE_ON_SIGNAL;
1717     break;
1718   case OPT_HISTORY:
1719     if (argument) {
1720       opt_history = argument;
1721     } else {
1722       opt_history = "";
1723     }
1724     break;
1725   case OPT_XTRA_ENCRYPT_FOR_SERVER_ID:
1726     opt_encrypt_for_server_id_specified = true;
1727     break;
1728   case 'p':
1729     if (argument == disabled_my_option)
1730       argument= (char*) "";                       /* Don't require password */
1731     if (argument)
1732     {
1733       hide_option(argument, &opt_password);
1734       tty_password = false;
1735     }
1736     else
1737       tty_password = true;
1738     break;
1739   case OPT_TRANSITION_KEY:
1740     if (argument == disabled_my_option)
1741       argument = (char*) "";                      /* Don't require password */
1742     if (argument)
1743     {
1744       hide_option(argument, &opt_transition_key);
1745       tty_transition_key = false;
1746     }
1747     else
1748       tty_transition_key = true;
1749     use_dumped_tablespace_keys = true;
1750     break;
1751   case OPT_GENERATE_TRANSITION_KEY:
1752     use_dumped_tablespace_keys = true;
1753     break;
1754   case OPT_XTRA_ENCRYPT_KEY:
1755     hide_option(argument, &xtrabackup_encrypt_key);
1756     break;
1757 
1758 #include "sslopt-case.h"
1759 
1760   case '?':
1761     usage();
1762     exit(EXIT_SUCCESS);
1763     break;
1764   case 'v':
1765     print_version();
1766     exit(EXIT_SUCCESS);
1767     break;
1768   default:
1769     break;
1770   }
1771   return 0;
1772 }
1773 
1774 /***********************************************************************
1775 Initializes log_block_size */
1776 static
1777 ibool
xb_init_log_block_size(void)1778 xb_init_log_block_size(void)
1779 {
1780 	srv_log_block_size = 0;
1781 	if (innobase_log_block_size != 512) {
1782 		uint	n_shift = get_bit_shift(innobase_log_block_size);
1783 
1784 		if (n_shift > 0) {
1785 			srv_log_block_size = (1 << n_shift);
1786 			msg("InnoDB: The log block size is set to %lu.\n",
1787 			    srv_log_block_size);
1788 		}
1789 	} else {
1790 		srv_log_block_size = 512;
1791 	}
1792 	if (!srv_log_block_size) {
1793 		msg("InnoDB: Error: %lu is not valid value for "
1794 		    "innodb_log_block_size.\n", innobase_log_block_size);
1795 		return FALSE;
1796 	}
1797 
1798 	return TRUE;
1799 }
1800 
1801 /** Check that a page_size is correct for InnoDB.
1802 If correct, set the associated page_size_shift which is the power of 2
1803 for this page size.
1804 @param[in]      page_size       Page Size to evaluate
1805 @return an associated page_size_shift if valid, 0 if invalid. */
1806 inline
1807 ulong
innodb_page_size_validate(ulong page_size)1808 innodb_page_size_validate(
1809         ulong   page_size)
1810 {
1811         ulong           n;
1812 
1813         for (n = UNIV_PAGE_SIZE_SHIFT_MIN;
1814              n <= UNIV_PAGE_SIZE_SHIFT_MAX;
1815              n++) {
1816                 if (page_size == static_cast<ulong>(1 << n)) {
1817                         return(n);
1818                 }
1819         }
1820 
1821         return(0);
1822 }
1823 
1824 static my_bool
innodb_init_param(void)1825 innodb_init_param(void)
1826 {
1827 	/* innobase_init */
1828 	static char	current_dir[3];		/* Set if using current lib */
1829 	char		*default_path;
1830         ulint		fsp_flags;
1831 
1832 	/* === some variables from mysqld === */
1833 	memset((G_PTR) &mysql_tmpdir_list, 0, sizeof(mysql_tmpdir_list));
1834 
1835 	if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir))
1836 		exit(EXIT_FAILURE);
1837 
1838 	/* dummy for initialize all_charsets[] */
1839 	get_charset_name(0);
1840 
1841 	/* Check that the value of system variable innodb_page_size was
1842 	set correctly.  Its value was put into srv_page_size. If valid,
1843 	return the associated srv_page_size_shift. */
1844 	srv_page_size_shift = innodb_page_size_validate(innobase_page_size);
1845 	if (!srv_page_size_shift) {
1846 		msg("xtrabackup: Invalid page size=%llu.\n", innobase_page_size);
1847 		goto error;
1848 	}
1849 	srv_page_size = innobase_page_size;
1850 
1851 	if (!xb_init_log_block_size()) {
1852 		goto error;
1853 	}
1854 
1855 	srv_fast_checksum = (ibool) innobase_fast_checksum;
1856 
1857 	/* Check that values don't overflow on 32-bit systems. */
1858 	if (sizeof(ulint) == 4) {
1859 		if (xtrabackup_use_memory > UINT_MAX32) {
1860 			msg("xtrabackup: use-memory can't be over 4GB"
1861 			    " on 32-bit systems\n");
1862 		}
1863 
1864 		if (innobase_buffer_pool_size > UINT_MAX32) {
1865 			msg("xtrabackup: innobase_buffer_pool_size can't be "
1866 			    "over 4GB on 32-bit systems\n");
1867 
1868 			goto error;
1869 		}
1870 
1871 		if (innobase_log_file_size > UINT_MAX32) {
1872 			msg("xtrabackup: innobase_log_file_size can't be "
1873 			    "over 4GB on 32-bit systemsi\n");
1874 
1875 			goto error;
1876 		}
1877 	}
1878 
1879   	os_innodb_umask = (ulint)0664;
1880 
1881 	os_file_set_umask(my_umask);
1882 
1883 	/* Setup the memory alloc/free tracing mechanisms before calling
1884 	any functions that could possibly allocate memory. */
1885 	ut_new_boot();
1886 
1887 	/* First calculate the default path for innodb_data_home_dir etc.,
1888 	in case the user has not given any value.
1889 
1890 	Note that when using the embedded server, the datadirectory is not
1891 	necessarily the current directory of this program. */
1892 
1893 	/* It's better to use current lib, to keep paths short */
1894 	current_dir[0] = FN_CURLIB;
1895 	current_dir[1] = 0;
1896 	default_path = current_dir;
1897 
1898 	ut_a(default_path);
1899 
1900 	fil_path_to_mysql_datadir = default_path;
1901 	folder_mysql_datadir = fil_path_to_mysql_datadir;
1902 
1903 	/* Set InnoDB initialization parameters according to the values
1904 	read from MySQL .cnf file */
1905 
1906 	if (xtrabackup_backup || xtrabackup_stats) {
1907 		msg("xtrabackup: using the following InnoDB configuration:\n");
1908 	} else {
1909 		msg("xtrabackup: using the following InnoDB configuration "
1910 		    "for recovery:\n");
1911 	}
1912 
1913 	/*--------------- Data files -------------------------*/
1914 
1915 	/* The default dir for data files is the datadir of MySQL */
1916 
1917 	srv_data_home = ((xtrabackup_backup || xtrabackup_stats) && innobase_data_home_dir
1918 			 ? innobase_data_home_dir : default_path);
1919 	msg("xtrabackup:   innodb_data_home_dir = %s\n", srv_data_home);
1920 
1921 	/*--------------- Shared tablespaces -------------------------*/
1922 
1923 	/* Set default InnoDB data file size to 10 MB and let it be
1924   	auto-extending. Thus users can use InnoDB in >= 4.0 without having
1925 	to specify any startup options. */
1926 
1927 	if (!innobase_data_file_path) {
1928   		innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
1929 	}
1930 	msg("xtrabackup:   innodb_data_file_path = %s\n",
1931 	    innobase_data_file_path);
1932 
1933 	/* This is the first time univ_page_size is used.
1934 	It was initialized to 16k pages before srv_page_size was set */
1935 	univ_page_size.copy_from(
1936 		page_size_t(srv_page_size, srv_page_size, false));
1937 
1938 	srv_sys_space.set_space_id(TRX_SYS_SPACE);
1939 
1940 	/* Create the filespace flags. */
1941 	fsp_flags = fsp_flags_init(
1942 		univ_page_size, false, false, false, false);
1943 	srv_sys_space.set_flags(fsp_flags);
1944 
1945 	srv_sys_space.set_name(reserved_system_space_name);
1946 	srv_sys_space.set_path(srv_data_home);
1947 
1948 	/* Supports raw devices */
1949 	if (!srv_sys_space.parse_params(innobase_data_file_path,
1950 					true, xtrabackup_prepare)) {
1951 		goto error;
1952 	}
1953 
1954 	/* Set default InnoDB temp data file size to 12 MB and let it be
1955 	auto-extending. */
1956 
1957 	if (!innobase_temp_data_file_path) {
1958 		innobase_temp_data_file_path = (char*) "ibtmp1:12M:autoextend";
1959 	}
1960 
1961 	/* We set the temporary tablspace id later, after recovery.
1962 	The temp tablespace doesn't support raw devices.
1963 	Set the name and path. */
1964 	srv_tmp_space.set_name(reserved_temporary_space_name);
1965 	srv_tmp_space.set_path(srv_data_home);
1966 
1967 	/* Create the filespace flags with the temp flag set. */
1968 	fsp_flags = fsp_flags_init(
1969 		univ_page_size, false, false, false, true);
1970 	srv_tmp_space.set_flags(fsp_flags);
1971 
1972 	if (!srv_tmp_space.parse_params(innobase_temp_data_file_path, false,
1973 					xtrabackup_prepare)) {
1974 		goto error;
1975 	}
1976 
1977 	/* Perform all sanity check before we take action of deleting files*/
1978 	if (srv_sys_space.intersection(&srv_tmp_space)) {
1979 		msg("%s and %s file names seem to be the same.",
1980 			srv_tmp_space.name(), srv_sys_space.name());
1981 		goto error;
1982 	}
1983 
1984 	/* -------------- Log files ---------------------------*/
1985 
1986 	/* The default dir for log files is the datadir of MySQL */
1987 
1988 	if (!((xtrabackup_backup || xtrabackup_stats) &&
1989 	      srv_log_group_home_dir)) {
1990 		srv_log_group_home_dir = default_path;
1991 	}
1992 	if (xtrabackup_prepare && xtrabackup_incremental_dir) {
1993 		srv_log_group_home_dir = xtrabackup_incremental_dir;
1994 	}
1995 	msg("xtrabackup:   innodb_log_group_home_dir = %s\n",
1996 	    srv_log_group_home_dir);
1997 
1998 	os_normalize_path(srv_log_group_home_dir);
1999 
2000 	if (strchr(srv_log_group_home_dir, ';')) {
2001 
2002 		msg("syntax error in innodb_log_group_home_dir, ");
2003 
2004 		goto error;
2005 	}
2006 
2007 	srv_adaptive_flushing = FALSE;
2008 	srv_file_format = 1; /* Barracuda */
2009 	srv_max_file_format_at_startup = UNIV_FORMAT_MIN; /* on */
2010 	/* --------------------------------------------------*/
2011 
2012 	srv_file_flush_method_str = innobase_unix_file_flush_method;
2013 
2014 	srv_n_log_files = (ulint) innobase_log_files_in_group;
2015 	srv_log_file_size = (ulint) innobase_log_file_size;
2016 	msg("xtrabackup:   innodb_log_files_in_group = %ld\n",
2017 	    srv_n_log_files);
2018 	msg("xtrabackup:   innodb_log_file_size = %lld\n",
2019 	    (long long int) srv_log_file_size);
2020 
2021 	srv_log_buffer_size = (ulint) innobase_log_buffer_size;
2022 
2023         /* We set srv_pool_size here in units of 1 kB. InnoDB internally
2024         changes the value so that it becomes the number of database pages. */
2025 
2026 	/* TDOD: add option */
2027 	srv_buf_pool_chunk_unit = 134217728;
2028 	srv_buf_pool_size = (ulint) xtrabackup_use_memory;
2029 	srv_buf_pool_instances = 1;
2030 
2031 	srv_n_file_io_threads = (ulint) innobase_file_io_threads;
2032 	srv_n_read_io_threads = (ulint) innobase_read_io_threads;
2033 	srv_n_write_io_threads = (ulint) innobase_write_io_threads;
2034 
2035 	srv_force_recovery = (ulint) innobase_force_recovery;
2036 
2037 	srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
2038 
2039 	if (!innobase_use_checksums) {
2040 
2041 		srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_NONE;
2042 	}
2043 
2044 	btr_search_enabled = (char) innobase_adaptive_hash_index;
2045 
2046 	os_use_large_pages = (ibool) innobase_use_large_pages;
2047 	os_large_page_size = (ulint) innobase_large_page_size;
2048 
2049 	row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
2050 
2051 	srv_file_per_table = (my_bool) innobase_file_per_table;
2052 
2053         srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
2054 
2055 	srv_max_n_open_files = (ulint) innobase_open_files;
2056 	srv_innodb_status = (ibool) innobase_create_status_file;
2057 
2058 	srv_print_verbose_log = 1;
2059 
2060 	/* Store the default charset-collation number of this MySQL
2061 	installation */
2062 
2063 	/* We cannot treat characterset here for now!! */
2064 	data_mysql_default_charset_coll = (ulint)default_charset_info->number;
2065 
2066 	//innobase_commit_concurrency_init_default();
2067 
2068 	/* Since we in this module access directly the fields of a trx
2069         struct, and due to different headers and flags it might happen that
2070 	mutex_t has a different size in this module and in InnoDB
2071 	modules, we check at run time that the size is the same in
2072 	these compilation modules. */
2073 
2074 	/* On 5.5+ srv_use_native_aio is TRUE by default. It is later reset
2075 	if it is not supported by the platform in
2076 	innobase_start_or_create_for_mysql(). As we don't call it in xtrabackup,
2077 	we have to duplicate checks from that function here. */
2078 
2079 #ifdef __WIN__
2080 	switch (os_get_os_version()) {
2081 	case OS_WIN95:
2082 	case OS_WIN31:
2083 	case OS_WINNT:
2084 		/* On Win 95, 98, ME, Win32 subsystem for Windows 3.1,
2085 		and NT use simulated aio. In NT Windows provides async i/o,
2086 		but when run in conjunction with InnoDB Hot Backup, it seemed
2087 		to corrupt the data files. */
2088 
2089 		srv_use_native_aio = FALSE;
2090 		break;
2091 
2092 	case OS_WIN2000:
2093 	case OS_WINXP:
2094 		/* On 2000 and XP, async IO is available. */
2095 		srv_use_native_aio = TRUE;
2096 		break;
2097 
2098 	default:
2099 		/* Vista and later have both async IO and condition variables */
2100 		srv_use_native_aio = TRUE;
2101 		srv_use_native_conditions = TRUE;
2102 		break;
2103 	}
2104 
2105 #elif defined(LINUX_NATIVE_AIO)
2106 
2107 	if (srv_use_native_aio) {
2108 		ut_print_timestamp(stderr);
2109 		msg(" InnoDB: Using Linux native AIO\n");
2110 	}
2111 #else
2112 	/* Currently native AIO is supported only on windows and linux
2113 	and that also when the support is compiled in. In all other
2114 	cases, we ignore the setting of innodb_use_native_aio. */
2115 	srv_use_native_aio = FALSE;
2116 
2117 #endif
2118 
2119 	/* Assign the default value to srv_undo_dir if it's not specified, as
2120 	my_getopt does not support default values for string options. We also
2121 	ignore the option and override innodb_undo_directory on --prepare,
2122 	because separate undo tablespaces are copied to the root backup
2123 	directory. */
2124 
2125 	if (!srv_undo_dir || !xtrabackup_backup) {
2126 		my_free(srv_undo_dir);
2127 		srv_undo_dir = my_strdup(PSI_NOT_INSTRUMENTED, ".", MYF(MY_FAE));
2128 	}
2129 
2130 	innodb_log_checksum_func_update(srv_log_checksum_algorithm);
2131 
2132 	return(FALSE);
2133 
2134 error:
2135 	msg("xtrabackup: innodb_init_param(): Error occured.\n");
2136 	return(TRUE);
2137 }
2138 
2139 static my_bool
innodb_init(void)2140 innodb_init(void)
2141 {
2142 	int	err;
2143 
2144 	os_event_global_init();
2145 	err = innobase_start_or_create_for_mysql();
2146 
2147 	if (err != DB_SUCCESS) {
2148 		free(internal_innobase_data_file_path);
2149 		internal_innobase_data_file_path = NULL;
2150 		goto error;
2151 	}
2152 
2153 	/* They may not be needed for now */
2154 //	(void) hash_init(&innobase_open_tables,system_charset_info, 32, 0, 0,
2155 //			 		(hash_get_key) innobase_get_key, 0, 0);
2156 //        pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
2157 //        pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
2158 //        pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
2159 //        pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
2160 //        pthread_cond_init(&commit_cond, NULL);
2161 
2162 	innodb_inited= 1;
2163 
2164 	return(FALSE);
2165 
2166 error:
2167 	msg("xtrabackup: innodb_init(): Error occured.\n");
2168 	return(TRUE);
2169 }
2170 
2171 static my_bool
innodb_end(void)2172 innodb_end(void)
2173 {
2174 	srv_fast_shutdown = (ulint) innobase_fast_shutdown;
2175 	innodb_inited = 0;
2176 
2177 	msg("xtrabackup: starting shutdown with innodb_fast_shutdown = %lu\n",
2178 	    srv_fast_shutdown);
2179 
2180 	if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
2181 		goto error;
2182 	}
2183 	free(internal_innobase_data_file_path);
2184 	internal_innobase_data_file_path = NULL;
2185 
2186 	/* They may not be needed for now */
2187 //	hash_free(&innobase_open_tables);
2188 //	pthread_mutex_destroy(&innobase_share_mutex);
2189 //	pthread_mutex_destroy(&prepare_commit_mutex);
2190 //	pthread_mutex_destroy(&commit_threads_m);
2191 //	pthread_mutex_destroy(&commit_cond_m);
2192 //	pthread_cond_destroy(&commit_cond);
2193 
2194 	return(FALSE);
2195 
2196 error:
2197 	msg("xtrabackup: innodb_end(): Error occured.\n");
2198 	return(TRUE);
2199 }
2200 
2201 /* ================= common ================= */
2202 
2203 /***********************************************************************
2204 Read backup meta info.
2205 @return TRUE on success, FALSE on failure. */
2206 static
2207 my_bool
xtrabackup_read_metadata(char * filename)2208 xtrabackup_read_metadata(char *filename)
2209 {
2210 	FILE	*fp;
2211 	my_bool	 r = TRUE;
2212 	int	 t;
2213 
2214 	fp = fopen(filename,"r");
2215 	if(!fp) {
2216 		msg("xtrabackup: Error: cannot open %s\n", filename);
2217 		return(FALSE);
2218 	}
2219 
2220 	if (fscanf(fp, "backup_type = %29s\n", metadata_type)
2221 	    != 1) {
2222 		r = FALSE;
2223 		goto end;
2224 	}
2225 	if (fscanf(fp, "from_lsn = " LSN_PF "\n", &metadata_from_lsn)
2226 			!= 1) {
2227 		r = FALSE;
2228 		goto end;
2229 	}
2230 	if (fscanf(fp, "to_lsn = " LSN_PF "\n", &metadata_to_lsn)
2231 			!= 1) {
2232 		r = FALSE;
2233 		goto end;
2234 	}
2235 	if (fscanf(fp, "last_lsn = " LSN_PF "\n", &metadata_last_lsn)
2236 			!= 1) {
2237 		metadata_last_lsn = 0;
2238 	}
2239 	/* Optional fields */
2240 
2241 	if (fscanf(fp, "compact = %d\n", &t) == 1) {
2242 		xtrabackup_compact = (t == 1);
2243 	} else {
2244 		xtrabackup_compact = 0;
2245 	}
2246 
2247 	if (fscanf(fp, "recover_binlog_info = %d\n", &t) == 1) {
2248 		recover_binlog_info = (t == 1);
2249 	}
2250 
2251 	if (fscanf(fp, "flushed_lsn = " LSN_PF "\n",
2252 		   &backup_redo_log_flushed_lsn) != 1) {
2253 		backup_redo_log_flushed_lsn = 0;
2254 	}
2255 end:
2256 	fclose(fp);
2257 
2258 	return(r);
2259 }
2260 
2261 /***********************************************************************
2262 Print backup meta info to a specified buffer. */
2263 static
2264 void
xtrabackup_print_metadata(char * buf,size_t buf_len)2265 xtrabackup_print_metadata(char *buf, size_t buf_len)
2266 {
2267 	snprintf(buf, buf_len,
2268 		 "backup_type = %s\n"
2269 		 "from_lsn = " LSN_PF "\n"
2270 		 "to_lsn = " LSN_PF "\n"
2271 		 "last_lsn = " LSN_PF "\n"
2272 		 "compact = %d\n"
2273 		 "recover_binlog_info = %d\n"
2274 		 "flushed_lsn = " LSN_PF "\n",
2275 		 metadata_type,
2276 		 metadata_from_lsn,
2277 		 metadata_to_lsn,
2278 		 metadata_last_lsn,
2279 		 MY_TEST(xtrabackup_compact == TRUE),
2280 		 MY_TEST((xtrabackup_backup &&
2281 			  (opt_binlog_info == BINLOG_INFO_LOCKLESS)) ||
2282 			 (xtrabackup_prepare && recover_binlog_info)),
2283 		 backup_redo_log_flushed_lsn);
2284 }
2285 
2286 /***********************************************************************
2287 Stream backup meta info to a specified datasink.
2288 @return TRUE on success, FALSE on failure. */
2289 static
2290 my_bool
xtrabackup_stream_metadata(ds_ctxt_t * ds_ctxt)2291 xtrabackup_stream_metadata(ds_ctxt_t *ds_ctxt)
2292 {
2293 	char		buf[1024];
2294 	size_t		len;
2295 	ds_file_t	*stream;
2296 	MY_STAT		mystat;
2297 	my_bool		rc = TRUE;
2298 
2299 	xtrabackup_print_metadata(buf, sizeof(buf));
2300 
2301 	len = strlen(buf);
2302 
2303 	mystat.st_size = len;
2304 	mystat.st_mtime = my_time(0);
2305 
2306 	stream = ds_open(ds_ctxt, XTRABACKUP_METADATA_FILENAME, &mystat);
2307 	if (stream == NULL) {
2308 		msg("xtrabackup: Error: cannot open output stream "
2309 		    "for %s\n", XTRABACKUP_METADATA_FILENAME);
2310 		return(FALSE);
2311 	}
2312 
2313 	if (ds_write(stream, buf, len)) {
2314 		rc = FALSE;
2315 	}
2316 
2317 	if (ds_close(stream)) {
2318 		rc = FALSE;
2319 	}
2320 
2321 	return(rc);
2322 }
2323 
2324 
2325 static
write_to_file(const char * filepath,const char * data)2326 my_bool write_to_file(const char *filepath, const char *data)
2327 {
2328 	size_t len = strlen(data);
2329 	FILE *fp = fopen(filepath, "w");
2330 	if(!fp) {
2331 		msg("xtrabackup: Error: cannot open %s\n", filepath);
2332 		return(FALSE);
2333 	}
2334 	if (fwrite(data, len, 1, fp) < 1) {
2335 		fclose(fp);
2336 		return(FALSE);
2337 	}
2338 
2339 	fclose(fp);
2340 	return TRUE;
2341 }
2342 
2343 
2344 /***********************************************************************
2345 Write backup meta info to a specified file.
2346 @return TRUE on success, FALSE on failure. */
2347 static
2348 my_bool
xtrabackup_write_metadata(const char * filepath)2349 xtrabackup_write_metadata(const char *filepath)
2350 {
2351 	char		buf[1024];
2352 
2353 	xtrabackup_print_metadata(buf, sizeof(buf));
2354 	return write_to_file(filepath, buf);
2355 }
2356 
2357 /***********************************************************************
2358 Read meta info for an incremental delta.
2359 @return TRUE on success, FALSE on failure. */
2360 static my_bool
xb_read_delta_metadata(const char * filepath,xb_delta_info_t * info)2361 xb_read_delta_metadata(const char *filepath, xb_delta_info_t *info)
2362 {
2363 	FILE*	fp;
2364 	char	key[51];
2365 	char	value[51];
2366 	my_bool	r			= TRUE;
2367 
2368 	/* set defaults */
2369 	info->page_size = ULINT_UNDEFINED;
2370 	info->zip_size = ULINT_UNDEFINED;
2371 	info->space_id = ULINT_UNDEFINED;
2372 	info->space_flags = 0;
2373 
2374 	fp = fopen(filepath, "r");
2375 	if (!fp) {
2376 		/* Meta files for incremental deltas are optional */
2377 		return(TRUE);
2378 	}
2379 
2380 	while (!feof(fp)) {
2381 		if (fscanf(fp, "%50s = %50s\n", key, value) == 2) {
2382 			if (strcmp(key, "page_size") == 0) {
2383 				info->page_size = strtoul(value, NULL, 10);
2384 			} else if (strcmp(key, "zip_size") == 0) {
2385 				info->zip_size = strtoul(value, NULL, 10);
2386 			} else if (strcmp(key, "space_id") == 0) {
2387 				info->space_id = strtoul(value, NULL, 10);
2388 			} else if (strcmp(key, "space_flags") == 0) {
2389 				info->space_flags = strtoul(value, NULL, 10);
2390 			}
2391 		}
2392 	}
2393 
2394 	fclose(fp);
2395 
2396 	if (info->page_size == ULINT_UNDEFINED) {
2397 		msg("xtrabackup: page_size is required in %s\n", filepath);
2398 		r = FALSE;
2399 	}
2400 	if (info->space_id == ULINT_UNDEFINED) {
2401 		msg("xtrabackup: Warning: This backup was taken with XtraBackup 2.0.1 "
2402 			"or earlier, some DDL operations between full and incremental "
2403 			"backups may be handled incorrectly\n");
2404 	}
2405 
2406 	return(r);
2407 }
2408 
2409 /***********************************************************************
2410 Write meta info for an incremental delta.
2411 @return TRUE on success, FALSE on failure. */
2412 my_bool
xb_write_delta_metadata(const char * filename,const xb_delta_info_t * info)2413 xb_write_delta_metadata(const char *filename, const xb_delta_info_t *info)
2414 {
2415 	ds_file_t	*f;
2416 	char		buf[200];
2417 	my_bool		ret;
2418 	size_t		len;
2419 	MY_STAT		mystat;
2420 
2421 	snprintf(buf, sizeof(buf),
2422 		 "page_size = %lu\n"
2423 		 "zip_size = %lu\n"
2424 		 "space_id = %lu\n"
2425 		 "space_flags = %lu\n",
2426 		 info->page_size, info->zip_size, info->space_id,
2427 		 info->space_flags);
2428 	len = strlen(buf);
2429 
2430 	mystat.st_size = len;
2431 	mystat.st_mtime = my_time(0);
2432 
2433 	f = ds_open(ds_meta, filename, &mystat);
2434 	if (f == NULL) {
2435 		msg("xtrabackup: Error: cannot open output stream for %s\n",
2436 		    filename);
2437 		return(FALSE);
2438 	}
2439 
2440 	ret = (ds_write(f, buf, len) == 0);
2441 
2442 	if (ds_close(f)) {
2443 		ret = FALSE;
2444 	}
2445 
2446 	return(ret);
2447 }
2448 
2449 static my_bool
xtrabackup_write_info(const char * filepath)2450 xtrabackup_write_info(const char *filepath)
2451 {
2452 	char *xtrabackup_info_data = get_xtrabackup_info(mysql_connection);
2453 	if (!xtrabackup_info_data) {
2454 		return FALSE;
2455 	}
2456 
2457 	my_bool result = write_to_file(filepath, xtrabackup_info_data);
2458 
2459 	free(xtrabackup_info_data);
2460 	return result;
2461 }
2462 
2463 /* ================= backup ================= */
2464 void
xtrabackup_io_throttling(void)2465 xtrabackup_io_throttling(void)
2466 {
2467 	if (xtrabackup_throttle && (--io_ticket) < 0) {
2468 		os_event_reset(wait_throttle);
2469 		os_event_wait(wait_throttle);
2470 	}
2471 }
2472 
2473 static
regex_list_check_match(const regex_list_t & list,const char * name)2474 my_bool regex_list_check_match(
2475 	const regex_list_t& list,
2476 	const char* name)
2477 {
2478 	xb_regmatch_t tables_regmatch[1];
2479 	for (regex_list_t::const_iterator i = list.begin(), end = list.end();
2480 	     i != end; ++i) {
2481 		const xb_regex_t& regex = *i;
2482 		int regres = xb_regexec(&regex, name, 1, tables_regmatch, 0);
2483 
2484 		if (regres != REG_NOMATCH) {
2485 			return(TRUE);
2486 		}
2487 	}
2488 	return(FALSE);
2489 }
2490 
2491 static
2492 my_bool
find_filter_in_hashtable(const char * name,hash_table_t * table,xb_filter_entry_t ** result)2493 find_filter_in_hashtable(
2494 	const char* name,
2495 	hash_table_t* table,
2496 	xb_filter_entry_t** result
2497 )
2498 {
2499 	xb_filter_entry_t* found = NULL;
2500 	HASH_SEARCH(name_hash, table, ut_fold_string(name),
2501 		    xb_filter_entry_t*,
2502 		    found, (void) 0,
2503 		    !strcmp(found->name, name));
2504 
2505 	if (found && result) {
2506 		*result = found;
2507 	}
2508 	return (found != NULL);
2509 }
2510 
2511 /************************************************************************
2512 Checks if a given table name matches any of specifications given in
2513 regex_list or tables_hash.
2514 
2515 @return TRUE on match or both regex_list and tables_hash are empty.*/
2516 static my_bool
check_if_table_matches_filters(const char * name,const regex_list_t & regex_list,hash_table_t * tables_hash)2517 check_if_table_matches_filters(const char *name,
2518 	const regex_list_t& regex_list,
2519 	hash_table_t* tables_hash)
2520 {
2521 	if (regex_list.empty() && !tables_hash) {
2522 		return(FALSE);
2523 	}
2524 
2525 	if (regex_list_check_match(regex_list, name)) {
2526 		return(TRUE);
2527 	}
2528 
2529 	if (tables_hash && find_filter_in_hashtable(name, tables_hash, NULL)) {
2530 		return(TRUE);
2531 	}
2532 
2533 	return FALSE;
2534 }
2535 
2536 enum skip_database_check_result {
2537 	DATABASE_SKIP,
2538 	DATABASE_SKIP_SOME_TABLES,
2539 	DATABASE_DONT_SKIP,
2540 	DATABASE_DONT_SKIP_UNLESS_EXPLICITLY_EXCLUDED,
2541 };
2542 
2543 /************************************************************************
2544 Checks if a database specified by name should be skipped from backup based on
2545 the --databases, --databases_file or --databases_exclude options.
2546 
2547 @return TRUE if entire database should be skipped,
2548 	FALSE otherwise.
2549 */
2550 static
2551 skip_database_check_result
check_if_skip_database(const char * name)2552 check_if_skip_database(
2553 	const char* name  /*!< in: path to the database */
2554 )
2555 {
2556 	/* There are some filters for databases, check them */
2557 	xb_filter_entry_t*	database = NULL;
2558 
2559 	if (databases_exclude_hash &&
2560 		find_filter_in_hashtable(name, databases_exclude_hash,
2561 					 &database) &&
2562 		!database->has_tables) {
2563 		/* Database is found and there are no tables specified,
2564 		   skip entire db. */
2565 		return DATABASE_SKIP;
2566 	}
2567 
2568 	if (databases_include_hash) {
2569 		if (!find_filter_in_hashtable(name, databases_include_hash,
2570 					      &database)) {
2571 		/* Database isn't found, skip the database */
2572 			return DATABASE_SKIP;
2573 		} else if (database->has_tables) {
2574 			return DATABASE_SKIP_SOME_TABLES;
2575 		} else {
2576 			return DATABASE_DONT_SKIP_UNLESS_EXPLICITLY_EXCLUDED;
2577 		}
2578 	}
2579 
2580 	return DATABASE_DONT_SKIP;
2581 }
2582 
2583 /************************************************************************
2584 Checks if a database specified by path should be skipped from backup based on
2585 the --databases, --databases_file or --databases_exclude options.
2586 
2587 @return TRUE if the table should be skipped. */
2588 my_bool
check_if_skip_database_by_path(const char * path)2589 check_if_skip_database_by_path(
2590 	const char* path /*!< in: path to the db directory. */
2591 )
2592 {
2593 	if (databases_include_hash == NULL &&
2594 		databases_exclude_hash == NULL) {
2595 		return(FALSE);
2596 	}
2597 
2598 	const char* db_name = strrchr(path, OS_PATH_SEPARATOR);
2599 	if (db_name == NULL) {
2600 		db_name = path;
2601 	} else {
2602 		++db_name;
2603 	}
2604 
2605 	return check_if_skip_database(db_name) == DATABASE_SKIP;
2606 }
2607 
2608 /************************************************************************
2609 Checks if a table specified as a name in the form "database/name" (InnoDB 5.6)
2610 or "./database/name.ibd" (InnoDB 5.5-) should be skipped from backup based on
2611 the --tables or --tables-file options.
2612 
2613 @return TRUE if the table should be skipped. */
2614 bool
check_if_skip_table(const char * name)2615 check_if_skip_table(
2616 /******************/
2617 	const char*	name)	/*!< in: path to the table */
2618 {
2619 	char buf[FN_REFLEN];
2620 	const char *dbname, *tbname;
2621 	const char *ptr;
2622 	char *eptr;
2623 
2624 	if (regex_exclude_list.empty() &&
2625 		regex_include_list.empty() &&
2626 		tables_include_hash == NULL &&
2627 		tables_exclude_hash == NULL &&
2628 		databases_include_hash == NULL &&
2629 		databases_exclude_hash == NULL) {
2630 		return(false);
2631 	}
2632 
2633 	dbname = NULL;
2634 	tbname = name;
2635 	while ((ptr = strchr(tbname, OS_PATH_SEPARATOR)) != NULL) {
2636 		dbname = tbname;
2637 		tbname = ptr + 1;
2638 	}
2639 
2640 	if (dbname == NULL) {
2641 		return(false);
2642 	}
2643 
2644 	strncpy(buf, dbname, FN_REFLEN);
2645 	buf[tbname - 1 - dbname] = 0;
2646 
2647 	const skip_database_check_result skip_database =
2648 			check_if_skip_database(buf);
2649 	if (skip_database == DATABASE_SKIP) {
2650 		return(true);
2651 	}
2652 
2653 	buf[FN_REFLEN - 1] = '\0';
2654 	buf[tbname - 1 - dbname] = '.';
2655 
2656 	/* Check if there's a suffix in the table name. If so, truncate it. We
2657 	rely on the fact that a dot cannot be a part of a table name (it is
2658 	encoded by the server with the @NNNN syntax). */
2659 	if ((eptr = strchr(&buf[tbname - dbname], '.')) != NULL) {
2660 
2661 		*eptr = '\0';
2662 	}
2663 
2664 	/* For partitioned tables first try to match against the regexp
2665 	without truncating the #P#... suffix so we can backup individual
2666 	partitions with regexps like '^test[.]t#P#p5' */
2667 	if (check_if_table_matches_filters(buf, regex_exclude_list,
2668 					   tables_exclude_hash)) {
2669 		return(true);
2670 	}
2671 	if (check_if_table_matches_filters(buf, regex_include_list,
2672 					   tables_include_hash)) {
2673 		return(false);
2674 	}
2675 	if ((eptr = strstr(buf, "#P#")) != NULL) {
2676 		*eptr = 0;
2677 
2678 		if (check_if_table_matches_filters(buf, regex_exclude_list,
2679 						   tables_exclude_hash)) {
2680 			return(true);
2681 		}
2682 		if (check_if_table_matches_filters(buf, regex_include_list,
2683 						   tables_include_hash)) {
2684 			return(false);
2685 		}
2686 	}
2687 
2688 	if (skip_database == DATABASE_DONT_SKIP_UNLESS_EXPLICITLY_EXCLUDED) {
2689 		/* Database is in include-list, and qualified name wasn't
2690 		   found in any of exclusion filters.*/
2691 		return(false);
2692 	}
2693 
2694 	if (skip_database == DATABASE_SKIP_SOME_TABLES ||
2695 		!regex_include_list.empty() ||
2696 		tables_include_hash) {
2697 
2698 		/* Include lists are present, but qualified name
2699 		   failed to match any.*/
2700 		return(true);
2701 	}
2702 
2703 	return(false);
2704 }
2705 
2706 /***********************************************************************
2707 Reads the space flags from a given data file and returns the
2708 page size. */
2709 const page_size_t
xb_get_zip_size(pfs_os_file_t file,bool * success)2710 xb_get_zip_size(pfs_os_file_t file, bool *success)
2711 {
2712 	byte		*buf;
2713 	byte		*page;
2714 	page_size_t	page_size(0, 0, false);
2715 	ibool		ret;
2716 	ulint		space;
2717 	IORequest	read_request(IORequest::READ);
2718 
2719 	buf = static_cast<byte *>(ut_malloc_nokey(2 * UNIV_PAGE_SIZE_MAX));
2720 	page = static_cast<byte *>(ut_align(buf, UNIV_PAGE_SIZE_MAX));
2721 
2722 	ret = os_file_read(read_request, file, page, 0, UNIV_PAGE_SIZE_MIN);
2723 	if (!ret) {
2724 		*success = false;
2725 		goto end;
2726 	}
2727 
2728 	space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
2729 	if (space == 0) {
2730 		page_size.copy_from(univ_page_size);
2731 	} else {
2732 		page_size.copy_from(page_size_t(fsp_header_get_flags(page)));
2733 	}
2734 	*success = true;
2735 end:
2736 	ut_free(buf);
2737 
2738 	return(page_size);
2739 }
2740 
2741 const char*
xb_get_copy_action(const char * dflt)2742 xb_get_copy_action(const char *dflt)
2743 {
2744 	const char *action;
2745 
2746 	if (xtrabackup_stream) {
2747 		if (xtrabackup_compress) {
2748 			if (xtrabackup_encrypt) {
2749 				action = "Compressing, encrypting and streaming";
2750 			} else {
2751 				action = "Compressing and streaming";
2752 			}
2753 		} else if (xtrabackup_encrypt) {
2754 			action = "Encrypting and streaming";
2755 		} else {
2756 			action = "Streaming";
2757 		}
2758 	} else {
2759 		if (xtrabackup_compress) {
2760 			if (xtrabackup_encrypt) {
2761 				action = "Compressing and encrypting";
2762 			} else {
2763 				action = "Compressing";
2764 			}
2765 		} else if (xtrabackup_encrypt) {
2766 			action = "Encrypting";
2767 		} else {
2768 			action = dflt;
2769 		}
2770 	}
2771 
2772 	return(action);
2773 }
2774 
2775 /* TODO: We may tune the behavior (e.g. by fil_aio)*/
2776 
2777 static
2778 my_bool
xtrabackup_copy_datafile(fil_node_t * node,uint thread_n)2779 xtrabackup_copy_datafile(fil_node_t* node, uint thread_n)
2780 {
2781 	char			 dst_name[FN_REFLEN];
2782 	ds_file_t		*dstfile = NULL;
2783 	xb_fil_cur_t		 cursor;
2784 	xb_fil_cur_result_t	 res;
2785 	xb_write_filt_t		*write_filter = NULL;
2786 	xb_write_filt_ctxt_t	 write_filt_ctxt;
2787 	const char		*action;
2788 	xb_read_filt_t		*read_filter;
2789 	ibool			is_system;
2790 	my_bool			rc = FALSE;
2791 
2792 	/* Get the name and the path for the tablespace. node->name always
2793 	contains the path (which may be absolute for remote tablespaces in
2794 	5.6+). space->name contains the tablespace name in the form
2795 	"./database/table.ibd" (in 5.5-) or "database/table" (in 5.6+). For a
2796 	multi-node shared tablespace, space->name contains the name of the first
2797 	node, but that's irrelevant, since we only need node_name to match them
2798 	against filters, and the shared tablespace is always copied regardless
2799 	of the filters value. */
2800 
2801 	const char* const node_name = node->space->name;
2802 	const char* const node_path = node->name;
2803 
2804 	is_system = !fil_is_user_tablespace_id(node->space->id);
2805 
2806 	if (!is_system && check_if_skip_table(node_name)) {
2807 		msg("[%02u] Skipping %s.\n", thread_n, node_name);
2808 		return(FALSE);
2809 	}
2810 
2811 	if (!changed_page_bitmap) {
2812 		read_filter = &rf_pass_through;
2813 	}
2814 	else {
2815 		read_filter = &rf_bitmap;
2816 	}
2817 	res = xb_fil_cur_open(&cursor, read_filter, node, thread_n);
2818 	if (res == XB_FIL_CUR_SKIP) {
2819 		goto skip;
2820 	} else if (res == XB_FIL_CUR_ERROR) {
2821 		goto error;
2822 	}
2823 
2824 	if (!is_system) {
2825 		snprintf(dst_name, sizeof(dst_name), "%s.ibd", node_name);
2826 	} else {
2827 		strncpy(dst_name, cursor.rel_path, sizeof(dst_name));
2828 	}
2829 
2830 	/* Setup the page write filter */
2831 	if (xtrabackup_incremental) {
2832 		write_filter = &wf_incremental;
2833 	} else if (xtrabackup_compact) {
2834 		write_filter = &wf_compact;
2835 	} else {
2836 		write_filter = &wf_write_through;
2837 	}
2838 
2839 	memset(&write_filt_ctxt, 0, sizeof(xb_write_filt_ctxt_t));
2840 	ut_a(write_filter->process != NULL);
2841 
2842 	if (write_filter->init != NULL &&
2843 	    !write_filter->init(&write_filt_ctxt, dst_name, &cursor)) {
2844 		msg("[%02u] xtrabackup: error: "
2845 		    "failed to initialize page write filter.\n", thread_n);
2846 		goto error;
2847 	}
2848 
2849 	dstfile = ds_open(ds_data, dst_name, &cursor.statinfo);
2850 	if (dstfile == NULL) {
2851 		msg("[%02u] xtrabackup: error: "
2852 		    "cannot open the destination stream for %s\n",
2853 		    thread_n, dst_name);
2854 		goto error;
2855 	}
2856 
2857 	action = xb_get_copy_action();
2858 
2859 	if (xtrabackup_stream) {
2860 		msg_ts("[%02u] %s %s\n", thread_n, action, node_path);
2861 	} else {
2862 		msg_ts("[%02u] %s %s to %s\n", thread_n, action,
2863 		       node_path, dstfile->path);
2864 	}
2865 
2866 	/* The main copy loop */
2867 	while ((res = xb_fil_cur_read(&cursor)) == XB_FIL_CUR_SUCCESS) {
2868 		if (!write_filter->process(&write_filt_ctxt, dstfile)) {
2869 			goto error;
2870 		}
2871 	}
2872 
2873 	if (res == XB_FIL_CUR_ERROR) {
2874 		goto error;
2875 	}
2876 
2877 	if (write_filter->finalize
2878 	    && !write_filter->finalize(&write_filt_ctxt, dstfile)) {
2879 		goto error;
2880 	}
2881 
2882 	/* close */
2883 	msg_ts("[%02u]        ...done\n", thread_n);
2884 	xb_fil_cur_close(&cursor);
2885 	if (ds_close(dstfile)) {
2886 		rc = TRUE;
2887 	}
2888 	if (write_filter && write_filter->deinit) {
2889 		write_filter->deinit(&write_filt_ctxt);
2890 	}
2891 	return(rc);
2892 
2893 error:
2894 	xb_fil_cur_close(&cursor);
2895 	if (dstfile != NULL) {
2896 		ds_close(dstfile);
2897 	}
2898 	if (write_filter && write_filter->deinit) {
2899 		write_filter->deinit(&write_filt_ctxt);
2900 	}
2901 	msg("[%02u] xtrabackup: Error: "
2902 	    "xtrabackup_copy_datafile() failed.\n", thread_n);
2903 	return(TRUE); /*ERROR*/
2904 
2905 skip:
2906 
2907 	if (dstfile != NULL) {
2908 		ds_close(dstfile);
2909 	}
2910 	if (write_filter && write_filter->deinit) {
2911 		write_filter->deinit(&write_filt_ctxt);
2912 	}
2913 	msg("[%02u] xtrabackup: Warning: We assume the "
2914 	    "table was dropped during xtrabackup execution "
2915 	    "and ignore the file.\n", thread_n);
2916 	msg("[%02u] xtrabackup: Warning: skipping tablespace %s.\n",
2917 	    thread_n, node_name);
2918 	return(FALSE);
2919 }
2920 
2921 static
2922 void
xtrabackup_choose_lsn_offset(lsn_t start_lsn)2923 xtrabackup_choose_lsn_offset(lsn_t start_lsn)
2924 {
2925 	ulint no, expected_no;
2926 	ulint blocks_in_group;
2927 	lsn_t end_lsn;
2928 	log_group_t *group;
2929 
2930 	start_lsn = ut_uint64_align_down(start_lsn, OS_FILE_LOG_BLOCK_SIZE);
2931 	end_lsn = start_lsn + RECV_SCAN_SIZE;
2932 
2933 	group = UT_LIST_GET_FIRST(log_sys->log_groups);
2934 
2935 	if (mysql_server_version < 50500) {
2936 		/* server doesn't support log files larger than 4G */
2937 		return;
2938 	}
2939 
2940 	if (server_flavor == FLAVOR_PERCONA_SERVER &&
2941 	    (mysql_server_version > 50500 && mysql_server_version < 50600)) {
2942 		/* it is Percona Server 5.5 */
2943 		group->lsn_offset = group->lsn_offset_ps55;
2944 		return;
2945 	}
2946 
2947 	if (group->lsn_offset_ps55 == group->lsn_offset ||
2948 	    group->lsn_offset_ps55 == (lsn_t) -1) {
2949 		/* we have only one option */
2950 		return;
2951 	}
2952 
2953 	no = (ulint) -1;
2954 
2955 	blocks_in_group = log_block_convert_lsn_to_no(
2956 		log_group_get_capacity(group)) - 1;
2957 
2958 	lsn_t offsets[2] = {group->lsn_offset,
2959 			    group->lsn_offset_ps55};
2960 
2961 	expected_no = log_block_convert_lsn_to_no(start_lsn);
2962 
2963 	for (int i = 0; i < 2; i++) {
2964 		group->lsn_offset = offsets[i];
2965 
2966 		/* read log block number */
2967 		if (group->lsn_offset < group->file_size * group->n_files &&
2968 		    (log_group_calc_lsn_offset(start_lsn, group) %
2969 		     UNIV_PAGE_SIZE) % OS_MIN_LOG_BLOCK_SIZE == 0) {
2970 			log_group_read_log_seg(log_sys->buf, group,
2971 					       start_lsn, end_lsn);
2972 			no = log_block_get_hdr_no(log_sys->buf);
2973 		}
2974 
2975 		if ((no <= expected_no &&
2976 			((expected_no - no) % blocks_in_group) == 0) ||
2977 		    ((expected_no | 0x40000000UL) - no) % blocks_in_group == 0) {
2978 			/* offset looks ok */
2979 			return;
2980 		}
2981 	}
2982 }
2983 
2984 /*******************************************************//**
2985 Scans log from a buffer and writes new log data to the outpud datasinc.
2986 @return true if success */
2987 static
2988 bool
xtrabackup_scan_log_recs(log_group_t * group,bool is_last,lsn_t start_lsn,lsn_t * contiguous_lsn,lsn_t * group_scanned_lsn,lsn_t checkpoint_lsn,bool * finished)2989 xtrabackup_scan_log_recs(
2990 /*===============*/
2991 	log_group_t*	group,		/*!< in: log group */
2992 	bool		is_last,	/*!< in: whether it is last segment
2993 					to copy */
2994 	lsn_t		start_lsn,	/*!< in: buffer start lsn */
2995 	lsn_t*		contiguous_lsn,	/*!< in/out: it is known that all log
2996 					groups contain contiguous log data up
2997 					to this lsn */
2998 	lsn_t*		group_scanned_lsn,/*!< out: scanning succeeded up to
2999 					this lsn */
3000 	lsn_t		checkpoint_lsn,	/*!< in: latest checkpoint LSN */
3001 	bool*		finished)	/*!< out: false if is not able to scan
3002 					any more in this log group */
3003 {
3004 	lsn_t		scanned_lsn;
3005 	ulint		data_len;
3006 	ulint		write_size;
3007 	const byte*	log_block;
3008 	bool		more_data	= false;
3009 
3010 	ulint		scanned_checkpoint_no = 0;
3011 
3012 	*finished = false;
3013 	scanned_lsn = start_lsn;
3014 	log_block = log_sys->buf;
3015 
3016 	while (log_block < log_sys->buf + RECV_SCAN_SIZE && !*finished) {
3017 		ulint	no = log_block_get_hdr_no(log_block);
3018 		ulint	scanned_no = log_block_convert_lsn_to_no(scanned_lsn);
3019 		ibool	checksum_is_ok = log_block_checksum_is_ok(log_block);
3020 
3021 		if (no != scanned_no && checksum_is_ok) {
3022 			ulint blocks_in_group;
3023 
3024 			blocks_in_group = log_block_convert_lsn_to_no(
3025 				log_group_get_capacity(group)) - 1;
3026 
3027 			if ((no < scanned_no &&
3028 			    ((scanned_no - no) % blocks_in_group) == 0) ||
3029 			    no == 0 ||
3030 			    /* Log block numbers wrap around at 0x3FFFFFFF */
3031 			    ((scanned_no | 0x40000000UL) - no) %
3032 			    blocks_in_group == 0) {
3033 
3034 				/* old log block, do nothing */
3035 				*finished = true;
3036 				break;
3037 			}
3038 
3039 			msg("xtrabackup: error:"
3040 			    " log block numbers mismatch:\n"
3041 			    "xtrabackup: error: expected log block no. %lu,"
3042 			    " but got no. %lu from the log file.\n",
3043 			    (ulong) scanned_no, (ulong) no);
3044 
3045 			if ((no - scanned_no) % blocks_in_group == 0) {
3046 				msg("xtrabackup: error:"
3047 				    " it looks like InnoDB log has wrapped"
3048 				    " around before xtrabackup could"
3049 				    " process all records due to either"
3050 				    " log copying being too slow, or "
3051 				    " log files being too small.\n");
3052 			}
3053 
3054 			return(false);
3055 		} else if (!checksum_is_ok) {
3056 			/* Garbage or an incompletely written log block */
3057 
3058 			msg("xtrabackup: warning: Log block checksum mismatch"
3059 			    " (block no %lu at lsn " LSN_PF "): \n"
3060 			    "expected %lu, calculated checksum %lu\n",
3061 				(ulong) no,
3062 				scanned_lsn,
3063 				(ulong) log_block_get_checksum(log_block),
3064 				(ulong) log_block_calc_checksum(log_block));
3065 			msg("xtrabackup: warning: this is possible when the "
3066 			    "log block has not been fully written by the "
3067 			    "server, will retry later.\n");
3068 			*finished = true;
3069 			break;
3070 		}
3071 
3072 		if (log_block_get_flush_bit(log_block)) {
3073 			/* This block was a start of a log flush operation:
3074 			we know that the previous flush operation must have
3075 			been completed for all log groups before this block
3076 			can have been flushed to any of the groups. Therefore,
3077 			we know that log data is contiguous up to scanned_lsn
3078 			in all non-corrupt log groups. */
3079 
3080 			if (scanned_lsn > *contiguous_lsn) {
3081 
3082 				*contiguous_lsn = scanned_lsn;
3083 			}
3084 		}
3085 
3086 		data_len = log_block_get_data_len(log_block);
3087 
3088 		if (
3089 		    (scanned_checkpoint_no > 0)
3090 		    && (log_block_get_checkpoint_no(log_block)
3091 		       < scanned_checkpoint_no)
3092 		    && (scanned_checkpoint_no
3093 			- log_block_get_checkpoint_no(log_block)
3094 			> 0x80000000UL)) {
3095 
3096 			/* Garbage from a log buffer flush which was made
3097 			before the most recent database recovery */
3098 
3099 			*finished = true;
3100 			break;
3101 		}
3102 
3103 		if (!recv_sys->parse_start_lsn
3104 		    && (log_block_get_first_rec_group(log_block) > 0)) {
3105 
3106 			/* We found a point from which to start the parsing
3107 			of log records */
3108 
3109 			recv_sys->parse_start_lsn = scanned_lsn
3110 				+ log_block_get_first_rec_group(log_block);
3111 			recv_sys->scanned_lsn = recv_sys->parse_start_lsn;
3112 			recv_sys->recovered_lsn = recv_sys->parse_start_lsn;
3113 		}
3114 
3115 		scanned_lsn = scanned_lsn + data_len;
3116 		scanned_checkpoint_no = log_block_get_checkpoint_no(log_block);
3117 
3118 		if (scanned_lsn > recv_sys->scanned_lsn) {
3119 
3120 			/* We were able to find more log data: add it to the
3121 			parsing buffer if parse_start_lsn is already
3122 			non-zero */
3123 
3124 			if (recv_sys->len + 4 * OS_FILE_LOG_BLOCK_SIZE
3125 			    >= RECV_PARSING_BUF_SIZE) {
3126 				ib::error() << "Log parsing buffer overflow."
3127 					" Recovery may have failed!";
3128 
3129 				recv_sys->found_corrupt_log = true;
3130 
3131 			} else if (!recv_sys->found_corrupt_log) {
3132 				more_data = recv_sys_add_to_parsing_buf(
3133 					log_block, scanned_lsn);
3134 			}
3135 
3136 			recv_sys->scanned_lsn = scanned_lsn;
3137 			recv_sys->scanned_checkpoint_no
3138 				= log_block_get_checkpoint_no(log_block);
3139 		}
3140 
3141 		if (data_len < OS_FILE_LOG_BLOCK_SIZE) {
3142 			/* Log data for this group ends here */
3143 
3144 			*finished = true;
3145 		} else {
3146 			log_block += OS_FILE_LOG_BLOCK_SIZE;
3147 		}
3148 	}
3149 
3150 	*group_scanned_lsn = scanned_lsn;
3151 
3152 	/* ===== write log to 'xtrabackup_logfile' ====== */
3153 	if (!*finished) {
3154 		write_size = RECV_SCAN_SIZE;
3155 	} else {
3156 		write_size = ut_uint64_align_up(scanned_lsn,
3157 					OS_FILE_LOG_BLOCK_SIZE) - start_lsn;
3158 		if (!is_last && scanned_lsn % OS_FILE_LOG_BLOCK_SIZE) {
3159 			write_size -= OS_FILE_LOG_BLOCK_SIZE;
3160 		}
3161 	}
3162 
3163 	if (ds_write(dst_log_file, log_sys->buf, write_size)) {
3164 		msg("xtrabackup: Error: "
3165 		    "write to logfile failed\n");
3166 		return(false);
3167 	}
3168 
3169 	if (more_data && !recv_sys->found_corrupt_log) {
3170 		/* Try to parse more log records */
3171 
3172 		if (recv_parse_log_recs(checkpoint_lsn,	/*!< in: latest checkpoint LSN */
3173 					STORE_NO)) {
3174 			ut_ad(recv_sys->found_corrupt_log
3175 			      || recv_sys->found_corrupt_fs
3176 			      || recv_sys->mlog_checkpoint_lsn
3177 			      == recv_sys->recovered_lsn);
3178 			return(true);
3179 		}
3180 
3181 		if (recv_sys->recovered_offset > RECV_PARSING_BUF_SIZE / 4) {
3182 			/* Move parsing buffer data to the buffer start */
3183 
3184 			recv_sys_justify_left_parsing_buf();
3185 		}
3186 	}
3187 
3188 	return(true);
3189 }
3190 
3191 static my_bool
xtrabackup_copy_logfile(lsn_t from_lsn,my_bool is_last)3192 xtrabackup_copy_logfile(lsn_t from_lsn, my_bool is_last)
3193 {
3194 	/* definition from recv_recovery_from_checkpoint_start() */
3195 	log_group_t*	group;
3196 	lsn_t		group_scanned_lsn;
3197 	lsn_t		contiguous_lsn;
3198 
3199 	ut_a(dst_log_file != NULL);
3200 
3201 	/* read from checkpoint_lsn_start to current */
3202 	contiguous_lsn = ut_uint64_align_down(from_lsn, OS_FILE_LOG_BLOCK_SIZE);
3203 
3204 	/* TODO: We must check the contiguous_lsn still exists in log file.. */
3205 
3206 	group = UT_LIST_GET_FIRST(log_sys->log_groups);
3207 
3208 	while (group) {
3209 		bool	finished;
3210 		lsn_t	start_lsn;
3211 		lsn_t	end_lsn;
3212 
3213 		/* reference recv_group_scan_log_recs() */
3214 		finished = false;
3215 
3216 		start_lsn = contiguous_lsn;
3217 
3218 		while (!finished) {
3219 
3220 			end_lsn = start_lsn + RECV_SCAN_SIZE;
3221 
3222 			xtrabackup_io_throttling();
3223 
3224 			mutex_enter(&log_sys->mutex);
3225 
3226 			log_group_read_log_seg(log_sys->buf,
3227 					       group, start_lsn, end_lsn);
3228 
3229 			 if (!xtrabackup_scan_log_recs(group, is_last,
3230 				start_lsn, &contiguous_lsn, &group_scanned_lsn,
3231 				from_lsn, &finished)) {
3232 				goto error;
3233 			 }
3234 
3235 			mutex_exit(&log_sys->mutex);
3236 
3237 			start_lsn = end_lsn;
3238 
3239 		}
3240 
3241 		group->scanned_lsn = group_scanned_lsn;
3242 
3243 		msg_ts(">> log scanned up to (" LSN_PF ")\n",
3244 		       group->scanned_lsn);
3245 
3246 		group = UT_LIST_GET_NEXT(log_groups, group);
3247 
3248 		/* update global variable*/
3249 		log_copy_scanned_lsn = group_scanned_lsn;
3250 
3251 		/* innodb_mirrored_log_groups must be 1, no other groups */
3252 		ut_a(group == NULL);
3253 
3254 		debug_sync_point("xtrabackup_copy_logfile_pause");
3255 
3256 	}
3257 
3258 
3259 	return(FALSE);
3260 
3261 error:
3262 	mutex_exit(&log_sys->mutex);
3263 	ds_close(dst_log_file);
3264 	msg("xtrabackup: Error: xtrabackup_copy_logfile() failed.\n");
3265 	return(TRUE);
3266 }
3267 
3268 static
3269 #ifndef __WIN__
3270 void*
3271 #else
3272 ulint
3273 #endif
log_copying_thread(void * arg)3274 log_copying_thread(
3275 	void*	arg __attribute__((unused)))
3276 {
3277 	/*
3278 	  Initialize mysys thread-specific memory so we can
3279 	  use mysys functions in this thread.
3280 	*/
3281 	my_thread_init();
3282 
3283 	ut_a(dst_log_file != NULL);
3284 
3285 	log_copying_running = TRUE;
3286 
3287 	while(log_copying) {
3288 		os_event_reset(log_copying_stop);
3289 		os_event_wait_time_low(log_copying_stop,
3290 				       xtrabackup_log_copy_interval * 1000ULL,
3291 				       0);
3292 		if (log_copying) {
3293 			if(xtrabackup_copy_logfile(log_copy_scanned_lsn,
3294 						   FALSE)) {
3295 
3296 				exit(EXIT_FAILURE);
3297 			}
3298 		}
3299 	}
3300 
3301 	/* last copying */
3302 	if(xtrabackup_copy_logfile(log_copy_scanned_lsn, TRUE)) {
3303 
3304 		exit(EXIT_FAILURE);
3305 	}
3306 
3307 	log_copying_running = FALSE;
3308 	my_thread_end();
3309 	os_thread_exit();
3310 
3311 	return(0);
3312 }
3313 
3314 /* io throttle watching (rough) */
3315 static
3316 #ifndef __WIN__
3317 void*
3318 #else
3319 ulint
3320 #endif
io_watching_thread(void * arg)3321 io_watching_thread(
3322 	void*	arg)
3323 {
3324 	(void)arg;
3325 	/* currently, for --backup only */
3326 	ut_a(xtrabackup_backup);
3327 
3328 	io_watching_thread_running = TRUE;
3329 
3330 	while (log_copying) {
3331 		os_thread_sleep(1000000); /*1 sec*/
3332 		io_ticket = xtrabackup_throttle;
3333 		os_event_set(wait_throttle);
3334 	}
3335 
3336 	/* stop io throttle */
3337 	xtrabackup_throttle = 0;
3338 	os_event_set(wait_throttle);
3339 
3340 	io_watching_thread_running = FALSE;
3341 
3342 	os_thread_exit();
3343 
3344 	return(0);
3345 }
3346 
3347 /************************************************************************
3348 I/o-handler thread function. */
3349 static
3350 
3351 #ifndef __WIN__
3352 void*
3353 #else
3354 ulint
3355 #endif
io_handler_thread(void * arg)3356 io_handler_thread(
3357 /*==============*/
3358 	void*	arg)
3359 {
3360 	ulint	segment;
3361 
3362 
3363 	segment = *((ulint*)arg);
3364 
3365  	while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) {
3366 		fil_aio_wait(segment);
3367 	}
3368 
3369 	/* We count the number of threads in os_thread_exit(). A created
3370 	thread should always use that to exit and not use return() to exit.
3371 	The thread actually never comes here because it is exited in an
3372 	os_event_wait(). */
3373 
3374 	os_thread_exit();
3375 
3376 #ifndef __WIN__
3377 	return(NULL);				/* Not reached */
3378 #else
3379 	return(0);
3380 #endif
3381 }
3382 
3383 /**************************************************************************
3384 Datafiles copying thread.*/
3385 static
3386 os_thread_ret_t
data_copy_thread_func(void * arg)3387 data_copy_thread_func(
3388 /*==================*/
3389 	void *arg) /* thread context */
3390 {
3391 	data_thread_ctxt_t	*ctxt = (data_thread_ctxt_t *) arg;
3392 	uint			num = ctxt->num;
3393 	fil_node_t*		node;
3394 
3395 	/*
3396 	  Initialize mysys thread-specific memory so we can
3397 	  use mysys functions in this thread.
3398 	*/
3399 	my_thread_init();
3400 
3401 	debug_sync_point("data_copy_thread_func");
3402 
3403 	while ((node = datafiles_iter_next(ctxt->it)) != NULL &&
3404 		!*(ctxt->error)) {
3405 
3406 		/* copy the datafile */
3407 		if(xtrabackup_copy_datafile(node, num)) {
3408 			msg("[%02u] xtrabackup: Error: "
3409 			    "failed to copy datafile.\n", num);
3410 			*(ctxt->error) = true;
3411 		}
3412 	}
3413 
3414 	mutex_enter(ctxt->count_mutex);
3415 	(*ctxt->count)--;
3416 	mutex_exit(ctxt->count_mutex);
3417 
3418 	my_thread_end();
3419 	os_thread_exit();
3420 	OS_THREAD_DUMMY_RETURN;
3421 }
3422 
3423 /************************************************************************
3424 Initialize the appropriate datasink(s). Both local backups and streaming in the
3425 'xbstream' format allow parallel writes so we can write directly.
3426 
3427 Otherwise (i.e. when streaming in the 'tar' format) we need 2 separate datasinks
3428 for the data stream (and don't allow parallel data copying) and for metainfo
3429 files (including xtrabackup_logfile). The second datasink writes to temporary
3430 files first, and then streams them in a serialized way when closed. */
3431 static void
xtrabackup_init_datasinks(void)3432 xtrabackup_init_datasinks(void)
3433 {
3434 	if (xtrabackup_parallel > 1 && xtrabackup_stream &&
3435 	    xtrabackup_stream_fmt == XB_STREAM_FMT_TAR) {
3436 		msg("xtrabackup: warning: the --parallel option does not have "
3437 		    "any effect when streaming in the 'tar' format. "
3438 		    "You can use the 'xbstream' format instead.\n");
3439 		xtrabackup_parallel = 1;
3440 	}
3441 
3442 	/* Start building out the pipelines from the terminus back */
3443 	if (xtrabackup_stream) {
3444 		/* All streaming goes to stdout */
3445 		ds_data = ds_meta = ds_redo = ds_create(xtrabackup_target_dir,
3446 						        DS_TYPE_STDOUT);
3447 	} else {
3448 		/* Local filesystem */
3449 		ds_data = ds_meta = ds_redo = ds_create(xtrabackup_target_dir,
3450 						        DS_TYPE_LOCAL);
3451 	}
3452 
3453 	/* Track it for destruction */
3454 	xtrabackup_add_datasink(ds_data);
3455 
3456 	/* Stream formatting */
3457 	if (xtrabackup_stream) {
3458 		ds_ctxt_t	*ds;
3459 		if (xtrabackup_stream_fmt == XB_STREAM_FMT_TAR) {
3460 			ds = ds_create(xtrabackup_target_dir, DS_TYPE_ARCHIVE);
3461 		} else if (xtrabackup_stream_fmt == XB_STREAM_FMT_XBSTREAM) {
3462 			ds = ds_create(xtrabackup_target_dir, DS_TYPE_XBSTREAM);
3463 		} else {
3464 			/* bad juju... */
3465 			ds = NULL;
3466 		}
3467 
3468 		xtrabackup_add_datasink(ds);
3469 
3470 		ds_set_pipe(ds, ds_data);
3471 		ds_data = ds;
3472 
3473 		if (xtrabackup_stream_fmt != XB_STREAM_FMT_XBSTREAM) {
3474 
3475 			/* 'tar' does not allow parallel streams */
3476 			ds_redo = ds_meta = ds_create(xtrabackup_target_dir,
3477 						      DS_TYPE_TMPFILE);
3478 			xtrabackup_add_datasink(ds_meta);
3479 			ds_set_pipe(ds_meta, ds);
3480 		} else {
3481 			ds_redo = ds_meta = ds_data;
3482 		}
3483 	}
3484 
3485 	/* Encryption */
3486 	if (xtrabackup_encrypt) {
3487 		ds_ctxt_t	*ds;
3488 
3489                 ds_encrypt_algo = xtrabackup_encrypt_algo;
3490                 ds_encrypt_key = xtrabackup_encrypt_key;
3491                 ds_encrypt_key_file = xtrabackup_encrypt_key_file;
3492                 ds_encrypt_encrypt_threads = xtrabackup_encrypt_threads;
3493                 ds_encrypt_encrypt_chunk_size = xtrabackup_encrypt_chunk_size;
3494 
3495 		ds = ds_create(xtrabackup_target_dir, DS_TYPE_ENCRYPT);
3496 		xtrabackup_add_datasink(ds);
3497 
3498 		ds_set_pipe(ds, ds_data);
3499 		if (ds_data != ds_meta) {
3500 			ds_data = ds;
3501 			ds = ds_create(xtrabackup_target_dir, DS_TYPE_ENCRYPT);
3502 			xtrabackup_add_datasink(ds);
3503 
3504 			ds_set_pipe(ds, ds_redo);
3505 			ds_redo = ds;
3506 		} else {
3507 			ds_redo = ds_data = ds;
3508 		}
3509 	}
3510 
3511 	/* Compression for ds_data and ds_redo */
3512 	if (xtrabackup_compress) {
3513 		ds_ctxt_t	*ds;
3514 
3515 		/* Use a 1 MB buffer for compressed output stream */
3516 		ds = ds_create(xtrabackup_target_dir, DS_TYPE_BUFFER);
3517 		ds_buffer_set_size(ds, opt_read_buffer_size);
3518 		xtrabackup_add_datasink(ds);
3519 		ds_set_pipe(ds, ds_data);
3520 		if (ds_data != ds_redo) {
3521 			ds_data = ds;
3522 			ds = ds_create(xtrabackup_target_dir, DS_TYPE_BUFFER);
3523 			ds_buffer_set_size(ds, opt_read_buffer_size);
3524 			xtrabackup_add_datasink(ds);
3525 			ds_set_pipe(ds, ds_redo);
3526 			ds_redo = ds;
3527 		} else {
3528 			ds_redo = ds_data = ds;
3529 		}
3530 
3531 		ds = ds_create(xtrabackup_target_dir, DS_TYPE_COMPRESS);
3532 		xtrabackup_add_datasink(ds);
3533 		ds_set_pipe(ds, ds_data);
3534 		if (ds_data != ds_redo) {
3535 			ds_data = ds;
3536 			ds = ds_create(xtrabackup_target_dir, DS_TYPE_COMPRESS);
3537 			xtrabackup_add_datasink(ds);
3538 			ds_set_pipe(ds, ds_redo);
3539 			ds_redo = ds;
3540 		} else {
3541 			ds_redo = ds_data = ds;
3542 		}
3543 	}
3544 }
3545 
3546 /************************************************************************
3547 Destroy datasinks.
3548 
3549 Destruction is done in the specific order to not violate their order in the
3550 pipeline so that each datasink is able to flush data down the pipeline. */
xtrabackup_destroy_datasinks(void)3551 static void xtrabackup_destroy_datasinks(void)
3552 {
3553 	for (uint i = actual_datasinks; i > 0; i--) {
3554 		ds_destroy(datasinks[i-1]);
3555 		datasinks[i-1] = NULL;
3556 	}
3557 	ds_data = NULL;
3558 	ds_meta = NULL;
3559 	ds_redo = NULL;
3560 }
3561 
3562 #define SRV_N_PENDING_IOS_PER_THREAD 	OS_AIO_N_PENDING_IOS_PER_THREAD
3563 #define SRV_MAX_N_PENDING_SYNC_IOS	100
3564 
3565 /************************************************************************
3566 @return TRUE if table should be opened. */
3567 static
3568 bool
xb_check_if_open_tablespace(const char * db,const char * table)3569 xb_check_if_open_tablespace(
3570 	const char*	db,
3571 	const char*	table)
3572 {
3573 	char buf[FN_REFLEN];
3574 
3575 	snprintf(buf, sizeof(buf), "%s/%s", db, table);
3576 
3577 	return !check_if_skip_table(buf);
3578 }
3579 
3580 /************************************************************************
3581 Initializes the I/O and tablespace cache subsystems. */
3582 static
3583 void
xb_fil_io_init(void)3584 xb_fil_io_init(void)
3585 /*================*/
3586 {
3587 	srv_n_file_io_threads = srv_n_read_io_threads;
3588 
3589 	os_aio_init(srv_n_read_io_threads,
3590 		    srv_n_write_io_threads,
3591 		    SRV_MAX_N_PENDING_SYNC_IOS);
3592 
3593 	fil_init(srv_file_per_table ? 50000 : 5000, LONG_MAX);
3594 
3595 	fsp_init();
3596 }
3597 
xb_new_datafile(const char * name,bool is_remote)3598 Datafile *xb_new_datafile(
3599 	const char *name,
3600 	bool is_remote)
3601 {
3602 	if (is_remote) {
3603 		RemoteDatafile *remote_file = new RemoteDatafile();
3604 		remote_file->set_name(name);
3605 		return(remote_file);
3606 	} else {
3607 		Datafile *file = new Datafile();
3608 		file->set_name(name);
3609 		file->make_filepath(".", name, IBD);
3610 		return(file);
3611 	}
3612 }
3613 
3614 bool
validate_missing_encryption_tablespaces()3615 validate_missing_encryption_tablespaces()
3616 {
3617 	bool ret=true;
3618 	bool found = false;
3619 	if (invalid_encrypted_tablespace_ids.size() > 0)
3620 	{
3621 		std::vector<ulint>::iterator it;
3622 		for (it = invalid_encrypted_tablespace_ids.begin();
3623 		    it != invalid_encrypted_tablespace_ids.end();
3624 		    it++) {
3625 			found = false;
3626 			mutex_enter(&recv_sys->mutex);
3627 			if (recv_sys->encryption_list != NULL) {
3628 				encryption_list_t::iterator	it_enc;
3629 				for (it_enc = recv_sys->encryption_list->begin();
3630 				     it_enc != recv_sys->encryption_list->end();
3631 				     it_enc++) {
3632 					if (it_enc->space_id == (*it)) {
3633 						found = true;
3634 						break;
3635 					}
3636 				}
3637 			}
3638 			mutex_exit(&recv_sys->mutex);
3639 			if (!found)
3640 			{
3641 				msg_ts("xtrabackup: Error: Space ID %lu is missing encryption information.\n", (*it));
3642 				ret=false;
3643 			}
3644 		}
3645 	}
3646 	return ret;
3647 }
3648 
3649 void
xb_load_single_table_tablespace(const char * dirname,const char * filname,bool is_remote)3650 xb_load_single_table_tablespace(
3651 	const char *dirname,
3652 	const char *filname,
3653 	bool is_remote)
3654 {
3655 	/* Ignore .isl files on XtraBackup recovery. All tablespaces must be
3656 	local. */
3657 	if (is_remote && !srv_backup_mode) {
3658 		return;
3659 	}
3660 
3661 	/* The name ends in .ibd or .isl;
3662 	try opening the file */
3663 	char*	name;
3664 	size_t	dirlen		= dirname == NULL ? 0 : strlen(dirname);
3665 	size_t	namelen		= strlen(filname);
3666 	ulint	pathlen		= dirname == NULL ? namelen + 1: dirlen + namelen + 2;
3667 	lsn_t	flush_lsn;
3668 	dberr_t	err;
3669 	fil_space_t	*space;
3670 
3671 	name = static_cast<char*>(ut_malloc_nokey(pathlen));
3672 
3673 	if (dirname != NULL) {
3674 		ut_snprintf(name, pathlen, "%s/%s", dirname, filname);
3675 		name[pathlen - 5] = 0;
3676 	} else {
3677 		ut_snprintf(name, pathlen, "%s", filname);
3678 		name[pathlen - 5] = 0;
3679 	}
3680 
3681 	Datafile *file = xb_new_datafile(name, is_remote);
3682 
3683 	if (file->open_read_only(true) != DB_SUCCESS) {
3684 		ut_free(name);
3685 		exit(EXIT_FAILURE);
3686 	}
3687 
3688 	err = file->validate_first_page(&flush_lsn, false);
3689 
3690 	if (err == DB_SUCCESS) {
3691 
3692 		os_offset_t	node_size = os_file_get_size(file->handle());
3693 		bool		is_tmp = FSP_FLAGS_GET_TEMPORARY(file->flags());
3694 		os_offset_t	n_pages;
3695 
3696 		ut_a(node_size != (os_offset_t) -1);
3697 
3698 		n_pages = node_size / page_size_t(file->flags()).physical();
3699 
3700 		space = fil_space_create(
3701 			name, file->space_id(), file->flags(),
3702 			is_tmp ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE);
3703 
3704 		ut_a(space != NULL);
3705 
3706 		/* For encrypted tablespace, initialize encryption
3707 		information.*/
3708 		if (FSP_FLAGS_GET_ENCRYPTION(file->flags())) {
3709 			if (srv_backup_mode || !use_dumped_tablespace_keys) {
3710 				byte*	key = file->m_encryption_key;
3711 				byte*	iv = file->m_encryption_iv;
3712 
3713 				if (key && iv) {
3714 					err = fil_set_encryption(
3715 						space->id,
3716 						Encryption::AES, key, iv);
3717 				}
3718 			} else {
3719 				byte key[ENCRYPTION_KEY_LEN];
3720 				byte iv[ENCRYPTION_KEY_LEN];
3721 
3722 				xb_fetch_tablespace_key(space->id, key, iv);
3723 
3724 				err = fil_set_encryption(space->id,
3725 					Encryption::AES, key, iv);
3726 			}
3727 
3728 			ut_ad(err == DB_SUCCESS);
3729 		}
3730 
3731 		if (!fil_node_create(file->filepath(), n_pages, space,
3732 				     false, false)) {
3733 			ut_error;
3734 		}
3735 
3736 		/* by opening the tablespace we forcing node and space objects
3737 		in the cache to be populated with fields from space header */
3738 		fil_space_open(space->name);
3739 
3740 		if (!srv_backup_mode || srv_close_files) {
3741 			fil_space_close(space->name);
3742 		}
3743 	} else {
3744 		/* allow corrupted first page for xtrabackup, it could be just
3745 		zero-filled page, which we'll restore from redo log later */
3746 
3747 		if (xtrabackup_backup && err != DB_PAGE_IS_BLANK) {
3748 			exit(EXIT_FAILURE);
3749 		}
3750 		if (xtrabackup_prepare) {
3751 			exit(EXIT_FAILURE);
3752 		}
3753 	}
3754 
3755 	ut_free(name);
3756 
3757 	delete file;
3758 }
3759 
3760 static
3761 bool
is_remote_tablespace_name(const char * path)3762 is_remote_tablespace_name(const char *path)
3763 {
3764 	size_t len = strlen(path);
3765 	return len > 4 && strcmp(path + len - 4, ".isl") == 0;
3766 }
3767 
3768 static
3769 bool
is_local_tablespace_name(const char * path)3770 is_local_tablespace_name(const char *path)
3771 {
3772 	size_t len = strlen(path);
3773 	return len > 4 && strcmp(path + len - 4, ".ibd") == 0;
3774 }
3775 
3776 static
3777 bool
is_tablespace_name(const char * path)3778 is_tablespace_name(const char *path)
3779 {
3780 	return is_remote_tablespace_name(path)
3781 		|| is_local_tablespace_name(path);
3782 }
3783 
3784 /********************************************************************//**
3785 At the server startup, if we need crash recovery, scans the database
3786 directories under the MySQL datadir, looking for .ibd files. Those files are
3787 single-table tablespaces. We need to know the space id in each of them so that
3788 we know into which file we should look to check the contents of a page stored
3789 in the doublewrite buffer, also to know where to apply log records where the
3790 space id is != 0.
3791 @return	DB_SUCCESS or error number */
3792 UNIV_INTERN
3793 dberr_t
xb_load_single_table_tablespaces(bool (* pred)(const char *,const char *))3794 xb_load_single_table_tablespaces(bool (*pred)(const char*, const char*))
3795 /*===================================*/
3796 {
3797 	int		ret;
3798 	char*		dbpath		= NULL;
3799 	ulint		dbpath_len	= 100;
3800 	os_file_dir_t	dir;
3801 	os_file_dir_t	dbdir;
3802 	os_file_stat_t	dbinfo;
3803 	os_file_stat_t	fileinfo;
3804 	dberr_t		err		= DB_SUCCESS;
3805 
3806 	/* The datadir of MySQL is always the default directory of mysqld */
3807 
3808 	dir = os_file_opendir(fil_path_to_mysql_datadir, true);
3809 
3810 	if (dir == NULL) {
3811 
3812 		return(DB_ERROR);
3813 	}
3814 
3815 	dbpath = static_cast<char*>(ut_malloc_nokey(dbpath_len));
3816 
3817 	/* Scan all directories under the datadir. They are the database
3818 	directories of MySQL. */
3819 
3820 	ret = fil_file_readdir_next_file(&err, fil_path_to_mysql_datadir, dir,
3821 					 &dbinfo);
3822 	while (ret == 0) {
3823 		ulint len;
3824 		bool is_tablespace;
3825 		bool is_remote;
3826 
3827 		is_tablespace = is_tablespace_name(dbinfo.name);
3828 		is_remote = is_remote_tablespace_name(dbinfo.name);
3829 
3830 		/* General tablespaces are always at the first level of the
3831 		data home dir */
3832 		if (dbinfo.type == OS_FILE_TYPE_FILE && is_tablespace &&
3833 		    !(pred && !pred(".", dbinfo.name))) {
3834 			xb_load_single_table_tablespace(
3835 				NULL, dbinfo.name, is_remote);
3836 		}
3837 
3838 		if (dbinfo.type == OS_FILE_TYPE_FILE
3839 		    || dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
3840 
3841 			goto next_datadir_item;
3842 		}
3843 
3844 		/* We found a symlink or a directory; try opening it to see
3845 		if a symlink is a directory */
3846 
3847 		len = strlen(fil_path_to_mysql_datadir)
3848 			+ strlen (dbinfo.name) + 2;
3849 		if (len > dbpath_len) {
3850 			dbpath_len = len;
3851 
3852 			if (dbpath) {
3853 				ut_free(dbpath);
3854 			}
3855 
3856 			dbpath = static_cast<char*>(ut_malloc_nokey(dbpath_len));
3857 		}
3858 		ut_snprintf(dbpath, dbpath_len,
3859 			    "%s/%s", fil_path_to_mysql_datadir, dbinfo.name);
3860 		os_normalize_path(dbpath);
3861 
3862 		if (check_if_skip_database_by_path(dbpath)) {
3863 			fprintf(stderr, "Skipping db: %s\n", dbpath);
3864 			goto next_datadir_item;
3865 		}
3866 
3867 		/* We want wrong directory permissions to be a fatal error for
3868 		XtraBackup. */
3869 		dbdir = os_file_opendir(dbpath, true);
3870 
3871 		if (dbdir != NULL) {
3872 
3873 			/* We found a database directory; loop through it,
3874 			looking for possible .ibd and .isl files in it */
3875 
3876 			ret = fil_file_readdir_next_file(&err, dbpath, dbdir,
3877 							 &fileinfo);
3878 			while (ret == 0) {
3879 				if (fileinfo.type == OS_FILE_TYPE_DIR) {
3880 					goto next_file_item;
3881 				}
3882 
3883 				is_tablespace = is_tablespace_name(
3884 					fileinfo.name);
3885 				is_remote = is_remote_tablespace_name(
3886 					fileinfo.name);
3887 
3888 				/* We found a symlink or a file */
3889 				if (is_tablespace
3890 				    && (!pred
3891 					|| pred(dbinfo.name, fileinfo.name))) {
3892 					xb_load_single_table_tablespace(
3893 						dbinfo.name, fileinfo.name,
3894 						is_remote);
3895 				}
3896 next_file_item:
3897 				ret = fil_file_readdir_next_file(&err,
3898 								 dbpath, dbdir,
3899 								 &fileinfo);
3900 			}
3901 
3902 			if (0 != os_file_closedir(dbdir)) {
3903 				fputs("InnoDB: Warning: could not"
3904 				      " close database directory ", stderr);
3905 				fputs(dbpath, stderr);
3906 				putc('\n', stderr);
3907 
3908 				err = DB_ERROR;
3909 			}
3910 
3911 		} else {
3912 
3913 			err = DB_ERROR;
3914 			break;
3915 
3916 		}
3917 
3918 next_datadir_item:
3919 		ret = fil_file_readdir_next_file(&err,
3920 						 fil_path_to_mysql_datadir,
3921 						 dir, &dbinfo);
3922 	}
3923 
3924 	ut_free(dbpath);
3925 
3926 	if (0 != os_file_closedir(dir)) {
3927 		fprintf(stderr,
3928 			"InnoDB: Error: could not close MySQL datadir\n");
3929 
3930 		return(DB_ERROR);
3931 	}
3932 
3933 	return(err);
3934 }
3935 
3936 /****************************************************************************
3937 Populates the tablespace memory cache by scanning for and opening data files.
3938 @returns DB_SUCCESS or error code.*/
3939 static
3940 ulint
xb_load_tablespaces(void)3941 xb_load_tablespaces(void)
3942 /*=====================*/
3943 {
3944 	ulint	i;
3945 	ulint	err;
3946 	ulint   sum_of_new_sizes;
3947         lsn_t	flush_lsn;
3948         bool	create_new_db;
3949 
3950 	for (i = 0; i < srv_n_file_io_threads; i++) {
3951 		thread_nr[i] = i;
3952 
3953 		os_thread_create(io_handler_thread, thread_nr + i,
3954 				 thread_ids + i);
3955     	}
3956 
3957 	os_thread_sleep(200000); /*0.2 sec*/
3958 
3959 	err = srv_sys_space.check_file_spec(&create_new_db, 0);
3960 
3961 	/* create_new_db must not be true. */
3962 	if (err != DB_SUCCESS || create_new_db) {
3963 		msg("xtrabackup: could not find data files at the "
3964 		    "specified datadir\n");
3965 		return(DB_ERROR);
3966 	}
3967 
3968 	err = srv_sys_space.open_or_create(false, false, &sum_of_new_sizes,
3969 					   &flush_lsn);
3970 
3971 	if (err != DB_SUCCESS) {
3972 		msg("xtrabackup: Could not open or create data files.\n"
3973 		    "xtrabackup: If you tried to add new data files, and it "
3974 		    "failed here,\n"
3975 		    "xtrabackup: you should now edit innodb_data_file_path in "
3976 		    "my.cnf back\n"
3977 		    "xtrabackup: to what it was, and remove the new ibdata "
3978 		    "files InnoDB created\n"
3979 		    "xtrabackup: in this failed attempt. InnoDB only wrote "
3980 		    "those files full of\n"
3981 		    "xtrabackup: zeros, but did not yet use them in any way. "
3982 		    "But be careful: do not\n"
3983 		    "xtrabackup: remove old data files which contain your "
3984 		    "precious data!\n");
3985 		return(err);
3986 	}
3987 
3988 	/* Add separate undo tablespaces to fil_system */
3989 
3990 	err = srv_undo_tablespaces_init(FALSE,
3991 					TRUE,
3992 					srv_undo_tablespaces,
3993 					&srv_undo_tablespaces_open);
3994 	if (err != DB_SUCCESS) {
3995 		return(err);
3996 	}
3997 
3998 	/* It is important to call fil_load_single_table_tablespace() after
3999 	srv_undo_tablespaces_init(), because fil_is_user_tablespace_id() *
4000 	relies on srv_undo_tablespaces_open to be properly initialized */
4001 
4002 	msg("xtrabackup: Generating a list of tablespaces\n");
4003 
4004 	err = xb_load_single_table_tablespaces(xb_check_if_open_tablespace);
4005 	if (err != DB_SUCCESS) {
4006 		return(err);
4007 	}
4008 
4009 	debug_sync_point("xtrabackup_load_tablespaces_pause");
4010 
4011 	return(DB_SUCCESS);
4012 }
4013 
4014 /************************************************************************
4015 Initialize the tablespace memory cache and populate it by scanning for and
4016 opening data files.
4017 @returns DB_SUCCESS or error code.*/
4018 ulint
xb_data_files_init(void)4019 xb_data_files_init(void)
4020 /*====================*/
4021 {
4022 	xb_fil_io_init();
4023 
4024 	return(xb_load_tablespaces());
4025 }
4026 
4027 /************************************************************************
4028 Destroy the tablespace memory cache. */
4029 void
xb_data_files_close(void)4030 xb_data_files_close(void)
4031 /*====================*/
4032 {
4033 	ulint	i;
4034 
4035 	srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
4036 
4037 	/* All threads end up waiting for certain events. Put those events
4038 	to the signaled state. Then the threads will exit themselves after
4039 	os_event_wait(). */
4040 	for (i = 0; i < 1000; i++) {
4041 
4042 		if (!buf_page_cleaner_is_active
4043 		    && os_aio_all_slots_free()) {
4044 			os_aio_wake_all_threads_at_shutdown();
4045 		}
4046 
4047 		/* f. dict_stats_thread is signaled from
4048 		logs_empty_and_mark_files_at_shutdown() and should have
4049 		already quit or is quitting right now. */
4050 
4051 		bool	active = os_thread_active();
4052 
4053 		os_thread_sleep(100000);
4054 
4055 		if (!active) {
4056 			break;
4057 		}
4058 	}
4059 
4060 	if (i == 1000) {
4061 		ib::warn() << os_thread_count << " threads created by InnoDB"
4062 			" had not exited at shutdown!";
4063 	}
4064 
4065 	os_aio_free();
4066 
4067 	fil_close_all_files();
4068 
4069 	fil_close();
4070 
4071 	/* Free the double write data structures. */
4072 	if (buf_dblwr) {
4073 		buf_dblwr_free();
4074 	}
4075 
4076 	/* Reset srv_file_io_threads to its default value to avoid confusing
4077 	warning on --prepare in innobase_start_or_create_for_mysql()*/
4078 	srv_n_file_io_threads = 4;
4079 
4080 	srv_shutdown_state = SRV_SHUTDOWN_NONE;
4081 }
4082 
4083 /***********************************************************************
4084 Allocate and initialize the entry for databases and tables filtering
4085 hash tables. If memory allocation is not successful, terminate program.
4086 @return pointer to the created entry.  */
4087 static
4088 xb_filter_entry_t *
xb_new_filter_entry(const char * name)4089 xb_new_filter_entry(
4090 /*================*/
4091 	const char*	name)	/*!< in: name of table/database */
4092 {
4093 	xb_filter_entry_t	*entry;
4094 	ulint namelen = strlen(name);
4095 
4096 	ut_a(namelen <= NAME_LEN * 2 + 1);
4097 
4098 	entry = static_cast<xb_filter_entry_t *>
4099 		(ut_zalloc_nokey(sizeof(xb_filter_entry_t) + namelen + 1));
4100 	entry->name = ((char*)entry) + sizeof(xb_filter_entry_t);
4101 	strcpy(entry->name, name);
4102 	entry->has_tables = FALSE;
4103 
4104 	return entry;
4105 }
4106 
4107 /***********************************************************************
4108 Add entry to hash table. If hash table is NULL, allocate and initialize
4109 new hash table */
4110 static
4111 xb_filter_entry_t*
xb_add_filter(const char * name,hash_table_t ** hash)4112 xb_add_filter(
4113 /*========================*/
4114 	const char*	name,	/*!< in: name of table/database */
4115 	hash_table_t**	hash)	/*!< in/out: hash to insert into */
4116 {
4117 	xb_filter_entry_t*	entry;
4118 
4119 	entry = xb_new_filter_entry(name);
4120 
4121 	if (UNIV_UNLIKELY(*hash == NULL)) {
4122 		*hash = hash_create(1000);
4123 	}
4124 	HASH_INSERT(xb_filter_entry_t,
4125 		name_hash, *hash,
4126 		ut_fold_string(entry->name),
4127 		entry);
4128 
4129 	return entry;
4130 }
4131 
4132 /***********************************************************************
4133 Validate name of table or database. If name is invalid, program will
4134 be finished with error code */
4135 static
4136 void
xb_validate_name(const char * name,size_t len)4137 xb_validate_name(
4138 /*=============*/
4139 	const char*	name,	/*!< in: name */
4140 	size_t		len)	/*!< in: length of name */
4141 {
4142 	const char*	p;
4143 
4144 	/* perform only basic validation. validate length and
4145 	path symbols */
4146 	if (len > NAME_LEN) {
4147 		msg("xtrabackup: name `%s` is too long.\n", name);
4148 		exit(EXIT_FAILURE);
4149 	}
4150 	p = strpbrk(name, "/\\~");
4151 	if (p && p - name < NAME_LEN) {
4152 		msg("xtrabackup: name `%s` is not valid.\n", name);
4153 		exit(EXIT_FAILURE);
4154 	}
4155 }
4156 
4157 /***********************************************************************
4158 Register new filter entry which can be either database
4159 or table name.  */
4160 static
4161 void
xb_register_filter_entry(const char * name,hash_table_t ** databases_hash,hash_table_t ** tables_hash)4162 xb_register_filter_entry(
4163 /*=====================*/
4164 	const char*	name,	/*!< in: name */
4165 	hash_table_t** databases_hash,
4166 	hash_table_t** tables_hash)
4167 {
4168 	const char*		p;
4169 	size_t			namelen;
4170 	xb_filter_entry_t*	db_entry = NULL;
4171 
4172 	namelen = strlen(name);
4173 	if ((p = strchr(name, '.')) != NULL) {
4174 		char dbname[NAME_LEN + 1];
4175 
4176 		xb_validate_name(name, p - name);
4177 		xb_validate_name(p + 1, namelen - (p - name));
4178 
4179 		strncpy(dbname, name, p - name);
4180 		dbname[p - name] = 0;
4181 
4182 		if (*databases_hash) {
4183 			HASH_SEARCH(name_hash, (*databases_hash),
4184 					ut_fold_string(dbname),
4185 					xb_filter_entry_t*,
4186 					db_entry, (void) 0,
4187 					!strcmp(db_entry->name, dbname));
4188 		}
4189 		if (!db_entry) {
4190 			db_entry = xb_add_filter(dbname, databases_hash);
4191 		}
4192 		db_entry->has_tables = TRUE;
4193 		xb_add_filter(name, tables_hash);
4194 	} else {
4195 		xb_validate_name(name, namelen);
4196 
4197 		xb_add_filter(name, databases_hash);
4198 	}
4199 }
4200 
4201 static
4202 void
xb_register_include_filter_entry(const char * name)4203 xb_register_include_filter_entry(
4204 	const char* name)
4205 {
4206 	xb_register_filter_entry(name, &databases_include_hash,
4207 				 &tables_include_hash);
4208 }
4209 
4210 static
4211 void
xb_register_exclude_filter_entry(const char * name)4212 xb_register_exclude_filter_entry(
4213 	const char* name)
4214 {
4215 	xb_register_filter_entry(name, &databases_exclude_hash,
4216 				 &tables_exclude_hash);
4217 }
4218 
4219 /***********************************************************************
4220 Register new table for the filter.  */
4221 static
4222 void
xb_register_table(const char * name)4223 xb_register_table(
4224 /*==============*/
4225 	const char* name)	/*!< in: name of table */
4226 {
4227 	if (strchr(name, '.') == NULL) {
4228 		msg("xtrabackup: `%s` is not fully qualified name.\n", name);
4229 		exit(EXIT_FAILURE);
4230 	}
4231 
4232 	xb_register_include_filter_entry(name);
4233 }
4234 
compile_regex(const char * regex_string,const char * error_context,xb_regex_t * compiled_re)4235 bool compile_regex(
4236 	const char* regex_string,
4237 	const char* error_context,
4238 	xb_regex_t* compiled_re)
4239 {
4240 	char	errbuf[100];
4241 	int	ret = xb_regcomp(compiled_re, regex_string, REG_EXTENDED);
4242 	if (ret != 0) {
4243 		xb_regerror(ret, compiled_re, errbuf, sizeof(errbuf));
4244 		msg("xtrabackup: error: %s regcomp(%s): %s\n",
4245 			error_context, regex_string, errbuf);
4246 		return false;
4247 	}
4248 	return true;
4249 }
4250 
4251 static
4252 void
xb_add_regex_to_list(const char * regex,const char * error_context,regex_list_t * list)4253 xb_add_regex_to_list(
4254 	const char* regex,  /*!< in: regex */
4255 	const char* error_context,  /*!< in: context to error message */
4256 	regex_list_t* list) /*! in: list to put new regex to */
4257 {
4258 	xb_regex_t compiled_regex;
4259 	if (!compile_regex(regex, error_context, &compiled_regex)) {
4260 		exit(EXIT_FAILURE);
4261 	}
4262 
4263 	list->push_back(compiled_regex);
4264 }
4265 
4266 /***********************************************************************
4267 Register new regex for the include filter.  */
4268 static
4269 void
xb_register_include_regex(const char * regex)4270 xb_register_include_regex(
4271 /*==============*/
4272 	const char* regex)	/*!< in: regex */
4273 {
4274 	xb_add_regex_to_list(regex, "tables", &regex_include_list);
4275 }
4276 
4277 /***********************************************************************
4278 Register new regex for the exclude filter.  */
4279 static
4280 void
xb_register_exclude_regex(const char * regex)4281 xb_register_exclude_regex(
4282 /*==============*/
4283 	const char* regex)	/*!< in: regex */
4284 {
4285 	xb_add_regex_to_list(regex, "tables-exclude", &regex_exclude_list);
4286 }
4287 
4288 typedef void (*insert_entry_func_t)(const char*);
4289 
4290 /***********************************************************************
4291 Scan string and load filter entries from it.  */
4292 static
4293 void
xb_load_list_string(char * list,const char * delimiters,insert_entry_func_t ins)4294 xb_load_list_string(
4295 /*================*/
4296 	char* list,			/*!< in: string representing a list */
4297 	const char* delimiters,		/*!< in: delimiters of entries */
4298 	insert_entry_func_t ins)	/*!< in: callback to add entry */
4299 {
4300 	char*	p;
4301 	char*	saveptr;
4302 
4303 	p = strtok_r(list, delimiters, &saveptr);
4304 	while (p) {
4305 
4306 		ins(p);
4307 
4308 		p = strtok_r(NULL, delimiters, &saveptr);
4309 	}
4310 }
4311 
4312 /***********************************************************************
4313 Scan file and load filter entries from it.  */
4314 static
4315 void
xb_load_list_file(const char * filename,insert_entry_func_t ins)4316 xb_load_list_file(
4317 /*==============*/
4318 	const char* filename,		/*!< in: name of file */
4319 	insert_entry_func_t ins)	/*!< in: callback to add entry */
4320 {
4321 	char	name_buf[NAME_LEN*2+2];
4322 	FILE*	fp;
4323 
4324 	/* read and store the filenames */
4325 	fp = fopen(filename, "r");
4326 	if (!fp) {
4327 		msg("xtrabackup: cannot open %s\n",
4328 		    filename);
4329 		exit(EXIT_FAILURE);
4330 	}
4331 	while (fgets(name_buf, sizeof(name_buf), fp) != NULL) {
4332 		char*	p = strchr(name_buf, '\n');
4333 		if (p) {
4334 			*p = '\0';
4335 		} else {
4336 			msg("xtrabackup: `%s...` name is too long", name_buf);
4337 			exit(EXIT_FAILURE);
4338 		}
4339 
4340 		ins(name_buf);
4341 	}
4342 
4343 	fclose(fp);
4344 }
4345 
4346 
4347 static
4348 void
xb_filters_init()4349 xb_filters_init()
4350 {
4351 	if (xtrabackup_databases) {
4352 		xb_load_list_string(xtrabackup_databases, " \t",
4353 				    xb_register_include_filter_entry);
4354 	}
4355 
4356 	if (xtrabackup_databases_file) {
4357 		xb_load_list_file(xtrabackup_databases_file,
4358 				  xb_register_include_filter_entry);
4359 	}
4360 
4361 	if (xtrabackup_databases_exclude) {
4362 		xb_load_list_string(xtrabackup_databases_exclude, " \t",
4363 				    xb_register_exclude_filter_entry);
4364 	}
4365 
4366 	if (xtrabackup_tables) {
4367 		xb_load_list_string(xtrabackup_tables, ",",
4368 				    xb_register_include_regex);
4369 	}
4370 
4371 	if (xtrabackup_tables_file) {
4372 		xb_load_list_file(xtrabackup_tables_file, xb_register_table);
4373 	}
4374 
4375 	if (xtrabackup_tables_exclude) {
4376 		xb_load_list_string(xtrabackup_tables_exclude, ",",
4377 				    xb_register_exclude_regex);
4378 	}
4379 }
4380 
4381 static
4382 void
xb_filter_hash_free(hash_table_t * hash)4383 xb_filter_hash_free(hash_table_t* hash)
4384 {
4385 	ulint	i;
4386 
4387 	/* free the hash elements */
4388 	for (i = 0; i < hash_get_n_cells(hash); i++) {
4389 		xb_filter_entry_t*	table;
4390 
4391 		table = static_cast<xb_filter_entry_t *>
4392 			(HASH_GET_FIRST(hash, i));
4393 
4394 		while (table) {
4395 			xb_filter_entry_t*	prev_table = table;
4396 
4397 			table = static_cast<xb_filter_entry_t *>
4398 				(HASH_GET_NEXT(name_hash, prev_table));
4399 
4400 			HASH_DELETE(xb_filter_entry_t, name_hash, hash,
4401 				ut_fold_string(prev_table->name), prev_table);
4402 			ut_free(prev_table);
4403 		}
4404 	}
4405 
4406 	/* free hash */
4407 	hash_table_free(hash);
4408 }
4409 
xb_regex_list_free(regex_list_t * list)4410 static void xb_regex_list_free(regex_list_t* list)
4411 {
4412 	while (list->size() > 0) {
4413 		xb_regfree(&list->front());
4414 		list->pop_front();
4415 	}
4416 }
4417 
4418 /************************************************************************
4419 Destroy table filters for partial backup. */
4420 static
4421 void
xb_filters_free()4422 xb_filters_free()
4423 {
4424 	xb_regex_list_free(&regex_include_list);
4425 	xb_regex_list_free(&regex_exclude_list);
4426 
4427 	if (tables_include_hash) {
4428 		xb_filter_hash_free(tables_include_hash);
4429 	}
4430 
4431 	if (tables_exclude_hash) {
4432 		xb_filter_hash_free(tables_exclude_hash);
4433 	}
4434 
4435 	if (databases_include_hash) {
4436 		xb_filter_hash_free(databases_include_hash);
4437 	}
4438 
4439 	if (databases_exclude_hash) {
4440 		xb_filter_hash_free(databases_exclude_hash);
4441 	}
4442 }
4443 
4444 /*********************************************************************//**
4445 Creates or opens the log files and closes them.
4446 @return	DB_SUCCESS or error code */
4447 static
4448 ulint
open_or_create_log_file(ibool create_new_db,ibool * log_file_created,ibool log_file_has_been_opened,ulint k,ulint i,fil_space_t ** log_space)4449 open_or_create_log_file(
4450 /*====================*/
4451 	ibool	create_new_db,		/*!< in: TRUE if we should create a
4452 					new database */
4453 	ibool*	log_file_created,	/*!< out: TRUE if new log file
4454 					created */
4455 	ibool	log_file_has_been_opened,/*!< in: TRUE if a log file has been
4456 					opened before: then it is an error
4457 					to try to create another log file */
4458 	ulint	k,			/*!< in: log group number */
4459 	ulint	i,			/*!< in: log file number in group */
4460 	fil_space_t**	log_space)	/*!< out: log space */
4461 {
4462 	bool		ret;
4463 	os_offset_t	size;
4464 	char		name[10000];
4465 	ulint		dirnamelen;
4466 
4467 	UT_NOT_USED(create_new_db);
4468 	UT_NOT_USED(log_file_has_been_opened);
4469 	UT_NOT_USED(k);
4470 	ut_ad(k == 0);
4471 
4472 	*log_file_created = FALSE;
4473 
4474 	os_normalize_path(srv_log_group_home_dir);
4475 
4476 	dirnamelen = strlen(srv_log_group_home_dir);
4477 	ut_a(dirnamelen < (sizeof name) - 10 - sizeof "ib_logfile");
4478 	memcpy(name, srv_log_group_home_dir, dirnamelen);
4479 
4480 	/* Add a path separator if needed. */
4481 	if (dirnamelen && name[dirnamelen - 1] != OS_PATH_SEPARATOR) {
4482 		name[dirnamelen++] = OS_PATH_SEPARATOR;
4483 	}
4484 
4485 	sprintf(name + dirnamelen, "%s%lu", "ib_logfile", (ulong) i);
4486 
4487 	files[i] = os_file_create(0, name,
4488 				  OS_FILE_OPEN, OS_FILE_NORMAL,
4489 				  OS_LOG_FILE, true, &ret);
4490 	if (!ret) {
4491 		fprintf(stderr, "InnoDB: Error in opening %s\n", name);
4492 
4493 		return(DB_ERROR);
4494 	}
4495 
4496 	size = os_file_get_size(files[i]);
4497 
4498 	if (size != srv_log_file_size * UNIV_PAGE_SIZE) {
4499 
4500 		fprintf(stderr,
4501 			"InnoDB: Error: log file %s is"
4502 			" of different size " UINT64PF " bytes\n"
4503 			"InnoDB: than specified in the .cnf"
4504 			" file " UINT64PF " bytes!\n",
4505 			name, size, srv_log_file_size * UNIV_PAGE_SIZE);
4506 
4507 		return(DB_ERROR);
4508 	}
4509 
4510 	ret = os_file_close(files[i]);
4511 	ut_a(ret);
4512 
4513 	if (i == 0) {
4514 		/* Create in memory the file space object
4515 		which is for this log group */
4516 
4517 		*log_space = fil_space_create(
4518 			name, 2 * k + SRV_LOG_SPACE_FIRST_ID,
4519 			fsp_flags_set_page_size(0, univ_page_size),
4520 			FIL_TYPE_LOG);
4521 	}
4522 
4523 	ut_a(*log_space != NULL);
4524 	ut_a(fil_validate());
4525 
4526 	ut_a(fil_node_create(name, srv_log_file_size, *log_space,
4527 			     false, false) != NULL);
4528 	if (i == 0) {
4529 		ut_a(log_group_init(k, srv_n_log_files,
4530 				    srv_log_file_size * UNIV_PAGE_SIZE,
4531 				    2 * k + SRV_LOG_SPACE_FIRST_ID));
4532 	}
4533 
4534 	return(DB_SUCCESS);
4535 }
4536 
4537 /*********************************************************************//**
4538 Normalizes init parameter values to use units we use inside InnoDB.
4539 @return	DB_SUCCESS or error code */
4540 static
4541 void
xb_normalize_init_values(void)4542 xb_normalize_init_values(void)
4543 /*==========================*/
4544 {
4545 	srv_sys_space.normalize();
4546 
4547 	srv_tmp_space.normalize();
4548 
4549 	srv_log_file_size /= UNIV_PAGE_SIZE;
4550 
4551 	srv_log_buffer_size /= UNIV_PAGE_SIZE;
4552 
4553 	srv_lock_table_size = 5 * (srv_buf_pool_size / UNIV_PAGE_SIZE);
4554 }
4555 
4556 /***********************************************************************
4557 Set the open files limit. Based on set_max_open_files().
4558 
4559 @return the resulting open files limit. May be less or more than the requested
4560 value.  */
4561 static uint
xb_set_max_open_files(uint max_file_limit)4562 xb_set_max_open_files(
4563 /*==================*/
4564 	uint max_file_limit)	/*!<in: open files limit */
4565 {
4566 #if defined(RLIMIT_NOFILE)
4567 	struct rlimit rlimit;
4568 	uint old_cur;
4569 
4570 	if (getrlimit(RLIMIT_NOFILE, &rlimit)) {
4571 
4572 		goto end;
4573 	}
4574 
4575 	old_cur = (uint) rlimit.rlim_cur;
4576 
4577 	if (rlimit.rlim_cur == RLIM_INFINITY) {
4578 
4579 		rlimit.rlim_cur = max_file_limit;
4580 	}
4581 
4582 	if (rlimit.rlim_cur >= max_file_limit) {
4583 
4584 		max_file_limit = rlimit.rlim_cur;
4585 		goto end;
4586 	}
4587 
4588 	rlimit.rlim_cur = rlimit.rlim_max = max_file_limit;
4589 
4590 	if (setrlimit(RLIMIT_NOFILE, &rlimit)) {
4591 
4592 		max_file_limit = old_cur;	/* Use original value */
4593 	} else {
4594 
4595 		rlimit.rlim_cur = 0;	/* Safety if next call fails */
4596 
4597 		(void) getrlimit(RLIMIT_NOFILE, &rlimit);
4598 
4599 		if (rlimit.rlim_cur) {
4600 
4601 			/* If call didn't fail */
4602 			max_file_limit = (uint) rlimit.rlim_cur;
4603 		}
4604 	}
4605 
4606 end:
4607 	return(max_file_limit);
4608 #else
4609 	return(0);
4610 #endif
4611 }
4612 
4613 /**************************************************************************
4614 Prints a warning for every table that uses unsupported engine and
4615 hence will not be backed up. */
4616 static void
xb_tables_compatibility_check()4617 xb_tables_compatibility_check()
4618 {
4619 	const char* query = "SELECT\n"
4620 			    "  CONCAT(table_schema, '/', table_name), engine\n"
4621 			    "FROM information_schema.tables\n"
4622 			    "WHERE engine NOT IN (\n"
4623 			    "  'MyISAM', 'InnoDB', 'CSV', 'MRG_MYISAM'\n"
4624 			    ")\n"
4625 			    "AND table_schema NOT IN (\n"
4626 			    "  'performance_schema', 'information_schema',"
4627 			    "  'mysql'\n"
4628 			    ");";
4629 
4630 	MYSQL_RES* result = xb_mysql_query(mysql_connection, query, true, true);
4631 	MYSQL_ROW row;
4632 	if (!result) {
4633 		return;
4634 	}
4635 
4636 	ut_a(mysql_num_fields(result) == 2);
4637 	while ((row = mysql_fetch_row(result))) {
4638 		if (!check_if_skip_table(row[0])) {
4639 			*strchr(row[0], '/') = '.';
4640 			msg("Warning: \"%s\" uses engine \"%s\" "
4641 			    "and will not be backed up.\n", row[0], row[1]);
4642 		}
4643 	}
4644 
4645 	mysql_free_result(result);
4646 }
4647 
4648 void
xtrabackup_backup_func(void)4649 xtrabackup_backup_func(void)
4650 {
4651 	MY_STAT			 stat_info;
4652 	lsn_t			 latest_cp;
4653 	uint			 i;
4654 	uint			 count;
4655 	ib_mutex_t		 count_mutex;
4656 	data_thread_ctxt_t 	*data_threads;
4657 
4658 	recv_is_making_a_backup = true;
4659 
4660 #ifdef USE_POSIX_FADVISE
4661 	msg("xtrabackup: uses posix_fadvise().\n");
4662 #endif
4663 
4664 	/* cd to datadir */
4665 
4666 	if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
4667 	{
4668 		msg("xtrabackup: cannot my_setwd %s\n", mysql_real_data_home);
4669 		exit(EXIT_FAILURE);
4670 	}
4671 	msg("xtrabackup: cd to %s\n", mysql_real_data_home);
4672 
4673 	msg("xtrabackup: open files limit requested %u, set to %u\n",
4674 	    (uint) xb_open_files_limit,
4675 	    xb_set_max_open_files(xb_open_files_limit));
4676 
4677 	mysql_data_home= mysql_data_home_buff;
4678 	mysql_data_home[0]=FN_CURLIB;		// all paths are relative from here
4679 	mysql_data_home[1]=0;
4680 
4681 	srv_read_only_mode = TRUE;
4682 
4683 	srv_backup_mode = TRUE;
4684 	/* We can safely close files if we don't allow DDL during the
4685 	backup */
4686 	srv_close_files = xb_close_files || opt_lock_ddl;
4687 
4688 	if (xb_close_files)
4689 		msg("xtrabackup: warning: close-files specified. Use it "
4690 		    "at your own risk. If there are DDL operations like table DROP TABLE "
4691 		    "or RENAME TABLE during the backup, inconsistent backup will be "
4692 		    "produced.\n");
4693 
4694 	/* initialize components */
4695         if(innodb_init_param())
4696                 exit(EXIT_FAILURE);
4697 
4698 	xb_normalize_init_values();
4699 
4700 #ifndef __WIN__
4701 	if (srv_file_flush_method_str == NULL) {
4702         	/* These are the default options */
4703 		srv_unix_file_flush_method = SRV_UNIX_FSYNC;
4704 	} else if (0 == ut_strcmp(srv_file_flush_method_str, "fsync")) {
4705 		srv_unix_file_flush_method = SRV_UNIX_FSYNC;
4706 	} else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DSYNC")) {
4707 	  	srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;
4708 
4709 	} else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DIRECT")) {
4710 	  	srv_unix_file_flush_method = SRV_UNIX_O_DIRECT;
4711 		msg("xtrabackup: using O_DIRECT\n");
4712 	} else if (0 == ut_strcmp(srv_file_flush_method_str, "littlesync")) {
4713 	  	srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;
4714 
4715 	} else if (0 == ut_strcmp(srv_file_flush_method_str, "nosync")) {
4716 	  	srv_unix_file_flush_method = SRV_UNIX_NOSYNC;
4717 	} else if (0 == ut_strcmp(srv_file_flush_method_str, "ALL_O_DIRECT")) {
4718 		srv_unix_file_flush_method = SRV_UNIX_ALL_O_DIRECT;
4719 		msg("xtrabackup: using ALL_O_DIRECT\n");
4720 	} else if (0 == ut_strcmp(srv_file_flush_method_str,
4721 				  "O_DIRECT_NO_FSYNC")) {
4722 		srv_unix_file_flush_method = SRV_UNIX_O_DIRECT_NO_FSYNC;
4723 		msg("xtrabackup: using O_DIRECT_NO_FSYNC\n");
4724 	} else {
4725 	  	msg("xtrabackup: Unrecognized value %s for "
4726 		    "innodb_flush_method\n", srv_file_flush_method_str);
4727 	  	exit(EXIT_FAILURE);
4728 	}
4729 #else /* __WIN__ */
4730 	/* We can only use synchronous unbuffered IO on Windows for now */
4731 	if (srv_file_flush_method_str != NULL) {
4732 		msg("xtrabackupp: Warning: "
4733 		    "ignoring innodb_flush_method = %s on Windows.\n");
4734 	}
4735 
4736 	srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;
4737 	srv_use_native_aio = FALSE;
4738 #endif
4739 
4740 	if (srv_buf_pool_size >= 1000 * 1024 * 1024) {
4741                                   /* Here we still have srv_pool_size counted
4742                                   in kilobytes (in 4.0 this was in bytes)
4743 				  srv_boot() converts the value to
4744                                   pages; if buffer pool is less than 1000 MB,
4745                                   assume fewer threads. */
4746                 srv_max_n_threads = 50000;
4747 
4748 	} else if (srv_buf_pool_size >= 8 * 1024 * 1024) {
4749 
4750                 srv_max_n_threads = 10000;
4751         } else {
4752 		srv_max_n_threads = 1000;       /* saves several MB of memory,
4753                                                 especially in 64-bit
4754                                                 computers */
4755         }
4756 
4757 	os_event_global_init();
4758 	srv_general_init();
4759 	ut_crc32_init();
4760 	crc_init();
4761 
4762 	xb_filters_init();
4763 
4764 	if (!xb_keyring_init_for_backup(mysql_connection)) {
4765 		msg("xtrabackup: Error: failed to init keyring plugin\n");
4766 		exit(EXIT_FAILURE);
4767 	}
4768 
4769 	if (opt_tables_compatibility_check) {
4770 		xb_tables_compatibility_check();
4771 	}
4772 
4773 	{
4774 	ibool	log_file_created;
4775 	ibool	log_created	= FALSE;
4776 	ibool	log_opened	= FALSE;
4777 	ulint	err;
4778 	ulint	i;
4779 	fil_space_t *log_space;
4780 
4781 	xb_fil_io_init();
4782 
4783 	log_init();
4784 
4785 	recv_sys_create();
4786 	recv_sys_init(buf_pool_get_curr_size());
4787 
4788 	lock_sys_create(srv_lock_table_size);
4789 
4790 	for (i = 0; i < srv_n_log_files; i++) {
4791 		err = open_or_create_log_file(FALSE, &log_file_created,
4792 					      log_opened, 0, i, &log_space);
4793 		if (err != DB_SUCCESS) {
4794 
4795 			//return((int) err);
4796 			exit(EXIT_FAILURE);
4797 		}
4798 
4799 		if (log_file_created) {
4800 			log_created = TRUE;
4801 		} else {
4802 			log_opened = TRUE;
4803 		}
4804 		if ((log_opened && log_created)) {
4805 			msg(
4806 	"xtrabackup: Error: all log files must be created at the same time.\n"
4807 	"xtrabackup: All log files must be created also in database creation.\n"
4808 	"xtrabackup: If you want bigger or smaller log files, shut down the\n"
4809 	"xtrabackup: database and make sure there were no errors in shutdown.\n"
4810 	"xtrabackup: Then delete the existing log files. Edit the .cnf file\n"
4811 	"xtrabackup: and start the database again.\n");
4812 
4813 			//return(DB_ERROR);
4814 			exit(EXIT_FAILURE);
4815 		}
4816 	}
4817 
4818 	/* log_file_created must not be TRUE, if online */
4819 	if (log_file_created) {
4820 		msg("xtrabackup: Something wrong with source files...\n");
4821 		exit(EXIT_FAILURE);
4822 	}
4823 
4824 	}
4825 
4826 	/* create extra LSN dir if it does not exist. */
4827 	if (xtrabackup_extra_lsndir
4828 		&&!my_stat(xtrabackup_extra_lsndir,&stat_info,MYF(0))
4829 		&& (my_mkdir(xtrabackup_extra_lsndir,0777,MYF(0)) < 0)) {
4830 		msg("xtrabackup: Error: cannot mkdir %d: %s\n",
4831 		    my_errno(), xtrabackup_extra_lsndir);
4832 		exit(EXIT_FAILURE);
4833 	}
4834 
4835 	/* create target dir if not exist */
4836 	if (!my_stat(xtrabackup_target_dir,&stat_info,MYF(0))
4837 		&& (my_mkdir(xtrabackup_target_dir,0777,MYF(0)) < 0)){
4838 		msg("xtrabackup: Error: cannot mkdir %d: %s\n",
4839 		    my_errno(), xtrabackup_target_dir);
4840 		exit(EXIT_FAILURE);
4841 	}
4842 
4843 
4844 	if (opt_dump_innodb_buffer_pool) {
4845 		dump_innodb_buffer_pool(mysql_connection);
4846 	}
4847 
4848         {
4849         fil_system_t*   f_system = fil_system;
4850 
4851 	/* definition from recv_recovery_from_checkpoint_start() */
4852 	log_group_t*	max_cp_group;
4853 	ulint		max_cp_field;
4854 	byte*		buf;
4855 	byte*		log_hdr_buf_;
4856 	byte*		log_hdr_buf;
4857 	ulint		err;
4858 	bool		data_copying_error = false;
4859 
4860 	/* start back ground thread to copy newer log */
4861 	os_thread_id_t log_copying_thread_id;
4862 	datafiles_iter_t *it;
4863 
4864 	log_hdr_buf_ = static_cast<byte *>
4865 		(ut_malloc_nokey(LOG_FILE_HDR_SIZE + UNIV_PAGE_SIZE_MAX));
4866 	log_hdr_buf = static_cast<byte *>
4867 		(ut_align(log_hdr_buf_, UNIV_PAGE_SIZE_MAX));
4868 
4869 	/* get current checkpoint_lsn */
4870 	/* Look for the latest checkpoint from any of the log groups */
4871 
4872 	mutex_enter(&log_sys->mutex);
4873 
4874 	err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
4875 
4876 	if (err != DB_SUCCESS) {
4877 
4878 		ut_free(log_hdr_buf_);
4879 		exit(EXIT_FAILURE);
4880 	}
4881 
4882 	log_group_header_read(max_cp_group, max_cp_field);
4883 	buf = log_sys->checkpoint_buf;
4884 
4885 	checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN);
4886 	checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO);
4887 
4888 	mutex_exit(&log_sys->mutex);
4889 
4890 reread_log_header:
4891 	fil_io(IORequest(IORequest::READ), true,
4892 	       page_id_t(max_cp_group->space_id, 0),
4893 	       univ_page_size,
4894 	       0, LOG_FILE_HDR_SIZE,
4895 	       log_hdr_buf, max_cp_group);
4896 
4897 	/* check consistency of log file header to copy */
4898 	mutex_enter(&log_sys->mutex);
4899 
4900 	err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
4901 
4902         if (err != DB_SUCCESS) {
4903 
4904 		ut_free(log_hdr_buf_);
4905                 exit(EXIT_FAILURE);
4906         }
4907 
4908         log_group_header_read(max_cp_group, max_cp_field);
4909         buf = log_sys->checkpoint_buf;
4910 
4911 	if(checkpoint_no_start != mach_read_from_8(buf + LOG_CHECKPOINT_NO)) {
4912 
4913 		checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN);
4914 		checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO);
4915 		mutex_exit(&log_sys->mutex);
4916 		goto reread_log_header;
4917 	}
4918 
4919 	mutex_exit(&log_sys->mutex);
4920 
4921 	xtrabackup_init_datasinks();
4922 
4923 	if (!select_history()) {
4924 		exit(EXIT_FAILURE);
4925 	}
4926 
4927 	/* open the log file */
4928 	memset(&stat_info, 0, sizeof(MY_STAT));
4929 	dst_log_file = ds_open(ds_redo, XB_LOG_FILENAME, &stat_info);
4930 	if (dst_log_file == NULL) {
4931 		msg("xtrabackup: error: failed to open the target stream for "
4932 		    "'%s'.\n", XB_LOG_FILENAME);
4933 		ut_free(log_hdr_buf_);
4934 		exit(EXIT_FAILURE);
4935 	}
4936 
4937 	/* label it */
4938 	strcpy((char*) log_hdr_buf + LOG_HEADER_CREATOR, "xtrabkup ");
4939 	ut_sprintf_timestamp(
4940 		(char*) log_hdr_buf + (LOG_HEADER_CREATOR
4941 				+ (sizeof "xtrabkup ") - 1));
4942 
4943 	if (ds_write(dst_log_file, log_hdr_buf, LOG_FILE_HDR_SIZE)) {
4944 		msg("xtrabackup: error: write to logfile failed\n");
4945 		ut_free(log_hdr_buf_);
4946 		exit(EXIT_FAILURE);
4947 	}
4948 
4949 	ut_free(log_hdr_buf_);
4950 
4951 	/* start flag */
4952 	log_copying = TRUE;
4953 
4954 	/* start io throttle */
4955 	if(xtrabackup_throttle) {
4956 		os_thread_id_t io_watching_thread_id;
4957 
4958 		io_ticket = xtrabackup_throttle;
4959 		wait_throttle = os_event_create("wait_throttle");
4960 
4961 		os_thread_create(io_watching_thread, NULL,
4962 				 &io_watching_thread_id);
4963 	}
4964 
4965 	mutex_enter(&log_sys->mutex);
4966 	xtrabackup_choose_lsn_offset(checkpoint_lsn_start);
4967 	mutex_exit(&log_sys->mutex);
4968 
4969 	if (opt_lock_ddl_per_table) {
4970 		mdl_lock_tables();
4971 	}
4972 
4973 	/* copy log file by current position */
4974 	if(xtrabackup_copy_logfile(checkpoint_lsn_start, FALSE))
4975 		exit(EXIT_FAILURE);
4976 
4977 	/*
4978 	* From this point forward, recv_parse_or_apply_log_rec_body should fail if
4979 	* MLOG_INDEX_LOAD event is parsed as its not safe to continue the backup
4980 	* in any situation (with or without --lock-ddl-per-table).
4981 	*/
4982 	mdl_taken = true;
4983 
4984 	log_copying_stop = os_event_create("log_copying_stop");
4985 	debug_sync_point("xtrabackup_pause_after_redo_catchup");
4986 	os_thread_create(log_copying_thread, NULL, &log_copying_thread_id);
4987 
4988 	/* Populate fil_system with tablespaces to copy */
4989 	err = xb_load_tablespaces();
4990 	if (err != DB_SUCCESS) {
4991 		msg("xtrabackup: error: xb_load_tablespaces() failed with"
4992 		    "error code %lu\n", err);
4993 		exit(EXIT_FAILURE);
4994 	}
4995 
4996 	/* FLUSH CHANGED_PAGE_BITMAPS call */
4997 	if (!flush_changed_page_bitmaps()) {
4998 		exit(EXIT_FAILURE);
4999 	}
5000 	debug_sync_point("xtrabackup_suspend_at_start");
5001 
5002 	if (xtrabackup_incremental) {
5003 		if (!xtrabackup_incremental_force_scan &&
5004 		    have_changed_page_bitmaps) {
5005 			changed_page_bitmap = xb_page_bitmap_init();
5006 		}
5007 		if (!changed_page_bitmap) {
5008 			msg("xtrabackup: using the full scan for incremental "
5009 			    "backup\n");
5010 		} else if (incremental_lsn != checkpoint_lsn_start) {
5011 			/* Do not print that bitmaps are used when dummy bitmap
5012 			is build for an empty LSN range. */
5013 			msg("xtrabackup: using the changed page bitmap\n");
5014 		}
5015 	}
5016 
5017 	ut_a(xtrabackup_parallel > 0);
5018 
5019 	if (xtrabackup_parallel > 1) {
5020 		msg("xtrabackup: Starting %u threads for parallel data "
5021 		    "files transfer\n", xtrabackup_parallel);
5022 	}
5023 
5024 	it = datafiles_iter_new(f_system);
5025 	if (it == NULL) {
5026 		msg("xtrabackup: Error: datafiles_iter_new() failed.\n");
5027 		exit(EXIT_FAILURE);
5028 	}
5029 
5030 	/* Create data copying threads */
5031 	data_threads = (data_thread_ctxt_t *)
5032 		ut_malloc_nokey(sizeof(data_thread_ctxt_t) *
5033                                 xtrabackup_parallel);
5034 	count = xtrabackup_parallel;
5035 	mutex_create(LATCH_ID_XTRA_COUNT_MUTEX, &count_mutex);
5036 
5037 	for (i = 0; i < (uint) xtrabackup_parallel; i++) {
5038 		data_threads[i].it = it;
5039 		data_threads[i].num = i+1;
5040 		data_threads[i].count = &count;
5041 		data_threads[i].count_mutex = &count_mutex;
5042 		data_threads[i].error = &data_copying_error;
5043 		os_thread_create(data_copy_thread_func, data_threads + i,
5044 				 &data_threads[i].id);
5045 	}
5046 
5047 	/* Wait for threads to exit */
5048 	while (1) {
5049 		os_thread_sleep(1000000);
5050 		mutex_enter(&count_mutex);
5051 		if (count == 0) {
5052 			mutex_exit(&count_mutex);
5053 			break;
5054 		}
5055 		mutex_exit(&count_mutex);
5056 	}
5057 
5058 	mutex_free(&count_mutex);
5059 	ut_free(data_threads);
5060 	datafiles_iter_free(it);
5061 
5062 	if (data_copying_error) {
5063 		exit(EXIT_FAILURE);
5064 	}
5065 
5066 	if (changed_page_bitmap) {
5067 		xb_page_bitmap_deinit(changed_page_bitmap);
5068 	}
5069 	}
5070 
5071 	if (!backup_start()) {
5072 		exit(EXIT_FAILURE);
5073 	}
5074 	if(opt_lock_ddl_per_table && opt_debug_sleep_before_unlock){
5075 		msg_ts("Debug sleep for %u seconds\n",
5076 		       opt_debug_sleep_before_unlock);
5077 		os_thread_sleep(opt_debug_sleep_before_unlock * 1000000);
5078 	}
5079 	/* read the latest checkpoint lsn */
5080 	latest_cp = 0;
5081 	{
5082 		log_group_t*	max_cp_group;
5083 		ulint	max_cp_field;
5084 		ulint	err;
5085 
5086 		mutex_enter(&log_sys->mutex);
5087 
5088 		err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field);
5089 
5090 		if (err != DB_SUCCESS) {
5091 			msg("xtrabackup: Error: recv_find_max_checkpoint() failed.\n");
5092 			mutex_exit(&log_sys->mutex);
5093 			goto skip_last_cp;
5094 		}
5095 
5096 		log_group_header_read(max_cp_group, max_cp_field);
5097 
5098 		xtrabackup_choose_lsn_offset(checkpoint_lsn_start);
5099 
5100 		latest_cp = mach_read_from_8(log_sys->checkpoint_buf +
5101 					     LOG_CHECKPOINT_LSN);
5102 
5103 		mutex_exit(&log_sys->mutex);
5104 
5105 		msg("xtrabackup: The latest check point (for incremental): "
5106 		    "'" LSN_PF "'\n", latest_cp);
5107 	}
5108 skip_last_cp:
5109 	/* stop log_copying_thread */
5110 	log_copying = FALSE;
5111 	os_event_set(log_copying_stop);
5112 	msg("xtrabackup: Stopping log copying thread.\n");
5113 	while (log_copying_running) {
5114 		msg(".");
5115 		os_thread_sleep(200000); /*0.2 sec*/
5116 	}
5117 	msg("\n");
5118 
5119 	os_event_destroy(log_copying_stop);
5120 	if (ds_close(dst_log_file)) {
5121 		exit(EXIT_FAILURE);
5122 	}
5123 
5124 	if (!validate_missing_encryption_tablespaces()) {
5125 		exit(EXIT_FAILURE);
5126 	}
5127 
5128 
5129 	if(!xtrabackup_incremental) {
5130 		strcpy(metadata_type, "full-backuped");
5131 		metadata_from_lsn = 0;
5132 	} else {
5133 		strcpy(metadata_type, "incremental");
5134 		metadata_from_lsn = incremental_lsn;
5135 	}
5136 	metadata_to_lsn = latest_cp;
5137 	metadata_last_lsn = log_copy_scanned_lsn;
5138 
5139 	if (!xtrabackup_stream_metadata(ds_meta)) {
5140 		msg("xtrabackup: Error: failed to stream metadata.\n");
5141 		exit(EXIT_FAILURE);
5142 	}
5143 
5144 	if (!backup_finish()) {
5145 		exit(EXIT_FAILURE);
5146 	}
5147 
5148 	if (xtrabackup_extra_lsndir) {
5149 		char	filename[FN_REFLEN];
5150 
5151 		sprintf(filename, "%s/%s", xtrabackup_extra_lsndir,
5152 			XTRABACKUP_METADATA_FILENAME);
5153 		if (!xtrabackup_write_metadata(filename)) {
5154 			msg("xtrabackup: Error: failed to write metadata "
5155 			    "to '%s'.\n", filename);
5156 			exit(EXIT_FAILURE);
5157 		}
5158 
5159 		sprintf(filename, "%s/%s", xtrabackup_extra_lsndir,
5160 			XTRABACKUP_INFO);
5161 		if (!xtrabackup_write_info(filename)) {
5162 			msg("xtrabackup: Error: failed to write info "
5163 			    "to '%s'.\n", filename);
5164 			exit(EXIT_FAILURE);
5165 		}
5166 
5167 	}
5168 
5169 	if (opt_lock_ddl_per_table) {
5170 		mdl_unlock_all();
5171 	}
5172 
5173 	if (opt_transition_key != NULL || opt_generate_transition_key) {
5174 		if (!xb_tablespace_keys_dump(ds_data, opt_transition_key,
5175                     opt_transition_key != NULL ?
5176                     	strlen(opt_transition_key) : 0)) {
5177 			msg("xtrabackup: Error: failed to dump "
5178 			    "tablespace keys.\n");
5179 			exit(EXIT_FAILURE);
5180 		}
5181 	}
5182 
5183 	xtrabackup_destroy_datasinks();
5184 
5185 	if (wait_throttle) {
5186 		/* wait for io_watching_thread completion */
5187 		while (io_watching_thread_running) {
5188 			os_thread_sleep(1000000);
5189 		}
5190 		os_event_destroy(wait_throttle);
5191 		wait_throttle = NULL;
5192 	}
5193 
5194 	msg("xtrabackup: Transaction log of lsn (" LSN_PF ") to (" LSN_PF
5195 	    ") was copied.\n", checkpoint_lsn_start, log_copy_scanned_lsn);
5196 	xb_filters_free();
5197 
5198 	xb_data_files_close();
5199 
5200 	recv_sys_debug_free();
5201 
5202 	log_shutdown();
5203 
5204 	trx_pool_close();
5205 
5206 	lock_sys_close();
5207 
5208 	os_thread_free();
5209 
5210 	row_mysql_close();
5211 
5212 	sync_check_close();
5213 
5214 	xb_keyring_shutdown();
5215 
5216 	/* Make sure that the latest checkpoint made it to xtrabackup_logfile */
5217 	if (latest_cp > log_copy_scanned_lsn) {
5218 		msg("xtrabackup: error: last checkpoint LSN (" LSN_PF
5219 		    ") is larger than last copied LSN (" LSN_PF ").\n",
5220 		    latest_cp, log_copy_scanned_lsn);
5221 		exit(EXIT_FAILURE);
5222 	}
5223 }
5224 
5225 /* ================= stats ================= */
5226 static my_bool
xtrabackup_stats_level(dict_index_t * index,ulint level)5227 xtrabackup_stats_level(
5228 	dict_index_t*	index,
5229 	ulint		level)
5230 {
5231 	ulint	space;
5232 	page_t*	page;
5233 
5234 	rec_t*	node_ptr;
5235 
5236 	ulint	right_page_no;
5237 
5238 	page_cur_t	cursor;
5239 
5240 	mtr_t	mtr;
5241 	mem_heap_t*	heap	= mem_heap_create(256);
5242 
5243 	ulint*	offsets = NULL;
5244 
5245 	ulonglong n_pages, n_pages_extern;
5246 	ulonglong sum_data, sum_data_extern;
5247 	ulonglong n_recs;
5248 	buf_block_t*	block;
5249 	page_size_t	page_size(0, 0, false);
5250 	bool		found;
5251 
5252 	n_pages = sum_data = n_recs = 0;
5253 	n_pages_extern = sum_data_extern = 0;
5254 
5255 
5256 	if (level == 0)
5257 		fprintf(stdout, "        leaf pages: ");
5258 	else
5259 		fprintf(stdout, "     level %lu pages: ", level);
5260 
5261 	mtr_start(&mtr);
5262 
5263 	mtr_x_lock(&(index->lock), &mtr);
5264 	block = btr_root_block_get(index, RW_X_LATCH, &mtr);
5265 	page = buf_block_get_frame(block);
5266 
5267 	space = page_get_space_id(page);
5268 	page_size.copy_from(fil_space_get_page_size(space, &found));
5269 
5270 	ut_a(found);
5271 
5272 	while (level != btr_page_get_level(page, &mtr)) {
5273 
5274 		ut_a(space == block->page.id.space());
5275 		ut_a(space == page_get_space_id(page));
5276 		ut_a(!page_is_leaf(page));
5277 
5278 		page_cur_set_before_first(block, &cursor);
5279 		page_cur_move_to_next(&cursor);
5280 
5281 		node_ptr = page_cur_get_rec(&cursor);
5282 		offsets = rec_get_offsets(node_ptr, index, offsets,
5283 					ULINT_UNDEFINED, &heap);
5284 		block = btr_node_ptr_get_child(node_ptr, index, offsets, &mtr);
5285 		page = buf_block_get_frame(block);
5286 	}
5287 
5288 loop:
5289 	mem_heap_empty(heap);
5290 	offsets = NULL;
5291 	mtr_x_lock(&(index->lock), &mtr);
5292 
5293 	right_page_no = btr_page_get_next(page, &mtr);
5294 
5295 
5296 	/*=================================*/
5297 	//fprintf(stdout, "%lu ", (ulint) buf_frame_get_page_no(page));
5298 
5299 	n_pages++;
5300 	sum_data += page_get_data_size(page);
5301 	n_recs += page_get_n_recs(page);
5302 
5303 
5304 	if (level == 0) {
5305 		page_cur_t	cur;
5306 		ulint	n_fields;
5307 		ulint	i;
5308 		mem_heap_t*	local_heap	= NULL;
5309 		ulint	offsets_[REC_OFFS_NORMAL_SIZE];
5310 		ulint*	local_offsets	= offsets_;
5311 
5312 		*offsets_ = (sizeof offsets_) / sizeof *offsets_;
5313 
5314 		page_cur_set_before_first(block, &cur);
5315 		page_cur_move_to_next(&cur);
5316 
5317 		for (;;) {
5318 			if (page_cur_is_after_last(&cur)) {
5319 				break;
5320 			}
5321 
5322 			local_offsets = rec_get_offsets(cur.rec, index, local_offsets,
5323 						ULINT_UNDEFINED, &local_heap);
5324 			n_fields = rec_offs_n_fields(local_offsets);
5325 
5326 			for (i = 0; i < n_fields; i++) {
5327 				if (rec_offs_nth_extern(local_offsets, i)) {
5328 					page_t*	local_page;
5329 					ulint	space_id;
5330 					ulint	page_no;
5331 					ulint	offset;
5332 					byte*	blob_header;
5333 					ulint	part_len;
5334 					mtr_t	local_mtr;
5335 					ulint	local_len;
5336 					byte*	data;
5337 					buf_block_t*	local_block;
5338 
5339 					data = rec_get_nth_field(cur.rec, local_offsets, i, &local_len);
5340 
5341 					ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
5342 					local_len -= BTR_EXTERN_FIELD_REF_SIZE;
5343 
5344 					space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
5345 					page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
5346 					offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
5347 
5348 					if (offset != FIL_PAGE_DATA)
5349 						msg("\nWarning: several record may share same external page.\n");
5350 
5351 					for (;;) {
5352 						mtr_start(&local_mtr);
5353 
5354 						local_block = btr_block_get(page_id_t(space_id, page_no), page_size, RW_S_LATCH, index, &local_mtr);
5355 						local_page = buf_block_get_frame(local_block);
5356 						blob_header = local_page + offset;
5357 #define BTR_BLOB_HDR_PART_LEN		0
5358 #define BTR_BLOB_HDR_NEXT_PAGE_NO	4
5359 						//part_len = btr_blob_get_part_len(blob_header);
5360 						part_len = mach_read_from_4(blob_header + BTR_BLOB_HDR_PART_LEN);
5361 
5362 						//page_no = btr_blob_get_next_page_no(blob_header);
5363 						page_no = mach_read_from_4(blob_header + BTR_BLOB_HDR_NEXT_PAGE_NO);
5364 
5365 						offset = FIL_PAGE_DATA;
5366 
5367 
5368 
5369 
5370 						/*=================================*/
5371 						//fprintf(stdout, "[%lu] ", (ulint) buf_frame_get_page_no(page));
5372 
5373 						n_pages_extern++;
5374 						sum_data_extern += part_len;
5375 
5376 
5377 						mtr_commit(&local_mtr);
5378 
5379 						if (page_no == FIL_NULL)
5380 							break;
5381 					}
5382 				}
5383 			}
5384 
5385 			page_cur_move_to_next(&cur);
5386 		}
5387 	}
5388 
5389 
5390 
5391 
5392 	mtr_commit(&mtr);
5393 	if (right_page_no != FIL_NULL) {
5394 		mtr_start(&mtr);
5395 		block = btr_block_get(page_id_t(space,
5396 						dict_index_get_page(index)),
5397 				      page_size,
5398 				      RW_X_LATCH, index, &mtr);
5399 		page = buf_block_get_frame(block);
5400 		goto loop;
5401 	}
5402 	mem_heap_free(heap);
5403 
5404 	if (level == 0)
5405 		fprintf(stdout, "recs=%llu, ", n_recs);
5406 
5407 	fprintf(stdout, "pages=%llu, data=%llu bytes, data/pages=%lld%%",
5408 		n_pages, sum_data,
5409 		((sum_data * 100) / page_size.physical()) / n_pages);
5410 
5411 
5412 	if (level == 0 && n_pages_extern) {
5413 		putc('\n', stdout);
5414 		/* also scan blob pages*/
5415 		fprintf(stdout, "    external pages: ");
5416 
5417 		fprintf(stdout, "pages=%llu, data=%llu bytes, data/pages=%lld%%",
5418 			n_pages_extern, sum_data_extern,
5419 			((sum_data_extern * 100) / page_size.physical())
5420 				/ n_pages_extern);
5421 	}
5422 
5423 	putc('\n', stdout);
5424 
5425 	if (level > 0) {
5426 		xtrabackup_stats_level(index, level - 1);
5427 	}
5428 
5429 	return(TRUE);
5430 }
5431 
5432 static void
xtrabackup_stats_func(int argc,char ** argv)5433 xtrabackup_stats_func(int argc, char **argv)
5434 {
5435 	ulint n;
5436 
5437 	/* cd to datadir */
5438 
5439 	if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
5440 	{
5441 		msg("xtrabackup: cannot my_setwd %s\n", mysql_real_data_home);
5442 		exit(EXIT_FAILURE);
5443 	}
5444 	msg("xtrabackup: cd to %s\n", mysql_real_data_home);
5445 
5446 	mysql_data_home= mysql_data_home_buff;
5447 	mysql_data_home[0]=FN_CURLIB;		// all paths are relative from here
5448 	mysql_data_home[1]=0;
5449 
5450 	/* set read only */
5451 	srv_read_only_mode = TRUE;
5452 
5453 	if (!xb_keyring_init_for_stats(argc, argv)) {
5454 		msg("xtrabackup: error: failed to init keyring plugin.\n");
5455 		exit(EXIT_FAILURE);
5456 	}
5457 
5458 	/* initialize components */
5459 	if(innodb_init_param()) {
5460 		exit(EXIT_FAILURE);
5461 	}
5462 
5463 	/* Check if the log files have been created, otherwise innodb_init()
5464 	will crash when called with srv_read_only == TRUE */
5465 	for (n = 0; n < srv_n_log_files; n++) {
5466 		char		logname[FN_REFLEN];
5467 		bool		exists;
5468 		os_file_type_t	type;
5469 
5470 		snprintf(logname, sizeof(logname), "%s%c%s%lu",
5471 			srv_log_group_home_dir, OS_PATH_SEPARATOR,
5472 			"ib_logfile", (ulong) n);
5473 		os_normalize_path(logname);
5474 
5475 		if (!os_file_status(logname, &exists, &type) || !exists ||
5476 		    type != OS_FILE_TYPE_FILE) {
5477 			msg("xtrabackup: Error: "
5478 			    "Cannot find log file %s.\n", logname);
5479 			msg("xtrabackup: Error: "
5480 			    "to use the statistics feature, you need a "
5481 			    "clean copy of the database including "
5482 			    "correctly sized log files, so you need to "
5483 			    "execute with --prepare twice to use this "
5484 			    "functionality on a backup.\n");
5485 			exit(EXIT_FAILURE);
5486 		}
5487 	}
5488 
5489 	msg("xtrabackup: Starting 'read-only' InnoDB instance to gather "
5490 	    "index statistics.\n"
5491 	    "xtrabackup: Using %lld bytes for buffer pool (set by "
5492 	    "--use-memory parameter)\n", xtrabackup_use_memory);
5493 
5494 	if(innodb_init())
5495 		exit(EXIT_FAILURE);
5496 
5497 	xb_filters_init();
5498 
5499 	fprintf(stdout, "\n\n<INDEX STATISTICS>\n");
5500 
5501 	/* gather stats */
5502 
5503 	{
5504 	dict_table_t*	sys_tables;
5505 	dict_index_t*	sys_index;
5506 	dict_table_t*	table;
5507 	btr_pcur_t	pcur;
5508 	rec_t*		rec;
5509 	byte*		field;
5510 	ulint		len;
5511 	mtr_t		mtr;
5512 
5513 	/* Enlarge the fatal semaphore wait timeout during the InnoDB table
5514 	monitor printout */
5515 
5516 	os_atomic_increment_ulint(
5517 		&srv_fatal_semaphore_wait_threshold,
5518 		72000);
5519 
5520 	mutex_enter(&(dict_sys->mutex));
5521 
5522 	mtr_start(&mtr);
5523 
5524 	sys_tables = dict_table_get_low("SYS_TABLES");
5525 	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
5526 
5527 	btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
5528 				    TRUE, 0, &mtr);
5529 loop:
5530 	btr_pcur_move_to_next_user_rec(&pcur, &mtr);
5531 
5532 	rec = btr_pcur_get_rec(&pcur);
5533 
5534 	if (!btr_pcur_is_on_user_rec(&pcur))
5535 	{
5536 		/* end of index */
5537 
5538 		btr_pcur_close(&pcur);
5539 		mtr_commit(&mtr);
5540 
5541 		mutex_exit(&(dict_sys->mutex));
5542 
5543 		/* Restore the fatal semaphore wait timeout */
5544 		os_atomic_increment_ulint(
5545 			&srv_fatal_semaphore_wait_threshold,
5546 			-72000);
5547 
5548 		goto end;
5549 	}
5550 
5551 	field = rec_get_nth_field_old(rec, 0, &len);
5552 
5553 	if (!rec_get_deleted_flag(rec, 0)) {
5554 
5555 		/* We found one */
5556 
5557                 char*	table_name = mem_strdupl((char*) field, len);
5558 
5559 		btr_pcur_store_position(&pcur, &mtr);
5560 
5561 		mtr_commit(&mtr);
5562 
5563 		table = dict_table_get_low(table_name);
5564 		ut_free(table_name);
5565 
5566 		if (table && check_if_skip_table(table->name.m_name))
5567 			goto skip;
5568 
5569 
5570 		if (table == NULL) {
5571 			fputs("InnoDB: Failed to load table ", stderr);
5572 			ut_print_name(stderr, NULL, (char*) field);
5573 			putc('\n', stderr);
5574 		} else {
5575 			dict_index_t*	index;
5576 
5577 			/* The table definition was corrupt if there
5578 			is no index */
5579 
5580 			if (dict_table_get_first_index(table)) {
5581 				dict_stats_update_transient(table);
5582 			}
5583 
5584 			//dict_table_print_low(table);
5585 
5586 			index = UT_LIST_GET_FIRST(table->indexes);
5587 			while (index != NULL) {
5588 {
5589 	ib_uint64_t	n_vals;
5590 	bool		found;
5591 
5592 	if (index->n_user_defined_cols > 0) {
5593 		n_vals = index->stat_n_diff_key_vals[
5594 					index->n_user_defined_cols];
5595 	} else {
5596 		n_vals = index->stat_n_diff_key_vals[1];
5597 	}
5598 
5599 	fprintf(stdout,
5600 		"  table: %s, index: %s, space id: %lu, root page: %lu"
5601 		", zip size: %lu"
5602 		"\n  estimated statistics in dictionary:\n"
5603 		"    key vals: %lu, leaf pages: %lu, size pages: %lu\n"
5604 		"  real statistics:\n",
5605 		table->name.m_name, index->name(),
5606 		(ulong) index->space,
5607 		(ulong) index->page,
5608 		(ulong) fil_space_get_page_size(index->space, &found).physical(),
5609 		(ulong) n_vals,
5610 		(ulong) index->stat_n_leaf_pages,
5611 		(ulong) index->stat_index_size);
5612 
5613 	{
5614 		mtr_t	local_mtr;
5615 		page_t*	root;
5616 		ulint	page_level;
5617 
5618 		mtr_start(&local_mtr);
5619 
5620 		mtr_x_lock(&(index->lock), &local_mtr);
5621 		root = btr_root_get(index, &local_mtr);
5622 		page_level = btr_page_get_level(root, &local_mtr);
5623 
5624 		xtrabackup_stats_level(index, page_level);
5625 
5626 		mtr_commit(&local_mtr);
5627 	}
5628 
5629 	putc('\n', stdout);
5630 }
5631 				index = UT_LIST_GET_NEXT(indexes, index);
5632 			}
5633 		}
5634 
5635 skip:
5636 		mtr_start(&mtr);
5637 
5638 		btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
5639 	}
5640 
5641 	goto loop;
5642 	}
5643 
5644 end:
5645 	putc('\n', stdout);
5646 
5647 	fflush(stdout);
5648 
5649 	xb_filters_free();
5650 
5651 	/* shutdown InnoDB */
5652 	if(innodb_end())
5653 		exit(EXIT_FAILURE);
5654 
5655 	xb_keyring_shutdown();
5656 }
5657 
5658 /* ================= prepare ================= */
5659 
5660 static
5661 bool
check_log_header_checksum_0(const byte * buf)5662 check_log_header_checksum_0(
5663 /*========================*/
5664 	const byte*	buf)	/*!< in: buffer containing checkpoint info */
5665 {
5666 	/** Offset of the first checkpoint checksum */
5667 	static const uint CHECKSUM_1 = 288;
5668 	/** Offset of the second checkpoint checksum */
5669 	static const uint CHECKSUM_2 = CHECKSUM_1 + 4;
5670 
5671 	if (static_cast<uint32_t>(ut_fold_binary(buf, CHECKSUM_1))
5672 	    != mach_read_from_4(buf + CHECKSUM_1)
5673 	    || static_cast<uint32_t>(
5674 		    ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
5675 				   CHECKSUM_2 - LOG_CHECKPOINT_LSN))
5676 	    != mach_read_from_4(buf + CHECKSUM_2)) {
5677 		return(false);
5678 	}
5679 
5680 	return(true);
5681 }
5682 
5683 static
5684 void
update_log_temp_checkpoint_0(byte * buf,lsn_t lsn)5685 update_log_temp_checkpoint_0(
5686 	byte*	buf,
5687 	lsn_t	lsn)
5688 {
5689 	/** Offset of the first checkpoint checksum */
5690 	static const uint CHECKSUM_1 = 288;
5691 	/** Offset of the second checkpoint checksum */
5692 	static const uint CHECKSUM_2 = CHECKSUM_1 + 4;
5693 	/** Most significant bits of the checkpoint offset */
5694 	static const uint OFFSET_HIGH32 = CHECKSUM_2 + 12;
5695 	/** Least significant bits of the checkpoint offset */
5696 	static const uint OFFSET_LOW32 = 16;
5697 
5698 	ulint		fold;
5699 
5700 	mach_write_to_8(buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_LSN, lsn);
5701 	mach_write_to_4(buf + LOG_CHECKPOINT_1 + OFFSET_LOW32,
5702 			LOG_FILE_HDR_SIZE +
5703 			(lsn -
5704 			 ut_uint64_align_down(lsn, OS_FILE_LOG_BLOCK_SIZE)));
5705 	mach_write_to_4(buf + LOG_CHECKPOINT_1 + OFFSET_HIGH32, 0);
5706 	fold = ut_fold_binary(buf + LOG_CHECKPOINT_1, CHECKSUM_1);
5707 	mach_write_to_4(buf + LOG_CHECKPOINT_1 + CHECKSUM_1, fold);
5708 
5709 	fold = ut_fold_binary(buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_LSN,
5710 		CHECKSUM_2 - LOG_CHECKPOINT_LSN);
5711 	mach_write_to_4(buf + LOG_CHECKPOINT_1 + CHECKSUM_2, fold);
5712 
5713 	mach_write_to_8(buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_LSN, lsn);
5714 	mach_write_to_4(buf + LOG_CHECKPOINT_2 + OFFSET_LOW32,
5715 			LOG_FILE_HDR_SIZE +
5716 			(lsn -
5717 			 ut_uint64_align_down(lsn,
5718 					      OS_FILE_LOG_BLOCK_SIZE)));
5719 	mach_write_to_4(buf + LOG_CHECKPOINT_2
5720 			    + LOG_CHECKPOINT_OFFSET_HIGH32, 0);
5721         fold = ut_fold_binary(buf + LOG_CHECKPOINT_2, CHECKSUM_1);
5722         mach_write_to_4(buf + LOG_CHECKPOINT_2 + CHECKSUM_1, fold);
5723 
5724         fold = ut_fold_binary(buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_LSN,
5725 			      CHECKSUM_2 - LOG_CHECKPOINT_LSN);
5726         mach_write_to_4(buf + LOG_CHECKPOINT_2 + CHECKSUM_2, fold);
5727 }
5728 
5729 static
5730 void
update_log_temp_checkpoint(byte * buf,lsn_t lsn)5731 update_log_temp_checkpoint(
5732 	byte*	buf,
5733 	lsn_t	lsn)
5734 {
5735 	if (redo_log_version == REDO_LOG_V0) {
5736 		update_log_temp_checkpoint_0(buf, lsn);
5737 		return;
5738 	}
5739 
5740 	/* Overwrite the both checkpoint area. */
5741 
5742 	lsn_t lsn_offset;
5743 
5744 	lsn_offset = LOG_FILE_HDR_SIZE + (lsn -
5745 			ut_uint64_align_down(lsn, OS_FILE_LOG_BLOCK_SIZE));
5746 
5747 	mach_write_to_8(buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_LSN,
5748 			lsn);
5749 	mach_write_to_8(buf + LOG_CHECKPOINT_1 + LOG_CHECKPOINT_OFFSET,
5750 			lsn_offset);
5751 
5752 	mach_write_to_8(buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_LSN,
5753 			lsn);
5754 	mach_write_to_8(buf + LOG_CHECKPOINT_2 + LOG_CHECKPOINT_OFFSET,
5755 			lsn_offset);
5756 
5757 	log_block_set_checksum(buf, log_block_calc_checksum_crc32(buf));
5758 	log_block_set_checksum(buf + LOG_CHECKPOINT_1,
5759 		log_block_calc_checksum_crc32(buf + LOG_CHECKPOINT_1));
5760 	log_block_set_checksum(buf + LOG_CHECKPOINT_2,
5761 		log_block_calc_checksum_crc32(buf + LOG_CHECKPOINT_2));
5762 }
5763 
5764 static my_bool
xtrabackup_init_temp_log(void)5765 xtrabackup_init_temp_log(void)
5766 {
5767 	pfs_os_file_t	src_file = XB_FILE_UNDEFINED;
5768 	char		src_path[FN_REFLEN];
5769 	char		dst_path[FN_REFLEN];
5770 	bool		success;
5771 
5772 	ulint		field;
5773 	byte		*log_buf;
5774 
5775 	ib_uint64_t	file_size;
5776 
5777 	lsn_t		max_no;
5778 	lsn_t		max_lsn;
5779 	lsn_t		checkpoint_no;
5780 
5781 	bool		checkpoint_found;
5782 
5783 	IORequest	read_request(IORequest::READ);
5784 	IORequest	write_request(IORequest::WRITE);
5785 
5786 	max_no = 0;
5787 
5788 	log_buf = static_cast<byte*>(ut_malloc_nokey(UNIV_PAGE_SIZE_MAX * 128));
5789 	if (log_buf == NULL) {
5790 		goto error;
5791 	}
5792 
5793 	if (!xb_init_log_block_size()) {
5794 		goto error;
5795 	}
5796 
5797 	if(!xtrabackup_incremental_dir) {
5798 		sprintf(dst_path, "%s/ib_logfile0", xtrabackup_target_dir);
5799 		sprintf(src_path, "%s/%s", xtrabackup_target_dir,
5800 			XB_LOG_FILENAME);
5801 	} else {
5802 		sprintf(dst_path, "%s/ib_logfile0", xtrabackup_incremental_dir);
5803 		sprintf(src_path, "%s/%s", xtrabackup_incremental_dir,
5804 			XB_LOG_FILENAME);
5805 	}
5806 
5807 	os_normalize_path(dst_path);
5808 	os_normalize_path(src_path);
5809 retry:
5810 	src_file = os_file_create_simple_no_error_handling(0, src_path,
5811 							   OS_FILE_OPEN,
5812 							   OS_FILE_READ_WRITE,
5813 							   srv_read_only_mode,
5814 							   &success);
5815 	if (!success) {
5816 		/* The following call prints an error message */
5817 		os_file_get_last_error(TRUE);
5818 
5819 		msg("xtrabackup: Warning: cannot open %s. will try to find.\n",
5820 		    src_path);
5821 
5822 		/* check if ib_logfile0 may be xtrabackup_logfile */
5823 		src_file = os_file_create_simple_no_error_handling(0, dst_path,
5824 								   OS_FILE_OPEN,
5825 								   OS_FILE_READ_WRITE,
5826 								   srv_read_only_mode,
5827 								   &success);
5828 		if (!success) {
5829 			os_file_get_last_error(TRUE);
5830 			msg("  xtrabackup: Fatal error: cannot find %s.\n",
5831 			    src_path);
5832 
5833 			goto error;
5834 		}
5835 
5836 		success = os_file_read(read_request, src_file, log_buf, 0,
5837 				       LOG_FILE_HDR_SIZE);
5838 		if (!success) {
5839 			goto error;
5840 		}
5841 
5842 		if (ut_memcmp(log_buf + LOG_HEADER_CREATOR, (byte*)"xtrabkup",
5843 			      (sizeof "xtrabkup") - 1) == 0) {
5844 			msg("  xtrabackup: 'ib_logfile0' seems to be "
5845 			    "'xtrabackup_logfile'. will retry.\n");
5846 
5847 			os_file_close(src_file);
5848 			src_file = XB_FILE_UNDEFINED;
5849 
5850 			/* rename and try again */
5851 			success = os_file_rename(0, dst_path, src_path);
5852 			if (!success) {
5853 				goto error;
5854 			}
5855 
5856 			goto retry;
5857 		}
5858 
5859 		msg("  xtrabackup: Fatal error: cannot find %s.\n",
5860 		src_path);
5861 
5862 		os_file_close(src_file);
5863 		src_file = XB_FILE_UNDEFINED;
5864 
5865 		goto error;
5866 	}
5867 
5868 	file_size = os_file_get_size(src_file);
5869 
5870 
5871 	/* TODO: We should skip the following modifies, if it is not the first time. */
5872 
5873 	/* read log file header */
5874 	success = os_file_read(read_request, src_file, log_buf, 0,
5875 			       LOG_FILE_HDR_SIZE);
5876 	if (!success) {
5877 		goto error;
5878 	}
5879 
5880 	if (ut_memcmp(log_buf + LOG_HEADER_CREATOR, (byte *)"xtrabkup",
5881 		      (sizeof "xtrabkup") - 1) != 0) {
5882 		if (xtrabackup_incremental_dir) {
5883 			msg("xtrabackup: error: xtrabackup_logfile was already used "
5884 			    "to '--prepare'.\n");
5885 			goto error;
5886 		}
5887 		msg("xtrabackup: notice: xtrabackup_logfile was already used "
5888 		    "to '--prepare'.\n");
5889 		goto skip_modify;
5890 	}
5891 
5892 	checkpoint_found = false;
5893 
5894 	/* read last checkpoint lsn */
5895 	for (field = LOG_CHECKPOINT_1; field <= LOG_CHECKPOINT_2;
5896 			field += LOG_CHECKPOINT_2 - LOG_CHECKPOINT_1) {
5897 
5898 		/* InnoDB using CRC32 by default since 5.7.9+ */
5899 		if (log_block_get_checksum(log_buf + field)
5900 		    == log_block_calc_checksum_crc32(log_buf + field) &&
5901 		    mach_read_from_4(log_buf + LOG_HEADER_FORMAT)
5902 		    == LOG_HEADER_FORMAT_CURRENT) {
5903 			redo_log_version = REDO_LOG_V1;
5904 			if (!innodb_log_checksum_algorithm_specified) {
5905 				srv_log_checksum_algorithm =
5906 					SRV_CHECKSUM_ALGORITHM_CRC32;
5907 			}
5908 			if (!innodb_checksum_algorithm_specified) {
5909 				srv_checksum_algorithm =
5910 					SRV_CHECKSUM_ALGORITHM_CRC32;
5911 			}
5912 		} else if (check_log_header_checksum_0(log_buf + field)) {
5913 			redo_log_version = REDO_LOG_V0;
5914 			if (!innodb_log_checksum_algorithm_specified) {
5915 				srv_log_checksum_algorithm =
5916 					SRV_CHECKSUM_ALGORITHM_INNODB;
5917 			}
5918 			if (!innodb_checksum_algorithm_specified) {
5919 				srv_checksum_algorithm =
5920 					SRV_CHECKSUM_ALGORITHM_INNODB;
5921 			}
5922 		} else {
5923 			goto not_consistent;
5924 		}
5925 
5926 		checkpoint_no = mach_read_from_8(log_buf + field +
5927 						 LOG_CHECKPOINT_NO);
5928 
5929 		if (checkpoint_no >= max_no) {
5930 
5931 			max_no = checkpoint_no;
5932 			max_lsn = mach_read_from_8(log_buf + field +
5933 						   LOG_CHECKPOINT_LSN);
5934 			checkpoint_found = true;
5935 		}
5936 not_consistent:
5937 		;
5938 	}
5939 
5940 	if (!checkpoint_found) {
5941 		msg("xtrabackup: No valid checkpoint found.\n");
5942 		goto error;
5943 	}
5944 
5945 	mach_write_to_4(log_buf + LOG_HEADER_FORMAT,
5946 			redo_log_version == REDO_LOG_V0 ?
5947 			0 : LOG_HEADER_FORMAT_CURRENT);
5948 	update_log_temp_checkpoint(log_buf, max_lsn);
5949 
5950 	success = os_file_write(write_request, src_path, src_file, log_buf, 0,
5951 				LOG_FILE_HDR_SIZE);
5952 	if (!success) {
5953 		goto error;
5954 	}
5955 
5956 	/* expand file size (9/8) and align to UNIV_PAGE_SIZE_MAX */
5957 
5958 	if (file_size % UNIV_PAGE_SIZE_MAX) {
5959 		ulint n = UNIV_PAGE_SIZE_MAX -
5960 				(ulint) (file_size % UNIV_PAGE_SIZE_MAX);
5961 		memset(log_buf, 0, UNIV_PAGE_SIZE_MAX);
5962 		success = os_file_write(write_request, src_path, src_file,
5963 					log_buf, file_size, n);
5964 		if (!success) {
5965 			goto error;
5966 		}
5967 
5968 		file_size = os_file_get_size(src_file);
5969 	}
5970 
5971 	/* TODO: We should judge whether the file is already expanded or not... */
5972 	{
5973 		ulint	expand;
5974 
5975 		memset(log_buf, 0, UNIV_PAGE_SIZE_MAX * 128);
5976 		expand = (ulint) (file_size / UNIV_PAGE_SIZE_MAX / 8);
5977 
5978 		for (; expand > 128; expand -= 128) {
5979 			success = os_file_write(write_request, src_path,
5980 						src_file, log_buf,
5981 						file_size,
5982 						UNIV_PAGE_SIZE_MAX * 128);
5983 			if (!success) {
5984 				goto error;
5985 			}
5986 			file_size += UNIV_PAGE_SIZE_MAX * 128;
5987 		}
5988 
5989 		if (expand) {
5990 			success = os_file_write(write_request, src_path,
5991 						src_file, log_buf,
5992 						file_size,
5993 						expand * UNIV_PAGE_SIZE_MAX);
5994 			if (!success) {
5995 				goto error;
5996 			}
5997 			file_size += UNIV_PAGE_SIZE_MAX * expand;
5998 		}
5999 	}
6000 
6001 	/* make larger than 128 * UNIV_PAGE_SIZE_MAX */
6002 	if (file_size < 128 * UNIV_PAGE_SIZE_MAX) {
6003 		memset(log_buf, 0, UNIV_PAGE_SIZE_MAX);
6004 		while (file_size < 128 * UNIV_PAGE_SIZE_MAX) {
6005 			success = os_file_write(write_request, src_path,
6006 						src_file, log_buf,
6007 						file_size,
6008 						UNIV_PAGE_SIZE_MAX);
6009 			if (!success) {
6010 				goto error;
6011 			}
6012 			file_size += UNIV_PAGE_SIZE_MAX;
6013 		}
6014 		file_size = os_file_get_size(src_file);
6015 	}
6016 
6017 	msg("xtrabackup: xtrabackup_logfile detected: size=" UINT64PF ", "
6018 	    "start_lsn=(" LSN_PF ")\n", file_size, max_lsn);
6019 
6020 	os_file_close(src_file);
6021 	src_file = XB_FILE_UNDEFINED;
6022 
6023 	/* fake InnoDB */
6024 	innobase_log_files_in_group_save = innobase_log_files_in_group;
6025 	srv_log_group_home_dir_save = srv_log_group_home_dir;
6026 	innobase_log_file_size_save = innobase_log_file_size;
6027 
6028 	srv_log_group_home_dir = NULL;
6029 	innobase_log_file_size      = file_size;
6030 	innobase_log_files_in_group = 1;
6031 
6032 	srv_thread_concurrency = 0;
6033 
6034 	/* rename 'xtrabackup_logfile' to 'ib_logfile0' */
6035 	success = os_file_rename(0, src_path, dst_path);
6036 	if (!success) {
6037 		goto error;
6038 	}
6039 	xtrabackup_logfile_is_renamed = TRUE;
6040 
6041 	if (log_buf != NULL) {
6042 		ut_free(log_buf);
6043 	}
6044 
6045 	return(FALSE);
6046 
6047 skip_modify:
6048 	if (log_buf != NULL) {
6049 		ut_free(log_buf);
6050 	}
6051 	os_file_close(src_file);
6052 	src_file = XB_FILE_UNDEFINED;
6053 	return(FALSE);
6054 
6055 error:
6056 	if (log_buf != NULL) {
6057 		ut_free(log_buf);
6058 	}
6059 	if (src_file != XB_FILE_UNDEFINED)
6060 		os_file_close(src_file);
6061 	msg("xtrabackup: Error: xtrabackup_init_temp_log() failed.\n");
6062 	return(TRUE); /*ERROR*/
6063 }
6064 
6065 /***********************************************************************
6066 Generates path to the meta file path from a given path to an incremental .delta
6067 by replacing trailing ".delta" with ".meta", or returns error if 'delta_path'
6068 does not end with the ".delta" character sequence.
6069 @return TRUE on success, FALSE on error. */
6070 static
6071 ibool
get_meta_path(const char * delta_path,char * meta_path)6072 get_meta_path(
6073 	const char	*delta_path,	/* in: path to a .delta file */
6074 	char 		*meta_path)	/* out: path to the corresponding .meta
6075 					file */
6076 {
6077 	size_t		len = strlen(delta_path);
6078 
6079 	if (len <= 6 || strcmp(delta_path + len - 6, ".delta")) {
6080 		return FALSE;
6081 	}
6082 	memcpy(meta_path, delta_path, len - 6);
6083 	strcpy(meta_path + len - 6, XB_DELTA_INFO_SUFFIX);
6084 
6085 	return TRUE;
6086 }
6087 
6088 /****************************************************************//**
6089 Create a new tablespace on disk and return the handle to its opened
6090 file. Code adopted from fiL_ibd_create with
6091 the main difference that only disk file is created without updating
6092 the InnoDB in-memory dictionary data structures.
6093 
6094 @return TRUE on success, FALSE on error.  */
6095 static
6096 bool
xb_space_create_file(const char * path,ulint space_id,ulint flags,pfs_os_file_t * file)6097 xb_space_create_file(
6098 /*==================*/
6099 	const char*	path,		/*!<in: path to tablespace */
6100 	ulint		space_id,	/*!<in: space id */
6101 	ulint		flags __attribute__((unused)),/*!<in: tablespace
6102 					flags */
6103 	pfs_os_file_t*	file)		/*!<out: file handle */
6104 {
6105 	const ulint	size = FIL_IBD_FILE_INITIAL_SIZE;
6106 	dberr_t		err;
6107 	byte*		buf2;
6108 	byte*		page;
6109 	bool		success;
6110 
6111 	IORequest	write_request(IORequest::WRITE);
6112 
6113 	ut_ad(!is_system_tablespace(space_id));
6114 	ut_ad(!srv_read_only_mode);
6115 	ut_a(space_id < SRV_LOG_SPACE_FIRST_ID);
6116 	ut_a(fsp_flags_is_valid(flags));
6117 
6118 	/* Create the subdirectories in the path, if they are
6119 	not there already. */
6120 	err = os_file_create_subdirs_if_needed(path);
6121 	if (err != DB_SUCCESS) {
6122 		return(false);
6123 	}
6124 
6125 	*file = os_file_create(
6126 		innodb_data_file_key, path,
6127 		OS_FILE_CREATE | OS_FILE_ON_ERROR_NO_EXIT,
6128 		OS_FILE_NORMAL,
6129 		OS_DATA_FILE,
6130 		srv_read_only_mode,
6131 		&success);
6132 
6133 	if (!success) {
6134 		/* The following call will print an error message */
6135 		ulint	error = os_file_get_last_error(true);
6136 
6137 		ib::error() << "Cannot create file '" << path << "'";
6138 
6139 		if (error == OS_FILE_ALREADY_EXISTS) {
6140 			ib::error() << "The file '" << path << "'"
6141 				" already exists though the"
6142 				" corresponding table did not exist"
6143 				" in the InnoDB data dictionary."
6144 				" Have you moved InnoDB .ibd files"
6145 				" around without using the SQL commands"
6146 				" DISCARD TABLESPACE and IMPORT TABLESPACE,"
6147 				" or did mysqld crash in the middle of"
6148 				" CREATE TABLE?"
6149 				" You can resolve the problem by removing"
6150 				" the file '" << path
6151 				<< "' under the 'datadir' of MySQL.";
6152 
6153 			return(false);
6154 		}
6155 
6156 		return(false);
6157 	}
6158 
6159 
6160 #if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
6161 	if (fil_fusionio_enable_atomic_write(*file)) {
6162 
6163 		/* This is required by FusionIO HW/Firmware */
6164 		int	ret = posix_fallocate(file->m_file, 0, size * UNIV_PAGE_SIZE);
6165 
6166 		if (ret != 0) {
6167 
6168 			ib::error() <<
6169 				"posix_fallocate(): Failed to preallocate"
6170 				" data for file " << path
6171 				<< ", desired size "
6172 				<< size * UNIV_PAGE_SIZE
6173 				<< " Operating system error number " << ret
6174 				<< ". Check"
6175 				" that the disk is not full or a disk quota"
6176 				" exceeded. Make sure the file system supports"
6177 				" this function. Some operating system error"
6178 				" numbers are described at " REFMAN
6179 				" operating-system-error-codes.html";
6180 
6181 			success = false;
6182 		} else {
6183 			success = true;
6184 		}
6185 	} else {
6186 
6187 		success = os_file_set_size(
6188 			path, *file, size * UNIV_PAGE_SIZE, srv_read_only_mode);
6189 	}
6190 #else
6191 	success = os_file_set_size(
6192 		path, *file, size * UNIV_PAGE_SIZE, srv_read_only_mode);
6193 #endif /* !NO_FALLOCATE && UNIV_LINUX */
6194 
6195 	if (!success) {
6196 		os_file_close(*file);
6197 		os_file_delete(innodb_data_file_key, path);
6198 		return(false);
6199 	}
6200 
6201 	/* printf("Creating tablespace %s id %lu\n", path, space_id); */
6202 
6203 	/* We have to write the space id to the file immediately and flush the
6204 	file to disk. This is because in crash recovery we must be aware what
6205 	tablespaces exist and what are their space id's, so that we can apply
6206 	the log records to the right file. It may take quite a while until
6207 	buffer pool flush algorithms write anything to the file and flush it to
6208 	disk. If we would not write here anything, the file would be filled
6209 	with zeros from the call of os_file_set_size(), until a buffer pool
6210 	flush would write to it. */
6211 
6212 	buf2 = static_cast<byte*>(ut_malloc_nokey(3 * UNIV_PAGE_SIZE));
6213 	/* Align the memory for file i/o if we might have O_DIRECT set */
6214 	page = static_cast<byte*>(ut_align(buf2, UNIV_PAGE_SIZE));
6215 
6216 	memset(page, '\0', UNIV_PAGE_SIZE);
6217 
6218 	/* Add the UNIV_PAGE_SIZE to the table flags and write them to the
6219 	tablespace header. */
6220 	flags = fsp_flags_set_page_size(flags, univ_page_size);
6221 	fsp_header_init_fields(page, space_id, flags);
6222 	mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
6223 
6224 	const page_size_t	page_size(flags);
6225 
6226 	if (!page_size.is_compressed()) {
6227 		buf_flush_init_for_writing(
6228 			NULL, page, NULL, 0,
6229 			fsp_is_checksum_disabled(space_id));
6230 		success = os_file_write(write_request, path, *file, page, 0,
6231 					page_size.physical());
6232 	} else {
6233 		page_zip_des_t	page_zip;
6234 
6235 		page_zip_set_size(&page_zip, page_size.physical());
6236 		page_zip.data = page + UNIV_PAGE_SIZE;
6237 #ifdef UNIV_DEBUG
6238 		page_zip.m_start =
6239 #endif /* UNIV_DEBUG */
6240 			page_zip.m_end = page_zip.m_nonempty =
6241 			page_zip.n_blobs = 0;
6242 
6243 		buf_flush_init_for_writing(
6244 			NULL, page, &page_zip, 0,
6245 			fsp_is_checksum_disabled(space_id));
6246 		success = os_file_write(write_request, path, *file,
6247 					page_zip.data, 0,
6248 					page_size.physical());
6249 	}
6250 
6251 	ut_free(buf2);
6252 
6253 	if (!success) {
6254 		ib::error() << "Could not write the first page to"
6255 			<< " tablespace '" << path << "'";
6256 		os_file_close(*file);
6257 		os_file_delete(innodb_data_file_key, path);
6258 		return(false);
6259 	}
6260 
6261 	success = os_file_flush(*file);
6262 
6263 	if (!success) {
6264 		ib::error() << "File flush of tablespace '"
6265 			<< path << "' failed";
6266 		os_file_close(*file);
6267 		os_file_delete(innodb_data_file_key, path);
6268 		return(false);
6269 	}
6270 
6271 	return(true);
6272 }
6273 
6274 /***********************************************************************
6275 Searches for matching tablespace file for given .delta file and space_id
6276 in given directory. When matching tablespace found, renames it to match the
6277 name of .delta file. If there was a tablespace with matching name and
6278 mismatching ID, renames it to xtrabackup_tmp_#ID.ibd. If there was no
6279 matching file, creates a new tablespace.
6280 @return file handle of matched or created file */
6281 static
6282 pfs_os_file_t
xb_delta_open_matching_space(const char * dbname,const char * name,ulint space_id,ulint space_flags,ulint zip_size,char * real_name,size_t real_name_len,bool * success)6283 xb_delta_open_matching_space(
6284 	const char*	dbname,		/* in: path to destination database dir */
6285 	const char*	name,		/* in: name of delta file (without .delta) */
6286 	ulint		space_id,	/* in: space id of delta file */
6287 	ulint		space_flags,	/* in: space flags of delta file */
6288 	ulint		zip_size,	/* in: zip_size of tablespace */
6289 	char*		real_name,	/* out: full path of destination file */
6290 	size_t		real_name_len,	/* out: buffer size for real_name */
6291 	bool* 		success)	/* out: indicates error. TRUE = success */
6292 {
6293 	char			dest_dir[FN_REFLEN];
6294 	char			dest_space_name[FN_REFLEN];
6295 	bool			ok;
6296 	fil_space_t*		fil_space;
6297 	pfs_os_file_t		file	= XB_FILE_UNDEFINED;
6298 	xb_filter_entry_t*	table;
6299 
6300 	*success = false;
6301 
6302 	if (dbname) {
6303 		snprintf(dest_dir, FN_REFLEN, "%s/%s",
6304 			xtrabackup_target_dir, dbname);
6305 		os_normalize_path(dest_dir);
6306 
6307 		snprintf(dest_space_name, FN_REFLEN, "%s/%s", dbname, name);
6308 	} else {
6309 		snprintf(dest_dir, FN_REFLEN, "%s", xtrabackup_target_dir);
6310 		os_normalize_path(dest_dir);
6311 
6312 		snprintf(dest_space_name, FN_REFLEN, "%s", name);
6313 	}
6314 
6315 	snprintf(real_name, real_name_len,
6316 		 "%s/%s",
6317 		 xtrabackup_target_dir, dest_space_name);
6318 	os_normalize_path(real_name);
6319 	/* Truncate ".ibd" */
6320 	dest_space_name[strlen(dest_space_name) - 4] = '\0';
6321 
6322 	/* Create the database directory if it doesn't exist yet */
6323 	if (!os_file_create_directory(dest_dir, FALSE)) {
6324 		msg("xtrabackup: error: cannot create dir %s\n", dest_dir);
6325 		return file;
6326 	}
6327 
6328 	if (space_id != ULINT_UNDEFINED
6329 	    && !fil_is_user_tablespace_id(space_id)) {
6330 		goto found;
6331 	}
6332 
6333 	/* remember space name for further reference */
6334 	table = static_cast<xb_filter_entry_t *>
6335 		(ut_malloc_nokey(sizeof(xb_filter_entry_t) +
6336 			strlen(dest_space_name) + 1));
6337 
6338 	table->name = ((char*)table) + sizeof(xb_filter_entry_t);
6339 	strcpy(table->name, dest_space_name);
6340 	HASH_INSERT(xb_filter_entry_t, name_hash, inc_dir_tables_hash,
6341 			ut_fold_string(table->name), table);
6342 
6343 	mutex_enter(&fil_system->mutex);
6344 	fil_space = fil_space_get_by_name(dest_space_name);
6345 	mutex_exit(&fil_system->mutex);
6346 
6347 	if (fil_space != NULL) {
6348 		if (fil_space->id == space_id || space_id == ULINT_UNDEFINED) {
6349 			/* we found matching space */
6350 			goto found;
6351 		} else {
6352 
6353 			char		tmpname[FN_REFLEN];
6354 			char		*oldpath;
6355 			bool		exists;
6356 			os_file_type_t	type;
6357 
6358 			if (dbname != NULL) {
6359 				snprintf(tmpname, FN_REFLEN,
6360 					 "%s/xtrabackup_tmp_#%lu",
6361 					 dbname, fil_space->id);
6362 			} else {
6363 				snprintf(tmpname, FN_REFLEN,
6364 					 "./xtrabackup_tmp_#%lu",
6365 					 fil_space->id);
6366 			}
6367 
6368 			oldpath = mem_strdup(
6369 				UT_LIST_GET_FIRST(fil_space->chain)->name);
6370 
6371 			msg("xtrabackup: Renaming %s to %s.ibd\n",
6372 				fil_space->name, tmpname);
6373 
6374 
6375 			ut_a(os_file_status(oldpath, &exists, &type));
6376 
6377 			if (exists && !fil_rename_tablespace(fil_space->id,
6378 						   oldpath, tmpname, NULL))
6379 			{
6380 				msg("xtrabackup: Cannot rename %s to %s\n",
6381 					fil_space->name, tmpname);
6382 				ut_free(oldpath);
6383 				goto exit;
6384 			}
6385 			ut_free(oldpath);
6386 		}
6387 	}
6388 
6389 	if (space_id == ULINT_UNDEFINED)
6390 	{
6391 		msg("xtrabackup: Error: Cannot handle DDL operation on "
6392 		    "tablespace %s\n", dest_space_name);
6393 		exit(EXIT_FAILURE);
6394 	}
6395 	mutex_enter(&fil_system->mutex);
6396 	fil_space = fil_space_get_by_id(space_id);
6397 	mutex_exit(&fil_system->mutex);
6398 	if (fil_space != NULL) {
6399 		char		tmpname[FN_REFLEN];
6400 		char		*oldpath;
6401 		bool		exists;
6402 		os_file_type_t	type;
6403 
6404 		strncpy(tmpname, dest_space_name, FN_REFLEN);
6405 
6406 		oldpath = mem_strdup(UT_LIST_GET_FIRST(fil_space->chain)->name);
6407 
6408 		msg("xtrabackup: Renaming %s to %s\n",
6409 		    fil_space->name, dest_space_name);
6410 
6411 		ut_a(os_file_status(oldpath, &exists, &type));
6412 
6413 		if (exists && !fil_rename_tablespace(fil_space->id, oldpath,
6414 					   tmpname, NULL))
6415 		{
6416 			msg("xtrabackup: Cannot rename %s to %s\n",
6417 				fil_space->name, dest_space_name);
6418 			ut_free(oldpath);
6419 			goto exit;
6420 		}
6421 		ut_free(oldpath);
6422 
6423 		goto found;
6424 	}
6425 
6426 	/* No matching space found. create the new one.  */
6427 
6428 	if (!fil_space_create(dest_space_name, space_id, space_flags,
6429 			      FIL_TYPE_TABLESPACE)) {
6430 		msg("xtrabackup: Cannot create tablespace %s\n",
6431 			dest_space_name);
6432 		goto exit;
6433 	}
6434 
6435 	/* Calculate correct tablespace flags for compressed tablespaces.  */
6436 	if (zip_size != 0 && zip_size != ULINT_UNDEFINED) {
6437 		space_flags
6438 			|= (get_bit_shift(zip_size >> PAGE_ZIP_MIN_SIZE_SHIFT
6439 					 << 1)
6440 			   << DICT_TF_ZSSIZE_SHIFT)
6441 			| DICT_TF_COMPACT
6442 			| (DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT);
6443 		ut_a(page_size_t(space_flags).physical() == zip_size);
6444 	}
6445 	*success = xb_space_create_file(real_name, space_id, space_flags,
6446 					&file);
6447 	goto exit;
6448 
6449 found:
6450 	/* open the file and return it's handle */
6451 
6452 	file = os_file_create_simple_no_error_handling(0, real_name,
6453 						       OS_FILE_OPEN,
6454 						       OS_FILE_READ_WRITE,
6455 						       srv_read_only_mode,
6456 						       &ok);
6457 
6458 	if (ok) {
6459 		*success = true;
6460 	} else {
6461 		msg("xtrabackup: Cannot open file %s\n", real_name);
6462 	}
6463 
6464 exit:
6465 
6466 	return file;
6467 }
6468 
6469 /************************************************************************
6470 Applies a given .delta file to the corresponding data file.
6471 @return TRUE on success */
6472 static
6473 ibool
xtrabackup_apply_delta(const char * dirname,const char * dbname,const char * filename,void *)6474 xtrabackup_apply_delta(
6475 	const char*	dirname,	/* in: dir name of incremental */
6476 	const char*	dbname,		/* in: database name (ibdata: NULL) */
6477 	const char*	filename,	/* in: file name (not a path),
6478 					including the .delta extension */
6479 	void*		/*data*/)
6480 {
6481 	pfs_os_file_t	src_file = XB_FILE_UNDEFINED;
6482 	pfs_os_file_t	dst_file = XB_FILE_UNDEFINED;
6483 	char	src_path[FN_REFLEN * 2 + 2];
6484 	char	dst_path[FN_REFLEN * 2 + 2];
6485 	char	meta_path[FN_REFLEN];
6486 	char	space_name[FN_REFLEN];
6487 	bool	success;
6488 
6489 	ibool	last_buffer = FALSE;
6490 	ulint	page_in_buffer;
6491 	ulint	incremental_buffers = 0;
6492 
6493 	xb_delta_info_t info;
6494 	ulint		page_size;
6495 	ulint		page_size_shift;
6496 	byte*		incremental_buffer_base = NULL;
6497 	byte*		incremental_buffer;
6498 
6499 	size_t		offset;
6500 
6501 	IORequest	read_request(IORequest::READ);
6502 	IORequest	write_request(IORequest::WRITE);
6503 
6504 	ut_a(xtrabackup_incremental);
6505 
6506 	if (dbname) {
6507 		snprintf(src_path, sizeof(src_path), "%s/%s/%s",
6508 			 dirname, dbname, filename);
6509 		snprintf(dst_path, sizeof(dst_path), "%s/%s/%s",
6510 			 xtrabackup_real_target_dir, dbname, filename);
6511 	} else {
6512 		snprintf(src_path, sizeof(src_path), "%s/%s",
6513 			 dirname, filename);
6514 		snprintf(dst_path, sizeof(dst_path), "%s/%s",
6515 			 xtrabackup_real_target_dir, filename);
6516 	}
6517 	dst_path[strlen(dst_path) - 6] = '\0';
6518 
6519 	strncpy(space_name, filename, FN_REFLEN);
6520 	space_name[strlen(space_name) -  6] = 0;
6521 
6522 	if (!get_meta_path(src_path, meta_path)) {
6523 		goto error;
6524 	}
6525 
6526 	os_normalize_path(dst_path);
6527 	os_normalize_path(src_path);
6528 	os_normalize_path(meta_path);
6529 
6530 	if (!xb_read_delta_metadata(meta_path, &info)) {
6531 		goto error;
6532 	}
6533 
6534 	page_size = info.page_size;
6535 	page_size_shift = get_bit_shift(page_size);
6536 	msg("xtrabackup: page size for %s is %lu bytes space id is %lu\n",
6537 	    src_path, page_size, info.space_id);
6538 	if (page_size_shift < 10 ||
6539 	    page_size_shift > UNIV_PAGE_SIZE_SHIFT_MAX) {
6540 		msg("xtrabackup: error: invalid value of page_size "
6541 		    "(%lu bytes) read from %s\n", page_size, meta_path);
6542 		goto error;
6543 	}
6544 
6545 	src_file = os_file_create_simple_no_error_handling(0, src_path,
6546 							   OS_FILE_OPEN,
6547 							   OS_FILE_READ_WRITE,
6548 							   srv_read_only_mode,
6549 							   &success);
6550 	if (!success) {
6551 		os_file_get_last_error(TRUE);
6552 		msg("xtrabackup: error: cannot open %s\n", src_path);
6553 		goto error;
6554 	}
6555 
6556 	posix_fadvise(src_file.m_file, 0, 0, POSIX_FADV_SEQUENTIAL);
6557 
6558 	os_file_set_nocache(src_file.m_file, src_path, "OPEN");
6559 
6560 	dst_file = xb_delta_open_matching_space(dbname, space_name,
6561 						info.space_id, info.space_flags,
6562 						info.zip_size, dst_path,
6563 						sizeof(dst_path), &success);
6564 	if (!success) {
6565 		msg("xtrabackup: error: cannot open %s\n", dst_path);
6566 		goto error;
6567 	}
6568 
6569 	posix_fadvise(dst_file.m_file, 0, 0, POSIX_FADV_DONTNEED);
6570 
6571 	os_file_set_nocache(dst_file.m_file, dst_path, "OPEN");
6572 
6573 	/* allocate buffer for incremental backup */
6574 	incremental_buffer_base = static_cast<byte *>
6575 		(ut_malloc_nokey((page_size / 4 + 1) * page_size +
6576 			UNIV_PAGE_SIZE_MAX));
6577 	incremental_buffer = static_cast<byte *>
6578 		(ut_align(incremental_buffer_base, UNIV_PAGE_SIZE_MAX));
6579 
6580 	msg("Applying %s to %s...\n", src_path, dst_path);
6581 
6582 	while (!last_buffer) {
6583 		ulint cluster_header;
6584 
6585 		/* read to buffer */
6586 		/* first block of block cluster */
6587 		offset = ((incremental_buffers * (page_size / 4))
6588 			 << page_size_shift);
6589 		success = os_file_read(read_request, src_file,
6590 				       incremental_buffer, offset, page_size);
6591 		if (!success) {
6592 			goto error;
6593 		}
6594 
6595 		cluster_header = mach_read_from_4(incremental_buffer);
6596 		switch(cluster_header) {
6597 			case 0x78747261UL: /*"xtra"*/
6598 				break;
6599 			case 0x58545241UL: /*"XTRA"*/
6600 				last_buffer = TRUE;
6601 				break;
6602 			default:
6603 				msg("xtrabackup: error: %s seems not "
6604 				    ".delta file.\n", src_path);
6605 				goto error;
6606 		}
6607 
6608 		for (page_in_buffer = 1; page_in_buffer < page_size / 4;
6609 		     page_in_buffer++) {
6610 			if (mach_read_from_4(incremental_buffer +
6611 					     page_in_buffer * 4)
6612 			    == 0xFFFFFFFFUL)
6613 				break;
6614 		}
6615 
6616 		ut_a(last_buffer || page_in_buffer == page_size / 4);
6617 
6618 		/* read whole of the cluster */
6619 		success = os_file_read(read_request, src_file,
6620 				       incremental_buffer, offset,
6621 				       page_in_buffer * page_size);
6622 		if (!success) {
6623 			goto error;
6624 		}
6625 
6626 		posix_fadvise(src_file.m_file, offset,
6627 			      page_in_buffer * page_size,
6628 			      POSIX_FADV_DONTNEED);
6629 
6630 		for (page_in_buffer = 1; page_in_buffer < page_size / 4;
6631 		     page_in_buffer++) {
6632 			ulint offset_on_page;
6633 
6634 			offset_on_page = mach_read_from_4(incremental_buffer +
6635 							  page_in_buffer * 4);
6636 
6637 			if (offset_on_page == 0xFFFFFFFFUL)
6638 				break;
6639 
6640 			success = os_file_write(write_request, dst_path,
6641 						dst_file,
6642 						incremental_buffer +
6643 						page_in_buffer * page_size,
6644 						(offset_on_page <<
6645 						 page_size_shift),
6646 						page_size);
6647 			if (!success) {
6648 				goto error;
6649 			}
6650 		}
6651 
6652 		incremental_buffers++;
6653 	}
6654 
6655 	if (incremental_buffer_base)
6656 		ut_free(incremental_buffer_base);
6657 	if (src_file != XB_FILE_UNDEFINED)
6658 		os_file_close(src_file);
6659 	if (dst_file != XB_FILE_UNDEFINED)
6660 		os_file_close(dst_file);
6661 	return TRUE;
6662 
6663 error:
6664 	if (incremental_buffer_base)
6665 		ut_free(incremental_buffer_base);
6666 	if (src_file != XB_FILE_UNDEFINED)
6667 		os_file_close(src_file);
6668 	if (dst_file != XB_FILE_UNDEFINED)
6669 		os_file_close(dst_file);
6670 	msg("xtrabackup: Error: xtrabackup_apply_delta(): "
6671 	    "failed to apply %s to %s.\n", src_path, dst_path);
6672 	return FALSE;
6673 }
6674 
6675 /************************************************************************
6676 Callback to handle datadir entry. Function of this type will be called
6677 for each entry which matches the mask by xb_process_datadir.
6678 @return should return TRUE on success */
6679 typedef ibool (*handle_datadir_entry_func_t)(
6680 /*=========================================*/
6681 	const char*	data_home_dir,		/*!<in: path to datadir */
6682 	const char*	db_name,		/*!<in: database name */
6683 	const char*	file_name,		/*!<in: file name with suffix */
6684 	void*		arg);			/*!<in: caller-provided data */
6685 
6686 /************************************************************************
6687 Callback to handle datadir entry. Deletes entry if it has no matching
6688 fil_space in fil_system directory.
6689 @return FALSE if delete attempt was unsuccessful */
6690 static
6691 ibool
rm_if_not_found(const char * data_home_dir,const char * db_name,const char * file_name,void * arg)6692 rm_if_not_found(
6693 	const char*	data_home_dir,		/*!<in: path to datadir */
6694 	const char*	db_name,		/*!<in: database name */
6695 	const char*	file_name,		/*!<in: file name with suffix */
6696 	void*		arg __attribute__((unused)))
6697 {
6698 	char			name[FN_REFLEN];
6699 	xb_filter_entry_t*	table;
6700 
6701 	if (db_name != NULL) {
6702 		snprintf(name, FN_REFLEN, "%s/%s", db_name, file_name);
6703 	} else {
6704 		snprintf(name, FN_REFLEN, "%s", file_name);
6705 	}
6706 	/* Truncate ".ibd" */
6707 	name[strlen(name) - 4] = '\0';
6708 
6709 	HASH_SEARCH(name_hash, inc_dir_tables_hash, ut_fold_string(name),
6710 		    xb_filter_entry_t*,
6711 		    table, (void) 0,
6712 		    !strcmp(table->name, name));
6713 
6714 	if (!table) {
6715 		if (db_name != NULL) {
6716 			snprintf(name, FN_REFLEN, "%s/%s/%s", data_home_dir,
6717 				 db_name, file_name);
6718 		} else {
6719 			snprintf(name, FN_REFLEN, "%s/%s", data_home_dir,
6720 				 file_name);
6721 		}
6722 		return os_file_delete(0, name);
6723 	}
6724 
6725 	return(TRUE);
6726 }
6727 
6728 /************************************************************************
6729 Function enumerates files in datadir (provided by path) which are matched
6730 by provided suffix. For each entry callback is called.
6731 @return FALSE if callback for some entry returned FALSE */
6732 static
6733 ibool
xb_process_datadir(const char * path,const char * suffix,handle_datadir_entry_func_t func,void * data)6734 xb_process_datadir(
6735 	const char*			path,	/*!<in: datadir path */
6736 	const char*			suffix,	/*!<in: suffix to match
6737 						against */
6738 	handle_datadir_entry_func_t	func,	/*!<in: callback */
6739 	void*				data)	/*!<in: additional argument for
6740 						callback */
6741 {
6742 	ulint		ret;
6743 	char		dbpath[FN_REFLEN];
6744 	os_file_dir_t	dir;
6745 	os_file_dir_t	dbdir;
6746 	os_file_stat_t	dbinfo;
6747 	os_file_stat_t	fileinfo;
6748 	ulint		suffix_len;
6749 	dberr_t		err 		= DB_SUCCESS;
6750 	static char	current_dir[2];
6751 
6752 	current_dir[0] = FN_CURLIB;
6753 	current_dir[1] = 0;
6754 	srv_data_home = current_dir;
6755 
6756 	suffix_len = strlen(suffix);
6757 
6758 	/* datafile */
6759 	dbdir = os_file_opendir(path, false);
6760 
6761 	if (dbdir != NULL) {
6762 		ret = fil_file_readdir_next_file(&err, path, dbdir,
6763 							&fileinfo);
6764 		while (ret == 0) {
6765 			if (fileinfo.type == OS_FILE_TYPE_DIR) {
6766 				goto next_file_item_1;
6767 			}
6768 
6769 			if (strlen(fileinfo.name) > suffix_len
6770 			    && 0 == strcmp(fileinfo.name +
6771 					strlen(fileinfo.name) - suffix_len,
6772 					suffix)) {
6773 				if (!func(
6774 					    path, NULL,
6775 					    fileinfo.name, data))
6776 				{
6777 					return(FALSE);
6778 				}
6779 			}
6780 next_file_item_1:
6781 			ret = fil_file_readdir_next_file(&err,
6782 							path, dbdir,
6783 							&fileinfo);
6784 		}
6785 
6786 		os_file_closedir(dbdir);
6787 	} else {
6788 		msg("xtrabackup: Cannot open dir %s\n",
6789 		    path);
6790 	}
6791 
6792 	/* single table tablespaces */
6793 	dir = os_file_opendir(path, false);
6794 
6795 	if (dir == NULL) {
6796 		msg("xtrabackup: Cannot open dir %s\n",
6797 		    path);
6798 	}
6799 
6800 		ret = fil_file_readdir_next_file(&err, path, dir,
6801 								&dbinfo);
6802 	while (ret == 0) {
6803 		if (dbinfo.type == OS_FILE_TYPE_FILE
6804 		    || dbinfo.type == OS_FILE_TYPE_UNKNOWN) {
6805 
6806 		        goto next_datadir_item;
6807 		}
6808 
6809 		fn_format(dbpath, dbinfo.name, path, "", MYF(0));
6810 		os_normalize_path(dbpath);
6811 
6812 		dbdir = os_file_opendir(dbpath, false);
6813 
6814 		if (dbdir != NULL) {
6815 
6816 			ret = fil_file_readdir_next_file(&err, dbpath, dbdir,
6817 								&fileinfo);
6818 			while (ret == 0) {
6819 
6820 			        if (fileinfo.type == OS_FILE_TYPE_DIR) {
6821 
6822 				        goto next_file_item_2;
6823 				}
6824 
6825 				if (strlen(fileinfo.name) > suffix_len
6826 				    && 0 == strcmp(fileinfo.name +
6827 						strlen(fileinfo.name) -
6828 								suffix_len,
6829 						suffix)) {
6830 					/* The name ends in suffix; process
6831 					the file */
6832 					if (!func(
6833 						    path,
6834 						    dbinfo.name,
6835 						    fileinfo.name, data))
6836 					{
6837 						return(FALSE);
6838 					}
6839 				}
6840 next_file_item_2:
6841 				ret = fil_file_readdir_next_file(&err,
6842 								dbpath, dbdir,
6843 								&fileinfo);
6844 			}
6845 
6846 			os_file_closedir(dbdir);
6847 		}
6848 next_datadir_item:
6849 		ret = fil_file_readdir_next_file(&err,
6850 						path,
6851 								dir, &dbinfo);
6852 	}
6853 
6854 	os_file_closedir(dir);
6855 
6856 	return(TRUE);
6857 }
6858 
6859 /************************************************************************
6860 Applies all .delta files from incremental_dir to the full backup.
6861 @return TRUE on success. */
6862 static
6863 ibool
xtrabackup_apply_deltas()6864 xtrabackup_apply_deltas()
6865 {
6866 	return xb_process_datadir(xtrabackup_incremental_dir, ".delta",
6867 		xtrabackup_apply_delta, NULL);
6868 }
6869 
6870 static my_bool
xtrabackup_close_temp_log(my_bool clear_flag)6871 xtrabackup_close_temp_log(my_bool clear_flag)
6872 {
6873 	pfs_os_file_t	src_file = XB_FILE_UNDEFINED;
6874 	char		src_path[FN_REFLEN];
6875 	char		dst_path[FN_REFLEN];
6876 	bool		success;
6877 	byte		log_buf[UNIV_PAGE_SIZE_MAX];
6878 	IORequest	read_request(IORequest::READ);
6879 	IORequest	write_request(IORequest::WRITE);
6880 
6881 	if (!xtrabackup_logfile_is_renamed)
6882 		return(FALSE);
6883 
6884 	/* rename 'ib_logfile0' to 'xtrabackup_logfile' */
6885 	if(!xtrabackup_incremental_dir) {
6886 		sprintf(dst_path, "%s/ib_logfile0", xtrabackup_target_dir);
6887 		sprintf(src_path, "%s/%s", xtrabackup_target_dir,
6888 			XB_LOG_FILENAME);
6889 	} else {
6890 		sprintf(dst_path, "%s/ib_logfile0", xtrabackup_incremental_dir);
6891 		sprintf(src_path, "%s/%s", xtrabackup_incremental_dir,
6892 			XB_LOG_FILENAME);
6893 	}
6894 
6895 	os_normalize_path(dst_path);
6896 	os_normalize_path(src_path);
6897 
6898 	success = os_file_rename(0, dst_path, src_path);
6899 	if (!success) {
6900 		goto error;
6901 	}
6902 	xtrabackup_logfile_is_renamed = FALSE;
6903 
6904 	if (!clear_flag)
6905 		return(FALSE);
6906 
6907 	/* clear LOG_HEADER_CREATOR field */
6908 	src_file = os_file_create_simple_no_error_handling(0, src_path,
6909 							   OS_FILE_OPEN,
6910 							   OS_FILE_READ_WRITE,
6911 							   srv_read_only_mode,
6912 							   &success);
6913 	if (!success) {
6914 		goto error;
6915 	}
6916 
6917 	success = os_file_read(read_request, src_file, log_buf, 0,
6918 			       LOG_FILE_HDR_SIZE);
6919 	if (!success) {
6920 		goto error;
6921 	}
6922 
6923 	memset(log_buf + LOG_HEADER_CREATOR, ' ', 4);
6924 
6925 	success = os_file_write(write_request, src_path, src_file, log_buf, 0,
6926 				LOG_FILE_HDR_SIZE);
6927 	if (!success) {
6928 		goto error;
6929 	}
6930 
6931 	// os_file_close(src_file);
6932 	src_file = XB_FILE_UNDEFINED;
6933 
6934 	innobase_log_files_in_group = innobase_log_files_in_group_save;
6935 	srv_log_group_home_dir = srv_log_group_home_dir_save;
6936 	innobase_log_file_size = innobase_log_file_size_save;
6937 
6938 	return(FALSE);
6939 error:
6940 	if (src_file != XB_FILE_UNDEFINED)
6941 		os_file_close(src_file);
6942 	msg("xtrabackup: Error: xtrabackup_close_temp_log() failed.\n");
6943 	return(TRUE); /*ERROR*/
6944 }
6945 
6946 
6947 /*********************************************************************//**
6948 Write the meta data (index user fields) config file.
6949 @return true in case of success otherwise false. */
6950 static
6951 bool
xb_export_cfg_write_index_fields(const dict_index_t * index,FILE * file)6952 xb_export_cfg_write_index_fields(
6953 /*===========================*/
6954 	const dict_index_t*	index,	/*!< in: write the meta data for
6955 					this index */
6956 	FILE*			file)	/*!< in: file to write to */
6957 {
6958 	byte			row[sizeof(ib_uint32_t) * 2];
6959 
6960 	for (ulint i = 0; i < index->n_fields; ++i) {
6961 		byte*			ptr = row;
6962 		const dict_field_t*	field = &index->fields[i];
6963 
6964 		mach_write_to_4(ptr, field->prefix_len);
6965 		ptr += sizeof(ib_uint32_t);
6966 
6967 		mach_write_to_4(ptr, field->fixed_len);
6968 
6969 		if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
6970 
6971 			msg("xtrabackup: Error: writing index fields.");
6972 
6973 			return(false);
6974 		}
6975 
6976 		/* Include the NUL byte in the length. */
6977 		ib_uint32_t	len = strlen(field->name) + 1;
6978 		ut_a(len > 1);
6979 
6980 		mach_write_to_4(row, len);
6981 
6982 		if (fwrite(row, 1,  sizeof(len), file) != sizeof(len)
6983 		    || fwrite(field->name, 1, len, file) != len) {
6984 
6985 			msg("xtrabackup: Error: writing index column.");
6986 
6987 			return(false);
6988 		}
6989 	}
6990 
6991 	return(true);
6992 }
6993 
6994 /*********************************************************************//**
6995 Write the meta data config file index information.
6996 @return true in case of success otherwise false. */
6997 static	__attribute__((nonnull, warn_unused_result))
6998 bool
xb_export_cfg_write_indexes(const dict_table_t * table,FILE * file)6999 xb_export_cfg_write_indexes(
7000 /*======================*/
7001 	const dict_table_t*	table,	/*!< in: write the meta data for
7002 					this table */
7003 	FILE*			file)	/*!< in: file to write to */
7004 {
7005 	{
7006 		byte		row[sizeof(ib_uint32_t)];
7007 
7008 		/* Write the number of indexes in the table. */
7009 		mach_write_to_4(row, UT_LIST_GET_LEN(table->indexes));
7010 
7011 		if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7012 			msg("xtrabackup: Error: writing index count.");
7013 
7014 			return(false);
7015 		}
7016 	}
7017 
7018 	bool			ret = true;
7019 
7020 	/* Write the index meta data. */
7021 	for (const dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
7022 	     index != 0 && ret;
7023 	     index = UT_LIST_GET_NEXT(indexes, index)) {
7024 
7025 		byte*		ptr;
7026 		byte		row[sizeof(ib_uint64_t)
7027 				    + sizeof(ib_uint32_t) * 8];
7028 
7029 		ptr = row;
7030 
7031 		ut_ad(sizeof(ib_uint64_t) == 8);
7032 		mach_write_to_8(ptr, index->id);
7033 		ptr += sizeof(ib_uint64_t);
7034 
7035 		mach_write_to_4(ptr, index->space);
7036 		ptr += sizeof(ib_uint32_t);
7037 
7038 		mach_write_to_4(ptr, index->page);
7039 		ptr += sizeof(ib_uint32_t);
7040 
7041 		mach_write_to_4(ptr, index->type);
7042 		ptr += sizeof(ib_uint32_t);
7043 
7044 		mach_write_to_4(ptr, index->trx_id_offset);
7045 		ptr += sizeof(ib_uint32_t);
7046 
7047 		mach_write_to_4(ptr, index->n_user_defined_cols);
7048 		ptr += sizeof(ib_uint32_t);
7049 
7050 		mach_write_to_4(ptr, index->n_uniq);
7051 		ptr += sizeof(ib_uint32_t);
7052 
7053 		mach_write_to_4(ptr, index->n_nullable);
7054 		ptr += sizeof(ib_uint32_t);
7055 
7056 		mach_write_to_4(ptr, index->n_fields);
7057 
7058 		if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7059 
7060 			msg("xtrabackup: Error: writing index meta-data.");
7061 
7062 			return(false);
7063 		}
7064 
7065 		/* Write the length of the index name.
7066 		NUL byte is included in the length. */
7067 		ib_uint32_t	len = strlen(index->name) + 1;
7068 		ut_a(len > 1);
7069 
7070 		mach_write_to_4(row, len);
7071 
7072 		if (fwrite(row, 1, sizeof(len), file) != sizeof(len)
7073 		    || fwrite(index->name, 1, len, file) != len) {
7074 
7075 			msg("xtrabackup: Error: writing index name.");
7076 
7077 			return(false);
7078 		}
7079 
7080 		ret = xb_export_cfg_write_index_fields(index, file);
7081 	}
7082 
7083 	return(ret);
7084 }
7085 
7086 /*********************************************************************//**
7087 Write the meta data (table columns) config file. Serialise the contents of
7088 dict_col_t structure, along with the column name. All fields are serialized
7089 as ib_uint32_t.
7090 @return true in case of success otherwise false. */
7091 static	__attribute__((nonnull, warn_unused_result))
7092 bool
xb_export_cfg_write_table(const dict_table_t * table,FILE * file)7093 xb_export_cfg_write_table(
7094 /*====================*/
7095 	const dict_table_t*	table,	/*!< in: write the meta data for
7096 					this table */
7097 	FILE*			file)	/*!< in: file to write to */
7098 {
7099 	dict_col_t*		col;
7100 	byte			row[sizeof(ib_uint32_t) * 7];
7101 
7102 	col = table->cols;
7103 
7104 	for (ulint i = 0; i < table->n_cols; ++i, ++col) {
7105 		byte*		ptr = row;
7106 
7107 		mach_write_to_4(ptr, col->prtype);
7108 		ptr += sizeof(ib_uint32_t);
7109 
7110 		mach_write_to_4(ptr, col->mtype);
7111 		ptr += sizeof(ib_uint32_t);
7112 
7113 		mach_write_to_4(ptr, col->len);
7114 		ptr += sizeof(ib_uint32_t);
7115 
7116 		mach_write_to_4(ptr, col->mbminmaxlen);
7117 		ptr += sizeof(ib_uint32_t);
7118 
7119 		mach_write_to_4(ptr, col->ind);
7120 		ptr += sizeof(ib_uint32_t);
7121 
7122 		mach_write_to_4(ptr, col->ord_part);
7123 		ptr += sizeof(ib_uint32_t);
7124 
7125 		mach_write_to_4(ptr, col->max_prefix);
7126 
7127 		if (fwrite(row, 1, sizeof(row), file) != sizeof(row)) {
7128 			msg("xtrabackup: Error: writing table column data.");
7129 
7130 			return(false);
7131 		}
7132 
7133 		/* Write out the column name as [len, byte array]. The len
7134 		includes the NUL byte. */
7135 		ib_uint32_t	len;
7136 		const char*	col_name;
7137 
7138 		col_name = dict_table_get_col_name(table, dict_col_get_no(col));
7139 
7140 		/* Include the NUL byte in the length. */
7141 		len = strlen(col_name) + 1;
7142 		ut_a(len > 1);
7143 
7144 		mach_write_to_4(row, len);
7145 
7146 		if (fwrite(row, 1,  sizeof(len), file) != sizeof(len)
7147 		    || fwrite(col_name, 1, len, file) != len) {
7148 
7149 			msg("xtrabackup: Error: writing column name.");
7150 
7151 			return(false);
7152 		}
7153 	}
7154 
7155 	return(true);
7156 }
7157 
7158 /*********************************************************************//**
7159 Write the meta data config file header.
7160 @return true in case of success otherwise false. */
7161 static	__attribute__((nonnull, warn_unused_result))
7162 bool
xb_export_cfg_write_header(const dict_table_t * table,FILE * file)7163 xb_export_cfg_write_header(
7164 /*=====================*/
7165 	const dict_table_t*	table,	/*!< in: write the meta data for
7166 					this table */
7167 	FILE*			file)	/*!< in: file to write to */
7168 {
7169 	byte			value[sizeof(ib_uint32_t)];
7170 
7171 	/* Write the meta-data version number. */
7172 	mach_write_to_4(value, IB_EXPORT_CFG_VERSION_V1);
7173 
7174 	if (fwrite(&value, 1, sizeof(value), file) != sizeof(value)) {
7175 		msg("xtrabackup: Error: writing meta-data version number.");
7176 
7177 		return(false);
7178 	}
7179 
7180 	/* Write the server hostname. */
7181 	ib_uint32_t		len;
7182 	const char*		hostname = "Hostname unknown";
7183 
7184 	/* The server hostname includes the NUL byte. */
7185 	len = strlen(hostname) + 1;
7186 	mach_write_to_4(value, len);
7187 
7188 	if (fwrite(&value, 1,  sizeof(value), file) != sizeof(value)
7189 	    || fwrite(hostname, 1,  len, file) != len) {
7190 
7191 		msg("xtrabackup: Error: writing hostname.");
7192 
7193 		return(false);
7194 	}
7195 
7196 	/* The table name includes the NUL byte. */
7197 	ut_a(table->name.m_name != NULL);
7198 	len = strlen(table->name.m_name) + 1;
7199 
7200 	/* Write the table name. */
7201 	mach_write_to_4(value, len);
7202 
7203 	if (fwrite(&value, 1,  sizeof(value), file) != sizeof(value)
7204 	    || fwrite(table->name.m_name, 1,  len, file) != len) {
7205 
7206 		msg("xtrabackup: Error: writing table name.");
7207 
7208 		return(false);
7209 	}
7210 
7211 	byte		row[sizeof(ib_uint32_t) * 3];
7212 
7213 	/* Write the next autoinc value. */
7214 	mach_write_to_8(row, table->autoinc);
7215 
7216 	if (fwrite(row, 1, sizeof(ib_uint64_t), file) != sizeof(ib_uint64_t)) {
7217 		msg("xtrabackup: Error: writing table autoinc value.");
7218 
7219 		return(false);
7220 	}
7221 
7222 	byte*		ptr = row;
7223 
7224 	/* Write the system page size. */
7225 	mach_write_to_4(ptr, UNIV_PAGE_SIZE);
7226 	ptr += sizeof(ib_uint32_t);
7227 
7228 	/* Write the table->flags. */
7229 	mach_write_to_4(ptr, table->flags);
7230 	ptr += sizeof(ib_uint32_t);
7231 
7232 	/* Write the number of columns in the table. */
7233 	mach_write_to_4(ptr, table->n_cols);
7234 
7235 	if (fwrite(row, 1,  sizeof(row), file) != sizeof(row)) {
7236 		msg("xtrabackup: Error: writing table meta-data.");
7237 
7238 		return(false);
7239 	}
7240 
7241 	return(true);
7242 }
7243 
7244 /*********************************************************************//**
7245 Write MySQL 5.6-style meta data config file.
7246 @return true in case of success otherwise false. */
7247 static
7248 bool
xb_export_cfg_write(const fil_node_t * node,const dict_table_t * table)7249 xb_export_cfg_write(
7250 	const fil_node_t*	node,
7251 	const dict_table_t*	table)	/*!< in: write the meta data for
7252 					this table */
7253 {
7254 	char	file_path[FN_REFLEN];
7255 	FILE*	file;
7256 	bool	success;
7257 
7258 	strcpy(file_path, node->name);
7259 	strcpy(file_path + strlen(file_path) - 4, ".cfg");
7260 
7261 	file = fopen(file_path, "w+b");
7262 
7263 	if (file == NULL) {
7264 		msg("xtrabackup: Error: cannot open %s\n", node->name);
7265 
7266 		success = false;
7267 	} else {
7268 
7269 		success = xb_export_cfg_write_header(table, file);
7270 
7271 		if (success) {
7272 			success = xb_export_cfg_write_table(table, file);
7273 		}
7274 
7275 		if (success) {
7276 			success = xb_export_cfg_write_indexes(table, file);
7277 		}
7278 
7279 		if (fclose(file) != 0) {
7280 			msg("xtrabackup: Error: cannot close %s\n", node->name);
7281 			success = false;
7282 		}
7283 
7284 	}
7285 
7286 	return(success);
7287 
7288 }
7289 
7290 /** Write the transfer key to CFP file.
7291 @param[in]	table		write the data for this table
7292 @param[in]	file		file to write to
7293 @return DB_SUCCESS or error code. */
7294 static	__attribute__((nonnull, warn_unused_result))
7295 dberr_t
xb_export_write_transfer_key(const dict_table_t * table,FILE * file)7296 xb_export_write_transfer_key(
7297 	const dict_table_t*	table,
7298 	FILE*			file)
7299 {
7300 	byte		key_size[sizeof(ib_uint32_t)];
7301 	byte		row[ENCRYPTION_KEY_LEN * 3];
7302 	byte*		ptr = row;
7303 	byte*		transfer_key = ptr;
7304 	lint		elen;
7305 
7306 	ut_ad(table->encryption_key != NULL
7307 	      && table->encryption_iv != NULL);
7308 
7309 	/* Write the encryption key size. */
7310 	mach_write_to_4(key_size, ENCRYPTION_KEY_LEN);
7311 
7312 	if (fwrite(&key_size, 1,  sizeof(key_size), file)
7313 		!= sizeof(key_size)) {
7314 		msg("IO Write error: (%d, %s) %s",
7315 			errno, strerror(errno),
7316 			"while writing key size.");
7317 
7318 		return(DB_IO_ERROR);
7319 	}
7320 
7321 	/* Generate and write the transfer key. */
7322 	Encryption::random_value(transfer_key);
7323 	if (fwrite(transfer_key, 1, ENCRYPTION_KEY_LEN, file)
7324 		!= ENCRYPTION_KEY_LEN) {
7325 		msg("IO Write error: (%d, %s) %s",
7326 			errno, strerror(errno),
7327 			"while writing transfer key.");
7328 
7329 		return(DB_IO_ERROR);
7330 	}
7331 
7332 	ptr += ENCRYPTION_KEY_LEN;
7333 
7334 	/* Encrypt tablespace key. */
7335 	elen = my_aes_encrypt(
7336 		reinterpret_cast<unsigned char*>(table->encryption_key),
7337 		ENCRYPTION_KEY_LEN,
7338 		ptr,
7339 		reinterpret_cast<unsigned char*>(transfer_key),
7340 		ENCRYPTION_KEY_LEN,
7341 		my_aes_256_ecb,
7342 		NULL, false);
7343 
7344 	if (elen == MY_AES_BAD_DATA) {
7345 		msg("IO Write error: (%d, %s) %s",
7346 			errno, strerror(errno),
7347 			"while encrypt tablespace key.");
7348 		return(DB_ERROR);
7349 	}
7350 
7351 	/* Write encrypted tablespace key */
7352 	if (fwrite(ptr, 1, ENCRYPTION_KEY_LEN, file)
7353 		!= ENCRYPTION_KEY_LEN) {
7354 		msg("IO Write error: (%d, %s) %s",
7355 			errno, strerror(errno),
7356 			"while writing encrypted tablespace key.");
7357 
7358 		return(DB_IO_ERROR);
7359 	}
7360 	ptr += ENCRYPTION_KEY_LEN;
7361 
7362 	/* Encrypt tablespace iv. */
7363 	elen = my_aes_encrypt(
7364 		reinterpret_cast<unsigned char*>(table->encryption_iv),
7365 		ENCRYPTION_KEY_LEN,
7366 		ptr,
7367 		reinterpret_cast<unsigned char*>(transfer_key),
7368 		ENCRYPTION_KEY_LEN,
7369 		my_aes_256_ecb,
7370 		NULL, false);
7371 
7372 	if (elen == MY_AES_BAD_DATA) {
7373 		msg("IO Write error: (%d, %s) %s",
7374 			errno, strerror(errno),
7375 			"while encrypt tablespace iv.");
7376 		return(DB_ERROR);
7377 	}
7378 
7379 	/* Write encrypted tablespace iv */
7380 	if (fwrite(ptr, 1, ENCRYPTION_KEY_LEN, file)
7381 		!= ENCRYPTION_KEY_LEN) {
7382 		msg("IO Write error: (%d, %s) %s",
7383 			errno, strerror(errno),
7384 			"while writing encrypted tablespace iv.");
7385 
7386 		return(DB_IO_ERROR);
7387 	}
7388 
7389 	return(DB_SUCCESS);
7390 }
7391 
7392 /** Write the encryption data after quiesce.
7393 @param[in]	table		write the data for this table
7394 @return DB_SUCCESS or error code */
7395 static	__attribute__((nonnull, warn_unused_result))
7396 dberr_t
xb_export_cfp_write(dict_table_t * table)7397 xb_export_cfp_write(
7398 	dict_table_t*	table)
7399 {
7400 	dberr_t			err;
7401 	char			name[OS_FILE_MAX_PATH];
7402 
7403 	/* If table is not encrypted, return. */
7404 	if (!dict_table_is_encrypted(table)) {
7405 		return(DB_SUCCESS);
7406 	}
7407 
7408 	/* Get the encryption key and iv from space */
7409 	/* For encrypted table, before we discard the tablespace,
7410 	we need save the encryption information into table, otherwise,
7411 	this information will be lost in fil_discard_tablespace along
7412 	with fil_space_free(). */
7413 	if (table->encryption_key == NULL) {
7414 		table->encryption_key =
7415 			static_cast<byte*>(mem_heap_alloc(table->heap,
7416 							  ENCRYPTION_KEY_LEN));
7417 
7418 		table->encryption_iv =
7419 			static_cast<byte*>(mem_heap_alloc(table->heap,
7420 							  ENCRYPTION_KEY_LEN));
7421 
7422 		fil_space_t*	space = fil_space_get(table->space);
7423 		ut_ad(space != NULL && FSP_FLAGS_GET_ENCRYPTION(space->flags));
7424 
7425 		memcpy(table->encryption_key,
7426 		       space->encryption_key,
7427 		       ENCRYPTION_KEY_LEN);
7428 		memcpy(table->encryption_iv,
7429 		       space->encryption_iv,
7430 		       ENCRYPTION_KEY_LEN);
7431 	}
7432 
7433 	srv_get_encryption_data_filename(table, name, sizeof(name));
7434 
7435 	ib::info() << "Writing table encryption data to '" << name << "'";
7436 
7437 	FILE*	file = fopen(name, "w+b");
7438 
7439 	if (file == NULL) {
7440 		msg("Can't create file '%-.200s' (errno: %d - %s)",
7441 			 name, errno, strerror(errno));
7442 
7443 		err = DB_IO_ERROR;
7444 	} else {
7445 		err = xb_export_write_transfer_key(table, file);
7446 
7447 		if (fflush(file) != 0) {
7448 
7449 			char	buf[BUFSIZ];
7450 
7451 			ut_snprintf(buf, sizeof(buf), "%s flush() failed",
7452 				    name);
7453 
7454 			msg("IO Write error: (%d, %s) %s",
7455 				errno, strerror(errno), buf);
7456 
7457 			err = DB_IO_ERROR;
7458 		}
7459 
7460 		if (fclose(file) != 0) {
7461 			char	buf[BUFSIZ];
7462 
7463 			ut_snprintf(buf, sizeof(buf), "%s flose() failed",
7464 				    name);
7465 
7466 			msg("IO Write error: (%d, %s) %s",
7467 				errno, strerror(errno), buf);
7468 			err = DB_IO_ERROR;
7469 		}
7470 	}
7471 
7472 	/* Clean the encryption information */
7473 	table->encryption_key = NULL;
7474 	table->encryption_iv = NULL;
7475 
7476 	return(err);
7477 }
7478 
7479 /*********************************************************************//**
7480 Re-encrypt tablespace keys with newly generated master key having ID
7481 based on new server-id.
7482 @return true in case of success otherwise false. */
7483 static
7484 bool
reencrypt_tablespace_keys(ulint new_server_id)7485 reencrypt_tablespace_keys(
7486 	ulint new_server_id)
7487 {
7488 	byte*			master_key = NULL;
7489 	bool			ret = false;
7490 	Encryption::Version	version;
7491 
7492 	/* Check if keyring loaded and the current master key
7493 	can be fetched. */
7494 	if (Encryption::master_key_id != 0) {
7495 		ulint			master_key_id;
7496 
7497 		Encryption::get_master_key(&master_key_id,
7498 					   &master_key,
7499 					   &version);
7500 		if (master_key == NULL) {
7501 			msg("xtrabackup: error: Can't find master key.\n");
7502 			return(false);
7503 		}
7504 		msg("xtrabackup: found master key version %s.\n",
7505 		    version == Encryption::ENCRYPTION_VERSION_1 ?
7506 		    "= 5.7.11" : ">= 5.7.12");
7507 		my_free(master_key);
7508 
7509 		if (version != Encryption::ENCRYPTION_VERSION_1) {
7510 			msg("xtrabackup: reencryption is not needed.\n");
7511 			return(true);
7512 		}
7513 	} else {
7514 
7515 		/* no encrypted tablespaces */
7516 
7517 		return(true);
7518 	}
7519 
7520 	master_key = NULL;
7521 
7522 	/* Generate the new master key. */
7523 	server_id = new_server_id;
7524 	Encryption::create_master_key_v0(&master_key);
7525 
7526         if (master_key == NULL) {
7527 		msg("xtrabackup: error: Can't create master key.\n");
7528                 return(false);
7529         }
7530 
7531 	ret = fil_encryption_rotate();
7532 
7533 	my_free(master_key);
7534 
7535 	/* If rotation failure, return error */
7536 	if (!ret) {
7537 		msg("xtrabackup: error: Can't rotate master key.\n");
7538 	} else {
7539 		msg("xtrabackup: Keys reencrypted for server-id %lu.\n",
7540 		    server_id);
7541 	}
7542 
7543 	return(ret);
7544 }
7545 
7546 #if 0
7547 /********************************************************************//**
7548 Searches archived log files in archived log directory. The min and max
7549 LSN's of found files as well as archived log file size are stored in
7550 xtrabackup_arch_first_file_lsn, xtrabackup_arch_last_file_lsn and
7551 xtrabackup_arch_file_size respectively.
7552 @return true on success
7553 */
7554 static
7555 bool
7556 xtrabackup_arch_search_files(
7557 /*=========================*/
7558 	ib_uint64_t	start_lsn)		/*!< in: filter out log files
7559 						witch does not contain data
7560 						with lsn < start_lsn */
7561 {
7562 	os_file_dir_t	dir;
7563 	os_file_stat_t	fileinfo;
7564 	ut_ad(innobase_log_arch_dir);
7565 
7566 	dir = os_file_opendir(innobase_log_arch_dir, FALSE);
7567 	if (!dir) {
7568 		msg("xtrabackup: error: cannot open archived log directory %s\n",
7569 		    innobase_log_arch_dir);
7570 		return false;
7571 	}
7572 
7573 	while(!os_file_readdir_next_file(innobase_log_arch_dir,
7574 					 dir,
7575 					 &fileinfo) ) {
7576 		lsn_t	log_file_lsn;
7577 		char*	log_str_end_lsn_ptr;
7578 
7579 		if (strncmp(fileinfo.name,
7580 			    IB_ARCHIVED_LOGS_PREFIX,
7581 			    sizeof(IB_ARCHIVED_LOGS_PREFIX) - 1)) {
7582 			continue;
7583 		}
7584 
7585 		log_file_lsn = strtoll(fileinfo.name +
7586 				       sizeof(IB_ARCHIVED_LOGS_PREFIX) - 1,
7587 				       &log_str_end_lsn_ptr, 10);
7588 
7589 		if (*log_str_end_lsn_ptr) {
7590 			continue;
7591 		}
7592 
7593 		if (log_file_lsn + (fileinfo.size - LOG_FILE_HDR_SIZE)	< start_lsn) {
7594 			continue;
7595 		}
7596 
7597 		if (!xtrabackup_arch_first_file_lsn ||
7598 		    log_file_lsn < xtrabackup_arch_first_file_lsn) {
7599 			xtrabackup_arch_first_file_lsn = log_file_lsn;
7600 		}
7601 		if (log_file_lsn > xtrabackup_arch_last_file_lsn) {
7602 			xtrabackup_arch_last_file_lsn = log_file_lsn;
7603 		}
7604 
7605 		//TODO: find the more suitable way to extract archived log file
7606 		//size
7607 		if (fileinfo.size > (int64_t)xtrabackup_arch_file_size) {
7608 			xtrabackup_arch_file_size = fileinfo.size;
7609 		}
7610 	}
7611 
7612 	return xtrabackup_arch_first_file_lsn != 0;
7613 }
7614 #endif
7615 
7616 static
7617 void
innodb_free_param()7618 innodb_free_param()
7619 {
7620 	srv_sys_space.shutdown();
7621 	srv_tmp_space.shutdown();
7622 	free(internal_innobase_data_file_path);
7623 	internal_innobase_data_file_path = NULL;
7624 	free_tmpdir(&mysql_tmpdir_list);
7625 }
7626 
7627 
7628 /**************************************************************************
7629 Store the current binary log coordinates in a specified file.
7630 @return 'false' on error. */
7631 static bool
store_binlog_info(const char * filename)7632 store_binlog_info(
7633 /*==============*/
7634 	const char *filename)	/*!< in: output file name */
7635 {
7636 	FILE *fp;
7637 
7638 	if (trx_sys_mysql_bin_log_name[0] == '\0') {
7639 		return(true);
7640 	}
7641 
7642 	fp = fopen(filename, "w");
7643 
7644 	if (!fp) {
7645 		msg("xtrabackup: failed to open '%s'\n", filename);
7646 		return(false);
7647 	}
7648 
7649 	fprintf(fp, "%s\t" UINT64PF "\n",
7650 		trx_sys_mysql_bin_log_name, trx_sys_mysql_bin_log_pos);
7651 	fclose(fp);
7652 
7653 	return(true);
7654 }
7655 
7656 
7657 /**************************************************************************
7658 Store current master key ID.
7659 @return 'false' on error. */
7660 static bool
store_master_key_id(const char * filename)7661 store_master_key_id(
7662 /*==============*/
7663 	const char *filename)	/*!< in: output file name */
7664 {
7665 	FILE *fp;
7666 
7667 	fp = fopen(filename, "w");
7668 
7669 	if (!fp) {
7670 		msg("xtrabackup: failed to open '%s'\n", filename);
7671 		return(false);
7672 	}
7673 
7674 	fprintf(fp, "%lu", Encryption::master_key_id);
7675 	fclose(fp);
7676 
7677 	return(true);
7678 }
7679 
7680 static void
xtrabackup_prepare_func(int argc,char ** argv)7681 xtrabackup_prepare_func(int argc, char **argv)
7682 {
7683 	ulint	err;
7684 	datafiles_iter_t	*it;
7685 	fil_node_t		*node;
7686 	fil_space_t		*space;
7687 	char			 metadata_path[FN_REFLEN];
7688 	IORequest		write_request(IORequest::WRITE);
7689 
7690 	mysql_mutex_init(key_LOCK_global_system_variables,
7691 			 &LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
7692 
7693 	/* cd to target-dir */
7694 
7695 	if (my_setwd(xtrabackup_real_target_dir,MYF(MY_WME)))
7696 	{
7697 		msg("xtrabackup: cannot my_setwd %s\n",
7698 		    xtrabackup_real_target_dir);
7699 		exit(EXIT_FAILURE);
7700 	}
7701 	msg("xtrabackup: cd to %s\n", xtrabackup_real_target_dir);
7702 
7703 	xtrabackup_target_dir= mysql_data_home_buff;
7704 	xtrabackup_target_dir[0]=FN_CURLIB;		// all paths are relative from here
7705 	xtrabackup_target_dir[1]=0;
7706 
7707 	/*
7708 	  read metadata of target, we don't need metadata reading in the case
7709 	  archived logs applying
7710 	*/
7711 	sprintf(metadata_path, "%s/%s", xtrabackup_target_dir,
7712 		XTRABACKUP_METADATA_FILENAME);
7713 
7714 	if (!xtrabackup_read_metadata(metadata_path)) {
7715 		msg("xtrabackup: Error: failed to read metadata from '%s'\n",
7716 		    metadata_path);
7717 		exit(EXIT_FAILURE);
7718 	}
7719 
7720 	if (!innobase_log_arch_dir)
7721 	{
7722 		if (!strcmp(metadata_type, "full-backuped")) {
7723 			msg("xtrabackup: This target seems to be not prepared "
7724 			    "yet.\n");
7725 		} else if (!strcmp(metadata_type, "log-applied")) {
7726 			msg("xtrabackup: This target seems to be already "
7727 			    "prepared with --apply-log-only.\n");
7728 			goto skip_check;
7729 		} else if (!strcmp(metadata_type, "full-prepared")) {
7730 			msg("xtrabackup: This target seems to be already "
7731 			    "prepared.\n");
7732 		} else {
7733 			msg("xtrabackup: This target seems not to have correct "
7734 			    "metadata...\n");
7735 			exit(EXIT_FAILURE);
7736 		}
7737 
7738 		if (xtrabackup_incremental) {
7739 			msg("xtrabackup: error: applying incremental backup "
7740 			    "needs target prepared with --apply-log-only.\n");
7741 			exit(EXIT_FAILURE);
7742 		}
7743 skip_check:
7744 		if (xtrabackup_incremental
7745 		    && metadata_to_lsn != incremental_lsn) {
7746 			msg("xtrabackup: error: This incremental backup seems "
7747 			    "not to be proper for the target.\n"
7748 			    "xtrabackup:  Check 'to_lsn' of the target and "
7749 			    "'from_lsn' of the incremental.\n");
7750 			exit(EXIT_FAILURE);
7751 		}
7752 	}
7753 
7754         if (xtrabackup_incremental) {
7755 		backup_redo_log_flushed_lsn = incremental_flushed_lsn;
7756         }
7757 
7758         /* Create logfiles for recovery from 'xtrabackup_logfile', before start InnoDB */
7759 	srv_max_n_threads = 1000;
7760 	/* temporally dummy value to avoid crash */
7761 	srv_page_size_shift = 14;
7762 	srv_page_size = (1 << srv_page_size_shift);
7763 	os_event_global_init();
7764 	sync_check_init();
7765 #ifdef UNIV_DEBUG
7766 	sync_check_enable();
7767 #endif
7768 	os_thread_init();
7769 	trx_pool_init();
7770 	ut_crc32_init();
7771 
7772 	xb_filters_init();
7773 
7774 	if(!innobase_log_arch_dir && xtrabackup_init_temp_log())
7775 		goto error_cleanup;
7776 
7777 	if(innodb_init_param()) {
7778 		goto error_cleanup;
7779 	}
7780 
7781 	if (opt_transition_key && !xb_tablespace_keys_exist()) {
7782 		msg("xtrabackup: Error: --transition-key specified, but "
7783 		    "xtrabackup_keys is not found.\n");
7784 		goto error_cleanup;
7785 	}
7786 
7787 	if (opt_transition_key) {
7788 		if (!xb_tablespace_keys_load(
7789 			xtrabackup_incremental,
7790 			opt_transition_key, strlen(opt_transition_key))) {
7791 			msg("xtrabackup: Error: failed to load tablespace "
7792 			    "keys\n");
7793 			goto error_cleanup;
7794 		}
7795 	} else {
7796 		if (!xb_keyring_init_for_prepare(argc, argv)) {
7797 			msg("xtrabackup: Error: failed to init keyring "
7798 			    "plugin\n");
7799 			goto error_cleanup;
7800 		}
7801 		if (xb_tablespace_keys_exist()) {
7802 			use_dumped_tablespace_keys = true;
7803 			if (!xb_tablespace_keys_load(
7804 				xtrabackup_incremental,
7805 				NULL, 0)) {
7806 				msg("xtrabackup: Error: failed to load "
7807 				    "tablespace keys\n");
7808 				goto error_cleanup;
7809 			}
7810 		}
7811 	}
7812 
7813 	/* Expand compacted datafiles */
7814 
7815 	if (xtrabackup_compact) {
7816 		srv_compact_backup = TRUE;
7817 
7818 		if (!xb_expand_datafiles()) {
7819 			goto error_cleanup;
7820 		}
7821 
7822 		/* Reset the 'compact' flag in xtrabackup_checkpoints so we
7823 		don't expand on subsequent invocations. */
7824 		xtrabackup_compact = FALSE;
7825 		if (!xtrabackup_write_metadata(metadata_path)) {
7826 			msg("xtrabackup: error: xtrabackup_write_metadata() "
7827 			    "failed\n");
7828 			goto error_cleanup;
7829 		}
7830 	}
7831 
7832 	xb_normalize_init_values();
7833 
7834 	if (xtrabackup_incremental || innobase_log_arch_dir) {
7835 		err = xb_data_files_init();
7836 		if (err != DB_SUCCESS) {
7837 			msg("xtrabackup: error: xb_data_files_init() failed "
7838 			    "with error code %lu\n", err);
7839 			goto error_cleanup;
7840 		}
7841 	}
7842 	if (xtrabackup_incremental) {
7843 		inc_dir_tables_hash = hash_create(1000);
7844 
7845 		if(!xtrabackup_apply_deltas()) {
7846 			xb_data_files_close();
7847 			xb_filter_hash_free(inc_dir_tables_hash);
7848 			goto error_cleanup;
7849 		}
7850 	}
7851 	if (xtrabackup_incremental || innobase_log_arch_dir) {
7852 		xb_data_files_close();
7853 	}
7854 	if (xtrabackup_incremental) {
7855 		/* Cleanup datadir from tablespaces deleted between full and
7856 		incremental backups */
7857 
7858 		xb_process_datadir("./", ".ibd", rm_if_not_found, NULL);
7859 
7860 		xb_filter_hash_free(inc_dir_tables_hash);
7861 	}
7862 	if (fil_system) {
7863 		fil_close();
7864 	}
7865 
7866 	trx_pool_close();
7867 
7868 	os_thread_free();
7869 
7870 	sync_check_close();
7871 
7872 	innodb_free_param();
7873 
7874 	/* Reset the configuration as it might have been changed by
7875 	xb_data_files_init(). */
7876 	if(innodb_init_param()) {
7877 		goto error_cleanup;
7878 	}
7879 
7880 	srv_apply_log_only = (ibool) xtrabackup_apply_log_only;
7881 	srv_rebuild_indexes = (ibool) xtrabackup_rebuild_indexes;
7882 
7883 	/* increase IO threads */
7884 	if(srv_n_file_io_threads < 10) {
7885 		srv_n_read_io_threads = 4;
7886 		srv_n_write_io_threads = 4;
7887 	}
7888 
7889 	msg("xtrabackup: Starting InnoDB instance for recovery.\n"
7890 	    "xtrabackup: Using %lld bytes for buffer pool "
7891 	    "(set by --use-memory parameter)\n", xtrabackup_use_memory);
7892 
7893 	if(innodb_init())
7894 		goto error_cleanup;
7895 
7896 	it = datafiles_iter_new(fil_system);
7897 	if (it == NULL) {
7898 		msg("xtrabackup: Error: datafiles_iter_new() failed.\n");
7899 		exit(EXIT_FAILURE);
7900 	}
7901 
7902 	while ((node = datafiles_iter_next(it)) != NULL) {
7903 		byte		*header;
7904 		ulint		 size;
7905 		mtr_t		 mtr;
7906 		buf_block_t	*block;
7907 		ulint		 flags;
7908 
7909 		space = node->space;
7910 
7911 		/* Align space sizes along with fsp header. We want to process
7912 		each space once, so skip all nodes except the first one in a
7913 		multi-node space. */
7914 		if (UT_LIST_GET_PREV(chain, node) != NULL) {
7915 			continue;
7916 		}
7917 
7918 		mtr_start(&mtr);
7919 
7920 		mtr_s_lock(fil_space_get_latch(space->id, &flags), &mtr);
7921 
7922 		block = buf_page_get(page_id_t(space->id, 0),
7923 				     page_size_t(flags),
7924 				     RW_S_LATCH, &mtr);
7925 		header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
7926 
7927 		size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES,
7928 				      &mtr);
7929 
7930 		mtr_commit(&mtr);
7931 
7932 		fil_space_extend(space, size);
7933 	}
7934 
7935 	datafiles_iter_free(it);
7936 
7937 	if (xtrabackup_export) {
7938 		msg("xtrabackup: export option is specified.\n");
7939 		pfs_os_file_t	info_file = XB_FILE_UNDEFINED;
7940 		char		info_file_path[FN_REFLEN];
7941 		bool		success;
7942 		char		table_name[FN_REFLEN];
7943 
7944 		byte*		page;
7945 		byte*		buf = NULL;
7946 
7947 		buf = static_cast<byte *>(ut_malloc_nokey(UNIV_PAGE_SIZE * 2));
7948 		page = static_cast<byte *>(ut_align(buf, UNIV_PAGE_SIZE));
7949 
7950 		/* flush insert buffer at shutdwon */
7951 		innobase_fast_shutdown = 0;
7952 
7953 		it = datafiles_iter_new(fil_system);
7954 		if (it == NULL) {
7955 			msg("xtrabackup: Error: datafiles_iter_new() "
7956 			    "failed.\n");
7957 			exit(EXIT_FAILURE);
7958 		}
7959 		while ((node = datafiles_iter_next(it)) != NULL) {
7960 			int		 len;
7961 			char		*next, *prev, *p;
7962 			dict_table_t*	 table;
7963 			dict_index_t*	 index;
7964 			ulint		 n_index;
7965 
7966 			space = node->space;
7967 
7968 			/* treat file_per_table only */
7969 			if (!fil_is_user_tablespace_id(space->id)) {
7970 				continue;
7971 			}
7972 
7973 			/* node exist == file exist, here */
7974 			strcpy(info_file_path, node->name);
7975 			strcpy(info_file_path +
7976 			       strlen(info_file_path) -
7977 			       4, ".exp");
7978 
7979 			len = strlen(info_file_path);
7980 
7981 			p = info_file_path;
7982 			prev = NULL;
7983 			while ((next = strchr(p, OS_PATH_SEPARATOR)) != NULL)
7984 			{
7985 				prev = p;
7986 				p = next + 1;
7987 			}
7988 			info_file_path[len - 4] = 0;
7989 			strncpy(table_name, prev, FN_REFLEN);
7990 
7991 			info_file_path[len - 4] = '.';
7992 
7993 			mutex_enter(&(dict_sys->mutex));
7994 
7995 			table = dict_table_get_low(table_name);
7996 			if (!table) {
7997 				msg("xtrabackup: error: "
7998 				    "cannot find dictionary "
7999 				    "record of table %s\n",
8000 				    table_name);
8001 				goto next_node;
8002 			}
8003 
8004 			/* Write MySQL 5.6 .cfg file */
8005 			if (!xb_export_cfg_write(node, table)) {
8006 				goto next_node;
8007 			}
8008 
8009 			index = dict_table_get_first_index(table);
8010 			n_index = UT_LIST_GET_LEN(table->indexes);
8011 			if (n_index > 31) {
8012 				msg("xtrabackup: warning: table '%s' has more "
8013 				    "than 31 indexes, .exp file was not "
8014 				    "generated. Table will fail to import "
8015 				    "on server version prior to 5.6.\n",
8016 				    table_name);
8017 				goto next_node;
8018 			}
8019 
8020 			/* Write transfer key for tablespace file */
8021 			if (!xb_export_cfp_write(table)) {
8022 				goto next_node;
8023 			}
8024 
8025 			/* init exp file */
8026 			memset(page, 0, UNIV_PAGE_SIZE);
8027 			mach_write_to_4(page    , 0x78706f72UL);
8028 			mach_write_to_4(page + 4, 0x74696e66UL);/*"xportinf"*/
8029 			mach_write_to_4(page + 8, n_index);
8030 			strncpy((char *) page + 12,
8031 				table_name, 500);
8032 
8033 			msg("xtrabackup: export metadata of "
8034 			    "table '%s' to file `%s` "
8035 			    "(%lu indexes)\n",
8036 			    table_name, info_file_path,
8037 			    n_index);
8038 
8039 			n_index = 1;
8040 			while (index) {
8041 				mach_write_to_8(page + n_index * 512, index->id);
8042 				mach_write_to_4(page + n_index * 512 + 8,
8043 						index->page);
8044 				strncpy((char *) page + n_index * 512 +
8045 					12, index->name, 500);
8046 
8047 				msg("xtrabackup:     name=%s, "
8048 				    "id.low=%lu, page=%lu\n",
8049 				    index->name(),
8050 				    (ulint)(index->id &
8051 					    0xFFFFFFFFUL),
8052 				    (ulint) index->page);
8053 				index = dict_table_get_next_index(index);
8054 				n_index++;
8055 			}
8056 
8057 			os_normalize_path(info_file_path);
8058 			info_file = os_file_create(
8059 				0,
8060 				info_file_path,
8061 				OS_FILE_OVERWRITE,
8062 				OS_FILE_NORMAL, OS_DATA_FILE,
8063 				false,
8064 				&success);
8065 			if (!success) {
8066 				os_file_get_last_error(TRUE);
8067 				goto next_node;
8068 			}
8069 			success = os_file_write(write_request, info_file_path,
8070 						info_file, page,
8071 						0, UNIV_PAGE_SIZE);
8072 			if (!success) {
8073 				os_file_get_last_error(TRUE);
8074 				goto next_node;
8075 			}
8076 			success = os_file_flush(info_file);
8077 			if (!success) {
8078 				os_file_get_last_error(TRUE);
8079 				goto next_node;
8080 			}
8081 next_node:
8082 			if (info_file != XB_FILE_UNDEFINED) {
8083 				os_file_close(info_file);
8084 				info_file = XB_FILE_UNDEFINED;
8085 			}
8086 			mutex_exit(&(dict_sys->mutex));
8087 		}
8088 
8089 		ut_free(buf);
8090 
8091 		datafiles_iter_free(it);
8092 	}
8093 
8094 	/* print the binary log position  */
8095 	trx_sys_print_mysql_binlog_offset();
8096 	msg("\n");
8097 
8098 	/* output to xtrabackup_binlog_pos_innodb and (if
8099 	backup_safe_binlog_info was available on the server) to
8100 	xtrabackup_binlog_info. In the latter case xtrabackup_binlog_pos_innodb
8101 	becomes redundant and is created only for compatibility. */
8102 	if (!store_binlog_info("xtrabackup_binlog_pos_innodb") ||
8103 	    (recover_binlog_info &&
8104 	     !store_binlog_info(XTRABACKUP_BINLOG_INFO))) {
8105 
8106 		exit(EXIT_FAILURE);
8107 	}
8108 
8109 	if (!store_master_key_id("xtrabackup_master_key_id")) {
8110 		exit(EXIT_FAILURE);
8111 	}
8112 
8113 	if (innobase_log_arch_dir)
8114 		srv_start_lsn = log_sys->lsn = recv_sys->recovered_lsn;
8115 
8116 	/* Check whether the log is applied enough or not. */
8117 	if ((xtrabackup_incremental
8118 	     && srv_start_lsn < incremental_to_lsn)
8119 	    ||(!xtrabackup_incremental
8120 	       && srv_start_lsn < metadata_to_lsn)) {
8121 		msg("xtrabackup: error: "
8122 		    "The transaction log file is corrupted.\n"
8123 		    "xtrabackup: error: "
8124 		    "The log was not applied to the intended LSN!\n");
8125 		msg("xtrabackup: Log applied to lsn " LSN_PF "\n",
8126 		    srv_start_lsn);
8127 		if (xtrabackup_incremental) {
8128 			msg("xtrabackup: The intended lsn is " LSN_PF "\n",
8129 			    incremental_to_lsn);
8130 		} else {
8131 			msg("xtrabackup: The intended lsn is " LSN_PF "\n",
8132 			    metadata_to_lsn);
8133 		}
8134 		exit(EXIT_FAILURE);
8135 	}
8136 
8137 	xb_write_galera_info(xtrabackup_incremental);
8138 
8139 	if(innodb_end())
8140 		goto error_cleanup;
8141 
8142         innodb_free_param();
8143 
8144 	/* re-init necessary components */
8145 	os_event_global_init();
8146 	sync_check_init();
8147 #ifdef UNIV_DEBUG
8148 	sync_check_enable();
8149 #endif
8150 	/* Reset the system variables in the recovery module. */
8151 	os_thread_init();
8152 	trx_pool_init();
8153 	que_init();
8154 
8155 	if(xtrabackup_close_temp_log(TRUE))
8156 		exit(EXIT_FAILURE);
8157 
8158 	/* output to metadata file */
8159 	{
8160 		char	filename[FN_REFLEN];
8161 
8162 		strcpy(metadata_type, srv_apply_log_only ?
8163 					"log-applied" : "full-prepared");
8164 
8165 		if(xtrabackup_incremental
8166 		   && metadata_to_lsn < incremental_to_lsn)
8167 		{
8168 			metadata_to_lsn = incremental_to_lsn;
8169 			metadata_last_lsn = incremental_last_lsn;
8170 		}
8171 
8172 		sprintf(filename, "%s/%s", xtrabackup_target_dir, XTRABACKUP_METADATA_FILENAME);
8173 		if (!xtrabackup_write_metadata(filename)) {
8174 
8175 			msg("xtrabackup: Error: failed to write metadata "
8176 			    "to '%s'\n", filename);
8177 			exit(EXIT_FAILURE);
8178 		}
8179 
8180 		if(xtrabackup_extra_lsndir) {
8181 			sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, XTRABACKUP_METADATA_FILENAME);
8182 			if (!xtrabackup_write_metadata(filename)) {
8183 				msg("xtrabackup: Error: failed to write "
8184 				    "metadata to '%s'\n", filename);
8185 				exit(EXIT_FAILURE);
8186 			}
8187 		}
8188 	}
8189 
8190 	if (!apply_log_finish()) {
8191 		exit(EXIT_FAILURE);
8192 	}
8193 
8194 	trx_pool_close();
8195 
8196 	if (fil_system) {
8197 		fil_close();
8198 	}
8199 
8200 	os_thread_free();
8201 
8202 	sync_check_close();
8203 
8204 	/* start InnoDB once again to create log files */
8205 
8206 	if (!xtrabackup_apply_log_only) {
8207 
8208 		/* xtrabackup_incremental_dir is used to indicate that
8209 		we are going to apply incremental backup. Here we already
8210 		applied incremental backup and are about to do final prepare
8211 		of the full backup */
8212 		xtrabackup_incremental_dir = NULL;
8213 
8214 		if(innodb_init_param()) {
8215 			goto error;
8216 		}
8217 
8218 		srv_apply_log_only = FALSE;
8219 		srv_rebuild_indexes = FALSE;
8220 
8221 		/* increase IO threads */
8222 		if(srv_n_file_io_threads < 10) {
8223 			srv_n_read_io_threads = 4;
8224 			srv_n_write_io_threads = 4;
8225 		}
8226 
8227 		srv_shutdown_state = SRV_SHUTDOWN_NONE;
8228 
8229 		if(innodb_init())
8230 			goto error;
8231 
8232 		if (opt_encrypt_for_server_id_specified) {
8233 			if (!reencrypt_tablespace_keys(opt_encrypt_server_id)) {
8234 				msg("xtrabackup: error: "
8235 				    "Tablespace keys are not reencrypted.\n");
8236 				goto error;
8237 			}
8238 		}
8239 
8240 		if(innodb_end())
8241 			goto error;
8242 
8243                 innodb_free_param();
8244 
8245 	}
8246 
8247 	if (!use_dumped_tablespace_keys) {
8248 		xb_keyring_shutdown();
8249 	}
8250 
8251 	mysql_mutex_destroy(&LOCK_global_system_variables);
8252 
8253 	xb_filters_free();
8254 
8255 	return;
8256 
8257 error_cleanup:
8258 
8259 	if (!use_dumped_tablespace_keys) {
8260 		xb_keyring_shutdown();
8261 	}
8262 
8263 	xtrabackup_close_temp_log(FALSE);
8264 
8265 	mysql_mutex_destroy(&LOCK_global_system_variables);
8266 
8267 	xb_filters_free();
8268 
8269 error:
8270 	exit(EXIT_FAILURE);
8271 }
8272 
8273 /**************************************************************************
8274 Signals-related setup. */
8275 static
8276 void
setup_signals()8277 setup_signals()
8278 /*===========*/
8279 {
8280 	struct sigaction sa;
8281 
8282 	/* Print a stacktrace on some signals */
8283 	sa.sa_flags = SA_RESETHAND | SA_NODEFER;
8284 	sigemptyset(&sa.sa_mask);
8285 	sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
8286 #ifdef HAVE_STACKTRACE
8287 	my_init_stacktrace();
8288 #endif
8289 	sa.sa_handler = handle_fatal_signal;
8290 	sigaction(SIGSEGV, &sa, NULL);
8291 	sigaction(SIGABRT, &sa, NULL);
8292 	sigaction(SIGBUS, &sa, NULL);
8293 	sigaction(SIGILL, &sa, NULL);
8294 	sigaction(SIGFPE, &sa, NULL);
8295 
8296 #ifdef __linux__
8297 	/* Ensure xtrabackup process is killed when the parent one
8298 	(innobackupex) is terminated with an unhandled signal */
8299 
8300 	if (prctl(PR_SET_PDEATHSIG, SIGKILL)) {
8301 		msg("prctl() failed with errno = %d\n", errno);
8302 		exit(EXIT_FAILURE);
8303 	}
8304 #endif
8305 }
8306 
8307 /**************************************************************************
8308 Append group name to xb_load_default_groups list. */
8309 static
8310 void
append_defaults_group(const char * group,const char * default_groups[],size_t default_groups_size)8311 append_defaults_group(const char *group, const char *default_groups[],
8312 		      size_t default_groups_size)
8313 {
8314 	uint i;
8315 	bool appended = false;
8316 	for (i = 0; i < default_groups_size - 1; i++) {
8317 		if (default_groups[i] == NULL) {
8318 			default_groups[i] = group;
8319 			appended = true;
8320 			break;
8321 		}
8322 	}
8323 	ut_a(appended);
8324 }
8325 
8326 bool
xb_init()8327 xb_init()
8328 {
8329 	const char *mixed_options[4] = {NULL, NULL, NULL, NULL};
8330 	int n_mixed_options;
8331 
8332 	/* sanity checks */
8333 	if (opt_lock_ddl && opt_lock_ddl_per_table) {
8334 		msg("Error: %s and %s are mutually exclusive\n",
8335 		    "--lock-ddl", "--lock-ddl-per-table");
8336 		return(false);
8337 	}
8338 
8339 	if (opt_slave_info
8340 		&& opt_no_lock
8341 		&& !opt_safe_slave_backup) {
8342 		msg("Error: --slave-info is used with --no-lock but "
8343 			"without --safe-slave-backup. The binlog position "
8344 			"cannot be consistent with the backup data.\n");
8345 		return(false);
8346 	}
8347 
8348 	if (opt_rsync && xtrabackup_stream_fmt) {
8349 		msg("Error: --rsync doesn't work with --stream\n");
8350 		return(false);
8351 	}
8352 
8353 	if (opt_transition_key && opt_generate_transition_key) {
8354 		msg("Error: options --transition-key and "
8355 		    "--generate-transition-key are mutually exclusive.\n");
8356 		return(false);
8357 	}
8358 
8359 	n_mixed_options = 0;
8360 
8361 	if (opt_decompress) {
8362 		mixed_options[n_mixed_options++] = "--decompress";
8363 	} else if (opt_decrypt) {
8364 		mixed_options[n_mixed_options++] = "--decrypt";
8365 	}
8366 
8367 	if (xtrabackup_copy_back) {
8368 		mixed_options[n_mixed_options++] = "--copy-back";
8369 	}
8370 
8371 	if (xtrabackup_move_back) {
8372 		mixed_options[n_mixed_options++] = "--move-back";
8373 	}
8374 
8375 	if (xtrabackup_prepare) {
8376 		mixed_options[n_mixed_options++] = "--apply-log";
8377 	}
8378 
8379 	if (n_mixed_options > 1) {
8380 		msg("Error: %s and %s are mutually exclusive\n",
8381 			mixed_options[0], mixed_options[1]);
8382 		return(false);
8383 	}
8384 
8385 	if (xtrabackup_backup) {
8386 
8387 #ifdef HAVE_VERSION_CHECK
8388 		if (!opt_noversioncheck) {
8389 			version_check();
8390 		}
8391 #endif
8392 
8393 		if ((mysql_connection = xb_mysql_connect()) == NULL) {
8394 			return(false);
8395 		}
8396 
8397 		if (!get_mysql_vars(mysql_connection)) {
8398 			return(false);
8399 		}
8400 
8401 		if (opt_lock_ddl_per_table && have_backup_locks) {
8402 			msg_ts("You are taking your backup with --lock-ddl-per-table."
8403 							" Please consider moving to a more safe option --lock-ddl.\n");
8404 		}
8405 
8406 		if (opt_check_privileges) {
8407 			check_all_privileges();
8408 		}
8409 
8410 		history_start_time = time(NULL);
8411 
8412 		if (opt_lock_ddl &&
8413 		    !lock_tables_for_backup(mysql_connection,
8414 					    opt_lock_ddl_timeout, 0)) {
8415 			return (false);
8416 		}
8417 
8418 		parse_show_engine_innodb_status(mysql_connection);
8419 
8420 	}
8421 
8422 	return(true);
8423 }
8424 
8425 static const char*
normalize_privilege_target_name(const char * name)8426 normalize_privilege_target_name(const char* name)
8427 {
8428 	if (strcmp(name, "*") == 0) {
8429 		return "\\*";
8430 	} else {
8431 		/* should have no regex special characters. */
8432 		ut_ad(strpbrk(name, ".()[]*+?") == 0);
8433 	}
8434 	return name;
8435 }
8436 
8437 /******************************************************************//**
8438 Check if specific privilege is granted.
8439 Uses regexp magic to check if requested privilege is granted for given
8440 database.table or database.* or *.*
8441 or if user has 'ALL PRIVILEGES' granted.
8442 @return true if requested privilege is granted, false otherwise. */
8443 static bool
has_privilege(const std::list<std::string> & granted,const char * required,const char * db_name,const char * table_name)8444 has_privilege(const std::list<std::string> &granted,
8445 	const char* required,
8446 	const char* db_name,
8447 	const char* table_name)
8448 {
8449 	char buffer[1000];
8450 	xb_regex_t priv_re;
8451 	xb_regmatch_t tables_regmatch[1];
8452 	bool result = false;
8453 
8454 	db_name = normalize_privilege_target_name(db_name);
8455 	table_name = normalize_privilege_target_name(table_name);
8456 
8457 	int written = snprintf(buffer, sizeof(buffer),
8458 		"GRANT .*(%s)|(ALL PRIVILEGES).* ON (\\*|`%s`)\\.(\\*|`%s`)",
8459 		required, db_name, table_name);
8460 	if (written < 0 || written == sizeof(buffer)
8461 		|| !compile_regex(buffer, "has_privilege", &priv_re)) {
8462 		exit(EXIT_FAILURE);
8463 	}
8464 
8465 	typedef std::list<std::string>::const_iterator string_iter;
8466 	for (string_iter i = granted.begin(), e = granted.end(); i != e; ++i) {
8467 		int res = xb_regexec(&priv_re, i->c_str(),
8468 			1, tables_regmatch, 0);
8469 
8470 		if (res != REG_NOMATCH) {
8471 			result = true;
8472 			break;
8473 		}
8474 	}
8475 
8476 	xb_regfree(&priv_re);
8477 	return result;
8478 }
8479 
8480 enum {
8481 	PRIVILEGE_OK = 0,
8482 	PRIVILEGE_WARNING = 1,
8483 	PRIVILEGE_ERROR = 2,
8484 };
8485 
8486 /******************************************************************//**
8487 Check if specific privilege is granted.
8488 Prints error message if required privilege is missing.
8489 @return PRIVILEGE_OK if requested privilege is granted, error otherwise. */
8490 static
check_privilege(const std::list<std::string> & granted_priv,const char * required,const char * target_database,const char * target_table,int error=PRIVILEGE_ERROR)8491 int check_privilege(
8492 	const std::list<std::string> &granted_priv, /* in: list of
8493 							granted privileges*/
8494 	const char* required,		/* in: required privilege name */
8495 	const char* target_database,	/* in: required privilege target
8496 						database name */
8497 	const char* target_table,	/* in: required privilege target
8498 						table name */
8499 	int error = PRIVILEGE_ERROR)	/* in: return value if privilege
8500 						is not granted */
8501 {
8502 	if (!has_privilege(granted_priv,
8503 		required, target_database, target_table)) {
8504 		msg("xtrabackup: %s: missing required privilege %s on %s.%s\n",
8505 			(error == PRIVILEGE_ERROR ? "Error" : "Warning"),
8506 			required, target_database, target_table);
8507 		return error;
8508 	}
8509 	return PRIVILEGE_OK;
8510 }
8511 
8512 /******************************************************************//**
8513 Check DB user privileges according to the intended actions.
8514 
8515 Fetches DB user privileges, determines intended actions based on
8516 command-line arguments and prints missing privileges.
8517 May terminate application with EXIT_FAILURE exit code.*/
8518 static void
check_all_privileges()8519 check_all_privileges()
8520 {
8521 	if (!mysql_connection) {
8522 		/* Not connected, no queries is going to be executed. */
8523 		return;
8524 	}
8525 
8526 	/* Fetch effective privileges. */
8527 	std::list<std::string> granted_privileges;
8528 	MYSQL_ROW row = 0;
8529 	MYSQL_RES* result = xb_mysql_query(mysql_connection, "SHOW GRANTS",
8530 		true);
8531 	while((row = mysql_fetch_row(result))) {
8532 		granted_privileges.push_back(*row);
8533 	}
8534 	mysql_free_result(result);
8535 
8536 	int check_result = PRIVILEGE_OK;
8537 	bool reload_checked = false;
8538 
8539 	/* SHOW DATABASES */
8540 	check_result |= check_privilege(granted_privileges,
8541 		"SHOW DATABASES", "*", "*");
8542 
8543 	/* SELECT 'INNODB_CHANGED_PAGES', COUNT(*) FROM INFORMATION_SCHEMA.PLUGINS */
8544 	check_result |= check_privilege(
8545 		granted_privileges,
8546 		"SELECT", "INFORMATION_SCHEMA", "PLUGINS");
8547 
8548 	/* SHOW ENGINE INNODB STATUS */
8549 	/* SHOW FULL PROCESSLIST */
8550 	check_result |= check_privilege(granted_privileges,
8551 		"PROCESS", "*", "*");
8552 
8553 	if (xb_mysql_numrows(mysql_connection,
8554 		"SHOW DATABASES LIKE 'PERCONA_SCHEMA';",
8555 		false) == 0) {
8556 		/* CREATE DATABASE IF NOT EXISTS PERCONA_SCHEMA */
8557 		check_result |= check_privilege(
8558 			granted_privileges,
8559 			"CREATE", "*", "*");
8560 	} else if (xb_mysql_numrows(mysql_connection,
8561 		"SHOW TABLES IN PERCONA_SCHEMA "
8562 		"LIKE 'xtrabackup_history';",
8563 		false) == 0) {
8564 		/* CREATE TABLE IF NOT EXISTS PERCONA_SCHEMA.xtrabackup_history */
8565 		check_result |= check_privilege(
8566 			granted_privileges,
8567 			"CREATE", "PERCONA_SCHEMA", "*");
8568 	}
8569 
8570 	/* FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS */
8571 	if (have_flush_engine_logs
8572 		/* FLUSH NO_WRITE_TO_BINLOG TABLES */
8573 		|| (opt_lock_wait_timeout && !opt_kill_long_queries_timeout
8574 			&& !opt_no_lock)
8575 		/* FLUSH TABLES WITH READ LOCK */
8576 		|| !opt_no_lock
8577 		/* LOCK BINLOG FOR BACKUP */
8578 		/* UNLOCK BINLOG */
8579 		|| (have_backup_locks && !opt_no_lock)) {
8580 		check_result |= check_privilege(
8581 			granted_privileges,
8582 			"RELOAD", "*", "*");
8583 		reload_checked = true;
8584 	}
8585 
8586 
8587 	/* FLUSH TABLES WITH READ LOCK */
8588 	if (!opt_no_lock
8589 		/* LOCK TABLES FOR BACKUP */
8590 		/* UNLOCK TABLES */
8591 		&& ((have_backup_locks && !opt_no_lock) || opt_slave_info
8592 		|| opt_binlog_info == BINLOG_INFO_ON)) {
8593 		check_result |= check_privilege(
8594 			granted_privileges,
8595 			"LOCK TABLES", "*", "*");
8596 	}
8597 
8598 	/* SELECT innodb_to_lsn FROM PERCONA_SCHEMA.xtrabackup_history ... */
8599 	if (opt_incremental_history_name || opt_incremental_history_uuid) {
8600 		check_result |= check_privilege(
8601 			granted_privileges,
8602 			"SELECT", "PERCONA_SCHEMA", "xtrabackup_history");
8603 	}
8604 
8605 	if (!reload_checked
8606 		/* FLUSH BINARY LOGS */
8607 		&& opt_galera_info) {
8608 		check_result |= check_privilege(
8609 			granted_privileges,
8610 			"RELOAD", "*", "*",
8611 			PRIVILEGE_WARNING);
8612 	}
8613 
8614 	/* KILL ... */
8615 	if (opt_kill_long_queries_timeout
8616 		/* START SLAVE SQL_THREAD */
8617 		/* STOP SLAVE SQL_THREAD */
8618 		|| opt_safe_slave_backup) {
8619 		check_result |= check_privilege(
8620 			granted_privileges,
8621 			"SUPER", "*", "*",
8622 			PRIVILEGE_WARNING);
8623 	}
8624 
8625 	/* SHOW MASTER STATUS */
8626 	/* SHOW SLAVE STATUS */
8627 	if (opt_galera_info || opt_slave_info
8628 		|| (opt_no_lock && opt_safe_slave_backup)
8629 		/* LOCK BINLOG FOR BACKUP */
8630 		|| (have_backup_locks && !opt_no_lock)) {
8631 		check_result |= check_privilege(granted_privileges,
8632 			"REPLICATION CLIENT", "*", "*",
8633 			PRIVILEGE_WARNING);
8634 	}
8635 
8636 	if (check_result & PRIVILEGE_ERROR) {
8637 		exit(EXIT_FAILURE);
8638 	}
8639 }
8640 
8641 void
handle_options(int argc,char ** argv,int * argc_client,char *** argv_client,int * argc_server,char *** argv_server)8642 handle_options(int argc, char **argv, int *argc_client, char ***argv_client,
8643 	       int *argc_server, char ***argv_server)
8644 {
8645 	int	i;
8646 	int	ho_error;
8647 	char	conf_file[FN_REFLEN];
8648 
8649 	char*	target_dir = NULL;
8650 	bool	prepare = false;
8651 
8652 	*argc_client = argc;
8653 	*argc_server = argc;
8654 	*argv_client = argv;
8655 	*argv_server = argv;
8656 
8657 	/* scan options for group and config file to load defaults from */
8658 	for (i = 1; i < argc; i++) {
8659 
8660 		char *optend = strcend(argv[i], '=');
8661 
8662 		if (strncmp(argv[i], "--defaults-group",
8663 			    optend - argv[i]) == 0) {
8664 			defaults_group = optend + 1;
8665 			append_defaults_group(defaults_group,
8666 				xb_server_default_groups,
8667 				array_elements(xb_server_default_groups));
8668 		}
8669 
8670 		if (strncmp(argv[i], "--login-path",
8671 			    optend - argv[i]) == 0) {
8672 			append_defaults_group(optend + 1,
8673 				xb_client_default_groups,
8674 				array_elements(xb_client_default_groups));
8675 		}
8676 
8677 		if (!strncmp(argv[i], "--prepare",
8678 			     optend - argv[i])) {
8679 			prepare = true;
8680 		}
8681 
8682 		if (!strncmp(argv[i], "--apply-log",
8683 			     optend - argv[i])) {
8684 			prepare = true;
8685 		}
8686 
8687 		if (!strncmp(argv[i], "--target-dir",
8688 			     optend - argv[i]) && *optend) {
8689 			target_dir = optend + 1;
8690 		}
8691 
8692 		if (!*optend && argv[i][0] != '-') {
8693 			target_dir = argv[i];
8694 		}
8695 	}
8696 
8697 	snprintf(conf_file, sizeof(conf_file), "my");
8698 
8699 	if (prepare && target_dir) {
8700 		snprintf(conf_file, sizeof(conf_file),
8701 			 "%s/backup-my.cnf", target_dir);
8702 	}
8703 	if (load_defaults(conf_file, xb_server_default_groups,
8704 			  argc_server, argv_server)) {
8705 		exit(EXIT_FAILURE);
8706 	}
8707 
8708 	print_param_str <<
8709 		"# This MySQL options file was generated by XtraBackup.\n"
8710 		"[" << defaults_group << "]\n";
8711 
8712 	/* We want xtrabackup to ignore unknown options, because it only
8713 	recognizes a small subset of server variables */
8714 	my_getopt_skip_unknown = TRUE;
8715 
8716 	/* Reset u_max_value for all options, as we don't want the
8717 	--maximum-... modifier to set the actual option values */
8718 	for (my_option *optp= xb_server_options; optp->name; optp++) {
8719 		optp->u_max_value = (G_PTR *) &global_max_value;
8720 	}
8721 
8722 	/* Throw a descriptive error if --defaults-file or --defaults-extra-file
8723 	is not the first command line argument */
8724 	for (int i = 2 ; i < argc ; i++) {
8725 		char *optend = strcend((argv)[i], '=');
8726 
8727 		if (optend - argv[i] == 15 &&
8728                     !strncmp(argv[i], "--defaults-file", optend - argv[i])) {
8729 
8730 			msg("xtrabackup: Error: --defaults-file "
8731 			    "must be specified first on the command "
8732 			    "line\n");
8733 			exit(EXIT_FAILURE);
8734 		}
8735                 if (optend - argv[i] == 21 &&
8736 		    !strncmp(argv[i], "--defaults-extra-file",
8737 			     optend - argv[i])) {
8738 
8739 			msg("xtrabackup: Error: --defaults-extra-file "
8740 			    "must be specified first on the command "
8741 			    "line\n");
8742 			exit(EXIT_FAILURE);
8743 		}
8744 	}
8745 
8746 	if (*argc_server > 0
8747 	    && (ho_error=handle_options(argc_server, argv_server,
8748 					xb_server_options, xb_get_one_option)))
8749 		exit(ho_error);
8750 
8751 	msg("xtrabackup: recognized server arguments: %s\n",
8752 	    param_str.str().c_str());
8753 	param_str.str("");
8754 
8755 	if (load_defaults(conf_file, xb_client_default_groups,
8756 			  argc_client, argv_client)) {
8757 		exit(EXIT_FAILURE);
8758 	}
8759 
8760 	if (strcmp(base_name(my_progname), INNOBACKUPEX_BIN_NAME) == 0 &&
8761 	    *argc_client > 0) {
8762 		/* emulate innobackupex script */
8763 		innobackupex_mode = true;
8764 		if (!ibx_handle_options(argc_client, argv_client)) {
8765 			exit(EXIT_FAILURE);
8766 		}
8767 	}
8768 
8769 	if (*argc_client > 0
8770 	    && (ho_error=handle_options(argc_client, argv_client,
8771 					xb_client_options, xb_get_one_option)))
8772 		exit(ho_error);
8773 
8774 	msg("xtrabackup: recognized client arguments: %s\n",
8775 	    param_str.str().c_str());
8776 	param_str.clear();
8777 
8778 	/* Reject command line arguments that don't look like options, i.e. are
8779 	not of the form '-X' (single-character options) or '--option' (long
8780 	options) */
8781 	for (int i = 0 ; i < *argc_client ; i++) {
8782 		const char * const opt = (*argv_client)[i];
8783 
8784 		if (strncmp(opt, "--", 2) &&
8785 		    !(strlen(opt) == 2 && opt[0] == '-')) {
8786 			bool server_option = true;
8787 
8788 			for (int j = 0; j < *argc_server; j++) {
8789 				if (opt == (*argv_server)[j]) {
8790 					server_option = false;
8791 					break;
8792 				}
8793 			}
8794 
8795 			if (!server_option) {
8796 				msg("xtrabackup: Error:"
8797 				    " unknown argument: '%s'\n", opt);
8798 				exit(EXIT_FAILURE);
8799 			}
8800 		}
8801 	}
8802 
8803 	if (tty_password) {
8804 		opt_password = get_tty_password(NullS);
8805 	}
8806 
8807 	if (tty_transition_key) {
8808 		opt_transition_key = get_tty_password("Enter transition key: ");
8809 	}
8810 }
8811 
setup_error_messages()8812 void setup_error_messages()
8813 {
8814 	static const char *all_msgs[4000];
8815 	my_default_lc_messages = &my_locale_en_US;
8816 	my_default_lc_messages->errmsgs->errmsgs = all_msgs;
8817 
8818 	struct {
8819 		int id;
8820 		const char *fmt;
8821 	}
8822 	xb_msgs[] = {
8823 		{ ER_DATABASE_NAME,"Database" },
8824 		{ ER_TABLE_NAME,"Table"},
8825 		{ ER_PARTITION_NAME, "Partition" },
8826 		{ ER_SUBPARTITION_NAME, "Subpartition" },
8827 		{ ER_TEMPORARY_NAME, "Temporary"},
8828 		{ ER_RENAMED_NAME, "Renamed"},
8829 		{ ER_CANT_FIND_DL_ENTRY, "Can't find symbol '%-.128s' in library"},
8830 		{ ER_CANT_OPEN_LIBRARY, "Can't open shared library '%-.192s' (errno: %d, %-.128s)" },
8831 		{ ER_OUTOFMEMORY, "Out of memory; restart server and try again (needed %d bytes)" },
8832 		{ ER_CANT_OPEN_LIBRARY, "Can't open shared library '%-.192s' (errno: %d, %-.128s)" },
8833 		{ ER_UDF_NO_PATHS, "No paths allowed for shared library" },
8834 		{ ER_CANT_INITIALIZE_UDF,"Can't initialize function '%-.192s'; %-.80s"},
8835 		{ ER_PLUGIN_IS_NOT_LOADED,"Plugin '%-.192s' is not loaded" }
8836 	};
8837 
8838 	for (int i = 0; i < (int)array_elements(all_msgs); i++) {
8839 		all_msgs[i] = "Unknown error";
8840 	}
8841 
8842 	for (int i = 0; i < (int)array_elements(xb_msgs); i++) {
8843 		all_msgs[xb_msgs[i].id - 1000] = xb_msgs[i].fmt;
8844 	}
8845 }
8846 
8847 /* ================= main =================== */
8848 
main(int argc,char ** argv)8849 int main(int argc, char **argv)
8850 {
8851 	char **client_defaults, **server_defaults;
8852 	int client_argc, server_argc;
8853 	char cwd[FN_REFLEN];
8854 
8855 	setup_signals();
8856 
8857 	MY_INIT(argv[0]);
8858 
8859 	if (my_create_thread_local_key(&THR_THD,NULL) ||
8860 	    my_create_thread_local_key(&THR_MALLOC,NULL))
8861 	{
8862 		exit(EXIT_FAILURE);
8863 	}
8864 	THR_THD_initialized = true;
8865 	THR_MALLOC_initialized = true;
8866 
8867 	my_thread_set_THR_THD(NULL);
8868 
8869 	xb_regex_init();
8870 
8871 	capture_tool_command(argc, argv);
8872 
8873 	if (mysql_server_init(-1, NULL, NULL))
8874 	{
8875 		exit(EXIT_FAILURE);
8876 	}
8877 
8878 	system_charset_info= &my_charset_utf8_general_ci;
8879 	key_map_full.set_all();
8880 
8881 	handle_options(argc, argv, &client_argc, &client_defaults,
8882 		       &server_argc, &server_defaults);
8883 
8884 	xb_libgcrypt_init();
8885 
8886 	if (innobackupex_mode) {
8887 		if (!ibx_init()) {
8888 			exit(EXIT_FAILURE);
8889 		}
8890 	}
8891 
8892 	if ((!xtrabackup_print_param) && (!xtrabackup_prepare) && (strcmp(mysql_data_home, "./") == 0)) {
8893 		if (!xtrabackup_print_param)
8894 			usage();
8895 		msg("\nxtrabackup: Error: Please set parameter 'datadir'\n");
8896 		exit(EXIT_FAILURE);
8897 	}
8898 
8899 	/* Expand target-dir, incremental-basedir, etc. */
8900 
8901 	my_getwd(cwd, sizeof(cwd), MYF(0));
8902 
8903 	my_load_path(xtrabackup_real_target_dir,
8904 		     xtrabackup_target_dir, cwd);
8905 	unpack_dirname(xtrabackup_real_target_dir,
8906 		       xtrabackup_real_target_dir);
8907 	xtrabackup_target_dir= xtrabackup_real_target_dir;
8908 
8909 	if (xtrabackup_incremental_basedir) {
8910 		my_load_path(xtrabackup_real_incremental_basedir,
8911 			     xtrabackup_incremental_basedir, cwd);
8912 		unpack_dirname(xtrabackup_real_incremental_basedir,
8913 			       xtrabackup_real_incremental_basedir);
8914 		xtrabackup_incremental_basedir =
8915 			xtrabackup_real_incremental_basedir;
8916 	}
8917 
8918 	if (xtrabackup_incremental_dir) {
8919 		my_load_path(xtrabackup_real_incremental_dir,
8920 			     xtrabackup_incremental_dir, cwd);
8921 		unpack_dirname(xtrabackup_real_incremental_dir,
8922 			       xtrabackup_real_incremental_dir);
8923 		xtrabackup_incremental_dir = xtrabackup_real_incremental_dir;
8924 	}
8925 
8926 	if (xtrabackup_extra_lsndir) {
8927 		my_load_path(xtrabackup_real_extra_lsndir,
8928 			     xtrabackup_extra_lsndir, cwd);
8929 		unpack_dirname(xtrabackup_real_extra_lsndir,
8930 			       xtrabackup_real_extra_lsndir);
8931 		xtrabackup_extra_lsndir = xtrabackup_real_extra_lsndir;
8932 	}
8933 
8934 	/* get default temporary directory */
8935 	if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0]) {
8936 		opt_mysql_tmpdir = getenv("TMPDIR");
8937 #if defined(__WIN__)
8938 		if (!opt_mysql_tmpdir) {
8939 			opt_mysql_tmpdir = getenv("TEMP");
8940 		}
8941 		if (!opt_mysql_tmpdir) {
8942 			opt_mysql_tmpdir = getenv("TMP");
8943 		}
8944 #endif
8945 		if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0]) {
8946 			opt_mysql_tmpdir = const_cast<char*>(DEFAULT_TMPDIR);
8947 		}
8948 	}
8949 
8950 	/* temporary setting of enough size */
8951 	srv_page_size_shift = UNIV_PAGE_SIZE_SHIFT_MAX;
8952 	srv_page_size = UNIV_PAGE_SIZE_MAX;
8953 	if (xtrabackup_backup && xtrabackup_incremental) {
8954 		/* direct specification is only for --backup */
8955 		/* and the lsn is prior to the other option */
8956 
8957 		char* endchar;
8958 		int error = 0;
8959 		incremental_lsn = strtoll(xtrabackup_incremental, &endchar, 10);
8960 		if (*endchar != '\0')
8961 			error = 1;
8962 
8963 		if (error) {
8964 			msg("xtrabackup: value '%s' may be wrong format for "
8965 			    "incremental option.\n", xtrabackup_incremental);
8966 			exit(EXIT_FAILURE);
8967 		}
8968 	} else if (xtrabackup_backup && xtrabackup_incremental_basedir) {
8969 		char	filename[FN_REFLEN];
8970 
8971 		sprintf(filename, "%s/%s", xtrabackup_incremental_basedir,
8972 			XTRABACKUP_METADATA_FILENAME);
8973 
8974 		if (!xtrabackup_read_metadata(filename)) {
8975 			msg("xtrabackup: error: failed to read metadata from "
8976 			    "%s\n", filename);
8977 			exit(EXIT_FAILURE);
8978 		}
8979 
8980 		incremental_lsn = metadata_to_lsn;
8981 		xtrabackup_incremental = xtrabackup_incremental_basedir; //dummy
8982 	} else if (xtrabackup_prepare && xtrabackup_incremental_dir) {
8983 		char	filename[FN_REFLEN];
8984 
8985 		sprintf(filename, "%s/%s", xtrabackup_incremental_dir,
8986 			XTRABACKUP_METADATA_FILENAME);
8987 
8988 		if (!xtrabackup_read_metadata(filename)) {
8989 			msg("xtrabackup: error: failed to read metadata from "
8990 			    "%s\n", filename);
8991 			exit(EXIT_FAILURE);
8992 		}
8993 
8994 		incremental_lsn = metadata_from_lsn;
8995 		incremental_to_lsn = metadata_to_lsn;
8996 		incremental_last_lsn = metadata_last_lsn;
8997 		incremental_flushed_lsn = backup_redo_log_flushed_lsn;
8998 		xtrabackup_incremental = xtrabackup_incremental_dir; //dummy
8999 
9000 	} else if (opt_incremental_history_name) {
9001 		xtrabackup_incremental = opt_incremental_history_name;
9002 	} else if (opt_incremental_history_uuid) {
9003 		xtrabackup_incremental = opt_incremental_history_uuid;
9004 	} else {
9005 		xtrabackup_incremental = NULL;
9006 	}
9007 
9008 	if (!xb_init()) {
9009 		exit(EXIT_FAILURE);
9010 	}
9011 
9012 	/* --print-param */
9013 	if (xtrabackup_print_param) {
9014 
9015 		printf("%s", print_param_str.str().c_str());
9016 
9017 		exit(EXIT_SUCCESS);
9018 	}
9019 
9020 	print_version();
9021 	if (xtrabackup_incremental) {
9022 		msg("incremental backup from " LSN_PF " is enabled.\n",
9023 		    incremental_lsn);
9024 	}
9025 
9026 	if (xtrabackup_export && innobase_file_per_table == FALSE) {
9027 		msg("xtrabackup: auto-enabling --innodb-file-per-table due to "
9028 		    "the --export option\n");
9029 		innobase_file_per_table = TRUE;
9030 	}
9031 
9032 	if (xtrabackup_incremental && xtrabackup_stream &&
9033 	    xtrabackup_stream_fmt == XB_STREAM_FMT_TAR) {
9034 		msg("xtrabackup: error: "
9035 		    "streaming incremental backups are incompatible with the \n"
9036 		    "'tar' streaming format. Use --stream=xbstream instead.\n");
9037 		exit(EXIT_FAILURE);
9038 	}
9039 
9040 	if ((xtrabackup_compress || xtrabackup_encrypt) && xtrabackup_stream &&
9041 	    xtrabackup_stream_fmt == XB_STREAM_FMT_TAR) {
9042 		msg("xtrabackup: error: "
9043 		    "compressed and encrypted backups are incompatible with the \n"
9044 		    "'tar' streaming format. Use --stream=xbstream instead.\n");
9045 		exit(EXIT_FAILURE);
9046 	}
9047 
9048 	if (!xtrabackup_prepare &&
9049 	    (innobase_log_arch_dir || xtrabackup_archived_to_lsn)) {
9050 
9051 		/* Default my.cnf can contain innobase_log_arch_dir option set
9052 		for server, reset it to allow backup. */
9053 		innobase_log_arch_dir= NULL;
9054 		xtrabackup_archived_to_lsn= 0;
9055 		msg("xtrabackup: warning: "
9056 		    "as --innodb-log-arch-dir and --to-archived-lsn can be used "
9057 		    "only with --prepare they will be reset\n");
9058 	}
9059 	if (xtrabackup_throttle && !xtrabackup_backup) {
9060 		xtrabackup_throttle = 0;
9061 		msg("xtrabackup: warning: --throttle has effect "
9062 		    "only with --backup\n");
9063 	}
9064 
9065 	if (xtrabackup_backup && xtrabackup_compact) {
9066 		msg("xtrabackup: error: compact backups are not supported "
9067 		    "by this version of xtrabackup\n");
9068 		exit(EXIT_FAILURE);
9069 	}
9070 
9071 	/* cannot execute both for now */
9072 	{
9073 		int num = 0;
9074 
9075 		if (xtrabackup_backup) num++;
9076 		if (xtrabackup_stats) num++;
9077 		if (xtrabackup_prepare) num++;
9078 		if (xtrabackup_copy_back) num++;
9079 		if (xtrabackup_move_back) num++;
9080 		if (xtrabackup_decrypt_decompress) num++;
9081 		if (num != 1) { /* !XOR (for now) */
9082 			usage();
9083 			exit(EXIT_FAILURE);
9084 		}
9085 	}
9086 
9087 #ifndef __WIN__
9088 	if (xtrabackup_debug_sync) {
9089 		signal(SIGCONT, sigcont_handler);
9090 	}
9091 #endif
9092 
9093 	system_charset_info= &my_charset_utf8_general_ci;
9094 	files_charset_info= &my_charset_utf8_general_ci;
9095 	national_charset_info= &my_charset_utf8_general_ci;
9096 	table_alias_charset= &my_charset_bin;
9097 	character_set_filesystem= &my_charset_bin;
9098 
9099 	sys_var_init();
9100 	setup_error_messages();
9101 
9102 	/* --backup */
9103 	if (xtrabackup_backup) {
9104 		xtrabackup_backup_func();
9105 	}
9106 
9107 	/* --stats */
9108 	if (xtrabackup_stats) {
9109 		xtrabackup_stats_func(server_argc, server_defaults);
9110 	}
9111 
9112 	/* --prepare */
9113 	if (xtrabackup_prepare) {
9114 		xtrabackup_prepare_func(server_argc, server_defaults);
9115 	}
9116 
9117 	if (xtrabackup_copy_back || xtrabackup_move_back) {
9118 		if (!check_if_param_set("datadir")) {
9119 			msg("Error: datadir must be specified.\n");
9120 			exit(EXIT_FAILURE);
9121 		}
9122 		mysql_mutex_init(key_LOCK_keyring_operations,
9123 				 &LOCK_keyring_operations, MY_MUTEX_INIT_FAST);
9124 		if (!copy_back(server_argc, server_defaults)) {
9125 			exit(EXIT_FAILURE);
9126 		}
9127 		mysql_mutex_destroy(&LOCK_keyring_operations);
9128 	}
9129 
9130 	if (xtrabackup_decrypt_decompress && !decrypt_decompress()) {
9131 		exit(EXIT_FAILURE);
9132 	}
9133 
9134 	backup_cleanup();
9135 
9136 	if (innobackupex_mode) {
9137 		ibx_cleanup();
9138 	}
9139 
9140 	xb_regex_end();
9141 
9142 	free_defaults(client_defaults);
9143 	free_defaults(server_defaults);
9144 
9145 	if (THR_THD)
9146 		(void) pthread_key_delete(THR_THD);
9147 
9148 	if (THR_THD_initialized) {
9149 		THR_THD_initialized = false;
9150 		(void) my_delete_thread_local_key(THR_THD);
9151 	}
9152 
9153 	if (THR_MALLOC_initialized) {
9154 		THR_MALLOC_initialized= false;
9155 		(void) my_delete_thread_local_key(THR_MALLOC);
9156 	}
9157 	msg_ts("completed OK!\n");
9158 
9159 	exit(EXIT_SUCCESS);
9160 }
9161