mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
70823e1d91
The reason for the failure was a bug in an include file on debian that causes 'struct stat' to have different sized depending on the environment. This patch fixes so that we always include my_global.h or my_config.h before we include any other files. Other things: - Removed #include <my_global.h> in some include files; Better to always do this at the top level to have as few "always-include-this-file-first' files as possible. - Removed usage of some include files that where already included by my_global.h or by other files. client/mysql_plugin.c: Use my_global.h first client/mysqlslap.c: Remove duplicated include files extra/comp_err.c: Remove duplicated include files include/m_string.h: Remove duplicated include files include/maria.h: Remove duplicated include files libmysqld/emb_qcache.cc: Use my_global.h first plugin/semisync/semisync.h: Use my_pthread.h first sql/datadict.cc: Use my_global.h first sql/debug_sync.cc: Use my_global.h first sql/derror.cc: Use my_global.h first sql/des_key_file.cc: Use my_global.h first sql/discover.cc: Use my_global.h first sql/event_data_objects.cc: Use my_global.h first sql/event_db_repository.cc: Use my_global.h first sql/event_parse_data.cc: Use my_global.h first sql/event_queue.cc: Use my_global.h first sql/event_scheduler.cc: Use my_global.h first sql/events.cc: Use my_global.h first sql/field.cc: Use my_global.h first Remove duplicated include files sql/field_conv.cc: Use my_global.h first sql/filesort.cc: Use my_global.h first Remove duplicated include files sql/gstream.cc: Use my_global.h first sql/ha_ndbcluster.cc: Use my_global.h first sql/ha_ndbcluster_binlog.cc: Use my_global.h first sql/ha_ndbcluster_cond.cc: Use my_global.h first sql/ha_partition.cc: Use my_global.h first sql/handler.cc: Use my_global.h first sql/hash_filo.cc: Use my_global.h first sql/hostname.cc: Use my_global.h first sql/init.cc: Use my_global.h first sql/item.cc: Use my_global.h first sql/item_buff.cc: Use my_global.h first sql/item_cmpfunc.cc: Use my_global.h first sql/item_create.cc: Use my_global.h first sql/item_geofunc.cc: Use my_global.h first sql/item_inetfunc.cc: Use my_global.h first sql/item_row.cc: Use my_global.h first sql/item_strfunc.cc: Use my_global.h first sql/item_subselect.cc: Use my_global.h first sql/item_sum.cc: Use my_global.h first sql/item_timefunc.cc: Use my_global.h first sql/item_xmlfunc.cc: Use my_global.h first sql/key.cc: Use my_global.h first sql/lock.cc: Use my_global.h first sql/log.cc: Use my_global.h first sql/log_event.cc: Use my_global.h first sql/log_event_old.cc: Use my_global.h first sql/mf_iocache.cc: Use my_global.h first sql/mysql_install_db.cc: Remove duplicated include files sql/mysqld.cc: Remove duplicated include files sql/net_serv.cc: Remove duplicated include files sql/opt_range.cc: Use my_global.h first sql/opt_subselect.cc: Use my_global.h first sql/opt_sum.cc: Use my_global.h first sql/parse_file.cc: Use my_global.h first sql/partition_info.cc: Use my_global.h first sql/procedure.cc: Use my_global.h first sql/protocol.cc: Use my_global.h first sql/records.cc: Use my_global.h first sql/records.h: Don't include my_global.h Better to do this at the upper level sql/repl_failsafe.cc: Use my_global.h first sql/rpl_filter.cc: Use my_global.h first sql/rpl_gtid.cc: Use my_global.h first sql/rpl_handler.cc: Use my_global.h first sql/rpl_injector.cc: Use my_global.h first sql/rpl_record.cc: Use my_global.h first sql/rpl_record_old.cc: Use my_global.h first sql/rpl_reporting.cc: Use my_global.h first sql/rpl_rli.cc: Use my_global.h first sql/rpl_tblmap.cc: Use my_global.h first sql/rpl_utility.cc: Use my_global.h first sql/set_var.cc: Added comment sql/slave.cc: Use my_global.h first sql/sp.cc: Use my_global.h first sql/sp_cache.cc: Use my_global.h first sql/sp_head.cc: Use my_global.h first sql/sp_pcontext.cc: Use my_global.h first sql/sp_rcontext.cc: Use my_global.h first sql/spatial.cc: Use my_global.h first sql/sql_acl.cc: Use my_global.h first sql/sql_admin.cc: Use my_global.h first sql/sql_analyse.cc: Use my_global.h first sql/sql_audit.cc: Use my_global.h first sql/sql_base.cc: Use my_global.h first sql/sql_binlog.cc: Use my_global.h first sql/sql_bootstrap.cc: Use my_global.h first Use my_global.h first sql/sql_cache.cc: Use my_global.h first sql/sql_class.cc: Use my_global.h first sql/sql_client.cc: Use my_global.h first sql/sql_connect.cc: Use my_global.h first sql/sql_crypt.cc: Use my_global.h first sql/sql_cursor.cc: Use my_global.h first sql/sql_db.cc: Use my_global.h first sql/sql_delete.cc: Use my_global.h first sql/sql_derived.cc: Use my_global.h first sql/sql_do.cc: Use my_global.h first sql/sql_error.cc: Use my_global.h first sql/sql_explain.cc: Use my_global.h first sql/sql_expression_cache.cc: Use my_global.h first sql/sql_handler.cc: Use my_global.h first sql/sql_help.cc: Use my_global.h first sql/sql_insert.cc: Use my_global.h first sql/sql_lex.cc: Use my_global.h first sql/sql_load.cc: Use my_global.h first sql/sql_locale.cc: Use my_global.h first sql/sql_manager.cc: Use my_global.h first sql/sql_parse.cc: Use my_global.h first sql/sql_partition.cc: Use my_global.h first sql/sql_plugin.cc: Added comment sql/sql_prepare.cc: Use my_global.h first sql/sql_priv.h: Added error if we use this before including my_global.h This check is here becasue so many files includes sql_priv.h first. sql/sql_profile.cc: Use my_global.h first sql/sql_reload.cc: Use my_global.h first sql/sql_rename.cc: Use my_global.h first sql/sql_repl.cc: Use my_global.h first sql/sql_select.cc: Use my_global.h first sql/sql_servers.cc: Use my_global.h first sql/sql_show.cc: Added comment sql/sql_signal.cc: Use my_global.h first sql/sql_statistics.cc: Use my_global.h first sql/sql_table.cc: Use my_global.h first sql/sql_tablespace.cc: Use my_global.h first sql/sql_test.cc: Use my_global.h first sql/sql_time.cc: Use my_global.h first sql/sql_trigger.cc: Use my_global.h first sql/sql_udf.cc: Use my_global.h first sql/sql_union.cc: Use my_global.h first sql/sql_update.cc: Use my_global.h first sql/sql_view.cc: Use my_global.h first sql/sys_vars.cc: Added comment sql/table.cc: Use my_global.h first sql/thr_malloc.cc: Use my_global.h first sql/transaction.cc: Use my_global.h first sql/uniques.cc: Use my_global.h first sql/unireg.cc: Use my_global.h first sql/unireg.h: Removed inclusion of my_global.h storage/archive/ha_archive.cc: Added comment storage/blackhole/ha_blackhole.cc: Use my_global.h first storage/csv/ha_tina.cc: Use my_global.h first storage/csv/transparent_file.cc: Use my_global.h first storage/federated/ha_federated.cc: Use my_global.h first storage/federatedx/federatedx_io.cc: Use my_global.h first storage/federatedx/federatedx_io_mysql.cc: Use my_global.h first storage/federatedx/federatedx_io_null.cc: Use my_global.h first storage/federatedx/federatedx_txn.cc: Use my_global.h first storage/heap/ha_heap.cc: Use my_global.h first storage/innobase/handler/handler0alter.cc: Use my_global.h first storage/maria/ha_maria.cc: Use my_global.h first storage/maria/unittest/ma_maria_log_cleanup.c: Remove duplicated include files storage/maria/unittest/test_file.c: Added comment storage/myisam/ha_myisam.cc: Move sql_plugin.h first as this includes my_global.h storage/myisammrg/ha_myisammrg.cc: Use my_global.h first storage/oqgraph/oqgraph_thunk.cc: Use my_config.h and my_global.h first One could not include my_global.h before oqgraph_thunk.h (don't know why) storage/spider/ha_spider.cc: Use my_global.h first storage/spider/hs_client/config.cpp: Use my_global.h first storage/spider/hs_client/escape.cpp: Use my_global.h first storage/spider/hs_client/fatal.cpp: Use my_global.h first storage/spider/hs_client/hstcpcli.cpp: Use my_global.h first storage/spider/hs_client/socket.cpp: Use my_global.h first storage/spider/hs_client/string_util.cpp: Use my_global.h first storage/spider/spd_conn.cc: Use my_global.h first storage/spider/spd_copy_tables.cc: Use my_global.h first storage/spider/spd_db_conn.cc: Use my_global.h first storage/spider/spd_db_handlersocket.cc: Use my_global.h first storage/spider/spd_db_mysql.cc: Use my_global.h first storage/spider/spd_db_oracle.cc: Use my_global.h first storage/spider/spd_direct_sql.cc: Use my_global.h first storage/spider/spd_i_s.cc: Use my_global.h first storage/spider/spd_malloc.cc: Use my_global.h first storage/spider/spd_param.cc: Use my_global.h first storage/spider/spd_ping_table.cc: Use my_global.h first storage/spider/spd_sys_table.cc: Use my_global.h first storage/spider/spd_table.cc: Use my_global.h first storage/spider/spd_trx.cc: Use my_global.h first storage/xtradb/handler/handler0alter.cc: Use my_global.h first storage/xtradb/handler/i_s.cc: Use my_global.h first
595 lines
18 KiB
C++
595 lines
18 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 <my_global.h>
|
|
#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 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 */
|
|
set_current_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 (master_info_index)
|
|
{
|
|
if (!(mi= (master_info_index->
|
|
get_master_info(&connection_name,
|
|
Sql_condition::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->ull_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, NULL, 0))
|
|
{
|
|
/* 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 (master_info_index)
|
|
{
|
|
if (!(mi= (master_info_index->
|
|
get_master_info(&lex_mi->connection_name,
|
|
Sql_condition::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
|
|
and FLUSH TABLES <table_list> FOR EXPORT
|
|
|
|
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;
|
|
}
|
|
|
|
if (thd->lex->type & REFRESH_READ_LOCK)
|
|
{
|
|
/*
|
|
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_OPEN_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))
|
|
goto error;
|
|
|
|
if (thd->lex->type & REFRESH_FOR_EXPORT)
|
|
{
|
|
// Check if all storage engines support FOR EXPORT.
|
|
for (TABLE_LIST *table_list= all_tables; table_list;
|
|
table_list= table_list->next_global)
|
|
{
|
|
if (!(table_list->table->file->ha_table_flags() & HA_CAN_EXPORT))
|
|
{
|
|
my_error(ER_ILLEGAL_HA, MYF(0),table_list->table->file->table_type(),
|
|
table_list->db, table_list->table_name);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (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
|
|
}
|
|
}
|
|
|