innobackupex备份源码解析

目前MySQL的物理备份大多数采用xtrabackupex进行,其备份过程如下图所示,这里通过解析 xtrabackup 的源码来详细看看其是如何进行备份的,xtrabackup 版本为 2.4.26。

innobackupex备份源码解析

这里只解析其全量备份的过程,通过源码可以发现很多细节,其核心详细的备份流程如下:

  1. 从 log group 的 log header 中获取 lastest checkpoint lsn.

  2. 从 lastest checkpoint lsn 开始从 log group 中拷贝 redo log,直到没有 redo log为止,此时拷贝的 redo log 点位记为 log_copy_scanned_lsn

  3. 启动后台的 redo log copy 线程,循环从 log_copy_scanned_lsn 点位开始拷贝 redo log 。

  4. 获取 ibdata1, undo tablespace 和所有的 ibd 文件,根据指定的 –parallel 参数创建并发的拷贝线程,拷贝数据文件。

  5. 待数据拷贝结束,则加全局读锁。这里有一个小细节,如果 MySQL 支持备份锁,且没有指定 –no-backup-locks,则会优先使用备份锁:LOCK TABLES FOR BACKUP;

如果不能使用备份锁,则走正常的加锁流程,这其中包含 xtrabackupex 防止阻塞逻辑。

5.1. 如果没有指定 kill-long-queries-timeout & ftwrl-wait-timeout,则首先执行 FLUSH NO_WRITE_TO_BINLOG TABLES;这是为了防止因为存在 long update 操作而导致 FTWRL操作阻塞整个MySQL服务。当存在 long update操作,FLUSH TABLES 将被阻塞,但是整个 mysql 服务不会被阻塞。当 long update结束,FTWRL操作会很快结束。

5.2. 接着,针对 ftwrl-wait-timeout & ftwrl-wait-threshold 参数,ftwrl-wait-threshold 为认定操作未 long update 操作的阈值,针对 long update操作,xtrabackup 最多再等待 ftwrl-wait-timeout,如果超时 long update操作尚未结束,则 xtrabackup 直接退出。

5.3. 紧接着处理 kill-long-queries-timeout 参数,启动一个后台线程,监控当前数据库的所有操作;该参数为开始 FTWRL 到 KILL 掉阻塞该操作的 query之间的耗时。

5.4. FLUSH TABLES WITH READ LOCK。

5.5. 关闭处理 kill-long-queries-timeout 的后台线程

  1. 开始拷贝非 ibd 文件。

  2. 如果设置了 slave_info,则会将SHOW SLAVE STATUS的相关信息,记录在xtrabackup_slave_info中;如果之前使用了备份锁,这里会锁定 BINLOG: LOCK BINLOG FOR BACKUP;

  3. 输出 SHOW MASTER STATUS 信息到 xtrabackup_binlog_info中;

  4. 执行 FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS,将 redo log持久化到磁盘供 redo log copy 线程拷贝

  5. 读取最新的 checkpoint lsn,用于后续的增量备份。

  6. 停止redo log拷贝线程. 将备份的元数据信息记录在XTRABACKUP_METADATA_FILENAME中,即xtrabackup_checkpoints。这里停止之后,redo log copy 线程会做最后一次 copy, 而后停止。

  7. 释放全局读锁,UNLOCK BINLOG(如果之前锁定了BINLOG) & UNLOCK TABLES,生成back-my.cnf 配置文件,将备份相关信息记录到 xtrabackup_info 文件中。

  8. 结束。

其核心代码如下:

