mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
manual merge: mysql-5.1-rep+2 (bug tree) --> mysql-5.1-rep+2 (latest)
CONFLICTS ========= Text conflict in sql/sql_yacc.yy 1 conflicts encountered.
This commit is contained in:
@ -703,329 +703,5 @@ bool show_slave_hosts(THD* thd)
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi)
|
||||
{
|
||||
DBUG_ENTER("connect_to_master");
|
||||
|
||||
if (!mi->host || !*mi->host) /* empty host */
|
||||
{
|
||||
strmov(mysql->net.last_error, "Master is not configured");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
|
||||
mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (mi->ssl)
|
||||
{
|
||||
mysql_ssl_set(mysql,
|
||||
mi->ssl_key[0]?mi->ssl_key:0,
|
||||
mi->ssl_cert[0]?mi->ssl_cert:0,
|
||||
mi->ssl_ca[0]?mi->ssl_ca:0,
|
||||
mi->ssl_capath[0]?mi->ssl_capath:0,
|
||||
mi->ssl_cipher[0]?mi->ssl_cipher:0);
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
|
||||
&mi->ssl_verify_server_cert);
|
||||
}
|
||||
#endif
|
||||
|
||||
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
|
||||
mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);
|
||||
if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
|
||||
mi->port, 0, 0))
|
||||
DBUG_RETURN(1);
|
||||
mysql->reconnect= 1;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
static inline void cleanup_mysql_results(MYSQL_RES* db_res,
|
||||
MYSQL_RES** cur, MYSQL_RES** start)
|
||||
{
|
||||
for (; cur >= start; --cur)
|
||||
{
|
||||
if (*cur)
|
||||
mysql_free_result(*cur);
|
||||
}
|
||||
mysql_free_result(db_res);
|
||||
}
|
||||
|
||||
|
||||
static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db,
|
||||
MYSQL_RES *table_res, Master_info *mi)
|
||||
{
|
||||
MYSQL_ROW row;
|
||||
for (row = mysql_fetch_row(table_res); row;
|
||||
row = mysql_fetch_row(table_res))
|
||||
{
|
||||
TABLE_LIST table;
|
||||
const char* table_name= row[0];
|
||||
int error;
|
||||
if (rpl_filter->is_on())
|
||||
{
|
||||
bzero((char*) &table, sizeof(table)); //just for safe
|
||||
table.db= (char*) db;
|
||||
table.table_name= (char*) table_name;
|
||||
table.updating= 1;
|
||||
|
||||
if (!rpl_filter->tables_ok(thd->db, &table))
|
||||
continue;
|
||||
}
|
||||
/* download master's table and overwrite slave's table */
|
||||
if ((error= fetch_master_table(thd, db, table_name, mi, mysql, 1)))
|
||||
return error;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Load all MyISAM tables from master to this slave.
|
||||
|
||||
REQUIREMENTS
|
||||
- No active transaction (flush_relay_log_info would not work in this case).
|
||||
|
||||
@todo
|
||||
- add special option, not enabled
|
||||
by default, to allow inclusion of mysql database into load
|
||||
data from master
|
||||
*/
|
||||
|
||||
bool load_master_data(THD* thd)
|
||||
{
|
||||
MYSQL mysql;
|
||||
MYSQL_RES* master_status_res = 0;
|
||||
int error = 0;
|
||||
const char* errmsg=0;
|
||||
int restart_thread_mask;
|
||||
HA_CREATE_INFO create_info;
|
||||
|
||||
mysql_init(&mysql);
|
||||
|
||||
/*
|
||||
We do not want anyone messing with the slave at all for the entire
|
||||
duration of the data load.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
lock_slave_threads(active_mi);
|
||||
init_thread_mask(&restart_thread_mask,active_mi,0 /*not inverse*/);
|
||||
if (restart_thread_mask &&
|
||||
(error=terminate_slave_threads(active_mi,restart_thread_mask,
|
||||
1 /*skip lock*/)))
|
||||
{
|
||||
my_message(error, ER(error), MYF(0));
|
||||
unlock_slave_threads(active_mi);
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (connect_to_master(thd, &mysql, active_mi))
|
||||
{
|
||||
my_error(error= ER_CONNECT_TO_MASTER, MYF(0), mysql_error(&mysql));
|
||||
goto err;
|
||||
}
|
||||
|
||||
// now that we are connected, get all database and tables in each
|
||||
{
|
||||
MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res;
|
||||
uint num_dbs;
|
||||
|
||||
if (mysql_real_query(&mysql, STRING_WITH_LEN("SHOW DATABASES")) ||
|
||||
!(db_res = mysql_store_result(&mysql)))
|
||||
{
|
||||
my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(num_dbs = (uint) mysql_num_rows(db_res)))
|
||||
goto err;
|
||||
/*
|
||||
In theory, the master could have no databases at all
|
||||
and run with skip-grant
|
||||
*/
|
||||
|
||||
if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*))))
|
||||
{
|
||||
my_message(error = ER_OUTOFMEMORY, ER(ER_OUTOFMEMORY), MYF(0));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
This is a temporary solution until we have online backup
|
||||
capabilities - to be replaced once online backup is working
|
||||
we wait to issue FLUSH TABLES WITH READ LOCK for as long as we
|
||||
can to minimize the lock time.
|
||||
*/
|
||||
if (mysql_real_query(&mysql,
|
||||
STRING_WITH_LEN("FLUSH TABLES WITH READ LOCK")) ||
|
||||
mysql_real_query(&mysql, STRING_WITH_LEN("SHOW MASTER STATUS")) ||
|
||||
!(master_status_res = mysql_store_result(&mysql)))
|
||||
{
|
||||
my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
Go through every table in every database, and if the replication
|
||||
rules allow replicating it, get it
|
||||
*/
|
||||
|
||||
table_res_end = table_res + num_dbs;
|
||||
|
||||
for (cur_table_res = table_res; cur_table_res < table_res_end;
|
||||
cur_table_res++)
|
||||
{
|
||||
// since we know how many rows we have, this can never be NULL
|
||||
MYSQL_ROW row = mysql_fetch_row(db_res);
|
||||
char* db = row[0];
|
||||
|
||||
/*
|
||||
Do not replicate databases excluded by rules. We also test
|
||||
replicate_wild_*_table rules (replicate_wild_ignore_table='db1.%' will
|
||||
be considered as "ignore the 'db1' database as a whole, as it already
|
||||
works for CREATE DATABASE and DROP DATABASE).
|
||||
Also skip 'mysql' database - in most cases the user will
|
||||
mess up and not exclude mysql database with the rules when
|
||||
he actually means to - in this case, he is up for a surprise if
|
||||
his priv tables get dropped and downloaded from master
|
||||
TODO - add special option, not enabled
|
||||
by default, to allow inclusion of mysql database into load
|
||||
data from master
|
||||
*/
|
||||
|
||||
if (!rpl_filter->db_ok(db) ||
|
||||
!rpl_filter->db_ok_with_wild_table(db) ||
|
||||
!strcmp(db,"mysql") ||
|
||||
is_schema_db(db))
|
||||
{
|
||||
*cur_table_res = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
bzero((char*) &create_info, sizeof(create_info));
|
||||
create_info.options= HA_LEX_CREATE_IF_NOT_EXISTS;
|
||||
|
||||
if (mysql_create_db(thd, db, &create_info, 1))
|
||||
{
|
||||
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
|
||||
goto err;
|
||||
}
|
||||
/* Clear the result of mysql_create_db(). */
|
||||
thd->main_da.reset_diagnostics_area();
|
||||
|
||||
if (mysql_select_db(&mysql, db) ||
|
||||
mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) ||
|
||||
!(*cur_table_res = mysql_store_result(&mysql)))
|
||||
{
|
||||
my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
|
||||
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((error = fetch_db_tables(thd,&mysql,db,*cur_table_res,active_mi)))
|
||||
{
|
||||
// we do not report the error - fetch_db_tables handles it
|
||||
cleanup_mysql_results(db_res, cur_table_res, table_res);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
|
||||
|
||||
// adjust replication coordinates from the master
|
||||
if (master_status_res)
|
||||
{
|
||||
MYSQL_ROW row = mysql_fetch_row(master_status_res);
|
||||
|
||||
/*
|
||||
We need this check because the master may not be running with
|
||||
log-bin, but it will still allow us to do all the steps
|
||||
of LOAD DATA FROM MASTER - no reason to forbid it, really,
|
||||
although it does not make much sense for the user to do it
|
||||
*/
|
||||
if (row && row[0] && row[1])
|
||||
{
|
||||
/*
|
||||
If the slave's master info is not inited, we init it, then we write
|
||||
the new coordinates to it. Must call init_master_info() *before*
|
||||
setting active_mi, because init_master_info() sets active_mi with
|
||||
defaults.
|
||||
*/
|
||||
int error_2;
|
||||
|
||||
if (init_master_info(active_mi, master_info_file, relay_log_info_file,
|
||||
0, (SLAVE_IO | SLAVE_SQL)))
|
||||
my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
|
||||
strmake(active_mi->master_log_name, row[0],
|
||||
sizeof(active_mi->master_log_name) -1);
|
||||
active_mi->master_log_pos= my_strtoll10(row[1], (char**) 0, &error_2);
|
||||
/* at least in recent versions, the condition below should be false */
|
||||
if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE)
|
||||
active_mi->master_log_pos = BIN_LOG_HEADER_SIZE;
|
||||
/*
|
||||
Relay log's IO_CACHE may not be inited (even if we are sure that some
|
||||
host was specified; there could have been a problem when replication
|
||||
started, which led to relay log's IO_CACHE to not be inited.
|
||||
*/
|
||||
if (flush_master_info(active_mi, 0))
|
||||
sql_print_error("Failed to flush master info file");
|
||||
}
|
||||
mysql_free_result(master_status_res);
|
||||
}
|
||||
|
||||
if (mysql_real_query(&mysql, STRING_WITH_LEN("UNLOCK TABLES")))
|
||||
{
|
||||
my_error(error= ER_QUERY_ON_MASTER, MYF(0), mysql_error(&mysql));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
thd_proc_info(thd, "purging old relay logs");
|
||||
if (purge_relay_logs(&active_mi->rli,thd,
|
||||
0 /* not only reset, but also reinit */,
|
||||
&errmsg))
|
||||
{
|
||||
my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg);
|
||||
unlock_slave_threads(active_mi);
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
return TRUE;
|
||||
}
|
||||
pthread_mutex_lock(&active_mi->rli.data_lock);
|
||||
active_mi->rli.group_master_log_pos = active_mi->master_log_pos;
|
||||
strmake(active_mi->rli.group_master_log_name,active_mi->master_log_name,
|
||||
sizeof(active_mi->rli.group_master_log_name)-1);
|
||||
/*
|
||||
Cancel the previous START SLAVE UNTIL, as the fact to download
|
||||
a new copy logically makes UNTIL irrelevant.
|
||||
*/
|
||||
active_mi->rli.clear_until_condition();
|
||||
|
||||
/*
|
||||
No need to update rli.event* coordinates, they will be when the slave
|
||||
threads start ; only rli.group* coordinates are necessary here.
|
||||
*/
|
||||
flush_relay_log_info(&active_mi->rli);
|
||||
pthread_cond_broadcast(&active_mi->rli.data_cond);
|
||||
pthread_mutex_unlock(&active_mi->rli.data_lock);
|
||||
thd_proc_info(thd, "starting slave");
|
||||
if (restart_thread_mask)
|
||||
{
|
||||
error=start_slave_threads(0 /* mutex not needed */,
|
||||
1 /* wait for start */,
|
||||
active_mi,master_info_file,relay_log_info_file,
|
||||
restart_thread_mask);
|
||||
}
|
||||
|
||||
err:
|
||||
unlock_slave_threads(active_mi);
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
thd_proc_info(thd, 0);
|
||||
|
||||
mysql_close(&mysql); // safe to call since we always do mysql_init()
|
||||
if (!error)
|
||||
my_ok(thd);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
||||
|
Reference in New Issue
Block a user