Extract reload_acl_and_cache() and flush_tables_with_read_lock()
into an own implementation file.
This commit is contained in:
parent
7c3de33a4f
commit
8ce6e98aa3
@ -997,6 +997,7 @@ libmysqld/.deps/sql_cursor.Po
|
|||||||
libmysqld/.deps/sql_db.Po
|
libmysqld/.deps/sql_db.Po
|
||||||
libmysqld/.deps/sql_delete.Po
|
libmysqld/.deps/sql_delete.Po
|
||||||
libmysqld/.deps/sql_truncate.Po
|
libmysqld/.deps/sql_truncate.Po
|
||||||
|
libmysqld/.deps/sql_reload.Po
|
||||||
libmysqld/.deps/datadict.Po
|
libmysqld/.deps/datadict.Po
|
||||||
libmysqld/.deps/sql_derived.Po
|
libmysqld/.deps/sql_derived.Po
|
||||||
libmysqld/.deps/sql_do.Po
|
libmysqld/.deps/sql_do.Po
|
||||||
@ -1175,6 +1176,7 @@ libmysqld/sql_cursor.h
|
|||||||
libmysqld/sql_db.cc
|
libmysqld/sql_db.cc
|
||||||
libmysqld/sql_delete.cc
|
libmysqld/sql_delete.cc
|
||||||
libmysqld/sql_truncate.cc
|
libmysqld/sql_truncate.cc
|
||||||
|
libmysqld/sql_reload.cc
|
||||||
libmysqld/datadict.cc
|
libmysqld/datadict.cc
|
||||||
libmysqld/sql_derived.cc
|
libmysqld/sql_derived.cc
|
||||||
libmysqld/sql_do.cc
|
libmysqld/sql_do.cc
|
||||||
@ -2067,6 +2069,7 @@ sql/.deps/sql_cursor.Po
|
|||||||
sql/.deps/sql_db.Po
|
sql/.deps/sql_db.Po
|
||||||
sql/.deps/sql_delete.Po
|
sql/.deps/sql_delete.Po
|
||||||
sql/.deps/sql_truncate.Po
|
sql/.deps/sql_truncate.Po
|
||||||
|
sql/.deps/sql_reload.Po
|
||||||
sql/.deps/datadict.Po
|
sql/.deps/datadict.Po
|
||||||
sql/.deps/sql_derived.Po
|
sql/.deps/sql_derived.Po
|
||||||
sql/.deps/sql_do.Po
|
sql/.deps/sql_do.Po
|
||||||
|
@ -64,7 +64,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
|
|||||||
../sql/sql_db.cc ../sql/sql_delete.cc ../sql/sql_derived.cc
|
../sql/sql_db.cc ../sql/sql_delete.cc ../sql/sql_derived.cc
|
||||||
../sql/sql_do.cc ../sql/sql_error.cc ../sql/sql_handler.cc
|
../sql/sql_do.cc ../sql/sql_error.cc ../sql/sql_handler.cc
|
||||||
../sql/sql_help.cc ../sql/sql_insert.cc ../sql/datadict.cc
|
../sql/sql_help.cc ../sql/sql_insert.cc ../sql/datadict.cc
|
||||||
../sql/sql_truncate.cc
|
../sql/sql_truncate.cc ../sql/sql_reload.cc
|
||||||
../sql/sql_lex.cc ../sql/keycaches.cc
|
../sql/sql_lex.cc ../sql/keycaches.cc
|
||||||
../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc
|
../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc
|
||||||
../sql/sql_binlog.cc ../sql/sql_manager.cc
|
../sql/sql_binlog.cc ../sql/sql_manager.cc
|
||||||
|
@ -64,6 +64,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
|
|||||||
opt_sum.cc procedure.cc records.cc sql_acl.cc \
|
opt_sum.cc procedure.cc records.cc sql_acl.cc \
|
||||||
sql_load.cc discover.cc sql_locale.cc \
|
sql_load.cc discover.cc sql_locale.cc \
|
||||||
sql_profile.cc sql_truncate.cc datadict.cc \
|
sql_profile.cc sql_truncate.cc datadict.cc \
|
||||||
|
sql_reload.cc \
|
||||||
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
|
sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \
|
||||||
sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \
|
sql_crypt.cc sql_db.cc sql_delete.cc sql_error.cc sql_insert.cc \
|
||||||
sql_lex.cc sql_list.cc sql_manager.cc \
|
sql_lex.cc sql_list.cc sql_manager.cc \
|
||||||
|
@ -75,6 +75,7 @@ SET (SQL_SOURCE
|
|||||||
sql_profile.cc event_parse_data.cc
|
sql_profile.cc event_parse_data.cc
|
||||||
sql_signal.cc rpl_handler.cc mdl.cc
|
sql_signal.cc rpl_handler.cc mdl.cc
|
||||||
transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
|
transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
|
||||||
|
sql_reload.cc
|
||||||
${GEN_SOURCES}
|
${GEN_SOURCES}
|
||||||
${MYSYS_LIBWRAP_SOURCE})
|
${MYSYS_LIBWRAP_SOURCE})
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ DTRACEFILES = filesort.o \
|
|||||||
sql_cursor.o \
|
sql_cursor.o \
|
||||||
sql_delete.o \
|
sql_delete.o \
|
||||||
sql_truncate.o \
|
sql_truncate.o \
|
||||||
|
sql_reload.o \
|
||||||
sql_insert.o \
|
sql_insert.o \
|
||||||
datadict.o \
|
datadict.o \
|
||||||
sql_parse.o \
|
sql_parse.o \
|
||||||
@ -59,6 +60,7 @@ DTRACEFILES_DEPEND = filesort.o \
|
|||||||
sql_cursor.o \
|
sql_cursor.o \
|
||||||
sql_delete.o \
|
sql_delete.o \
|
||||||
sql_truncate.o \
|
sql_truncate.o \
|
||||||
|
sql_reload.o \
|
||||||
sql_insert.o \
|
sql_insert.o \
|
||||||
datadict.o \
|
datadict.o \
|
||||||
sql_parse.o \
|
sql_parse.o \
|
||||||
@ -126,7 +128,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||||||
contributors.h sql_servers.h sql_signal.h records.h \
|
contributors.h sql_servers.h sql_signal.h records.h \
|
||||||
sql_prepare.h rpl_handler.h replication.h mdl.h \
|
sql_prepare.h rpl_handler.h replication.h mdl.h \
|
||||||
sql_plist.h transaction.h sys_vars.h sql_truncate.h \
|
sql_plist.h transaction.h sys_vars.h sql_truncate.h \
|
||||||
datadict.h
|
sql_reload.h datadict.h
|
||||||
|
|
||||||
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
||||||
item.cc item_sum.cc item_buff.cc item_func.cc \
|
item.cc item_sum.cc item_buff.cc item_func.cc \
|
||||||
@ -140,7 +142,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
|||||||
sql_connect.cc scheduler.cc sql_parse.cc \
|
sql_connect.cc scheduler.cc sql_parse.cc \
|
||||||
keycaches.cc set_var.cc sql_yacc.yy sys_vars.cc \
|
keycaches.cc set_var.cc sql_yacc.yy sys_vars.cc \
|
||||||
sql_base.cc table.cc sql_select.cc sql_insert.cc \
|
sql_base.cc table.cc sql_select.cc sql_insert.cc \
|
||||||
datadict.cc sql_profile.cc \
|
sql_reload.cc datadict.cc sql_profile.cc \
|
||||||
sql_prepare.cc sql_error.cc sql_locale.cc \
|
sql_prepare.cc sql_error.cc sql_locale.cc \
|
||||||
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
|
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
|
||||||
procedure.cc sql_test.cc sql_truncate.cc \
|
procedure.cc sql_test.cc sql_truncate.cc \
|
||||||
|
42
sql/lock.h
42
sql/lock.h
@ -9,48 +9,6 @@ struct TABLE_LIST;
|
|||||||
class THD;
|
class THD;
|
||||||
typedef struct st_mysql_lock MYSQL_LOCK;
|
typedef struct st_mysql_lock MYSQL_LOCK;
|
||||||
|
|
||||||
/* mysql_lock_tables() and open_table() flags bits */
|
|
||||||
#define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001
|
|
||||||
#define MYSQL_OPEN_IGNORE_FLUSH 0x0002
|
|
||||||
#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004
|
|
||||||
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
|
|
||||||
#define MYSQL_LOCK_LOG_TABLE 0x0010
|
|
||||||
/**
|
|
||||||
Do not try to acquire a metadata lock on the table: we
|
|
||||||
already have one.
|
|
||||||
*/
|
|
||||||
#define MYSQL_OPEN_HAS_MDL_LOCK 0x0020
|
|
||||||
/**
|
|
||||||
If in locked tables mode, ignore the locked tables and get
|
|
||||||
a new instance of the table.
|
|
||||||
*/
|
|
||||||
#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
|
|
||||||
/** Don't look up the table in the list of temporary tables. */
|
|
||||||
#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080
|
|
||||||
/** Fail instead of waiting when conficting metadata lock is discovered. */
|
|
||||||
#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
|
|
||||||
/** Open tables using MDL_SHARED lock instead of one specified in parser. */
|
|
||||||
#define MYSQL_OPEN_FORCE_SHARED_MDL 0x0200
|
|
||||||
/**
|
|
||||||
Open tables using MDL_SHARED_HIGH_PRIO lock instead of one specified
|
|
||||||
in parser.
|
|
||||||
*/
|
|
||||||
#define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0400
|
|
||||||
/**
|
|
||||||
When opening or locking the table, use the maximum timeout
|
|
||||||
(LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value.
|
|
||||||
*/
|
|
||||||
#define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800
|
|
||||||
|
|
||||||
/** Please refer to the internals manual. */
|
|
||||||
#define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\
|
|
||||||
MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |\
|
|
||||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
|
|
||||||
MYSQL_LOCK_IGNORE_TIMEOUT |\
|
|
||||||
MYSQL_OPEN_GET_NEW_TABLE |\
|
|
||||||
MYSQL_OPEN_SKIP_TEMPORARY |\
|
|
||||||
MYSQL_OPEN_HAS_MDL_LOCK)
|
|
||||||
|
|
||||||
|
|
||||||
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags);
|
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags);
|
||||||
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
|
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
#include <errmsg.h>
|
#include <errmsg.h>
|
||||||
#include "sp_rcontext.h"
|
#include "sp_rcontext.h"
|
||||||
#include "sp_cache.h"
|
#include "sp_cache.h"
|
||||||
|
#include "sql_reload.h" // reload_acl_and_cache
|
||||||
|
|
||||||
#ifdef HAVE_POLL_H
|
#ifdef HAVE_POLL_H
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
@ -89,6 +89,49 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
|
|||||||
|
|
||||||
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
|
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
|
||||||
uint lock_flags);
|
uint lock_flags);
|
||||||
|
|
||||||
|
/* mysql_lock_tables() and open_table() flags bits */
|
||||||
|
#define MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK 0x0001
|
||||||
|
#define MYSQL_OPEN_IGNORE_FLUSH 0x0002
|
||||||
|
#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004
|
||||||
|
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
|
||||||
|
#define MYSQL_LOCK_LOG_TABLE 0x0010
|
||||||
|
/**
|
||||||
|
Do not try to acquire a metadata lock on the table: we
|
||||||
|
already have one.
|
||||||
|
*/
|
||||||
|
#define MYSQL_OPEN_HAS_MDL_LOCK 0x0020
|
||||||
|
/**
|
||||||
|
If in locked tables mode, ignore the locked tables and get
|
||||||
|
a new instance of the table.
|
||||||
|
*/
|
||||||
|
#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
|
||||||
|
/** Don't look up the table in the list of temporary tables. */
|
||||||
|
#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080
|
||||||
|
/** Fail instead of waiting when conficting metadata lock is discovered. */
|
||||||
|
#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
|
||||||
|
/** Open tables using MDL_SHARED lock instead of one specified in parser. */
|
||||||
|
#define MYSQL_OPEN_FORCE_SHARED_MDL 0x0200
|
||||||
|
/**
|
||||||
|
Open tables using MDL_SHARED_HIGH_PRIO lock instead of one specified
|
||||||
|
in parser.
|
||||||
|
*/
|
||||||
|
#define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0400
|
||||||
|
/**
|
||||||
|
When opening or locking the table, use the maximum timeout
|
||||||
|
(LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value.
|
||||||
|
*/
|
||||||
|
#define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800
|
||||||
|
|
||||||
|
/** Please refer to the internals manual. */
|
||||||
|
#define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\
|
||||||
|
MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |\
|
||||||
|
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
|
||||||
|
MYSQL_LOCK_IGNORE_TIMEOUT |\
|
||||||
|
MYSQL_OPEN_GET_NEW_TABLE |\
|
||||||
|
MYSQL_OPEN_SKIP_TEMPORARY |\
|
||||||
|
MYSQL_OPEN_HAS_MDL_LOCK)
|
||||||
|
|
||||||
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||||
Open_table_context *ot_ctx);
|
Open_table_context *ot_ctx);
|
||||||
bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
|
bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
|
||||||
|
407
sql/sql_parse.cc
407
sql/sql_parse.cc
@ -50,6 +50,7 @@
|
|||||||
// mysql_backup_table,
|
// mysql_backup_table,
|
||||||
// mysql_restore_table
|
// mysql_restore_table
|
||||||
#include "sql_truncate.h" // mysql_truncate_table
|
#include "sql_truncate.h" // mysql_truncate_table
|
||||||
|
#include "sql_reload.h" // reload_acl_and_cache
|
||||||
#include "sql_connect.h" // check_user,
|
#include "sql_connect.h" // check_user,
|
||||||
// decrease_user_connections,
|
// decrease_user_connections,
|
||||||
// thd_init_client_charset, check_mqh,
|
// thd_init_client_charset, check_mqh,
|
||||||
@ -1695,153 +1696,6 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
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
|
|
||||||
- currently incompatible with the GRL (@todo: fix)
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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).
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables)
|
|
||||||
{
|
|
||||||
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
|
|
||||||
TABLE_LIST *table_list;
|
|
||||||
MDL_request_list mdl_requests;
|
|
||||||
|
|
||||||
/*
|
|
||||||
This is called from SQLCOM_FLUSH, the transaction has
|
|
||||||
been committed implicitly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* RELOAD_ACL is checked by the caller. Check table-level privileges. */
|
|
||||||
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
|
|
||||||
FALSE, UINT_MAX, FALSE))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (thd->locked_tables_mode)
|
|
||||||
{
|
|
||||||
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Acquire SNW locks on tables to be flushed. We can't use
|
|
||||||
lock_table_names() here as this call will also acquire global IX
|
|
||||||
and database-scope IX locks on the tables, and this will make
|
|
||||||
this statement incompatible with FLUSH TABLES WITH READ LOCK.
|
|
||||||
*/
|
|
||||||
for (table_list= all_tables; table_list;
|
|
||||||
table_list= table_list->next_global)
|
|
||||||
mdl_requests.push_front(&table_list->mdl_request);
|
|
||||||
|
|
||||||
if (thd->mdl_context.acquire_locks(&mdl_requests,
|
|
||||||
thd->variables.lock_wait_timeout))
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* Skip views and temporary tables. */
|
|
||||||
table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
|
|
||||||
table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
if (open_and_lock_tables(thd, all_tables, FALSE,
|
|
||||||
MYSQL_OPEN_HAS_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read query from packet and store in thd->query.
|
Read query from packet and store in thd->query.
|
||||||
Used in COM_QUERY and COM_STMT_PREPARE.
|
Used in COM_QUERY and COM_STMT_PREPARE.
|
||||||
@ -3972,6 +3826,10 @@ end_with_restore_list:
|
|||||||
|
|
||||||
if (first_table && lex->type & REFRESH_READ_LOCK)
|
if (first_table && lex->type & REFRESH_READ_LOCK)
|
||||||
{
|
{
|
||||||
|
/* Check table-level privileges. */
|
||||||
|
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
|
||||||
|
FALSE, UINT_MAX, FALSE))
|
||||||
|
goto error;
|
||||||
if (flush_tables_with_read_lock(thd, all_tables))
|
if (flush_tables_with_read_lock(thd, all_tables))
|
||||||
goto error;
|
goto error;
|
||||||
my_ok(thd);
|
my_ok(thd);
|
||||||
@ -6704,261 +6562,6 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
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 True 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, ulong options, TABLE_LIST *tables,
|
|
||||||
bool *write_to_binlog)
|
|
||||||
{
|
|
||||||
bool result=0;
|
|
||||||
select_errors=0; /* Write if more errors */
|
|
||||||
bool tmp_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), "FLUSH PRIVILEGES failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
|
||||||
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())
|
|
||||||
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
|
|
||||||
}
|
|
||||||
if (options & REFRESH_RELAY_LOG)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_REPLICATION
|
|
||||||
mysql_mutex_lock(&LOCK_active_mi);
|
|
||||||
rotate_relay_log(active_mi);
|
|
||||||
mysql_mutex_unlock(&LOCK_active_mi);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#ifdef HAVE_QUERY_CACHE
|
|
||||||
if (options & REFRESH_QUERY_CACHE_FREE)
|
|
||||||
{
|
|
||||||
query_cache.pack(); // 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))
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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->open_tables, t->db,
|
|
||||||
t->table_name, FALSE))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
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)))
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
result=1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef OPENSSL
|
|
||||||
if (options & REFRESH_DES_KEY_FILE)
|
|
||||||
{
|
|
||||||
if (des_key_file && load_des_key_file(des_key_file))
|
|
||||||
result= 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_REPLICATION
|
|
||||||
if (options & REFRESH_SLAVE)
|
|
||||||
{
|
|
||||||
tmp_write_to_binlog= 0;
|
|
||||||
mysql_mutex_lock(&LOCK_active_mi);
|
|
||||||
if (reset_slave(thd, active_mi))
|
|
||||||
result=1;
|
|
||||||
mysql_mutex_unlock(&LOCK_active_mi);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (options & REFRESH_USER_RESOURCES)
|
|
||||||
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
|
|
||||||
*write_to_binlog= tmp_write_to_binlog;
|
|
||||||
/*
|
|
||||||
If the query was killed then this function must fail.
|
|
||||||
*/
|
|
||||||
return result || (thd ? thd->killed : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
kill on thread.
|
kill on thread.
|
||||||
|
|
||||||
|
@ -93,8 +93,6 @@ void mysql_init_multi_delete(LEX *lex);
|
|||||||
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
|
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
|
||||||
void create_table_set_open_action_and_adjust_tables(LEX *lex);
|
void create_table_set_open_action_and_adjust_tables(LEX *lex);
|
||||||
pthread_handler_t handle_bootstrap(void *arg);
|
pthread_handler_t handle_bootstrap(void *arg);
|
||||||
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
|
|
||||||
bool *write_to_binlog);
|
|
||||||
int mysql_execute_command(THD *thd);
|
int mysql_execute_command(THD *thd);
|
||||||
bool do_command(THD *thd);
|
bool do_command(THD *thd);
|
||||||
void do_handle_bootstrap(THD *thd);
|
void do_handle_bootstrap(THD *thd);
|
||||||
|
427
sql/sql_reload.cc
Normal file
427
sql/sql_reload.cc
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
/* Copyright (c) 2010, 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 "debug_sync.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
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 True 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, bool *write_to_binlog)
|
||||||
|
{
|
||||||
|
bool result=0;
|
||||||
|
select_errors=0; /* Write if more errors */
|
||||||
|
bool tmp_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), "FLUSH PRIVILEGES failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
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())
|
||||||
|
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
|
||||||
|
}
|
||||||
|
if (options & REFRESH_RELAY_LOG)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_REPLICATION
|
||||||
|
mysql_mutex_lock(&LOCK_active_mi);
|
||||||
|
rotate_relay_log(active_mi);
|
||||||
|
mysql_mutex_unlock(&LOCK_active_mi);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef HAVE_QUERY_CACHE
|
||||||
|
if (options & REFRESH_QUERY_CACHE_FREE)
|
||||||
|
{
|
||||||
|
query_cache.pack(); // 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))
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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->open_tables, t->db,
|
||||||
|
t->table_name, FALSE))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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)))
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
result=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef OPENSSL
|
||||||
|
if (options & REFRESH_DES_KEY_FILE)
|
||||||
|
{
|
||||||
|
if (des_key_file && load_des_key_file(des_key_file))
|
||||||
|
result= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_REPLICATION
|
||||||
|
if (options & REFRESH_SLAVE)
|
||||||
|
{
|
||||||
|
tmp_write_to_binlog= 0;
|
||||||
|
mysql_mutex_lock(&LOCK_active_mi);
|
||||||
|
if (reset_slave(thd, active_mi))
|
||||||
|
result=1;
|
||||||
|
mysql_mutex_unlock(&LOCK_active_mi);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (options & REFRESH_USER_RESOURCES)
|
||||||
|
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
|
||||||
|
*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
|
||||||
|
- currently incompatible with the GRL (@todo: fix)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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;
|
||||||
|
MDL_request_list mdl_requests;
|
||||||
|
|
||||||
|
/*
|
||||||
|
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. We can't use
|
||||||
|
lock_table_names() here as this call will also acquire global IX
|
||||||
|
and database-scope IX locks on the tables, and this will make
|
||||||
|
this statement incompatible with FLUSH TABLES WITH READ LOCK.
|
||||||
|
*/
|
||||||
|
for (table_list= all_tables; table_list;
|
||||||
|
table_list= table_list->next_global)
|
||||||
|
mdl_requests.push_front(&table_list->mdl_request);
|
||||||
|
|
||||||
|
if (thd->mdl_context.acquire_locks(&mdl_requests,
|
||||||
|
thd->variables.lock_wait_timeout))
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Skip views and temporary tables. */
|
||||||
|
table_list->required_type= FRMTYPE_TABLE; /* Don't try to flush views. */
|
||||||
|
table_list->open_type= OT_BASE_ONLY; /* Ignore temporary tables. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
if (open_and_lock_tables(thd, all_tables, FALSE,
|
||||||
|
MYSQL_OPEN_HAS_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
26
sql/sql_reload.h
Normal file
26
sql/sql_reload.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef SQL_RELOAD_INCLUDED
|
||||||
|
#define SQL_RELOAD_INCLUDED
|
||||||
|
/* Copyright (c) 2010, 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 */
|
||||||
|
|
||||||
|
class THD;
|
||||||
|
struct TABLE_LIST;
|
||||||
|
|
||||||
|
bool reload_acl_and_cache(THD *thd, unsigned long options,
|
||||||
|
TABLE_LIST *tables, bool *write_to_binlog);
|
||||||
|
|
||||||
|
bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables);
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user