cpp;gutter:true; /<strong> * xtrabackup 入口函数 */ int main(int argc, char </strong>argv) { ...</p> <pre><code>/* --backup backup 逻辑, 这里主要关注 backup */ if (xtrabackup_backup) { xtrabackup_backup_func(); } /* --stats */ if (xtrabackup_stats) { xtrabackup_stats_func(server_argc, server_defaults); } /* --prepare */ if (xtrabackup_prepare) { xtrabackup_prepare_func(server_argc, server_defaults); } ... </code></pre> <p>}</p> <pre><code> ;gutter:true;
/**
* backup 逻辑
*/
void
xtrabackup_backup_func(void)
{

/* start back ground thread to copy newer log
创建 redo log 后台拷贝线程。可以看到,其首先在主线程中从 lastest chechkpoint lsn 点位开始拷贝 log group 中的 redo log,直到拷贝完成,拷贝完成的点位记为log_copy_scanned_lsn ,而后再启动后台的 redo log copy 线程,从log_copy_scanned_lsn位置继续拷贝 redo log。

cpp;gutter:true; <em>/ os_thread_id_t log_copying_thread_id; datafiles_iter_t </em>it;</p> <pre><code>log_hdr_buf_ = static_cast (ut_malloc_nokey(LOG_FILE_HDR_SIZE + UNIV_PAGE_SIZE_MAX)); log_hdr_buf = static_cast (ut_align(log_hdr_buf_, UNIV_PAGE_SIZE_MAX)); /* get current checkpoint_lsn 获取当前的 checkpoint_lsn */ /* Look for the latest checkpoint from any of the log groups 获取最新的 checkpoint lsn */ mutex_enter(&log_sys->mutex); err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field); if (err != DB_SUCCESS) { ut_free(log_hdr_buf_); exit(EXIT_FAILURE); } // 读取 log group header page log_group_header_read(max_cp_group, max_cp_field); buf = log_sys->checkpoint_buf; // 读取 checkpoint_lsn 和 checkpoint_no checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN); checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO); mutex_exit(&log_sys->mutex); </code></pre> <p>reread_log_header: fil_io(IORequest(IORequest::READ), true, page_id_t(max_cp_group->space_id, 0), univ_page_size, 0, LOG_FILE_HDR_SIZE, log_hdr_buf, max_cp_group);</p> <pre><code>/* check consistency of log file header to copy */ mutex_enter(&log_sys->mutex); err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field); if (err != DB_SUCCESS) { ut_free(log_hdr_buf_); exit(EXIT_FAILURE); } log_group_header_read(max_cp_group, max_cp_field); buf = log_sys->checkpoint_buf; if(checkpoint_no_start != mach_read_from_8(buf + LOG_CHECKPOINT_NO)) { checkpoint_lsn_start = mach_read_from_8(buf + LOG_CHECKPOINT_LSN); checkpoint_no_start = mach_read_from_8(buf + LOG_CHECKPOINT_NO); mutex_exit(&log_sys->mutex); goto reread_log_header; } mutex_exit(&log_sys->mutex); xtrabackup_init_datasinks(); if (!select_history()) { exit(EXIT_FAILURE); } /* open the log file 打开 xtrabackup_logfile */ memset(&stat_info, 0, sizeof(MY_STAT)); dst_log_file = ds_open(ds_redo, XB_LOG_FILENAME, &stat_info); if (dst_log_file == NULL) { msg("xtrabackup: error: failed to open the target stream for " "'%s'.\n", XB_LOG_FILENAME); ut_free(log_hdr_buf_); exit(EXIT_FAILURE); } /* label it 在 xtrabackup_logfile 头部写入 lobel 信息: */ strcpy((char*) log_hdr_buf + LOG_HEADER_CREATOR, "xtrabkup "); ut_sprintf_timestamp( (char*) log_hdr_buf + (LOG_HEADER_CREATOR + (sizeof "xtrabkup ") - 1)); if (ds_write(dst_log_file, log_hdr_buf, LOG_FILE_HDR_SIZE)) { msg("xtrabackup: error: write to logfile failed\n"); ut_free(log_hdr_buf_); exit(EXIT_FAILURE); } ut_free(log_hdr_buf_); /* start flag */ log_copying = TRUE; /* start io throttle */ if(xtrabackup_throttle) { os_thread_id_t io_watching_thread_id; io_ticket = xtrabackup_throttle; wait_throttle = os_event_create("wait_throttle"); os_thread_create(io_watching_thread, NULL, &io_watching_thread_id); } mutex_enter(&log_sys->mutex); xtrabackup_choose_lsn_offset(checkpoint_lsn_start); mutex_exit(&log_sys->mutex); if (opt_lock_ddl_per_table) { mdl_lock_tables(); } /* copy log file by current position 从最新的 checkpoint_lsn 开始拷贝 redo log; 拷贝到最新 redo log 结束, 停止拷贝, 停止拷贝点位: log_copy_scanned_lsn */ if(xtrabackup_copy_logfile(checkpoint_lsn_start, FALSE)) exit(EXIT_FAILURE); /* * From this point forward, recv_parse_or_apply_log_rec_body should fail if * MLOG_INDEX_LOAD event is parsed as its not safe to continue the backup * in any situation (with or without --lock-ddl-per-table). */ mdl_taken = true; log_copying_stop = os_event_create("log_copying_stop"); debug_sync_point("xtrabackup_pause_after_redo_catchup"); // 创建 redo log 后台拷贝线程 os_thread_create(log_copying_thread, NULL, &log_copying_thread_id); /* Populate fil_system with tablespaces to copy 获取 ibdata1, undo tablespace 和所有的 ibd 文件 */ err = xb_load_tablespaces(); if (err != DB_SUCCESS) { msg("xtrabackup: error: xb_load_tablespaces() failed with" "error code %lu\n", err); exit(EXIT_FAILURE); } /* FLUSH CHANGED_PAGE_BITMAPS call */ if (!flush_changed_page_bitmaps()) { exit(EXIT_FAILURE); } debug_sync_point("xtrabackup_suspend_at_start"); if (xtrabackup_incremental) { if (!xtrabackup_incremental_force_scan && have_changed_page_bitmaps) { changed_page_bitmap = xb_page_bitmap_init(); } if (!changed_page_bitmap) { msg("xtrabackup: using the full scan for incremental " "backup\n"); } else if (incremental_lsn != checkpoint_lsn_start) { /* Do not print that bitmaps are used when dummy bitmap is build for an empty LSN range. */ msg("xtrabackup: using the changed page bitmap\n"); } } ut_a(xtrabackup_parallel > 0); if (xtrabackup_parallel > 1) { msg("xtrabackup: Starting %u threads for parallel data " "files transfer\n", xtrabackup_parallel); } it = datafiles_iter_new(f_system); if (it == NULL) { msg("xtrabackup: Error: datafiles_iter_new() failed.\n"); exit(EXIT_FAILURE); } /* Create data copying threads 创建数据拷贝线程 */ data_threads = (data_thread_ctxt_t *) ut_malloc_nokey(sizeof(data_thread_ctxt_t) * xtrabackup_parallel); count = xtrabackup_parallel; mutex_create(LATCH_ID_XTRA_COUNT_MUTEX, &count_mutex); // 拷贝物理文件, 其中, xtrabackup_parallel 是拷贝并发线程数, 由 --parallel 参数指定 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; data_threads[i].error = &data_copying_error; // 创建数据拷贝线程 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); mutex_enter(&count_mutex); if (count == 0) { mutex_exit(&count_mutex); break; } mutex_exit(&count_mutex); } mutex_free(&count_mutex); ut_free(data_threads); datafiles_iter_free(it); if (data_copying_error) { exit(EXIT_FAILURE); } if (changed_page_bitmap) { xb_page_bitmap_deinit(changed_page_bitmap); } } // 调用 backup_start() 函数, 这个函数会加全局读锁, 拷贝非 ibd 文件 if (!backup_start()) { exit(EXIT_FAILURE); } if(opt_lock_ddl_per_table && opt_debug_sleep_before_unlock){ msg_ts("Debug sleep for %u seconds\n", opt_debug_sleep_before_unlock); os_thread_sleep(opt_debug_sleep_before_unlock * 1000000); } /* read the latest checkpoint lsn 读取最新的 checkpoint lsn, 用于后续的增量备份 */ latest_cp = 0; { log_group_t* max_cp_group; ulint max_cp_field; ulint err; mutex_enter(&log_sys->mutex); err = recv_find_max_checkpoint(&max_cp_group, &max_cp_field); if (err != DB_SUCCESS) { msg("xtrabackup: Error: recv_find_max_checkpoint() failed.\n"); mutex_exit(&log_sys->mutex); goto skip_last_cp; } log_group_header_read(max_cp_group, max_cp_field); xtrabackup_choose_lsn_offset(checkpoint_lsn_start); latest_cp = mach_read_from_8(log_sys->checkpoint_buf + LOG_CHECKPOINT_LSN); mutex_exit(&log_sys->mutex); msg("xtrabackup: The latest check point (for incremental): " "'" LSN_PF "'\n", latest_cp); } </code></pre> <p>skip_last_cp: /<em> stop log_copying_thread 停止redo log拷贝线程. 将备份的元数据信息记录在XTRABACKUP_METADATA_FILENAME中,即xtrabackup_checkpoints。 log_copying = FALSE 后, 后台的 redo log copy 线程会做最后一次 copy。 </em>/ log_copying = FALSE; os_event_set(log_copying_stop); msg("xtrabackup: Stopping log copying thread.\n"); while (log_copying_running) { msg("."); os_thread_sleep(200000); /<em>0.2 sec</em>/ } msg("\n");</p> <pre><code>os_event_destroy(log_copying_stop); if (ds_close(dst_log_file)) { exit(EXIT_FAILURE); } if (!validate_missing_encryption_tablespaces()) { exit(EXIT_FAILURE); } if(!xtrabackup_incremental) { strcpy(metadata_type, "full-backuped"); metadata_from_lsn = 0; } else { strcpy(metadata_type, "incremental"); metadata_from_lsn = incremental_lsn; } metadata_to_lsn = latest_cp; metadata_last_lsn = log_copy_scanned_lsn; if (!xtrabackup_stream_metadata(ds_meta)) { msg("xtrabackup: Error: failed to stream metadata.\n"); exit(EXIT_FAILURE); } /* 调用backup_finish函数,这个函数会释放全局读锁 */ if (!backup_finish()) { exit(EXIT_FAILURE); } if (xtrabackup_extra_lsndir) { char filename[FN_REFLEN]; sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, XTRABACKUP_METADATA_FILENAME); if (!xtrabackup_write_metadata(filename)) { msg("xtrabackup: Error: failed to write metadata " "to '%s'.\n", filename); exit(EXIT_FAILURE); } sprintf(filename, "%s/%s", xtrabackup_extra_lsndir, XTRABACKUP_INFO); if (!xtrabackup_write_info(filename)) { msg("xtrabackup: Error: failed to write info " "to '%s'.\n", filename); exit(EXIT_FAILURE); } } if (opt_lock_ddl_per_table) { mdl_unlock_all(); } if (opt_transition_key != NULL || opt_generate_transition_key) { if (!xb_tablespace_keys_dump(ds_data, opt_transition_key, opt_transition_key != NULL ? strlen(opt_transition_key) : 0)) { msg("xtrabackup: Error: failed to dump " "tablespace keys.\n"); exit(EXIT_FAILURE); } } xtrabackup_destroy_datasinks(); if (wait_throttle) { /* wait for io_watching_thread completion */ while (io_watching_thread_running) { os_thread_sleep(1000000); } os_event_destroy(wait_throttle); wait_throttle = NULL; } msg("xtrabackup: Transaction log of lsn (" LSN_PF ") to (" LSN_PF ") was copied.\n", checkpoint_lsn_start, log_copy_scanned_lsn); xb_filters_free(); xb_data_files_close(); recv_sys_debug_free(); log_shutdown(); trx_pool_close(); lock_sys_close(); os_thread_free(); row_mysql_close(); sync_check_close(); xb_keyring_shutdown(); /* Make sure that the latest checkpoint made it to xtrabackup_logfile */ if (latest_cp > log_copy_scanned_lsn) { msg("xtrabackup: error: last checkpoint LSN (" LSN_PF ") is larger than last copied LSN (" LSN_PF ").\n", latest_cp, log_copy_scanned_lsn); exit(EXIT_FAILURE); } </code></pre> <p>}</p> <pre><code> ;gutter:true;
static
#ifndef __WIN__
void*
#else
ulint
#endif
log_copying_thread(
void* arg __attribute__((unused)))
{
/*
Initialize mysys thread-specific memory so we can
use mysys functions in this thread.
*/
my_thread_init();

ut_a(dst_log_file != NULL);

log_copying_running = TRUE;

while(log_copying) {
os_event_reset(log_copying_stop);
os_event_wait_time_low(log_copying_stop,
xtrabackup_log_copy_interval * 1000ULL,
0);
if (log_copying) {
if(xtrabackup_copy_logfile(log_copy_scanned_lsn,
FALSE)) {

exit(EXIT_FAILURE);
}
}
}

/* last copying */
if(xtrabackup_copy_logfile(log_copy_scanned_lsn, TRUE)) {

exit(EXIT_FAILURE);
}

log_copying_running = FALSE;
my_thread_end();
os_thread_exit();

return(0);
}

