if (mysql_query(connection, query)) { if (die_on_error) {
die("failed to execute query %s: %s", query, mysql_error(connection));
} else {
msg("Error: failed to execute query %s: %s", query, mysql_error(connection));
} return(NULL);
}
/* store result set on client if there is a result */ if (mysql_field_count(connection) > 0) { if ((mysql_result = mysql_store_result(connection)) == NULL) {
die("failed to fetch query result %s: %s",
query, mysql_error(connection));
}
if (!use_result) {
mysql_free_result(mysql_result);
mysql_result = NULL;
}
}
if (opt_galera_info && !have_galera_enabled)
{
msg("--galera-info is specified on the command " "line, but the server does not support Galera " "replication. Ignoring the option.");
opt_galera_info= false;
}
/* make sure datadir value is the same in configuration file */ if (check_if_param_set("datadir"))
{ if (!directory_exists(mysql_data_home, false))
{
msg("Warning: option 'datadir' points to " "nonexistent directory '%s'",
mysql_data_home);
} if (!directory_exists(datadir_var, false))
{
msg("Warning: MariaDB variable 'datadir' points to " "nonexistent directory '%s'",
datadir_var);
} if (!equal_paths(mysql_data_home, datadir_var))
{
msg("Warning: option 'datadir' has different " "values:\n" " '%s' in defaults file\n" " '%s' in SHOW VARIABLES",
mysql_data_home, datadir_var);
}
}
/* get some default values is they are missing from my.cnf */ if (datadir_var && *datadir_var)
{
strmake(mysql_real_data_home, datadir_var, FN_REFLEN - 1);
mysql_data_home= mysql_real_data_home;
}
if (innodb_data_file_path_var && *innodb_data_file_path_var)
innobase_data_file_path= my_once_strdup(innodb_data_file_path_var,
MYF(MY_FAE));
if (innodb_data_home_dir_var)
innobase_data_home_dir= my_once_strdup(innodb_data_home_dir_var,
MYF(MY_FAE));
if (innodb_log_group_home_dir_var && *innodb_log_group_home_dir_var)
srv_log_group_home_dir= my_once_strdup(innodb_log_group_home_dir_var,
MYF(MY_FAE));
if (innodb_undo_directory_var && *innodb_undo_directory_var)
srv_undo_dir= my_once_strdup(innodb_undo_directory_var, MYF(MY_FAE));
if (opt_incremental_history_name)
opt_incremental_history_name_len=
strlen(opt_incremental_history_name);
if (opt_incremental_history_uuid)
opt_incremental_history_uuid_len=
strlen(opt_incremental_history_uuid);
if (opt_incremental_history_name_len*2 > sizeof(buf))
die("Incremental history table name '%s' is too long.",
opt_incremental_history_name);
if (opt_incremental_history_uuid_len*2 > sizeof(buf))
die("Incremental history uuid '%s' is too long.",
opt_incremental_history_uuid);
if (opt_incremental_history_name && opt_incremental_history_name[0]
&& opt_incremental_history_uuid && opt_incremental_history_uuid[0])
die("It is allowed to use either --incremental-history-name " "or --incremental-history-uuid, but not both.");
if (opt_incremental_history_name) {
mysql_real_escape_string(mysql_connection, buf,
opt_incremental_history_name,
(unsignedlong) opt_incremental_history_name_len);
snprintf(query, sizeof(query), "SELECT innodb_to_lsn " "FROM " XB_HISTORY_TABLE " " "WHERE name = '%s' " "AND innodb_to_lsn IS NOT NULL " "ORDER BY innodb_to_lsn DESC LIMIT 1",
buf);
} elseif (opt_incremental_history_uuid) {
mysql_real_escape_string(mysql_connection, buf,
opt_incremental_history_uuid,
(unsignedlong) opt_incremental_history_uuid_len);
snprintf(query, sizeof(query), "SELECT innodb_to_lsn " "FROM " XB_HISTORY_TABLE " " "WHERE uuid = '%s' " "AND innodb_to_lsn IS NOT NULL " "ORDER BY innodb_to_lsn DESC LIMIT 1",
buf);
}
/* xb_mysql_query(..,.., true) will die on error, so
mysql_result can't be nullptr */
mysql_result = xb_mysql_query(mysql_connection, query, true);
ut_ad(mysql_num_fields(mysql_result) == 1); const MYSQL_ROW row = mysql_fetch_row(mysql_result); if (row) {
*incremental_lsn = strtoull(row[0], NULL, 10);
msg("Found and using lsn: " LSN_PF " for %s %s",
*incremental_lsn,
opt_incremental_history_uuid ? "uuid" : "name",
opt_incremental_history_uuid ?
opt_incremental_history_uuid :
opt_incremental_history_name);
} else {
msg("Error while attempting to find history record " "for %s %s",
opt_incremental_history_uuid ? "uuid" : "name",
opt_incremental_history_uuid ?
opt_incremental_history_uuid :
opt_incremental_history_name);
}
/*********************************************************************//**
Function acquires backup locks
@returns trueif lock acquired */
bool
lock_for_backup_stage_start(MYSQL *connection)
{ if (have_lock_wait_timeout || opt_lock_wait_timeout)
{ char buf[FN_REFLEN]; /* Set the maximum supported session value for lock_wait_timeoutifopt_lock_wait_timeoutisnotsettoprevent
unnecessary timeouts when the global value is changed from the default */
snprintf(buf, sizeof(buf), "SET SESSION lock_wait_timeout=%u",
opt_lock_wait_timeout ? opt_lock_wait_timeout : 31536000);
xb_mysql_query(connection, buf, false);
}
if (opt_lock_wait_timeout)
{ if (!wait_for_no_updates(connection, opt_lock_wait_timeout,
opt_lock_wait_threshold))
{ return (false);
}
}
msg("Acquiring BACKUP LOCKS...");
if (opt_kill_long_queries_timeout)
{
start_query_killer();
}
if (have_galera_enabled)
{
xb_mysql_query(connection, "SET SESSION wsrep_sync_wait=0", false);
}
xb_mysql_query(connection, "BACKUP STAGE START", true);
DBUG_MARIABACKUP_EVENT("after_backup_stage_start", {}); /* Set the maximum supported session value for lock_wait_timeouttopreventunnecessarytimeoutswhenthe
global value is changed from the default */ if (opt_lock_wait_timeout)
xb_mysql_query(connection, "SET SESSION lock_wait_timeout=31536000", false);
if (opt_kill_long_queries_timeout)
{
stop_query_killer();
}
std::unordered_set<std::string>
get_tables_in_use(MYSQL *con) {
std::unordered_set<std::string> result;
MYSQL_RES *q_res =
xb_mysql_query(con, "SHOW OPEN TABLES WHERE In_use = 1", true); while (MYSQL_ROW row = mysql_fetch_row(q_res)) { auto tk = table_key(row[0], row[1]);
msg("Table %s is in use", tk.c_str());
result.insert(std::move(tk));
} if (q_res)
mysql_free_result(q_res); return result;
}
/*********************************************************************//**
Releases either global read lock acquired with FTWRL and the binlog
lock acquired with LOCK BINLOG FOR BACKUP, depending on
the locking strategy being used */ void
unlock_all(MYSQL *connection)
{ if (opt_debug_sleep_before_unlock) {
msg("Debug sleep for %u seconds",
opt_debug_sleep_before_unlock);
std::this_thread::sleep_for(
std::chrono::milliseconds(opt_debug_sleep_before_unlock));
}
static int
get_open_temp_tables(MYSQL *connection)
{ char *slave_open_temp_tables = NULL;
mysql_variable status[] = {
{"Slave_open_temp_tables", &slave_open_temp_tables},
{NULL, NULL}
}; int result = false;
read_mysql_variables(connection, "SHOW STATUS LIKE 'slave_open_temp_tables'", status, true);
result = slave_open_temp_tables ? atoi(slave_open_temp_tables) : 0;
free_mysql_variables(status);
return(result);
}
/*********************************************************************//**
Wait until it's safe to backup a slave. Returns immediately if
the host isn't a slave. Currently there's only one check:
Slave_open_temp_tables has to be zero. Dies on timeout. */ bool
wait_for_safe_slave(MYSQL *connection)
{ char *read_master_log_pos = NULL; char *slave_sql_running = NULL; int n_attempts = 1; constint sleep_time = 3; int open_temp_tables = 0; bool result = true;
if (!(read_master_log_pos && slave_sql_running)) {
msg("Not checking slave open temp tables for " "--safe-slave-backup because host is not a slave"); goto cleanup;
}
class Show_slave_status
{
Var m_mariadb_connection_name; // MariaDB: e.g. 'master1'
Var m_master; // e.g. 'localhost'
Var m_filename; // e.g. 'source-bin.000002'
Var m_position; // a number
Var m_mysql_gtid_executed; // MySQL56: e.g. single '<UUID>:1-5" or multiline // '<UUID1>:1-10,\n<UUID2>:1-20\n<UUID3>:1-30'
Var m_mariadb_using_gtid; // MariaDB: 'No','Slave_Pos','Current_Pos'
staticvoid msg_is_not_slave()
{
msg("Failed to get master binlog coordinates " "from SHOW SLAVE STATUS.This means that the server is not a " "replication slave. Ignoring the --slave-info option");
}
/* Getmasterinfointostrings"sql"and"comment"fromaMYSQL_RES. @returnfalseonsuccess @returntrueonerror
*/ staticbool get_slave_info(MYSQL_RES *show_slave_info_result, const Var >id_slave_pos,
String *sql, String *comment)
{ if (!gtid_slave_pos.is_null_or_empty())
{ // Print gtid_slave_pos if any of the masters really needs it. while (MYSQL_ROW row= mysql_fetch_row(show_slave_info_result))
{
Show_slave_status status;
status.init(show_slave_info_result, row); if (status.is_mariadb_using_gtid())
{ if (gtid_slave_pos.print_set_global(sql) ||
comment->append(STRING_WITH_LEN("gtid_slave_pos ")) ||
gtid_slave_pos.print_quoted(comment)) returntrue; // Error break;
}
}
}
// Print the list of masters
mysql_data_seek(show_slave_info_result, 0); while (MYSQL_ROW row= mysql_fetch_row(show_slave_info_result))
{
Show_slave_status status;
status.init(show_slave_info_result, row); if (start_comment_chunk(comment) ||
status.print(sql, comment, gtid_slave_pos)) returntrue; // Error
} returnfalse; // Success
}
/* Getmasterinfointostrings"sql"and"comment". @returnfalseonsuccess @returntrueonerror
*/ staticbool get_slave_info(MYSQL *mysql, bool show_all_slave_status,
String *sql, String *comment)
{ bool rc= false; // Success // gtid_slave_pos - MariaDB variable : e.g. "0-1-1" or "1-10-100,2-20-500"
Var gtid_slave_pos("gtid_slave_pos", mysql); constchar *query= show_all_slave_status ? "SHOW ALL SLAVES STATUS" : "SHOW SLAVE STATUS";
MYSQL_RES *mysql_result= xb_mysql_query(mysql, query, true); if (!mysql_num_rows(mysql_result))
{
msg_is_not_slave(); // Don't change rc, we still want to continue the backup
} else
{
rc= get_slave_info(mysql_result, gtid_slave_pos, sql, comment);
}
mysql_free_result(mysql_result); return rc;
}
};
/*********************************************************************//**
Retrieves MySQL binlog position of the master server in a replication
setup and saves it in a file. It also saves it in mysql_slave_position
variable.
@returns false on error
@returns true on success
*/ bool
write_slave_info(ds_ctxt *datasink, MYSQL *connection)
{
String sql, comment;
if (Show_slave_status::get_slave_info(connection, true, &sql, &comment)) returnfalse; // Error
/*********************************************************************//**
Retrieves MySQL Galera and saves it in a file. It also prints it to stdout.
We should create xtrabackup_galelera_info file even when backup locks
are used because donor's wsrep_gtid_domain_id is needed later in joiner.
Note that at this stage wsrep_local_state_uuid and wsrep_last_committed
are inconsistent but they are not used in joiner. Joiner will rewrite this file
at mariabackup --prepare phase and thus there is extra file donor_galera_info.
Information is needed to maintain wsrep_gtid_domain_id and gtid_binlog_pos
same across the cluster. If joiner node have different wsrep_gtid_domain_id
we should still receive effective domain id from the donor node, and use it.
*/ bool
write_galera_info(ds_ctxt *datasink, MYSQL *connection)
{ char *state_uuid = NULL, *state_uuid55 = NULL; char *last_committed = NULL, *last_committed55 = NULL; char *domain_id = NULL, *domain_id55 = NULL; bool result=true;
uint n_values=0; char *wsrep_on = NULL, *wsrep_on55 = NULL;
if (n_values == 0 || (wsrep_on == NULL && wsrep_on55 == NULL))
{
msg("Server is not Galera node thus --galera-info does not " "have any effect.");
result = true; goto cleanup;
}
if ((state_uuid == NULL && state_uuid55 == NULL)
|| (last_committed == NULL && last_committed55 == NULL))
{
msg("Warning: failed to get master wsrep state from SHOW STATUS.");
result = true; goto cleanup;
}
n_values= read_mysql_variables(connection, "SHOW VARIABLES LIKE 'wsrep%'", value, true);
if (n_values == 0 || (domain_id == NULL && domain_id55 == NULL))
{
msg("Warning: failed to get master wsrep state from SHOW VARIABLES.");
result = true; goto cleanup;
}
/*********************************************************************//**
Flush and copy the current binary log file into the backup, if GTID is enabled.
MDEV-38147: the file name that FLUSH BINARY LOGS rotates to is
remembered in the global mysql_binlog_file. write_binlog_info() then records
that exact name in xtrabackup_binlog_info, so the file the SST joiner looks for is guaranteed to be the file that was shipped. Previously the shipped file
(determined here) and the recorded file (determined independently later by
write_binlog_info()) were read by two separate SHOW MASTER STATUS calls; a
binary log rotation happening in between made them diverge and the wrong file
was sent. */ bool
write_current_binlog_file(ds_ctxt *datasink, MYSQL *connection)
{ char *executed_gtid_set = NULL; char *gtid_binlog_state = NULL; char *gtid_current_pos = NULL; char *log_bin_file = NULL; char *log_bin_pos = NULL; char *log_bin_gtid_executed = NULL; char *log_bin_dir = NULL; bool gtid_exists; bool result = true; char filepath[FN_REFLEN];
/* Capture the shipped file's coordinates together, right after the flush,
so they describe exactly the file that is copied below. */
mysql_variable status_after_flush[] = {
{"File", &log_bin_file},
{"Position", &log_bin_pos},
{"Executed_Gtid_Set", &log_bin_gtid_executed},
{NULL, NULL}
};
/* strip final slash if it is not the only path component */ if (log_bin_dir_length > 1 &&
log_bin_dir[log_bin_dir_length - 1] == FN_LIBCHAR) {
log_bin_dir[log_bin_dir_length - 1] = 0;
}
if (filename == NULL || position == NULL) { /* Do not create MB_BINLOG_INFO if binary
log is disabled */
result = true; goto cleanup;
}
/* MDEV-38147:ifwrite_current_binlog_file()alreadyrotated andshippedabinarylogunder--galera-info,recordthatexactfile namehereratherthanwhateverSHOWMASTERSTATUSreportsnow.Thetwo arenormallyidentical,butabinarylogrotationbetweenthetwo SHOWMASTERSTATUScallswouldotherwisemakemariadb_backup_binlog_info nameafiledifferentfromtheonethatwasshipped,sotheSSTjoiner wouldlookforafilethatisnotthere.Useaseparatepointersothe stringownedbythestatus[]arrayisstillfreedatcleanup.
*/
out_filename = filename;
out_position = position;
out_gtid_executed = gtid_executed;
out_gtid_current_pos = gtid_current_pos; if (mysql_binlog_file != NULL && strcmp(filename, mysql_binlog_file)) {
msg("Binary log rotated to '%s' after '%s' was shipped; recording " "the shipped file and its coordinates in "
MB_BINLOG_INFO, filename, mysql_binlog_file); /* Record the whole tuple from the shipped file, not just its name, sofile/position/GTIDstayconsistent(thepositionandGTIDfrom
the SHOW MASTER STATUS above belong to the current, newer file). */
out_filename = mysql_binlog_file;
out_position = mysql_binlog_file_pos;
out_gtid_executed = mysql_binlog_file_gtid_executed;
out_gtid_current_pos = mysql_binlog_file_gtid_current_pos;
}
static
std::ostream& operator<<(std::ostream& s, const escape_and_quote& eq)
{ if (!eq.str) return s << "NULL";
s << '\'';
size_t len = strlen(eq.str); char* escaped = (char *)alloca(2 * len + 1);
len = mysql_real_escape_string(eq.mysql, escaped, eq.str, (ulong)len);
s << std::string(escaped, len);
s << '\''; return s;
}
/*********************************************************************//**
Writes MB_INFO file andif backup_history is enable creates
mysql.mariabackup_history and writes a new history record to the
table containing all the history info particular to the just completed
backup. */ bool
write_xtrabackup_info(ds_ctxt *datasink,
MYSQL *connection, constchar * filename, bool history, bool stream)
{
void
mdl_lock_init()
{
mdl_con = xb_mysql_connect(); if (!mdl_con)
{
msg("FATAL: cannot create connection for MDL locks"); exit(1);
} constchar *query = "SELECT NAME, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE '%%/%%'";
MYSQL_RES *mysql_result = xb_mysql_query(mdl_con, query, true, true); while (MYSQL_ROW row = mysql_fetch_row(mysql_result)) { int err;
ulint id = (ulint)my_strtoll10(row[1], 0, &err);
spaceid_to_tablename[id] = ut_get_name(0, row[0]);
}
mysql_free_result(mysql_result);
xb_mysql_query(mdl_con, "BEGIN", false, true);
}
void
mdl_lock_table(ulint space_id)
{ if (space_id == 0) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.