/** Implement --backup @return whether the operation succeeded */ static bool xtrabackup_backup_func() { os_thread_create(log_copying_thread, NULL, &log_copying_thread_id); datafiles_iter_t *it = datafiles_iter_new(); for (i = 0; i < (uint) xtrabackup_parallel; i++) { data_threads[i].it = it; data_threads[i].num = i+1; data_threads[i].count = &count; data_threads[i].count_mutex = &count_mutex; os_thread_create(data_copy_thread_func, data_threads + i, &data_threads[i].id); } /* Wait for threads to exit */ while (1) { os_thread_sleep(1000000); pthread_mutex_lock(&count_mutex); bool stop = count == 0; bool ok = backup_start(); --------- Datafiles copying thread.*/ static os_thread_ret_t DECLARE_THREAD(data_copy_thread_func)( /*==================*/ void *arg) /* thread context */ { data_thread_ctxt_t *ctxt = (data_thread_ctxt_t *) arg; while ((node = datafiles_iter_next(ctxt->it)) != NULL) { DBUG_MARIABACKUP_EVENT("before_copy", node->space->name); /* copy the datafile */ if (xtrabackup_copy_datafile(node, num, NULL, xtrabackup_incremental ? wf_incremental : wf_write_through)) die("failed to copy datafile."); DBUG_MARIABACKUP_EVENT("after_copy", node->space->name); ------- /** Copy innodb data file to the specified destination. @param[in] node file node of a tablespace @param[in] thread_n thread id, used in the text of diagnostic messages @param[in] dest_name destination file name @param[in] write_filter write filter to copy data, can be pass-through filter for full backup, pages filter for incremental backup, etc. @return FALSE on success and TRUE on error */ static my_bool xtrabackup_copy_datafile(fil_node_t *node, uint thread_n, const char *dest_name, const xb_write_filt_t &write_filter) { const char* const node_name = node->space->name; const char* const node_path = node->name; res = xb_fil_cur_open(&cursor, read_filter, node, thread_n, ULLONG_MAX); strncpy(dst_name, dest_name ? dest_name : cursor.rel_path, dstfile = ds_open(ds_data, dst_name, &cursor.statinfo); msg(thread_n, "%s %s", action, node_path); /* The main copy loop */ while ((res = xb_fil_cur_read(&cursor)) == XB_FIL_CUR_SUCCESS) { if (!write_filter.process(&write_filt_ctxt, dstfile)) { goto error; } } ------- backup_start() if (!backup_files(fil_path_to_mysql_datadir, true)) { if (!lock_tables(mysql_connection)) { if (!backup_files(fil_path_to_mysql_datadir, false)) { if (!backup_files_from_datadir(fil_path_to_mysql_datadir)) { msg("Waiting for log copy thread to read lsn %llu", (ulonglong)server_lsn_after_lock); backup_wait_for_lsn(server_lsn_after_lock); backup_fix_ddl(); ------- bool backup_files(const char *from, bool prep_mode) { if (prep_mode && !opt_rsync) { return(true); } msg("Starting %s non-InnoDB tables and files", prep_mode ? "prep copy of" : "to backup"); while (datadir_iter_next(it, &node)) { if (!node.is_empty_dir) { ret = datafile_copy_backup(node.filepath, 1); ------ /* Copy some files from top level datadir. Do not copy the Innodb files (ibdata1, redo log files), as this is done in a separate step. */ static bool backup_files_from_datadir(const char *dir_path) { while (os_file_readdir_next_file(dir_path, dir, &info) == 0) { if (info.type != OS_FILE_TYPE_FILE) continue; if (!(ret = copy_file(ds_data, full_path.c_str() , info.name, 1))) break; bool datafile_copy_backup(const char *filepath, uint thread_n) { const char *ext_list[] = {"frm", "isl", "MYD", "MYI", "MAD", "MAI", "MRG", "TRG", "TRN", "ARM", "ARZ", "CSM", "CSV", "opt", "par", NULL}; if (filename_matches(filepath, ext_list)) { return copy_file(ds_data, filepath, filepath, thread_n); } ---------- bool copy_file(ds_ctxt_t *datasink, const char *src_file_path, const char *dst_file_path, uint thread_n) msg(thread_n, "%s %s to %s", xb_get_copy_action(), src_file_path, dstfile->path); /* The main copy loop */ while ((res = datafile_read(&cursor)) == XB_FIL_CUR_SUCCESS) { if (ds_write(dstfile, cursor.buf, cursor.buf_read)) { goto error; } } /* close */ msg(thread_n," ...done");