cpp;gutter:true; /<em><em> * 调用 backup_start() 函数, 这个函数会加全局读锁, 拷贝非 ibd 文件 </em>/ bool backup_start() { // opt_no_lock 指的是 no-lock 参数 if (!opt_no_lock) { /</em> 如果指定了--safe-slave-backup,会关闭SQL线程,等待Slave_open_temp_tables变量为0。 如果使用的是statement格式,且使用了临时表,建议设置--safe-slave-backup。 对于row格式,无需指定该选项 */ if (opt_safe_slave_backup) { if (!wait_for_safe_slave(mysql_connection)) { return(false); } } // 调用 backup_files 备份非 ibd 文件, 加了全局读锁还会调用一次. // 这一次, 实际上针对的是 --rsync 方式。 这里不做深入研究。 if (!backup_files(fil_path_to_mysql_datadir, true)) { return(false); }</p> <pre><code> history_lock_time = time(NULL); // 加全局读锁, 如果支持备份锁, 且没有设置 --no-backup-locks, 会优先使用备份锁。 if (!lock_tables_maybe(mysql_connection, opt_backup_lock_timeout, opt_backup_lock_retry_count)) { return(false); } } // 备份非 ibd 文件 if (!backup_files(fil_path_to_mysql_datadir, false)) { return(false); } // There is no need to stop slave thread before coping non-Innodb data when // --no-lock option is used because --no-lock option requires that no DDL or // DML to non-transaction tables can occur. if (opt_no_lock) { if (opt_safe_slave_backup) { if (!wait_for_safe_slave(mysql_connection)) { return(false); } } } // 如果设置了 slave_info, 会将SHOW SLAVE STATUS的相关信息,记录在xtrabackup_slave_info中 if (opt_slave_info) { /* 如果之前使用了备份锁,这里会先锁定Binlog(LOCK BINLOG FOR BACKUP)*/ lock_binlog_maybe(mysql_connection, opt_backup_lock_timeout, opt_backup_lock_retry_count); if (!write_slave_info(mysql_connection)) { return(false); } } /* The only reason why Galera/binlog info is written before wait_for_ibbackup_log_copy_finish() is that after that call the xtrabackup binary will start streamig a temporary copy of REDO log to stdout and thus, any streaming from innobackupex would interfere. The only way to avoid that is to have a single process, i.e. merge innobackupex and xtrabackup. */ if (opt_galera_info) { if (!write_galera_info(mysql_connection)) { return(false); } write_current_binlog_file(mysql_connection); } /* 如果--binlog-info设置的是ON(默认是AUTO),则会将SHOW MASTER STATUS的相关信息,记录在xtrabackup_binlog_info中 */ if (opt_binlog_info == BINLOG_INFO_ON) { lock_binlog_maybe(mysql_connection, opt_backup_lock_timeout, opt_backup_lock_retry_count); write_binlog_info(mysql_connection); } // 执行 FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS, 将 redo log 持久化到磁盘共 redo log copy 线程拷贝。 if (have_flush_engine_logs) { msg_ts("Executing FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS...\n"); xb_mysql_query(mysql_connection, "FLUSH NO_WRITE_TO_BINLOG ENGINE LOGS", false); } return(true); </code></pre> <p>}</p> <pre><code> ;gutter:true;
/*********************************************************************//**
加全局读锁, 如果支持备份锁, 且没有设置 –no-backup-locks, 会优先使用备份锁
Function acquires either a backup tables lock, if supported
by the server, or a global read lock (FLUSH TABLES WITH READ LOCK)
otherwise.

@returns true if lock acquired */
bool
lock_tables_maybe(MYSQL *connection, int timeout, int retry_count)
{
if (tables_locked || opt_lock_ddl_per_table) {
return(true);
}
// 如果指定了 –no-backup-locks, 则使用备份锁。目前, mysql5.7.27 不支持备份锁
if (have_backup_locks) {
return lock_tables_for_backup(connection, timeout, retry_count);
}
// lock_wait_timeout
if (have_lock_wait_timeout) {
char query[200];

ut_snprintf(query, sizeof(query),
"SET SESSION lock_wait_timeout=%d", timeout);

xb_mysql_query(connection, query, false);
}
// 没有 lock_wait_timeout & kill_long_query_timeout
if (!opt_lock_wait_timeout && !opt_kill_long_queries_timeout) {

/*
首先 FLUSH TABLES. 如果 long update 正在进行, 那么 FLUSH TABLES 将等待, 但不会暂停整个 mysqld 服务,
当 long update 完成时, FLUSH TABLES WITH READ LOCK 将启动被很快成功。

因此, FLUSH TABLES 是为了降低 mysqldump 和大多数客户端连接都暂停的可能性。 FLUSH TABLES 语句被某个表阻塞不影响其他表的操作,
例如 table A 正在进行 long update, 那么 flush tables 将被该 long update 阻塞, 但是 FLUSH tables 阻塞过程中 table B 可以进行操作。

然而, 如果在两次刷新之间进行了 long update, 那将出现长时间的暂停。

lock_wait_timeout 选项具有相同的用途, 与该技巧不兼容。
*/

msg_ts("Executing FLUSH NO_WRITE_TO_BINLOG TABLES…\n");
// 执行 FLUSH NO_WRITE_TO_BINLOG TABLES, 这是 FLUSH TABLES 操作, 该语句不写入 binlog
// 关闭所有打开的表, 强制关闭所有打开正在使用的表,
xb_mysql_query(connection,
"FLUSH NO_WRITE_TO_BINLOG TABLES", false);
}
// opt_lock_wait_timeout: 对于 long query 最多再等待 opt_lock_wait_timeout 时间, 如果该时间内 long query 执行完成,
// 则继续执行, 否则退出。
// opt_lock_wait_threshold: long query 的阈值, 对于 long query 最多再等待 lock_wait_timeout.
if (opt_lock_wait_timeout) {
if (!wait_for_no_updates(connection, opt_lock_wait_timeout,
opt_lock_wait_threshold)) {
return(false);
}
}

msg_ts("Executing FLUSH TABLES WITH READ LOCK…\n");
// opt_kill_long_queries_timeout: 从 flush tables with read lock 到 kill 掉阻塞他的操作之前等待的秒数。
if (opt_kill_long_queries_timeout) {
start_query_killer();
}

if (have_galera_enabled) {
xb_mysql_query(connection,
"SET SESSION wsrep_causal_reads=0", false);
}
/**
* FLUSH TABLES WITH READ LOCK.
* 关闭所有被打开的表, 并且使用全局读锁锁住所有库的所有表。
* 如果有事务存在, 那么事务提交时将被 hang 住, 不会回滚。
*/
xb_mysql_query(connection, "FLUSH TABLES WITH READ LOCK", false);

if (opt_kill_long_queries_timeout) {
stop_query_killer();
}

tables_locked = true;

return(true);
}

cpp;gutter:true; /<em> 调用backup_finish函数,这个函数会释放全局读锁 </em>/ bool backup_finish() { /<em> release all locks 释放所有锁, 如果锁定了 binlog, 还会解锁 binlog。 这里执行 UNLOCK BINLOG;& UNLOCK TABLES; </em>/ if (!opt_no_lock) { unlock_all(mysql_connection); history_lock_time = time(NULL) - history_lock_time; } else { history_lock_time = 0; } /*<em> * 如果设置了 --safe-slave-backup, 且 SQL 线程停止了, 则会开启 SQL 线程 </em>/ if (opt_safe_slave_backup && sql_thread_started) { msg("Starting slave SQL thread\n"); xb_mysql_query(mysql_connection, "START SLAVE SQL_THREAD", false); }</p> <pre><code>/* Copy buffer pool dump or LRU dump 拷贝 ib_buffer_pool 文件和 ib_lru_dump 文件 */ if (!opt_rsync) { if (opt_dump_innodb_buffer_pool) { check_dump_innodb_buffer_pool(mysql_connection); } if (buffer_pool_filename && file_exists(buffer_pool_filename)) { const char *dst_name; dst_name = trim_dotslash(buffer_pool_filename); copy_file(ds_data, buffer_pool_filename, dst_name, 0); } if (file_exists("ib_lru_dump")) { copy_file(ds_data, "ib_lru_dump", "ib_lru_dump", 0); } if (file_exists("ddl_log.log")) { copy_file(ds_data, "ddl_log.log", "ddl_log.log", 0); } } msg_ts("Backup created in directory '%s'\n", xtrabackup_target_dir); if (mysql_binlog_position != NULL) { msg("MySQL binlog position: %s\n", mysql_binlog_position); } if (!mysql_slave_position.empty() && opt_slave_info) { msg("MySQL slave binlog position: %s\n", mysql_slave_position.c_str()); } // 生成配置文件: back-my.cnf if (!write_backup_config_file()) { return(false); } // 将备份的相关信息记录在 xtrabackup_info 文件中 if (!write_xtrabackup_info(mysql_connection)) { return(false); } return(true); </code></pre> <p>}

Original: https://www.cnblogs.com/juanmaofeifei/p/16375772.html
Author: 卷毛狒狒
Title: innobackupex备份源码解析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/590929/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Python 3.10 is coming!

    看看Python 官网的文档 whatsnew,Python 3.10 已然距离我们越来越近了,然我们看看 Python 3.10 相较于 Python 3.9 有哪些改变吧 新特…

    数据库 2023年6月6日
    092
  • java 桥接方法

    1.桥接方法简介 桥接方法是jdk1.5引入泛型后,为使java泛型方法生成的字节码与jdk1.5版本之前的字节码兼容由编译器自动生成的。 可用 method.isBridge()…

    数据库 2023年6月16日
    089
  • java使用EasyExcel导入导出excel

    使用alibab的EasyExce完成导入导出excel 一、准备工作 1、导包 org.apache.poi poi 3.17 org.apache.poi poi-ooxml-…

    数据库 2023年6月6日
    078
  • 利用VBS循环弹窗

    VBScript是Visual Basic Script的简称,即 Visual Basic 脚本语言,有时也被缩写为VBS。 将以下代码复制到文本文档中,保存后修改文件后缀名称为…

    数据库 2023年6月11日
    0125
  • Linux定时任务调度

    任务调度是指系统在某个时间执行特定的命令或程序,任务调度主要有两种,第一种是系统工作,需要周而复始的执行,比如病毒扫描。第二种是个人用户工作,用户需要在某个特定的事件执行某些程序,…

    数据库 2023年6月16日
    079
  • Tomcat8下的Redis会话共享

    前言: 最近在做网站的升级,从 Tomcat7升级到 Tomcat8版本,因为没接触过,就以为升级下Tomcat的版本就万事大吉,可是天不如人愿,很顺利的将应用升级到了Tomcat…

    数据库 2023年6月14日
    0100
  • 计算机操作系统(慕课版)思维导图

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据库 2023年6月16日
    086
  • mysql8.x docker 远程访问配置

    环境情况 mysql 8.x 是通过 docker 方式部署的,启动的 docker-compose.yml 如下: version: "3.2" servic…

    数据库 2023年5月24日
    061
  • MySQL实战45讲 19

    19 | 为什么我只查一行的语句,也执行这么慢? 有些情况下,”查一行”,也会执行得特别慢。 需要说明的是,如果 MySQL 数据库本身就有很大的压力,导致…

    数据库 2023年5月24日
    045
  • DM-DM之间的DBLINK

    1 创建外部链接 创建一个外部链接。 语法格式 CREATE [OR REPLACE] [PUBLIC] LINK STANDBY FIRST | PRIMARY ONLY | S…

    数据库 2023年6月11日
    068
  • 不扒瞎,这个程序让我从300s优化到了10s

    /*** RedisTemplate&#x914D;&#x7F6E;* @param lettuceConnectionFactory* @return*/ @Be…

    数据库 2023年6月9日
    051
  • Java异步执行器CompletableFuture源码解析

    CompletableFuture是对 Future的一种强有力的扩展, Future只能通过轮询 isDone()方法或者调用 get()阻塞等待获取一个异步任务的结果,才能继续…

    数据库 2023年6月11日
    082
  • 非华为电脑开启多屏协同

    非华为电脑开启多屏协同 配置 windows 10系统(五代i7的辣鸡配置) WIFI、蓝牙(网上说需要5GHz,但本人的电脑是2.4G的也是有效) 华为、荣耀手机(EMUI 10…

    数据库 2023年6月11日
    0105
  • jmeter使用base64验证码登录

    依赖环境/工具:java环境、jmeter、python3、pycharm(ide工具) 此次主要操作步骤: 使用jmeter工具把验证码base64加密信息保存至本地。 编写py…

    数据库 2023年6月14日
    076
  • Mybatis第三方PageHelper分页插件原理

    欢迎关注公号:BiggerBoy,看更多文章 往期精品 此时commentAnalyses为Page对象(PageHelper插件包内定义的) 而Page对象继承自JDK中的Arr…

    数据库 2023年6月11日
    076
  • idea tags

    总结IDEA开发的26个常用设置https://zhuanlan.zhihu.com/p/108172369idea跳转到指定行列快捷键https://blog.51cto.com…

    数据库 2023年6月11日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球