mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
5eccc400b1
Documentation of the feature can be found at: http://kb.askmonty.org/en/multi-source-replication/ This code is based on code from Taobao, developed by Plinux Other things: - Added new commands: START ALL SLAVES, STOP ALL SLAVES and SHOW FULL SLAVE STATUS - Almost all usage of 'active_mi' is deleted. - Added parameter to reset_logs() so that one can specify if new logs should be created. - Check wildcard match as early as possible for SHOW STATUS. This makes SHOW STATUS like 'xxx' a lot faster and use less mutex - Made max_relay_log_size depending on master connection. - Added sys_vars.default_master_connection_basic to fix a failure in sys_vars.all_vars, modified sql_slave_skip_counter_basic to allow session-level settings - Added commands to mysqladmin: start-all-slaves & stop-all-slaves - Removed logging of "next log '%s' is currently active | not active" - Fixed bug in my_vsnprintf() when using positional parameters with length - Added fn_ext2(), which returns pointer to last '.' in file name - max_relay_log_size now acts as a normal slave specific variable - Don't store replication position if innobase_overwrite_relay_log_info is not set - max_relay_log_size copies it's values from max_binlog_size at startup BUILD/SETUP.sh: Added -Wno-invalid-offsetof to get rid of warning of offsetof() on C++ class (safe in the contex we use it) client/mysqladmin.cc: Added commands start-all-slaves & stop-all-slaves client/mysqltest.cc: Added support for error names starting with 'W' Added connection_name support to --sync_with_master cmake/maintainer.cmake: Added -Wno-invalid-offsetof to get rid of warning of offsetof() on C++ class (safe in the contex we use it) include/my_sys.h: Added fn_ext2(), which returns pointer to last '.' in file name include/mysql/plugin.h: Added SHOW_SIMPLE_FUNC include/mysql/plugin_audit.h.pp: Updated signature file include/mysql/plugin_auth.h.pp: Updated signature file include/mysql/plugin_ftparser.h.pp: Updated signature file mysql-test/extra/rpl_tests/rpl_max_relay_size.test: Updated test mysql-test/include/setup_fake_relay_log.inc: There is no orphan relay log files anymore mysql-test/mysql-test-run.pl: Added multi_source to test suite mysql-test/r/flush.result: Added test for new syntax of flush relay logs (can't repeat relay logs or slave) mysql-test/r/mysqld--help.result: Updated result mysql-test/r/mysqltest.result: Updated result mysql-test/r/parser.result: Updated result mysql-test/r/signal_code.result: Updated result after introducing new commands mysql-test/r/sp-code.result: Updated result after introducing new commands mysql-test/suite/multi_source: Tests for multi-source mysql-test/suite/multi_source/info_logs-master.opt: Test with strange file names mysql-test/suite/multi_source/info_logs.result: Test of logs mysql-test/suite/multi_source/info_logs.test: Test of logs mysql-test/suite/multi_source/my.cnf: Setup of multi-master tests Added log-warnings to get more information to the log files mysql-test/suite/multi_source/relaylog_events.result: Test relay log handling mysql-test/suite/multi_source/relaylog_events.test: Test relay log handling mysql-test/suite/multi_source/reset_slave.result: Test RESET SLAVE mysql-test/suite/multi_source/reset_slave.test: Test RESET SLAVE mysql-test/suite/multi_source/simple.result: Simple basic test of multi-source functionality mysql-test/suite/multi_source/simple.test: Simple basic test of multi-source functionality mysql-test/suite/multi_source/skip_counter.result: Testing skip_counter and max_relay_log_size mysql-test/suite/multi_source/skip_counter.test: Testing skip_counter and max_relay_log_size mysql-test/suite/multi_source/syntax.result: Test of multi-source syntax mysql-test/suite/multi_source/syntax.test: Test of multi-source syntax mysql-test/suite/rpl/r/rpl_deadlock_innodb.result: New warnings mysql-test/suite/rpl/r/rpl_filter_dbs_dynamic.result: Improved error texts mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result: Improved error texts mysql-test/suite/rpl/r/rpl_filter_wild_tables_dynamic.result: Improved error texts mysql-test/suite/rpl/r/rpl_flush_logs.result: Update results mysql-test/suite/rpl/r/rpl_heartbeat.result: Warning was removed mysql-test/suite/rpl/r/rpl_heartbeat_basic.result: Warning was removed mysql-test/suite/rpl/r/rpl_rotate_logs.result: Updated results because of new error messages mysql-test/suite/rpl/r/rpl_row_max_relay_size.result: Updated results mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result: Updated results after improved RESET SLAVE (we now use less relay log files) mysql-test/suite/rpl/r/rpl_skip_replication.result: New error message mysql-test/suite/rpl/r/rpl_start_slave_deadlock_sys_vars.result: Test removed as the old DBUG_SYNC entries doesn't exist anymore mysql-test/suite/rpl/r/rpl_stm_max_relay_size.result: Updated results mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result: Updated results after improved RESET SLAVE (we now use less relay log files) mysql-test/suite/rpl/t/rpl_flush_logs.test: Updated tests as relay log files is created a bit differently than before mysql-test/suite/rpl/t/rpl_start_slave_deadlock_sys_vars.test: Test removed as the old DBUG_SYNC entries doesn't exist anymore mysql-test/suite/sys_vars/r/default_master_connection_basic.result: New test to test usage of default_master_connection mysql-test/suite/sys_vars/r/max_relay_log_size_basic.result: Updated results mysql-test/suite/sys_vars/r/sql_slave_skip_counter_basic.result: Updated usage of sql_slave_skip_counter mysql-test/suite/sys_vars/t/default_master_connection_basic.test: New test to test usage of default_master_connection mysql-test/suite/sys_vars/t/max_relay_log_size_basic.test: Updated results mysql-test/suite/sys_vars/t/sql_slave_skip_counter_basic.test: Updated test for multi-source mysql-test/t/flush.test: Added test for new syntax of flush relay logs (can't repeat relay logs or slave) mysql-test/t/parser.test: Updated test as master_pos_wait() now takes more arguments than before mysys/mf_fn_ext.c: Added fn_ext2(), which returns pointer to last '.' in file name plugin/semisync/semisync_master_plugin.cc: Use SHOW_SIMPLE_FUNC to optimize SHOW STATUS sql/event_scheduler.cc: No reason to initialize slave_thread (it's guaranteed to be zero here) sql/item_create.cc: Added connection_name argument to master_pos_wait() Simplified code sql/item_func.cc: Added connection_name argument to master_pos_wait() sql/item_func.h: Added connection_name argument to master_pos_wait() sql/lex.h: Added SLAVES keyword sql/log.cc: Added tag "Master 'connection_name'" to slave errors that has a connection name. Added parameter to reset_logs() so that one can specify if new logs should be created. Removed some wrong casts Changed some constants to defines sql/log.h: Added parameter to reset_logs() Updated comment to reflect new code sql/log_event.cc: Updated DBUG_PRINT sql/mysqld.cc: Added variable mysqld_server_initialized so that other functions can test if server is fully initialized. Free all slave data in one place (fewer ifdef's) Removed not needed call to close_active_mi() Initialize slaves() later in startup to ensure that everthing is really initialized when slaves start. Made status variable slave_running multi-source safe max_relay_log_size copies it's values from max_binlog_size at startup SHOW_FUNC -> SHOW_SIMPLE_FUNC sql/mysqld.h: Added mysqld_server_initialized Removed max_relay_log_size sql/rpl_mi.cc: Store connection name and cmp_connection_name (only used for show full slave status) in Master_info Added code for Master_info_index, which handles storage of multi-master information Don't write the empty "" connection_name to multi-master.info file. This is handled by the original code. Create Master_info_index::index_file_names once at init More DBUG_PRINT Give error if Master_info_index::check_duplicate_master_info fails Added start|stop all slaves sql/rpl_mi.h: Added connection_name and Master_info_index Updated prototypes sql/rpl_rli.cc: Added connection_name to relay log files. If we do a full reset, don't create any new relay log files. Updated comment to reflect new code Made max_relay_log_size depending on master connection. sql/rpl_rli.h: Fixed type of slave_skip_counter as we now access it directly in sys_vars.cc, so it must be ulong Made executed_entries and max_relay_log_size depending on master connection. sql/set_var.cc: Fixed that one can get variable name also when one uses DEFAULT sql/set_var.h: Made option global so that one can check and change min & max values (sorry Sergei) sql/share/errmsg-utf8.txt: Added new error messages needed for multi-source Added multi-source name to error ER_MASTER_INFO and WARN_NO_MASTER_INFO Improved error message if connection exists sql/slave.cc: Moved things a bit around to make it easier to handle error conditions. Create a global master_info_index and add the "" connection to it Ensure that new Master_info doesn't fail. Don't call terminate_slave_threads(active_mi..) on end_slave() as this is now done automaticly when deleting master_info_index. Delete not needed function close_active_mi(). One can achive same thing by calling end_slave(). Added support for SHOW FULL SLAVE STATUS (show status for all master connections with connection_name as first column) Removed logging of "next log '%s' is currently active | not active" Added Slave_received_heartbeats and Slave_heartbeat_period sql/slave.h: Added new defines and prototypes sql/sql_base.cc: More DBUG_PRINT sql/sql_class.cc: Reset thd->connection_name and thd-->default_master_connection sql/sql_class.h: Added thd->connection_name and thd-->default_master_connection Made slave_skip_count and max_relay_log_size depending on master connection. These variables are in THD to make changing them thread safe. sql/sql_const.h: Added MAX_CONNECTION_NAME sql/sql_insert.cc: thd->slave_thread -> thd->rli_slave Removed usage of active_mi sql/sql_lex.cc: Reset 'lex->verbose' (to simplify some sql_yacc.yy code) sql/sql_lex.h: Added connection_name, relay_log_connection_name, SQLCOM_SLAVE_ALL_START and SQLCOM_SLAVE_ALL_STOP sql/sql_load.cc: thd->slave_thread -> thd->rli_slave Removed usage of active_mi sql/sql_parse.cc: Added support for connection_name to all SLAVE commands. - Instead of using active_mi, we now get the current Master_info from master_info_index. - Create new replication threads with CHANGE MASTER - Added support for show_all_master_info()- sql/sql_prepare.cc: Added SQLCOM_SLAVE_ALL_START and SQLCOM_SLAVE_ALL_STOP sql/sql_reload.cc: Made reset/full slave use master_info_index->get_master_info() instead of active_mi. If one uses 'RESET SLAVE "connection_name" all' the connection is removed from master_info_index. Fixed issues with FLUSH RELAY LOGS sql/sql_repl.cc: sql_slave_skip_counter is moved to thd->variables to make it thread safe and fix some bugs with it Add connection name to relay log files. Added connection name to errors. Added some logging for multi-master if log_warnings > 1 stop_slave(): - Don't check if thd is set. It's guaranteed to always be set. change_master(): - Check for duplicate connection names in change_master() - Check for wrong arguments first in file (to simplify error handling) - Register new connections in master_info_index ****** Added multi-source support to show relaylog events ****** check_duplicate_master_info() now generates an error Added parameter to reset_logs() ****** Updated calls to create_signed_file_name() sql/sql_show.cc: Check wildcard match as early as possible for SHOW STATUS. This makes SHOW STATUS like 'xxx' a lot faster and use less mutex sql/sql_yacc.yy: Added optional connection_name to a all relevant master/slave commands Added multi-source support to show relaylog events Added new commands START ALL SLAVES, STOP ALL SLAVES and SHOW FULL SLAVE STATUS sql/strfunc.cc: my_global.h shoud always be included first. sql/sys_vars.cc: Added variable default_master_connection Made variable sql_slave_skip_counter multi-source safe Made max_relay_log_size depending on master connection. Made old code more reusable sql/sys_vars.h: Added Sys_var_session_lexstring (needed for default_master_connection) Added Sys_var_multi_source_uint (needed for sql_slave_skip_counter). Changed Sys_var_multi_source_uint to ulong to be able to handle max_relay_log_size Made old code more reusable storage/example/ha_example.cc: Use SHOW_SIMPLE_FUNC to optimize SHOW STATUS storage/sphinx/ha_sphinx.cc: Use SHOW_SIMPLE_FUNC to optimize SHOW STATUS storage/xtradb/handler/ha_innodb.cc: Don't store replication position if innobase_overwrite_relay_log_info is not set strings/my_vsnprintf.c: Fixed bug when using positional parameters with length
568 lines
17 KiB
C++
568 lines
17 KiB
C++
/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#include "sql_reload.h"
|
|
#include "sql_priv.h"
|
|
#include "mysqld.h" // select_errors
|
|
#include "sql_class.h" // THD
|
|
#include "sql_acl.h" // acl_reload
|
|
#include "sql_servers.h" // servers_reload
|
|
#include "sql_connect.h" // reset_mqh
|
|
#include "sql_base.h" // close_cached_tables
|
|
#include "sql_db.h" // my_dbopt_cleanup
|
|
#include "hostname.h" // hostname_cache_refresh
|
|
#include "sql_repl.h" // reset_master, reset_slave
|
|
#include "rpl_mi.h" // Master_info::data_lock
|
|
#include "debug_sync.h"
|
|
#include "rpl_mi.h"
|
|
|
|
static void disable_checkpoints(THD *thd);
|
|
|
|
/**
|
|
Reload/resets privileges and the different caches.
|
|
|
|
@param thd Thread handler (can be NULL!)
|
|
@param options What should be reset/reloaded (tables, privileges, slave...)
|
|
@param tables Tables to flush (if any)
|
|
@param write_to_binlog < 0 if there was an error while interacting with the binary log inside
|
|
reload_acl_and_cache,
|
|
0 if we should not write to the binary log,
|
|
> 0 if we can write to the binlog.
|
|
|
|
|
|
@note Depending on 'options', it may be very bad to write the
|
|
query to the binlog (e.g. FLUSH SLAVE); this is a
|
|
pointer where reload_acl_and_cache() will put 0 if
|
|
it thinks we really should not write to the binlog.
|
|
Otherwise it will put 1.
|
|
|
|
@return Error status code
|
|
@retval 0 Ok
|
|
@retval !=0 Error; thd->killed is set or thd->is_error() is true
|
|
*/
|
|
|
|
bool reload_acl_and_cache(THD *thd, unsigned long options,
|
|
TABLE_LIST *tables, int *write_to_binlog)
|
|
{
|
|
bool result=0;
|
|
select_errors=0; /* Write if more errors */
|
|
int tmp_write_to_binlog= *write_to_binlog= 1;
|
|
|
|
DBUG_ASSERT(!thd || !thd->in_sub_stmt);
|
|
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
if (options & REFRESH_GRANT)
|
|
{
|
|
THD *tmp_thd= 0;
|
|
/*
|
|
If reload_acl_and_cache() is called from SIGHUP handler we have to
|
|
allocate temporary THD for execution of acl_reload()/grant_reload().
|
|
*/
|
|
if (!thd && (thd= (tmp_thd= new THD)))
|
|
{
|
|
thd->thread_stack= (char*) &tmp_thd;
|
|
thd->store_globals();
|
|
}
|
|
|
|
if (thd)
|
|
{
|
|
bool reload_acl_failed= acl_reload(thd);
|
|
bool reload_grants_failed= grant_reload(thd);
|
|
bool reload_servers_failed= servers_reload(thd);
|
|
|
|
if (reload_acl_failed || reload_grants_failed || reload_servers_failed)
|
|
{
|
|
result= 1;
|
|
/*
|
|
When an error is returned, my_message may have not been called and
|
|
the client will hang waiting for a response.
|
|
*/
|
|
my_error(ER_UNKNOWN_ERROR, MYF(0));
|
|
}
|
|
}
|
|
|
|
if (tmp_thd)
|
|
{
|
|
delete tmp_thd;
|
|
/* Remember that we don't have a THD */
|
|
my_pthread_setspecific_ptr(THR_THD, 0);
|
|
thd= 0;
|
|
}
|
|
reset_mqh((LEX_USER *)NULL, TRUE);
|
|
}
|
|
#endif
|
|
if (options & REFRESH_LOG)
|
|
{
|
|
/*
|
|
Flush the normal query log, the update log, the binary log,
|
|
the slow query log, the relay log (if it exists) and the log
|
|
tables.
|
|
*/
|
|
|
|
options|= REFRESH_BINARY_LOG;
|
|
options|= REFRESH_RELAY_LOG;
|
|
options|= REFRESH_SLOW_LOG;
|
|
options|= REFRESH_GENERAL_LOG;
|
|
options|= REFRESH_ENGINE_LOG;
|
|
options|= REFRESH_ERROR_LOG;
|
|
}
|
|
|
|
if (options & REFRESH_ERROR_LOG)
|
|
if (flush_error_log())
|
|
{
|
|
/*
|
|
When flush_error_log() failed, my_error() has not been called.
|
|
So, we have to do it here to keep the protocol.
|
|
*/
|
|
my_error(ER_UNKNOWN_ERROR, MYF(0));
|
|
result= 1;
|
|
}
|
|
|
|
if ((options & REFRESH_SLOW_LOG) && opt_slow_log)
|
|
logger.flush_slow_log();
|
|
|
|
if ((options & REFRESH_GENERAL_LOG) && opt_log)
|
|
logger.flush_general_log();
|
|
|
|
if (options & REFRESH_ENGINE_LOG)
|
|
if (ha_flush_logs(NULL))
|
|
result= 1;
|
|
|
|
if (options & REFRESH_BINARY_LOG)
|
|
{
|
|
/*
|
|
Writing this command to the binlog may result in infinite loops
|
|
when doing mysqlbinlog|mysql, and anyway it does not really make
|
|
sense to log it automatically (would cause more trouble to users
|
|
than it would help them)
|
|
*/
|
|
tmp_write_to_binlog= 0;
|
|
if (mysql_bin_log.is_open())
|
|
{
|
|
if (mysql_bin_log.rotate_and_purge(true))
|
|
*write_to_binlog= -1;
|
|
}
|
|
}
|
|
if (options & REFRESH_RELAY_LOG)
|
|
{
|
|
#ifdef HAVE_REPLICATION
|
|
LEX_STRING connection_name;
|
|
Master_info *mi;
|
|
if (thd)
|
|
connection_name= thd->lex->relay_log_connection_name;
|
|
else
|
|
{
|
|
connection_name.str= (char*) "";
|
|
connection_name.length= 0;
|
|
}
|
|
|
|
/*
|
|
Writing this command to the binlog may cause problems as the
|
|
slave is not likely to have the same connection names.
|
|
*/
|
|
tmp_write_to_binlog= 0;
|
|
mysql_mutex_lock(&LOCK_active_mi);
|
|
if (!(mi= (master_info_index->
|
|
get_master_info(&connection_name,
|
|
MYSQL_ERROR::WARN_LEVEL_ERROR))))
|
|
{
|
|
result= 1;
|
|
}
|
|
else
|
|
{
|
|
mysql_mutex_lock(&mi->data_lock);
|
|
if (rotate_relay_log(mi))
|
|
*write_to_binlog= -1;
|
|
mysql_mutex_unlock(&mi->data_lock);
|
|
}
|
|
mysql_mutex_unlock(&LOCK_active_mi);
|
|
#endif
|
|
}
|
|
#ifdef HAVE_QUERY_CACHE
|
|
if (options & REFRESH_QUERY_CACHE_FREE)
|
|
{
|
|
query_cache.pack(thd); // FLUSH QUERY CACHE
|
|
options &= ~REFRESH_QUERY_CACHE; // Don't flush cache, just free memory
|
|
}
|
|
if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
|
|
{
|
|
query_cache.flush(); // RESET QUERY CACHE
|
|
}
|
|
#endif /*HAVE_QUERY_CACHE*/
|
|
|
|
DBUG_ASSERT(!thd || thd->locked_tables_mode ||
|
|
!thd->mdl_context.has_locks() ||
|
|
thd->handler_tables_hash.records ||
|
|
thd->global_read_lock.is_acquired());
|
|
|
|
/*
|
|
Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
|
|
(see sql_yacc.yy)
|
|
*/
|
|
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
|
|
{
|
|
if ((options & REFRESH_READ_LOCK) && thd)
|
|
{
|
|
/*
|
|
On the first hand we need write lock on the tables to be flushed,
|
|
on the other hand we must not try to aspire a global read lock
|
|
if we have a write locked table as this would lead to a deadlock
|
|
when trying to reopen (and re-lock) the table after the flush.
|
|
*/
|
|
if (thd->locked_tables_mode)
|
|
{
|
|
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
|
|
return 1;
|
|
}
|
|
/*
|
|
Writing to the binlog could cause deadlocks, as we don't log
|
|
UNLOCK TABLES
|
|
*/
|
|
tmp_write_to_binlog= 0;
|
|
if (thd->global_read_lock.lock_global_read_lock(thd))
|
|
return 1; // Killed
|
|
if (close_cached_tables(thd, tables,
|
|
((options & REFRESH_FAST) ? FALSE : TRUE),
|
|
thd->variables.lock_wait_timeout))
|
|
{
|
|
/*
|
|
NOTE: my_error() has been already called by reopen_tables() within
|
|
close_cached_tables().
|
|
*/
|
|
result= 1;
|
|
}
|
|
|
|
if (thd->global_read_lock.make_global_read_lock_block_commit(thd)) // Killed
|
|
{
|
|
/* Don't leave things in a half-locked state */
|
|
thd->global_read_lock.unlock_global_read_lock(thd);
|
|
return 1;
|
|
}
|
|
if (options & REFRESH_CHECKPOINT)
|
|
disable_checkpoints(thd);
|
|
}
|
|
else
|
|
{
|
|
if (thd && thd->locked_tables_mode)
|
|
{
|
|
/*
|
|
If we are under LOCK TABLES we should have a write
|
|
lock on tables which we are going to flush.
|
|
*/
|
|
if (tables)
|
|
{
|
|
for (TABLE_LIST *t= tables; t; t= t->next_local)
|
|
if (!find_table_for_mdl_upgrade(thd, t->db, t->table_name, false))
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
It is not safe to upgrade the metadata lock without GLOBAL IX lock.
|
|
This can happen with FLUSH TABLES <list> WITH READ LOCK as we in
|
|
these cases don't take a GLOBAL IX lock in order to be compatible
|
|
with global read lock.
|
|
*/
|
|
if (thd->open_tables &&
|
|
!thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
|
|
MDL_INTENTION_EXCLUSIVE))
|
|
{
|
|
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
|
|
thd->open_tables->s->table_name.str);
|
|
return true;
|
|
}
|
|
|
|
for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
|
|
{
|
|
if (! tab->mdl_ticket->is_upgradable_or_exclusive())
|
|
{
|
|
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),
|
|
tab->s->table_name.str);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (close_cached_tables(thd, tables,
|
|
((options & REFRESH_FAST) ? FALSE : TRUE),
|
|
(thd ? thd->variables.lock_wait_timeout :
|
|
LONG_TIMEOUT)))
|
|
{
|
|
/*
|
|
NOTE: my_error() has been already called by reopen_tables() within
|
|
close_cached_tables().
|
|
*/
|
|
result= 1;
|
|
}
|
|
}
|
|
my_dbopt_cleanup();
|
|
}
|
|
if (options & REFRESH_HOSTS)
|
|
hostname_cache_refresh();
|
|
if (thd && (options & REFRESH_STATUS))
|
|
refresh_status(thd);
|
|
if (options & REFRESH_THREADS)
|
|
flush_thread_cache();
|
|
#ifdef HAVE_REPLICATION
|
|
if (options & REFRESH_MASTER)
|
|
{
|
|
DBUG_ASSERT(thd);
|
|
tmp_write_to_binlog= 0;
|
|
if (reset_master(thd))
|
|
{
|
|
/* NOTE: my_error() has been already called by reset_master(). */
|
|
result= 1;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef OPENSSL
|
|
if (options & REFRESH_DES_KEY_FILE)
|
|
{
|
|
if (des_key_file && load_des_key_file(des_key_file))
|
|
{
|
|
/* NOTE: my_error() has been already called by load_des_key_file(). */
|
|
result= 1;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef HAVE_REPLICATION
|
|
if (options & REFRESH_SLAVE)
|
|
{
|
|
LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
|
|
Master_info *mi;
|
|
tmp_write_to_binlog= 0;
|
|
mysql_mutex_lock(&LOCK_active_mi);
|
|
|
|
if (!(mi= (master_info_index->
|
|
get_master_info(&lex_mi->connection_name,
|
|
MYSQL_ERROR::WARN_LEVEL_ERROR))))
|
|
{
|
|
result= 1;
|
|
}
|
|
else if (reset_slave(thd, mi))
|
|
{
|
|
/* NOTE: my_error() has been already called by reset_slave(). */
|
|
result= 1;
|
|
}
|
|
else if (mi->connection_name.length && thd->lex->reset_slave_info.all)
|
|
{
|
|
/* If not default connection and 'all' is used */
|
|
master_info_index->remove_master_info(&mi->connection_name);
|
|
}
|
|
mysql_mutex_unlock(&LOCK_active_mi);
|
|
}
|
|
#endif
|
|
if (options & REFRESH_USER_RESOURCES)
|
|
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
|
|
if (options & REFRESH_TABLE_STATS)
|
|
{
|
|
mysql_mutex_lock(&LOCK_global_table_stats);
|
|
free_global_table_stats();
|
|
init_global_table_stats();
|
|
mysql_mutex_unlock(&LOCK_global_table_stats);
|
|
}
|
|
if (options & REFRESH_INDEX_STATS)
|
|
{
|
|
mysql_mutex_lock(&LOCK_global_index_stats);
|
|
free_global_index_stats();
|
|
init_global_index_stats();
|
|
mysql_mutex_unlock(&LOCK_global_index_stats);
|
|
}
|
|
if (options & (REFRESH_USER_STATS | REFRESH_CLIENT_STATS))
|
|
{
|
|
mysql_mutex_lock(&LOCK_global_user_client_stats);
|
|
if (options & REFRESH_USER_STATS)
|
|
{
|
|
free_global_user_stats();
|
|
init_global_user_stats();
|
|
}
|
|
if (options & REFRESH_CLIENT_STATS)
|
|
{
|
|
free_global_client_stats();
|
|
init_global_client_stats();
|
|
}
|
|
mysql_mutex_unlock(&LOCK_global_user_client_stats);
|
|
}
|
|
if (*write_to_binlog != -1)
|
|
*write_to_binlog= tmp_write_to_binlog;
|
|
/*
|
|
If the query was killed then this function must fail.
|
|
*/
|
|
return result || (thd ? thd->killed : 0);
|
|
}
|
|
|
|
|
|
/**
|
|
Implementation of FLUSH TABLES <table_list> WITH READ LOCK.
|
|
|
|
In brief: take exclusive locks, expel tables from the table
|
|
cache, reopen the tables, enter the 'LOCKED TABLES' mode,
|
|
downgrade the locks.
|
|
Note: the function is written to be called from
|
|
mysql_execute_command(), it is not reusable in arbitrary
|
|
execution context.
|
|
|
|
Required privileges
|
|
-------------------
|
|
Since the statement implicitly enters LOCK TABLES mode,
|
|
it requires LOCK TABLES privilege on every table.
|
|
But since the rest of FLUSH commands require
|
|
the global RELOAD_ACL, it also requires RELOAD_ACL.
|
|
|
|
Compatibility with the global read lock
|
|
---------------------------------------
|
|
We don't wait for the GRL, since neither the
|
|
5.1 combination that this new statement is intended to
|
|
replace (LOCK TABLE <list> WRITE; FLUSH TABLES;),
|
|
nor FLUSH TABLES WITH READ LOCK do.
|
|
@todo: this is not implemented, Dmitry disagrees.
|
|
Currently we wait for GRL in another connection,
|
|
but are compatible with a GRL in our own connection.
|
|
|
|
Behaviour under LOCK TABLES
|
|
---------------------------
|
|
Bail out: i.e. don't perform an implicit UNLOCK TABLES.
|
|
This is not consistent with LOCK TABLES statement, but is
|
|
in line with behaviour of FLUSH TABLES WITH READ LOCK, and we
|
|
try to not introduce any new statements with implicit
|
|
semantics.
|
|
|
|
Compatibility with parallel updates
|
|
-----------------------------------
|
|
As a result, we will wait for all open transactions
|
|
against the tables to complete. After the lock downgrade,
|
|
new transactions will be able to read the tables, but not
|
|
write to them.
|
|
|
|
Differences from FLUSH TABLES <list>
|
|
-------------------------------------
|
|
- you can't flush WITH READ LOCK a non-existent table
|
|
- you can't flush WITH READ LOCK under LOCK TABLES
|
|
|
|
Effect on views and temporary tables.
|
|
------------------------------------
|
|
You can only apply this command to existing base tables.
|
|
If a view with such name exists, ER_WRONG_OBJECT is returned.
|
|
If a temporary table with such name exists, it's ignored:
|
|
if there is a base table, it's used, otherwise ER_NO_SUCH_TABLE
|
|
is returned.
|
|
|
|
Handling of MERGE tables
|
|
------------------------
|
|
For MERGE table this statement will open and lock child tables
|
|
for read (it is impossible to lock parent table without it).
|
|
Child tables won't be flushed unless they are explicitly present
|
|
in the statement's table list.
|
|
|
|
Implicit commit
|
|
---------------
|
|
This statement causes an implicit commit before and
|
|
after it.
|
|
|
|
HANDLER SQL
|
|
-----------
|
|
If this connection has HANDLERs open against
|
|
some of the tables being FLUSHed, these handlers
|
|
are implicitly flushed (lose their position).
|
|
*/
|
|
|
|
bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
|
{
|
|
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
|
TABLE_LIST *table_list;
|
|
|
|
/*
|
|
This is called from SQLCOM_FLUSH, the transaction has
|
|
been committed implicitly.
|
|
*/
|
|
|
|
if (thd->locked_tables_mode)
|
|
{
|
|
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
|
|
goto error;
|
|
}
|
|
|
|
/*
|
|
Acquire SNW locks on tables to be flushed. Don't acquire global
|
|
IX and database-scope IX locks on the tables as this will make
|
|
this statement incompatible with FLUSH TABLES WITH READ LOCK.
|
|
*/
|
|
if (lock_table_names(thd, all_tables, NULL,
|
|
thd->variables.lock_wait_timeout,
|
|
MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
|
|
goto error;
|
|
|
|
DEBUG_SYNC(thd,"flush_tables_with_read_lock_after_acquire_locks");
|
|
|
|
for (table_list= all_tables; table_list;
|
|
table_list= table_list->next_global)
|
|
{
|
|
/* Request removal of table from cache. */
|
|
tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
|
|
table_list->db,
|
|
table_list->table_name, FALSE);
|
|
/* Reset ticket to satisfy asserts in open_tables(). */
|
|
table_list->mdl_request.ticket= NULL;
|
|
}
|
|
|
|
/*
|
|
Before opening and locking tables the below call also waits
|
|
for old shares to go away, so the fact that we don't pass
|
|
MYSQL_LOCK_IGNORE_FLUSH flag to it is important.
|
|
Also we don't pass MYSQL_OPEN_HAS_MDL_LOCK flag as we want
|
|
to open underlying tables if merge table is flushed.
|
|
For underlying tables of the merge the below call has to
|
|
acquire SNW locks to ensure that they can be locked for
|
|
read without further waiting.
|
|
*/
|
|
if (open_and_lock_tables(thd, all_tables, FALSE,
|
|
MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK,
|
|
&lock_tables_prelocking_strategy) ||
|
|
thd->locked_tables_list.init_locked_tables(thd))
|
|
{
|
|
goto error;
|
|
}
|
|
thd->variables.option_bits|= OPTION_TABLE_LOCK;
|
|
|
|
/*
|
|
We don't downgrade MDL_SHARED_NO_WRITE here as the intended
|
|
post effect of this call is identical to LOCK TABLES <...> READ,
|
|
and we didn't use thd->in_lock_talbes and
|
|
thd->sql_command= SQLCOM_LOCK_TABLES hacks to enter the LTM.
|
|
*/
|
|
|
|
return FALSE;
|
|
|
|
error:
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
Disable checkpoints for all handlers
|
|
This is released in unlock_global_read_lock()
|
|
*/
|
|
|
|
static void disable_checkpoints(THD *thd)
|
|
{
|
|
if (!thd->global_disable_checkpoint)
|
|
{
|
|
thd->global_disable_checkpoint= 1;
|
|
if (!global_disable_checkpoint++)
|
|
ha_checkpoint_state(1); // Disable checkpoints
|
|
}
|
|
}
|
|
|