Commit d41d43f4 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-4065 thd_kill_statement service

parent 5649377b
......@@ -72,7 +72,7 @@ typedef struct st_mysql_xid MYSQL_XID;
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0103
/* MariaDB plugin interface version */
#define MARIA_PLUGIN_INTERFACE_VERSION 0x0103
#define MARIA_PLUGIN_INTERFACE_VERSION 0x0104
/*
The allowable types of plugins
......@@ -625,22 +625,6 @@ void thd_inc_row_count(MYSQL_THD thd);
*/
int mysql_tmpfile(const char *prefix);
/**
Check the killed state of a connection
@details
In MySQL support for the KILL statement is cooperative. The KILL
statement only sets a "killed" flag. This function returns the value
of that flag. A thread should check it often, especially inside
time-consuming loops, and gracefully abort the operation if it is
non-zero.
@param thd user thread connection handle
@retval 0 the connection is active
@retval 1 the connection has been killed
*/
int thd_killed(const MYSQL_THD thd);
/**
Return the thread id of a user thread
......
......@@ -82,6 +82,16 @@ const char *set_thd_proc_info(void*, const char * info, const char *func,
const char *file, unsigned int line);
#include <mysql/service_debug_sync.h>
extern void (*debug_sync_C_callback_ptr)(void*, const char *, size_t);
#include <mysql/service_kill_statement.h>
enum thd_kill_levels {
THD_IS_NOT_KILLED=0,
THD_ABORT_SOFTLY=50,
THD_ABORT_ASAP=100,
};
extern struct kill_statement_service_st {
enum thd_kill_levels (*thd_kill_level_func)(const void*);
} *thd_kill_statement_service;
enum thd_kill_levels thd_kill_level(const void*);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......@@ -226,7 +236,6 @@ char *thd_security_context(void* thd, char *buffer, unsigned int length,
unsigned int max_query_len);
void thd_inc_row_count(void* thd);
int mysql_tmpfile(const char *prefix);
int thd_killed(const void* thd);
unsigned long thd_get_thread_id(const void* thd);
void thd_get_xid(const void* thd, MYSQL_XID *xid);
void mysql_query_cache_invalidate4(void* thd,
......
......@@ -82,6 +82,16 @@ const char *set_thd_proc_info(void*, const char * info, const char *func,
const char *file, unsigned int line);
#include <mysql/service_debug_sync.h>
extern void (*debug_sync_C_callback_ptr)(void*, const char *, size_t);
#include <mysql/service_kill_statement.h>
enum thd_kill_levels {
THD_IS_NOT_KILLED=0,
THD_ABORT_SOFTLY=50,
THD_ABORT_ASAP=100,
};
extern struct kill_statement_service_st {
enum thd_kill_levels (*thd_kill_level_func)(const void*);
} *thd_kill_statement_service;
enum thd_kill_levels thd_kill_level(const void*);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......@@ -226,7 +236,6 @@ char *thd_security_context(void* thd, char *buffer, unsigned int length,
unsigned int max_query_len);
void thd_inc_row_count(void* thd);
int mysql_tmpfile(const char *prefix);
int thd_killed(const void* thd);
unsigned long thd_get_thread_id(const void* thd);
void thd_get_xid(const void* thd, MYSQL_XID *xid);
void mysql_query_cache_invalidate4(void* thd,
......
......@@ -82,6 +82,16 @@ const char *set_thd_proc_info(void*, const char * info, const char *func,
const char *file, unsigned int line);
#include <mysql/service_debug_sync.h>
extern void (*debug_sync_C_callback_ptr)(void*, const char *, size_t);
#include <mysql/service_kill_statement.h>
enum thd_kill_levels {
THD_IS_NOT_KILLED=0,
THD_ABORT_SOFTLY=50,
THD_ABORT_ASAP=100,
};
extern struct kill_statement_service_st {
enum thd_kill_levels (*thd_kill_level_func)(const void*);
} *thd_kill_statement_service;
enum thd_kill_levels thd_kill_level(const void*);
struct st_mysql_xid {
long formatID;
long gtrid_length;
......@@ -179,7 +189,6 @@ char *thd_security_context(void* thd, char *buffer, unsigned int length,
unsigned int max_query_len);
void thd_inc_row_count(void* thd);
int mysql_tmpfile(const char *prefix);
int thd_killed(const void* thd);
unsigned long thd_get_thread_id(const void* thd);
void thd_get_xid(const void* thd, MYSQL_XID *xid);
void mysql_query_cache_invalidate4(void* thd,
......
/* Copyright (c) 2013, Monty Program Ab.
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 */
#ifndef MYSQL_SERVICE_KILL_STATEMENT_INCLUDED
#define MYSQL_SERVICE_KILL_STATEMENT_INCLUDED
/**
@file
This service provides functions that allow plugins to support
the KILL statement.
In MySQL support for the KILL statement is cooperative. The KILL
statement only sets a "killed" flag. This function returns the value
of that flag. A thread should check it often, especially inside
time-consuming loops, and gracefully abort the operation if it is
non-zero.
thd_is_killed(thd)
@return 0 - no KILL statement was issued, continue normally
@return 1 - there was a KILL statement, abort the execution.
thd_kill_level(thd)
@return thd_kill_levels_enum values
*/
#ifdef __cplusplus
extern "C" {
#endif
enum thd_kill_levels {
THD_IS_NOT_KILLED=0,
THD_ABORT_SOFTLY=50, /**< abort when possible, don't leave tables corrupted */
THD_ABORT_ASAP=100, /**< abort asap */
};
extern struct kill_statement_service_st {
enum thd_kill_levels (*thd_kill_level_func)(const MYSQL_THD);
} *thd_kill_statement_service;
/* backward compatibility helper */
#define thd_killed(THD) (thd_kill_level(THD) == THD_ABORT_ASAP)
#ifdef MYSQL_DYNAMIC_PLUGIN
#define thd_kill_level(THD) \
thd_kill_statement_service->thd_kill_level_func(THD)
#else
enum thd_kill_levels thd_kill_level(const MYSQL_THD);
#endif
#ifdef __cplusplus
}
#endif
#endif
......@@ -24,6 +24,7 @@ extern "C" {
#include <mysql/service_thread_scheduler.h>
#include <mysql/service_progress_report.h>
#include <mysql/service_debug_sync.h>
#include <mysql/service_kill_statement.h>
#ifdef __cplusplus
}
......
......@@ -19,9 +19,11 @@
#define SERVICE_VERSION void *
#endif
#define VERSION_my_snprintf 0x0100
#define VERSION_thd_alloc 0x0100
#define VERSION_thd_wait 0x0100
#define VERSION_my_thread_scheduler 0x0100
#define VERSION_progress_report 0x0100
#define VERSION_debug_sync 0x1000
#define VERSION_my_snprintf 0x0100
#define VERSION_thd_alloc 0x0100
#define VERSION_thd_wait 0x0100
#define VERSION_my_thread_scheduler 0x0100
#define VERSION_progress_report 0x0100
#define VERSION_debug_sync 0x1000
#define VERSION_kill_statement 0x1000
......@@ -21,7 +21,8 @@ SET(MYSQLSERVICES_SOURCES
thd_wait_service.c
my_thread_scheduler_service.c
progress_report_service.c
debug_sync_service.c)
debug_sync_service.c
kill_statement_service.c)
ADD_CONVENIENCE_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
INSTALL(TARGETS mysqlservices DESTINATION ${INSTALL_LIBDIR} COMPONENT Development)
/* Copyright (c) 2013, Monty Program Ab.
Use is subject to license terms.
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 <service_versions.h>
SERVICE_VERSION thd_kill_statement_service= (void*)VERSION_kill_statement;
......@@ -5,7 +5,7 @@ plugin_version 1.0
plugin_status ACTIVE
plugin_type DAEMON
plugin_library handlersocket.so
plugin_library_version 1.3
plugin_library_version 1.4
plugin_author higuchi dot akira at dena dot jp
plugin_description Direct access into InnoDB
plugin_license BSD
......
......@@ -15,7 +15,7 @@ PLUGIN_STATUS ACTIVE
PLUGIN_TYPE STORAGE ENGINE
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
PLUGIN_LIBRARY_VERSION 1.3
PLUGIN_LIBRARY_VERSION 1.4
PLUGIN_AUTHOR Brian Aker, MySQL AB
PLUGIN_DESCRIPTION Example storage engine
PLUGIN_LICENSE GPL
......@@ -28,7 +28,7 @@ PLUGIN_STATUS ACTIVE
PLUGIN_TYPE DAEMON
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
PLUGIN_LIBRARY_VERSION 1.3
PLUGIN_LIBRARY_VERSION 1.4
PLUGIN_AUTHOR Sergei Golubchik
PLUGIN_DESCRIPTION Unusable Daemon
PLUGIN_LICENSE GPL
......@@ -57,7 +57,7 @@ PLUGIN_STATUS DELETED
PLUGIN_TYPE STORAGE ENGINE
PLUGIN_TYPE_VERSION #
PLUGIN_LIBRARY ha_example.so
PLUGIN_LIBRARY_VERSION 1.3
PLUGIN_LIBRARY_VERSION 1.4
PLUGIN_AUTHOR Brian Aker, MySQL AB
PLUGIN_DESCRIPTION Example storage engine
PLUGIN_LICENSE GPL
......
......@@ -673,21 +673,20 @@ void ha_close_connection(THD* thd)
}
static my_bool kill_handlerton(THD *thd, plugin_ref plugin,
void *hard_kill)
void *level)
{
handlerton *hton= plugin_data(plugin, handlerton *);
if (hton->state == SHOW_OPTION_YES && hton->kill_query &&
thd_get_ha_data(thd, hton))
hton->kill_query(hton, thd, * (my_bool*) hard_kill);
hton->kill_query(hton, thd, *(enum thd_kill_levels *) level);
return FALSE;
}
void ha_kill_query(THD* thd, my_bool hard_kill)
void ha_kill_query(THD* thd, enum thd_kill_levels level)
{
DBUG_ENTER("ha_kill_query");
plugin_foreach(thd, kill_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
&hard_kill);
plugin_foreach(thd, kill_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, &level);
DBUG_VOID_RETURN;
}
......@@ -4721,7 +4720,9 @@ extern "C" enum icp_result handler_index_cond_check(void* h_arg)
THD *thd= h->table->in_use;
enum icp_result res;
if (thd_killed(thd))
enum thd_kill_levels abort_at= h->has_transactions() ?
THD_ABORT_SOFTLY : THD_ABORT_ASAP;
if (thd_kill_level(thd) > abort_at)
return ICP_ABORTED_BY_USER;
if (h->end_range && h->compare_key2(h->end_range) > 0)
......
......@@ -866,10 +866,8 @@ struct handlerton
int (*close_connection)(handlerton *hton, THD *thd);
/*
Tell handler that query has been killed.
hard_kill is set in case of HARD KILL (abort query even if
it may corrupt table).
*/
void (*kill_query)(handlerton *hton, THD *thd, my_bool hard_kill);
void (*kill_query)(handlerton *hton, THD *thd, enum thd_kill_levels level);
/*
sv points to an uninitialized storage area of requested size
(see savepoint_offset description)
......@@ -2983,7 +2981,7 @@ int ha_finalize_handlerton(st_plugin_int *plugin);
TYPELIB *ha_known_exts(void);
int ha_panic(enum ha_panic_function flag);
void ha_close_connection(THD* thd);
void ha_kill_query(THD* thd, my_bool hard_kill);
void ha_kill_query(THD* thd, enum thd_kill_levels level);
bool ha_flush_logs(handlerton *db_type);
void ha_drop_database(char* path);
void ha_checkpoint_state(bool disable);
......
......@@ -1613,7 +1613,7 @@ void THD::awake(killed_state state_to_set)
/* Interrupt target waiting inside a storage engine. */
if (state_to_set != NOT_KILLED)
ha_kill_query(this, test(state_to_set & KILL_HARD_BIT));
ha_kill_query(this, thd_kill_level(this));
/* Broadcast a condition to kick the target if it is waiting on it. */
if (mysys_var)
......@@ -3834,15 +3834,13 @@ void THD::restore_backup_open_tables_state(Open_tables_backup *backup)
DBUG_VOID_RETURN;
}
#if MARIA_PLUGIN_INTERFACE_VERSION < 0x0200
/**
Check the killed state of a user thread
@param thd user thread
@retval 0 the user thread is active
@retval 1 the user thread has been killed
This is used to signal a storage engine if it should be killed.
This is a backward compatibility method, made obsolete
by the thd_kill_statement service. Keep it here to avoid breaking the
ABI in case some binary plugins still use it.
*/
#undef thd_killed
extern "C" int thd_killed(const MYSQL_THD thd)
{
if (!thd)
......@@ -3850,9 +3848,26 @@ extern "C" int thd_killed(const MYSQL_THD thd)
if (!(thd->killed & KILL_HARD_BIT))
return 0;
return thd->killed;
return thd->killed != 0;
}
#else
#error now thd_killed() function can go away
#endif
/*
return thd->killed status to the client,
mapped to the API enum thd_kill_levels values.
*/
extern "C" enum thd_kill_levels thd_kill_level(const MYSQL_THD thd)
{
if (!thd)
thd= current_thd;
if (likely(thd->killed == NOT_KILLED))
return THD_IS_NOT_KILLED;
return thd->killed & KILL_HARD_BIT ? THD_ABORT_ASAP : THD_ABORT_SOFTLY;
}
/**
Send an out-of-band progress report to the client
......
......@@ -1872,8 +1872,11 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
DBUG_RETURN(FALSE);
error:
mysql_mutex_unlock(&LOCK_plugin);
sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
name.str, dl.str);
if (name.str)
sql_print_error("Couldn't load plugin '%s' from '%s'.",
name.str, dl.str);
else
sql_print_error("Couldn't load plugins from '%s'.", dl.str);
DBUG_RETURN(TRUE);
}
......
......@@ -54,13 +54,18 @@ static struct progress_report_service_st progress_report_handler= {
set_thd_proc_info
};
static struct kill_statement_service_st thd_kill_statement_handler= {
thd_kill_level
};
static struct st_service_ref list_of_services[]=
{
{ "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
{ "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler },
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
{ "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler },
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
{ "my_thread_scheduler_service", VERSION_my_thread_scheduler, &my_thread_scheduler_handler },
{ "progress_report_service", VERSION_progress_report, &progress_report_handler },
{ "debug_sync_service", VERSION_debug_sync, 0 } // updated in plugin_init()
{ "progress_report_service", VERSION_progress_report, &progress_report_handler },
{ "debug_sync_service", VERSION_debug_sync, 0 }, // updated in plugin_init()
{ "thd_kill_statement_service", VERSION_kill_statement, &thd_kill_statement_handler }
};
......@@ -339,7 +339,7 @@ static PSI_file_info all_innodb_files[] = {
static INNOBASE_SHARE *get_share(const char *table_name);
static void free_share(INNOBASE_SHARE *share);
static int innobase_close_connection(handlerton *hton, THD* thd);
static void innobase_kill_query(handlerton *hton, THD* thd, my_bool hard_kill);
static void innobase_kill_query(handlerton *hton, THD* thd, enum thd_kill_levels level);
static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all);
static int innobase_commit(handlerton *hton, THD* thd, bool all);
static int innobase_rollback(handlerton *hton, THD* thd, bool all);
......@@ -2153,7 +2153,7 @@ trx_is_interrupted(
/*===============*/
trx_t* trx) /*!< in: transaction */
{
return(trx && trx->mysql_thd && thd_killed((THD*) trx->mysql_thd));
return(trx && trx->mysql_thd && thd_kill_level((THD*) trx->mysql_thd));
}
/**********************************************************************//**
......@@ -2283,7 +2283,7 @@ innobase_init(
innobase_hton->flags=HTON_NO_FLAGS;
innobase_hton->release_temporary_latches=innobase_release_temporary_latches;
innobase_hton->alter_table_flags = innobase_alter_table_flags;
innobase_hton->kill_query = innobase_kill_query;
innobase_hton->kill_query = innobase_kill_query;
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
......@@ -3193,9 +3193,9 @@ static
void
innobase_kill_query(
/*======================*/
handlerton* hton, /*!< in: innobase handlerton */
THD* thd, /*!< in: handle to the MySQL thread being killed */
my_bool hard_kill) /*!< in: If hard kill */
handlerton* hton, /*!< in: innobase handlerton */
THD* thd, /*!< in: MySQL thread being killed */
enum thd_kill_levels level) /*!< in: kill level */
{
trx_t* trx;
DBUG_ENTER("innobase_kill_query");
......@@ -3207,7 +3207,6 @@ innobase_kill_query(
/* Cancel a pending lock request. */
if (trx && trx->wait_lock) {
//trx->killed= 1;
lock_cancel_waiting_and_release(trx->wait_lock);
}
......@@ -8724,7 +8723,7 @@ ha_innobase::check(
row_mysql_unlock_data_dictionary(prebuilt->trx);
}
if (thd_killed(user_thd)) {
if (thd_kill_level(user_thd)) {
break;
}
......@@ -8781,7 +8780,7 @@ ha_innobase::check(
mutex_exit(&kernel_mutex);
prebuilt->trx->op_info = "";
if (thd_killed(user_thd)) {
if (thd_kill_level(user_thd)) {
my_error(ER_QUERY_INTERRUPTED, MYF(0));
}
......
......@@ -378,7 +378,7 @@ static PSI_file_info all_innodb_files[] = {
static INNOBASE_SHARE *get_share(const char *table_name);
static void free_share(INNOBASE_SHARE *share);
static int innobase_close_connection(handlerton *hton, THD* thd);
static void innobase_kill_query(handlerton *hton, THD* thd, my_bool hard_kill);
static void innobase_kill_query(handlerton *hton, THD* thd, enum thd_kill_levels level);
static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all);
static int innobase_commit(handlerton *hton, THD* thd, bool all);
static int innobase_rollback(handlerton *hton, THD* thd, bool all);
......@@ -2378,7 +2378,7 @@ trx_is_interrupted(
/*===============*/
trx_t* trx) /*!< in: transaction */
{
return(trx && trx->mysql_thd && thd_killed((THD*) trx->mysql_thd));
return(trx && trx->mysql_thd && thd_kill_level((THD*) trx->mysql_thd));
}
/**********************************************************************//**
......@@ -2634,7 +2634,7 @@ innobase_init(
innobase_hton->flags=HTON_NO_FLAGS;
innobase_hton->release_temporary_latches=innobase_release_temporary_latches;
innobase_hton->alter_table_flags = innobase_alter_table_flags;
innobase_hton->kill_query = innobase_kill_query;
innobase_hton->kill_query = innobase_kill_query;
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
......@@ -3780,9 +3780,9 @@ static
void
innobase_kill_query(
/*======================*/
handlerton* hton, /*!< in: innobase handlerton */
THD* thd, /*!< in: handle to the MySQL thread being killed */
my_bool hard_kill) /*!< in: If hard kill */
handlerton* hton, /*!< in: innobase handlerton */
THD* thd, /*!< in: MySQL thread being killed */
enum thd_kill_levels level) /*!< in: kill level */
{
trx_t* trx;
DBUG_ENTER("innobase_kill_query");
......@@ -3794,7 +3794,6 @@ innobase_kill_query(
/* Cancel a pending lock request. */
if (trx && trx->wait_lock) {
//trx->killed= 1;
lock_cancel_waiting_and_release(trx->wait_lock);
}
......@@ -9731,7 +9730,7 @@ ha_innobase::check(
row_mysql_unlock_data_dictionary(prebuilt->trx);
}
if (thd_killed(user_thd)) {
if (thd_kill_level(user_thd)) {
break;
}
......@@ -9788,7 +9787,7 @@ ha_innobase::check(
mutex_exit(&kernel_mutex);
prebuilt->trx->op_info = "";
if (thd_killed(user_thd)) {
if (thd_kill_level(user_thd)) {
my_error(ER_QUERY_INTERRUPTED, MYF(0));
}
......@@ -13587,7 +13586,7 @@ int ha_innobase::multi_range_read_explain_info(uint mrr_mode, char *str, size_t
bool ha_innobase::is_thd_killed()
{
return thd_killed(user_thd);
return thd_kill_level(user_thd);
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment