ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

innobackupex备份源码解析

2022-06-15 18:00:48  阅读:224  来源: 互联网

标签:opt log lsn lock 备份 源码 xtrabackup innobackupex backup


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

 

 

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

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 的后台线程

6. 开始拷贝非 ibd 文件。

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

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

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

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

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

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

13. 结束。

其核心代码如下:

/**
 * xtrabackup 入口函数
*/
int main(int argc, char **argv)
{
	...

	/* --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);
	}

	...
}

  

/**
 * 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。
	*/
	os_thread_id_t log_copying_thread_id;
	datafiles_iter_t *it;

	log_hdr_buf_ = static_cast<byte *>
		(ut_malloc_nokey(LOG_FILE_HDR_SIZE + UNIV_PAGE_SIZE_MAX));
	log_hdr_buf = static_cast<byte *>
		(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);

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);

	/* 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);
	}
skip_last_cp:
	/* stop log_copying_thread 
	停止redo log拷贝线程. 将备份的元数据信息记录在XTRABACKUP_METADATA_FILENAME中,即xtrabackup_checkpoints。
log_copying = FALSE 后, 后台的 redo log copy 线程会做最后一次 copy。 */ 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); /*0.2 sec*/ } msg("\n"); 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); } }

  

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);
}

  

/**
 * 调用 backup_start() 函数, 这个函数会加全局读锁, 拷贝非 ibd 文件
*/
bool
backup_start()
{
	// opt_no_lock 指的是 no-lock 参数
	if (!opt_no_lock) {
		/* 如果指定了--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);
		}

		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);
}

 

/*********************************************************************//**
加全局读锁, 如果支持备份锁, 且没有设置 --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);
}

  

/* 调用backup_finish函数,这个函数会释放全局读锁 */
bool
backup_finish()
{
	/* release all locks 
	释放所有锁, 如果锁定了 binlog, 还会解锁 binlog。
        这里执行 UNLOCK BINLOG;& UNLOCK TABLES;
	*/
	if (!opt_no_lock) {
		unlock_all(mysql_connection);
		history_lock_time = time(NULL) - history_lock_time;
	} else {
		history_lock_time = 0;
	}
	/**
	 * 如果设置了 --safe-slave-backup, 且 SQL 线程停止了, 则会开启 SQL 线程
	*/
	if (opt_safe_slave_backup && sql_thread_started) {
		msg("Starting slave SQL thread\n");
		xb_mysql_query(mysql_connection,
				"START SLAVE SQL_THREAD", false);
	}

	/* 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);
}

  

标签:opt,log,lsn,lock,备份,源码,xtrabackup,innobackupex,backup
来源: https://www.cnblogs.com/juanmaofeifei/p/16375772.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有