diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index b2b64a0..6acfb34 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -54,6 +54,7 @@ SET(HEADERS m_ctype.h my_attribute.h my_compiler.h + governor.h ${HEADERS_GEN_CONFIGURE} ) diff --git a/include/governor.h b/include/governor.h new file mode 100644 index 0000000..7ee5698 --- /dev/null +++ b/include/governor.h @@ -0,0 +1,14 @@ +/* + * governor_pthread_wrapper.h + * + * Created on: Sep 26, 2012 + * Author: alexey +*/ + +#ifndef GOVERNOR_PTHREAD_WRAPPER_H_ +#define GOVERNOR_PTHREAD_WRAPPER_H_ + +#include + + +#endif /* GOVERNOR_PTHREAD_WRAPPER_H_ */ diff --git a/include/my_pthread.h b/include/my_pthread.h index e521564..a45ad34 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -192,6 +192,7 @@ int pthread_cancel(pthread_t thread); #include #undef sigwait #endif +#include #include #ifndef _REENTRANT #define _REENTRANT @@ -497,6 +498,13 @@ typedef struct st_safe_mutex_info_t } safe_mutex_info_t; #endif /* SAFE_MUTEX_DETECT_DESTROY */ +int put_in_lve(char *user); +void lve_thr_exit(); +void governor_setlve_mysql_thread_info(pid_t thread_id); +void governor_detroy_mysql_thread_info(); +__attribute__((noinline)) void my_release_slot(); +__attribute__((noinline)) void my_reserve_slot(); + int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, const char *file, uint line); int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line); @@ -512,6 +520,8 @@ void safe_mutex_end(FILE *file); /* Wrappers if safe mutex is actually used */ #ifdef SAFE_MUTEX + + #undef pthread_mutex_init #undef pthread_mutex_lock #undef pthread_mutex_unlock @@ -565,12 +575,22 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp); #undef pthread_cond_timedwait #undef pthread_mutex_trylock #define pthread_mutex_init(A,B) my_pthread_fastmutex_init((A),(B)) -#define pthread_mutex_lock(A) my_pthread_fastmutex_lock(A) -#define pthread_mutex_unlock(A) pthread_mutex_unlock(&(A)->mutex) + +int put_in_lve(char *user); +void lve_thr_exit(); +void governor_setlve_mysql_thread_info(pid_t thread_id); +void governor_detroy_mysql_thread_info(); +__attribute__ ((noinline)) int my_pthread_lvemutex_unlock(pthread_mutex_t *mutex); +__attribute__ ((noinline)) int my_pthread_lvemutex_lock(my_pthread_fastmutex_t *mp); +__attribute__ ((noinline)) int my_pthread_lvemutex_trylock(pthread_mutex_t *mutex); +__attribute__((noinline)) void my_release_slot(); +__attribute__((noinline)) void my_reserve_slot(); +#define pthread_mutex_lock(A) my_pthread_lvemutex_lock(A) +#define pthread_mutex_unlock(A) my_pthread_lvemutex_unlock(&(A)->mutex) +#define pthread_mutex_trylock(A) my_pthread_lvemutex_trylock(&(A)->mutex) #define pthread_mutex_destroy(A) pthread_mutex_destroy(&(A)->mutex) #define pthread_cond_wait(A,B) pthread_cond_wait((A),&(B)->mutex) #define pthread_cond_timedwait(A,B,C) pthread_cond_timedwait((A),&(B)->mutex,(C)) -#define pthread_mutex_trylock(A) pthread_mutex_trylock(&(A)->mutex) #define pthread_mutex_t my_pthread_fastmutex_t #endif /* defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) */ diff --git a/max_connection2_mysql_5_5_30_b403.patch b/max_connection2_mysql_5_5_30_b403.patch new file mode 100644 index 0000000..8eba89d diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index 4d05139..4c8cec2 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -25,12 +25,49 @@ #include "my_static.h" #include +void * (*governor_load_lve_library)() = NULL; +int (*governor_init_lve)() = NULL; +void (*governor_destroy_lve)() = NULL; +int (*governor_enter_lve)(uint32_t *, char *) = NULL; +void (*governor_lve_exit)(uint32_t *) = NULL; +int (*governor_enter_lve_light)(uint32_t *) = NULL; +void (*governor_lve_exit_null)() = NULL; +int (*governor_lve_enter_pid)(pid_t) = NULL; + +void governor_setlve_mysql_thread_info(pid_t thread_id) { + thread_id = 0; + return; +} + +__attribute__((noinline)) int put_in_lve(char *user) { + user = NULL; + return 0; +} + +__attribute__((noinline)) void lve_thr_exit() { + return; +} + +void governor_detroy_mysql_thread_info(){ + return; +} + +__attribute__((noinline)) void my_release_slot(){ + return; +} + +__attribute__((noinline)) void my_reserve_slot(){ + return; +} + + #ifndef DO_NOT_REMOVE_THREAD_WRAPPERS /* Remove wrappers */ #undef pthread_mutex_t #undef pthread_mutex_init #undef pthread_mutex_lock #undef pthread_mutex_unlock +#undef pthread_mutex_trylock #undef pthread_mutex_destroy #undef pthread_cond_wait #undef pthread_cond_timedwait @@ -399,6 +436,8 @@ void safe_mutex_end(FILE *file __attribute__((unused))) #if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) +#include + #include "mysys_priv.h" #include "my_static.h" #include @@ -492,6 +531,298 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp) return pthread_mutex_lock(&mp->mutex); } +void * (*governor_load_lve_library)() = NULL; +int (*governor_init_lve)() = NULL; +void (*governor_destroy_lve)() = NULL; +int (*governor_enter_lve)(uint32_t *, char *) = NULL; +void (*governor_lve_exit)(uint32_t *) = NULL; +int (*governor_enter_lve_light)(uint32_t *) = NULL; +void (*governor_lve_exit_null)() = NULL; +int (*governor_lve_enter_pid)(pid_t) = NULL; + +extern CHARSET_INFO my_charset_latin1_bin; +CHARSET_INFO governor_charset_bin; + +__thread uint32_t lve_cookie = 0; + +pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + +typedef struct __mysql_mutex { + pid_t *key; + int is_in_lve; + int is_in_mutex; + int put_in_lve; +} mysql_mutex; + +static HASH *mysql_lve_mutex_governor = NULL; + +__thread mysql_mutex *mysql_lve_mutex_governor_ptr = 0; + +pthread_mutex_t mtx_mysql_lve_mutex_governor_ptr = PTHREAD_MUTEX_INITIALIZER; + +void governor_value_destroyed(mysql_mutex *data) { + free(data); +} + +uchar *governor_get_key_table_mutex(mysql_mutex *table_mutex, size_t *length, + my_bool not_used __attribute__((unused))) { + *length = sizeof(table_mutex->key); + return (uchar*) table_mutex->key; +} + +/* ++ * RETURN ++ * < 0 s < t ++ * 0 s == t ++ * > 0 s > t ++ */ +int governor_my_strnncoll_8bit_bin(CHARSET_INFO * cs __attribute__((unused)), const uchar *s, + size_t slen, const uchar *t, size_t tlen, my_bool t_is_prefix) { + int res = 0; + pid_t s1 = (pid_t)s, t1 = (pid_t)t; + if (s1 < t1) + res = -1; + else if (s1 == t1) + res = 0; + else + res = 1; + return res; +} + +void governor_hash_sort_8bit_bin(CHARSET_INFO *cs __attribute__((unused)), + const uchar *key, size_t len, + ulong *nr1, ulong *nr2) +{ + return; +} + +HASH *governor_create_hash_table() { + mysql_lve_mutex_governor = (HASH *) calloc(1, sizeof(HASH)); + if (mysql_lve_mutex_governor) { + memcpy(&governor_charset_bin, &my_charset_latin1_bin, + sizeof(CHARSET_INFO)); + governor_charset_bin.coll->strnncoll = governor_my_strnncoll_8bit_bin; + governor_charset_bin.coll->hash_sort = governor_hash_sort_8bit_bin; + if (my_hash_init(mysql_lve_mutex_governor, &governor_charset_bin, 500, 0, + 0, (my_hash_get_key) governor_get_key_table_mutex, + (my_hash_free_key) governor_value_destroyed, 0)) { + mysql_lve_mutex_governor = NULL; + } + } + return mysql_lve_mutex_governor; +} + +int governor_add_mysql_thread_info() { + pid_t *buf = NULL; + pthread_mutex_lock(&mtx_mysql_lve_mutex_governor_ptr); + mysql_mutex *mm = NULL; + if (!mysql_lve_mutex_governor) { + mysql_lve_mutex_governor = governor_create_hash_table(); + if (!mysql_lve_mutex_governor){ + pthread_mutex_unlock(&mtx_mysql_lve_mutex_governor_ptr); + return -1; + } + } + buf = (pid_t *)syscall(__NR_gettid); + mm = (mysql_mutex *) my_hash_search(mysql_lve_mutex_governor, + (uchar *) buf, sizeof(buf)); + if (!mm) { + mm = (mysql_mutex *) calloc(1, sizeof(mysql_mutex)); + if (!mm) + return -1; + mm->key = (pid_t *)syscall(__NR_gettid); + if (my_hash_insert(mysql_lve_mutex_governor, (uchar *) mm)) { + free(mm); + pthread_mutex_unlock(&mtx_mysql_lve_mutex_governor_ptr); + return -1; + } + } + pthread_mutex_unlock(&mtx_mysql_lve_mutex_governor_ptr); + mysql_lve_mutex_governor_ptr = mm; + return 0; +} + +void governor_remove_mysql_thread_info() { + pid_t *buf = NULL; + pthread_mutex_lock(&mtx_mysql_lve_mutex_governor_ptr); + mysql_mutex *mm = NULL; + if (mysql_lve_mutex_governor) { + buf = (pid_t *)syscall(__NR_gettid); + mm = (mysql_mutex *) my_hash_search(mysql_lve_mutex_governor, + (uchar *) buf, sizeof(buf)); + if (mm) + my_hash_delete(mysql_lve_mutex_governor, (uchar *) mm); + } + pthread_mutex_unlock(&mtx_mysql_lve_mutex_governor_ptr); + mysql_lve_mutex_governor_ptr = NULL; +} + +void governor_setlve_mysql_thread_info(pid_t thread_id) { + pid_t *buf = NULL; + pthread_mutex_lock(&mtx_mysql_lve_mutex_governor_ptr); + mysql_mutex *mm = NULL; + if (mysql_lve_mutex_governor) { + buf = (pid_t *)thread_id; + mm = (mysql_mutex *) my_hash_search(mysql_lve_mutex_governor, + (uchar *) buf, sizeof(buf)); + if (mm) { + if (!mm->is_in_lve) { + mm->put_in_lve = 1; + //if (mm->is_in_mutex) { + // mm->put_in_lve = 1; + //} else { + // mm->put_in_lve = 1; + // governor_lve_enter_pid(thread_id); + //} + } + } + } + pthread_mutex_unlock(&mtx_mysql_lve_mutex_governor_ptr); +} + +void governor_detroy_mysql_thread_info() { + if (mysql_lve_mutex_governor) { + pthread_mutex_lock(&mtx_mysql_lve_mutex_governor_ptr); + my_hash_free(mysql_lve_mutex_governor); + free(mysql_lve_mutex_governor); + pthread_mutex_unlock(&mtx_mysql_lve_mutex_governor_ptr); + } +} + +__attribute__((noinline)) int put_in_lve(char *user) { + if (governor_add_mysql_thread_info()<0) return -1; + if (mysql_lve_mutex_governor_ptr) { + if (!governor_enter_lve(&lve_cookie, user)) { + mysql_lve_mutex_governor_ptr->is_in_lve = 1; + } + mysql_lve_mutex_governor_ptr->is_in_mutex = 0; + } + return 0; +} + +__attribute__((noinline)) void lve_thr_exit() { + if (mysql_lve_mutex_governor_ptr && mysql_lve_mutex_governor_ptr->is_in_lve + == 1) { + governor_lve_exit(&lve_cookie); + mysql_lve_mutex_governor_ptr->is_in_lve = 0; + } + governor_remove_mysql_thread_info(); +} + +__attribute__((noinline)) int my_pthread_lvemutex_lock(my_pthread_fastmutex_t *mp) { + if (mysql_lve_mutex_governor_ptr) { + if (mysql_lve_mutex_governor_ptr->is_in_lve == 1) { + governor_lve_exit(&lve_cookie); + mysql_lve_mutex_governor_ptr->is_in_lve = 2; + } else if (mysql_lve_mutex_governor_ptr->is_in_lve > 1) { + mysql_lve_mutex_governor_ptr->is_in_lve++; + } /*else if (mysql_lve_mutex_governor_ptr->put_in_lve + && !mysql_lve_mutex_governor_ptr->is_in_mutex) { + //governor_lve_exit_null(); + mysql_lve_mutex_governor_ptr->put_in_lve = 0; + mysql_lve_mutex_governor_ptr->is_in_lve = 2; + }*/ + mysql_lve_mutex_governor_ptr->is_in_mutex++; + } + return my_pthread_fastmutex_lock(mp); +} + +__attribute__((noinline)) int my_pthread_lvemutex_trylock(pthread_mutex_t *mutex) { + if (mysql_lve_mutex_governor_ptr) { + if (mysql_lve_mutex_governor_ptr->is_in_lve == 1) { + governor_lve_exit(&lve_cookie); + } + } + int ret = pthread_mutex_trylock(mutex); + if (mysql_lve_mutex_governor_ptr) { + if (ret != EBUSY){ + if (mysql_lve_mutex_governor_ptr->is_in_lve == 1) { + mysql_lve_mutex_governor_ptr->is_in_lve = 2; + } else if (mysql_lve_mutex_governor_ptr->is_in_lve > 1) { + mysql_lve_mutex_governor_ptr->is_in_lve++; + } + mysql_lve_mutex_governor_ptr->is_in_mutex++; + } else { + if (mysql_lve_mutex_governor_ptr->is_in_lve == 1){ + if (!governor_enter_lve_light(&lve_cookie)) { + mysql_lve_mutex_governor_ptr->is_in_lve = 1; + } else { + mysql_lve_mutex_governor_ptr->is_in_lve = 0; + } + } + } + } + return ret; +} + + +__attribute__((noinline)) int my_pthread_lvemutex_unlock( + pthread_mutex_t *mutex) { + int ret = pthread_mutex_unlock(mutex); + if (mysql_lve_mutex_governor_ptr) { + if ((mysql_lve_mutex_governor_ptr->is_in_lve == 2) + && governor_enter_lve_light) { + if (!governor_enter_lve_light(&lve_cookie)) { + mysql_lve_mutex_governor_ptr->is_in_lve = 1; + } + } else if (mysql_lve_mutex_governor_ptr->is_in_lve > 2) { + mysql_lve_mutex_governor_ptr->is_in_lve--; + } + mysql_lve_mutex_governor_ptr->is_in_mutex--; + /*if (mysql_lve_mutex_governor_ptr->put_in_lve + && !mysql_lve_mutex_governor_ptr->is_in_mutex) { + if (governor_enter_lve_light && !governor_enter_lve_light( + &lve_cookie)) { + mysql_lve_mutex_governor_ptr->is_in_lve = 1; + mysql_lve_mutex_governor_ptr->put_in_lve = 0; + } + }*/ + } + return ret; +} + +__attribute__((noinline)) void my_reserve_slot() { + if (mysql_lve_mutex_governor_ptr) { + if (mysql_lve_mutex_governor_ptr->is_in_lve == 1) { + governor_lve_exit(&lve_cookie); + mysql_lve_mutex_governor_ptr->is_in_lve = 2; + } else if (mysql_lve_mutex_governor_ptr->is_in_lve > 1) { + mysql_lve_mutex_governor_ptr->is_in_lve++; + } /*else if (mysql_lve_mutex_governor_ptr->put_in_lve + && !mysql_lve_mutex_governor_ptr->is_in_mutex) { + //governor_lve_exit_null(); + mysql_lve_mutex_governor_ptr->put_in_lve = 0; + mysql_lve_mutex_governor_ptr->is_in_lve = 2; + }*/ + mysql_lve_mutex_governor_ptr->is_in_mutex++; + } + return; +} + +__attribute__((noinline)) void my_release_slot() { + if (mysql_lve_mutex_governor_ptr) { + if ((mysql_lve_mutex_governor_ptr->is_in_lve == 2) + && governor_enter_lve_light) { + if (!governor_enter_lve_light(&lve_cookie)) { + mysql_lve_mutex_governor_ptr->is_in_lve = 1; + } + } else if (mysql_lve_mutex_governor_ptr->is_in_lve > 2) { + mysql_lve_mutex_governor_ptr->is_in_lve--; + } + mysql_lve_mutex_governor_ptr->is_in_mutex--; + /*if (mysql_lve_mutex_governor_ptr->put_in_lve + && !mysql_lve_mutex_governor_ptr->is_in_mutex) { + if (governor_enter_lve_light && !governor_enter_lve_light( + &lve_cookie)) { + mysql_lve_mutex_governor_ptr->is_in_lve = 1; + mysql_lve_mutex_governor_ptr->put_in_lve = 0; + } + }*/ + } + return; +} + + void fastmutex_global_init(void) { @@ -501,3 +832,45 @@ void fastmutex_global_init(void) } #endif /* defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) */ + +#if !defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) + +#include + +void * (*governor_load_lve_library)() = NULL; +int (*governor_init_lve)() = NULL; +void (*governor_destroy_lve)() = NULL; +int (*governor_enter_lve)(uint32_t *, char *) = NULL; +void (*governor_lve_exit)(uint32_t *) = NULL; +int (*governor_enter_lve_light)(uint32_t *) = NULL; +void (*governor_lve_exit_null)() = NULL; +int (*governor_lve_enter_pid)(pid_t) = NULL; + +void governor_setlve_mysql_thread_info(pid_t thread_id) { + thread_id = 0; + return; +} + +__attribute__((noinline)) int put_in_lve(char *user) { + user = NULL; + return 0; +} + +__attribute__((noinline)) void lve_thr_exit() { + return; +} + +void governor_detroy_mysql_thread_info(){ + return; +} + +__attribute__((noinline)) void my_release_slot(){ + return; +} + +__attribute__((noinline)) void my_reserve_slot(){ + return; +} + + +#endif diff --git a/sql/lex.h b/sql/lex.h index 9e90725..33e6d12 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -191,6 +191,10 @@ static SYMBOL symbols[] = { { "ELSE", SYM(ELSE)}, { "ELSEIF", SYM(ELSEIF_SYM)}, { "ENABLE", SYM(ENABLE_SYM)}, + { "ENABLE_GOVERNOR", SYM(ENABLE_GOVERNOR_SYM)}, + { "ENABLE_GOVERNOR_RECON", SYM(ENABLE_GOVERNOR_RECONN_SYM)}, + { "ENABLE_GOVERNOR_LVE", SYM(ENABLE_GOVERNOR_LVE_SYM)}, + { "ENABLE_GOVERNOR_RECON_LVE", SYM(ENABLE_GOVERNOR_RECONN_LVE_SYM)}, { "ENCLOSED", SYM(ENCLOSED)}, { "END", SYM(END)}, { "ENDS", SYM(ENDS_SYM)}, @@ -316,6 +320,7 @@ static SYMBOL symbols[] = { { "LONGTEXT", SYM(LONGTEXT)}, { "LOOP", SYM(LOOP_SYM)}, { "LOW_PRIORITY", SYM(LOW_PRIORITY)}, + { "LVECMD", SYM(LVECMD_SYM)}, { "MASTER", SYM(MASTER_SYM)}, { "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM)}, { "MASTER_HOST", SYM(MASTER_HOST_SYM)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9df9436..ee14dff 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -69,6 +69,9 @@ #include "debug_sync.h" #include "sql_callback.h" +#include +#include + #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE #include "../storage/perfschema/pfs_server.h" #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ @@ -186,6 +189,10 @@ typedef fp_except fp_except_t; # endif #endif +#ifndef GETTID +pid_t gettid(void) {return syscall(__NR_gettid);} +#endif + extern "C" my_bool reopen_fstreams(const char *filename, FILE *outstream, FILE *errstream); @@ -245,6 +252,28 @@ inline void setup_fpu() } /* cplusplus */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +extern void * (*governor_load_lve_library)(); +extern int (*governor_init_lve)(); +extern void (*governor_destroy_lve)(); +extern int (*governor_enter_lve)(uint32_t *, char *); +extern int (*governor_enter_lve_light)(uint32_t *); +extern void (*governor_lve_exit)(uint32_t *); +extern void (*governor_lve_exit_null)(); +extern int (*governor_lve_enter_pid)(pid_t); +#ifdef __cplusplus +} +#endif + +volatile int governor_get_command = 0; +int (*connect_to_server)() = NULL; +int (*send_info_begin)(char *) = NULL; +int (*send_info_end)(char *) = NULL; +int (*close_sock)() = NULL; +void * governor_library_handle = NULL; + #define MYSQL_KILL_SIGNAL SIGTERM #include // For thr_setconcurency() @@ -1513,6 +1542,20 @@ void clean_up(bool print_message) free_global_thread_stats(); free_global_table_stats(); free_global_index_stats(); + + governor_detroy_mysql_thread_info(); + + if(governor_destroy_lve){ + governor_destroy_lve(); + } + + if(close_sock){ + (*close_sock)(); + } + if (governor_library_handle) { + dlclose(governor_library_handle); + } + #ifdef HAVE_REPLICATION end_slave_list(); #endif @@ -2982,6 +3025,10 @@ SHOW_VAR com_status_vars[]= { {"drop_user", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_USER]), SHOW_LONG_STATUS}, {"drop_view", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_VIEW]), SHOW_LONG_STATUS}, {"empty_query", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_EMPTY_QUERY]), SHOW_LONG_STATUS}, + {"enable_governor", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ENABLE_GOVERNOR]), SHOW_LONG_STATUS}, + {"enable_governor_reconn",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ENABLE_RECONN_GOVERNOR]), SHOW_LONG_STATUS}, + {"enable_governor_lve", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ENABLE_GOVERNOR_LVE]), SHOW_LONG_STATUS}, + {"enable_governor_reconn_lve",(char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ENABLE_RECONN_GOVERNOR_LVE]), SHOW_LONG_STATUS}, {"execute_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_EXECUTE]), SHOW_LONG_STATUS}, {"flush", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_FLUSH]), SHOW_LONG_STATUS}, {"grant", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_GRANT]), SHOW_LONG_STATUS}, @@ -2995,6 +3042,7 @@ SHOW_VAR com_status_vars[]= { {"kill", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_KILL]), SHOW_LONG_STATUS}, {"load", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD]), SHOW_LONG_STATUS}, {"lock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOCK_TABLES]), SHOW_LONG_STATUS}, + {"lvecmd", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LVECMD]), SHOW_LONG_STATUS}, {"optimize", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_OPTIMIZE]), SHOW_LONG_STATUS}, {"preload_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PRELOAD_KEYS]), SHOW_LONG_STATUS}, {"prepare_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PREPARE]), SHOW_LONG_STATUS}, @@ -6525,6 +6573,7 @@ SHOW_VAR status_vars[]= { {"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG}, {"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_NOFLUSH}, {"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG}, + {"Enable_governor", (char*) &governor_get_command, SHOW_INT}, {"Flush_commands", (char*) &refresh_version, SHOW_LONG_NOFLUSH}, {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS}, {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS}, @@ -6749,6 +6798,25 @@ To see what values a running MySQL server is using, type\n\ } #endif /*!EMBEDDED_LIBRARY*/ +void governor_set_fn_ptr_to_null(){ + governor_load_lve_library = NULL; + governor_init_lve = NULL; + governor_destroy_lve = NULL; + governor_enter_lve = NULL; + governor_lve_exit = NULL; + governor_enter_lve_light = NULL; + governor_lve_exit_null = NULL; + governor_lve_enter_pid = NULL; +} + +void governor_set_fn2_ptr_to_null(){ + connect_to_server = NULL; + send_info_begin = NULL; + send_info_end = NULL; + close_sock = NULL; +} + + /** Initialize MySQL global variables to default values. @@ -6946,6 +7014,115 @@ static int mysql_init_variables(void) tmpenv = DEFAULT_MYSQL_HOME; (void) strmake(mysql_home, tmpenv, sizeof(mysql_home)-1); #endif + + + + governor_get_command = 0; + connect_to_server = NULL; + send_info_begin = NULL; + send_info_end = NULL; + close_sock = NULL; + governor_library_handle = NULL; + + char *error_dl = NULL; + governor_library_handle = dlopen("libgovernor.so", RTLD_LAZY); + if (governor_library_handle) { + sql_print_information("libgovernor.so found"); + while(1){ + connect_to_server = (int (*)())dlsym(governor_library_handle, "connect_to_server"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn2_ptr_to_null(); + break; + } + send_info_begin = (int (*)(char *))dlsym(governor_library_handle, "send_info_begin"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn2_ptr_to_null(); + break; + } + send_info_end = (int (*)(char *))dlsym(governor_library_handle, "send_info_end"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn2_ptr_to_null(); + break; + } + close_sock = (int (*)())dlsym(governor_library_handle, "close_sock"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn2_ptr_to_null(); + break; + } + sql_print_information("All governors functions found too"); + break; + } + } else { + sql_print_information("libgovernor.so not found"); + } + if(connect_to_server){ + if(!(*connect_to_server)()){ + sql_print_information("Governor connected"); + } else { + sql_print_error("Governor not connected"); + } + } + if (governor_library_handle){ + + while(1){ + governor_load_lve_library = (void * (*)())dlsym(governor_library_handle, "governor_load_lve_library"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + governor_init_lve = (int (*)())dlsym(governor_library_handle, "governor_init_lve"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + governor_destroy_lve = (void (*)())dlsym(governor_library_handle, "governor_destroy_lve"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + governor_enter_lve = (int (*)(uint32_t *, char *))dlsym(governor_library_handle, "governor_enter_lve"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + + governor_lve_exit = (void (*)(uint32_t *))dlsym(governor_library_handle, "governor_lve_exit"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + + governor_enter_lve_light = (int (*)(uint32_t *))dlsym(governor_library_handle, "governor_enter_lve_light"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + + governor_lve_exit_null = (void (*)(void))dlsym(governor_library_handle, "governor_lve_exit_null"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + + governor_lve_enter_pid = (int (*)(pid_t))dlsym(governor_library_handle, "governor_lve_enter_pid"); + if ((error_dl = dlerror()) != NULL){ + governor_set_fn_ptr_to_null(); + break; + } + + sql_print_information("All governors lve functions found too"); + break; + } + + } + + if(governor_load_lve_library){ + if(!governor_load_lve_library()){ + sql_print_information("Can't get LVE functions"); + } + } + + return 0; } @@ -7471,6 +7648,7 @@ static void set_server_version(void) #endif if (opt_log || opt_slow_log || opt_bin_log) strmov(end, "-log"); // This may slow down system + end= strmov(end, "-cll-lve"); } @@ -7737,8 +7915,8 @@ static void delete_pid_file(myf flags) File file; if (opt_bootstrap || !pid_file_created || - !(file= mysql_file_open(key_file_pid, pidfile_name, - O_RDONLY, flags))) + ((file= mysql_file_open(key_file_pid, pidfile_name, + O_RDONLY, flags))<0)) return; /* Make sure that the pid file was created by the same process. */ diff --git a/sql/mysqld.h b/sql/mysqld.h index 959c9d6..9fa02bf 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -16,6 +16,8 @@ #ifndef MYSQLD_INCLUDED #define MYSQLD_INCLUDED +#include + #include "my_global.h" /* MYSQL_PLUGIN_IMPORT, FN_REFLEN, FN_EXTLEN */ #include "sql_bitmap.h" /* Bitmap */ #include "my_decimal.h" /* my_decimal */ @@ -138,6 +140,14 @@ extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size; extern ulong tc_log_page_waits; extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; extern my_bool relay_log_recovery; + +extern volatile int governor_get_command; +extern int (*connect_to_server)(); +extern int (*send_info_begin)(char *); +extern int (*send_info_end)(char *); +extern int (*close_sock)(); +extern void * governor_library_handle; + extern uint test_flags,select_errors,ha_open_options; extern uint protocol_version, mysqld_port, dropping_tables; extern ulong delay_key_write_options; @@ -477,6 +487,14 @@ void free_global_index_stats(void); void free_global_client_stats(void); void free_global_thread_stats(void); +extern "C" pid_t gettid(void); + +void set_governor_variable(); +void set_governor_variable_reconn(); +void set_governor_variable_lve(); +void set_governor_variable_reconn_lve(); + + /* TODO: Replace this with an inline function. */ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fdd9b10..51d6129 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -903,7 +903,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) { /* Starting from 5.0.3 we have max_user_connections field */ ptr= get_field(thd->mem_root, table->field[next_field++]); - user.user_resource.user_conn= ptr ? atoi(ptr) : 0; + user.user_resource.user_conn= ptr ? atoll(ptr) : 0; } if (table->s->fields >= 41) @@ -9584,10 +9584,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) } /* Don't allow the user to connect if he has done too many queries */ - if ((acl_user->user_resource.questions || acl_user->user_resource.updates || - acl_user->user_resource.conn_per_hour || - acl_user->user_resource.user_conn || - global_system_variables.max_user_connections) && + if ( get_or_create_user_conn(thd, (opt_old_style_user_limits ? sctx->user : sctx->priv_user), (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host), diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1afcf23..8bd9167 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -809,6 +809,8 @@ THD::THD() { ulong tmp; + thread_tid_cll = 0; + mdl_context.init(this); /* Pass nominal parameters to init_alloc_root only to ensure that @@ -1340,6 +1342,7 @@ void THD::update_stats(bool ran_command) void THD::init_for_queries() { + thread_tid_cll = gettid(); set_time(); ha_enable_transaction(this,TRUE); diff --git a/sql/sql_class.h b/sql/sql_class.h index b555b98..8e946fd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2006,6 +2006,7 @@ public: ulong statement_id_counter; ulong rand_saved_seed1, rand_saved_seed2; pthread_t real_id; /* For debugging */ + pid_t thread_tid_cll; my_thread_id thread_id; uint tmp_table; uint server_status,open_options; @@ -3745,6 +3746,7 @@ inline bool add_group_to_list(THD *thd, Item *item, bool asc) #endif /* MYSQL_SERVER */ + /** The meat of thd_proc_info(THD*, char*), a macro that packs the last three calling-info parameters. diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 12493be..28a2b31 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -81,6 +81,10 @@ extern mysql_mutex_t LOCK_global_index_stats; #ifndef NO_EMBEDDED_ACCESS_CHECKS static HASH hash_user_connections; +int is_root_access(char *user_name){ + return !strcmp(user_name,"root")||!strcmp(user_name,"mysql"); +} + int get_or_create_user_conn(THD *thd, const char *user, const char *host, const USER_RESOURCES *mqh) @@ -735,6 +739,16 @@ int check_for_max_user_connections(THD *thd, const USER_CONN *uc) DBUG_ENTER("check_for_max_user_connections"); mysql_mutex_lock(&LOCK_user_conn); + + + + if (((uc->user_resources.user_conn==(uint)~0) || (global_system_variables.max_user_connections == (uint)~0)) && !is_root_access(uc->user)) + { + my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user); + error=1; + goto end; + } + if (global_system_variables.max_user_connections && !uc->user_resources.user_conn && global_system_variables.max_user_connections < (uint) uc->connections) @@ -1373,6 +1387,7 @@ void prepare_new_connection_state(THD* thd) pthread_handler_t handle_one_connection(void *arg) { THD *thd= (THD*) arg; + thd->thread_tid_cll = gettid(); mysql_thread_set_psi_id(thd->thread_id); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d16166a..00eee9a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -193,7 +193,8 @@ enum enum_sql_command { SQLCOM_SHOW_RELAYLOG_EVENTS, // TODO(mcallaghan): update status_vars in mysqld to export these SQLCOM_SHOW_USER_STATS, SQLCOM_SHOW_TABLE_STATS, SQLCOM_SHOW_INDEX_STATS, - SQLCOM_SHOW_CLIENT_STATS, SQLCOM_SHOW_THREAD_STATS, + SQLCOM_SHOW_CLIENT_STATS, SQLCOM_SHOW_THREAD_STATS, SQLCOM_ENABLE_GOVERNOR, SQLCOM_ENABLE_RECONN_GOVERNOR, + SQLCOM_ENABLE_GOVERNOR_LVE, SQLCOM_ENABLE_RECONN_GOVERNOR_LVE, SQLCOM_LVECMD, /* When a command is added here, be sure it's also added in mysqld.cc in "struct show_var_st status_vars[]= {" ... diff --git a/sql/sql_list.cc b/sql/sql_list.cc index 99aeccd..d8bea45 100644 --- a/sql/sql_list.cc +++ b/sql/sql_list.cc @@ -39,6 +39,14 @@ void free_list(I_List *list) } +void free_list(I_List *list) +{ + i_thd *tmp; + while ((tmp= list->get())) + delete tmp; +} + + base_list::base_list(const base_list &rhs, MEM_ROOT *mem_root) { if (rhs.elements) diff --git a/sql/sql_list.h b/sql/sql_list.h index bdbe381..dea32d2 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -570,6 +570,15 @@ public: i_string(const char* s) : ptr(s) {} }; +/* DB_GOVERNOR ADDITIONS */ +class i_thd: public ilink +{ + public: + THD* ptr; + i_thd():ptr(0) { } + i_thd(THD* s) : ptr(s) {} +}; + /* needed for linked list of two strings for replicate-rewrite-db */ class i_string_pair: public ilink { @@ -723,5 +732,6 @@ list_copy_and_replace_each_value(List &list, MEM_ROOT *mem_root) void free_list(I_List *list); void free_list(I_List *list); +void free_list(I_List *list); #endif // INCLUDES_MYSQL_SQL_LIST_H diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8e2841c..d4e8345 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -13,6 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#define HAVE_CLOCK_GETTIME 1 #define MYSQL_LEX 1 #include "my_global.h" #include "sql_priv.h" @@ -95,6 +96,21 @@ #include "probes_mysql.h" #include "set_var.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern void * (*governor_load_lve_library)(); +extern int (*governor_init_lve)(); +extern void (*governor_destroy_lve)(); +extern int (*governor_enter_lve)(uint32_t *, char *); +extern int (*governor_enter_lve_light)(uint32_t *); +extern void (*governor_lve_exit)(uint32_t *); + +#ifdef __cplusplus +} +#endif + #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") /** @@ -114,6 +130,8 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); static void sql_kill(THD *thd, ulong id, bool only_kill_query); +static void sql_kill_user(THD *thd, char *user, bool only_kill_query); +static void sql_kill_user_lve(THD *thd, char *user, bool only_kill_query); // Uses the THD to update the global stats by user name and client IP void update_global_user_stats(THD* thd, bool create_user, time_t now); @@ -170,6 +188,52 @@ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) } #endif +void set_governor_variable(){ + governor_get_command = 1; +} + +void set_governor_variable_reconn(){ + governor_get_command = 1; + if(close_sock){ + (*close_sock)(); + } + if(connect_to_server){ + if(!(*connect_to_server)()){ + sql_print_information("Governor reconnected"); + } else { + sql_print_error("Governor not reconnected. Failed connection"); + } + } +} + +void set_governor_variable_lve(){ + if(!governor_get_command){ + if(governor_init_lve){ + if(governor_init_lve()){ + sql_print_error("Governor LVE initialization error"); + } + } + } + governor_get_command = 2; +} + +void set_governor_variable_reconn_lve(){ + set_governor_variable_reconn(); + governor_get_command = 2; + if(governor_init_lve){ + if(governor_init_lve()){ + sql_print_error("Governor LVE initialization error"); + } + } +} + + +my_bool chek_governors_avaliable_command(THD *thd){ + return (thd->lex->sql_command!=SQLCOM_ENABLE_GOVERNOR&&thd->lex->sql_command!=SQLCOM_ENABLE_RECONN_GOVERNOR + &&thd->lex->sql_command!=SQLCOM_ENABLE_GOVERNOR_LVE&&thd->lex->sql_command!=SQLCOM_ENABLE_RECONN_GOVERNOR_LVE)&& + (thd->security_ctx && thd->security_ctx->user && thd->security_ctx->user[0]); +} + static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) { @@ -3717,9 +3781,42 @@ end_with_restore_list: MYF(0)); goto error; } - sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY); + if(it->type()==Item::STRING_ITEM){ + sql_kill_user(thd, it->val_str(0)->c_ptr(), lex->type & ONLY_KILL_QUERY); + } else { + sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY); + } + break; } + case SQLCOM_LVECMD: + { + Item *it= (Item *)lex->value_list.head(); + + if (lex->table_or_sp_used()) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "Usage of subqueries or stored " + "function calls as part of this statement"); + break; + } + + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) + { + my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), + MYF(0)); + goto error; + } + + if(it->type()==Item::STRING_ITEM){ + sql_kill_user_lve(thd, it->val_str(0)->c_ptr(), lex->type & ONLY_KILL_QUERY); + } else { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), "LVE by thread ID is not supported yet"); + } + + + break; + } + #ifndef NO_EMBEDDED_ACCESS_CHECKS case SQLCOM_SHOW_GRANTS: { @@ -5626,6 +5723,17 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, } } + if(send_info_begin&&governor_get_command&&chek_governors_avaliable_command(thd)){ + (*send_info_begin)(thd->security_ctx->user); + } + +/* if(governor_enter_lve && (governor_get_command==2) && chek_governors_avaliable_command(thd)){ + if(thd->security_ctx && thd->security_ctx->user && thd->security_ctx->user[0]) + governor_enter_lve(&cookie, thd->security_ctx->user); + }*/ + + + if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0) { LEX *lex= thd->lex; @@ -5674,8 +5782,13 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, &thd->security_ctx->priv_user[0], (char *) thd->security_ctx->host_or_ip, 0); - + if(governor_enter_lve && (governor_get_command==2) && chek_governors_avaliable_command(thd)){ + if(put_in_lve(thd->security_ctx->user)<0){ + my_error(ER_GET_ERRNO, MYF(0), "Can't enter into LVE"); + } + } error= mysql_execute_command(thd); + lve_thr_exit(); MYSQL_QUERY_EXEC_DONE(error); } } @@ -5696,6 +5809,14 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, DBUG_ASSERT(thd->change_list.is_empty()); } +/* if(governor_lve_exit && (governor_get_command==2) && cookie &&chek_governors_avaliable_command(thd)){ + governor_lve_exit(&cookie); + }*/ + + if(send_info_end&&governor_get_command&&chek_governors_avaliable_command(thd)){ + (*send_info_end)(thd->security_ctx->user); + } + if (opt_userstat) { // Gets the end time. @@ -6614,6 +6735,24 @@ void sql_kill(THD *thd, ulong id, bool only_kill_query) my_error(error, MYF(0), id); } +static void sql_kill_user(THD *thd, char *user, bool only_kill_query) +{ + uint error; + if (!(error= kill_user_thread(thd, user, only_kill_query))){ + if (! thd->killed) my_ok(thd); + } else + my_error(error, MYF(0), user); +} + +void sql_kill_user_lve(THD *thd, char *user, bool only_kill_query) +{ + uint error; + if (!(error= kill_user_thread_lve(thd, user, only_kill_query))) + my_ok(thd); + else + my_error(error, MYF(0), user); +} + /** If pointer is not a null pointer, append filename to it. */ @@ -7529,3 +7668,107 @@ merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl) } return cs; } + + +uint kill_user_thread(THD *thd, char *user, bool only_kill_query) +{ + THD *tmp; + uint error=0; + DBUG_ENTER("kill_user_thread"); + DBUG_PRINT("enter", ("id=%s only_kill=%d", !user?"nop":user, only_kill_query)); + i_thd *thd_tmp; + I_List threads_tmp; + threads_tmp.empty(); + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + I_List_iterator it(threads); + while ((tmp=it++)) + { + if (tmp->command == COM_DAEMON) + continue; + if((tmp)&&(user)&&(tmp->get_user_connect())&&(tmp->get_user_connect()->user)){ + if (!strncmp(tmp->get_user_connect()->user,user,16)) + { + mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + thd_tmp = new i_thd(tmp); + if (thd_tmp) threads_tmp.append(thd_tmp); + else mysql_mutex_unlock(&tmp->LOCK_thd_data); + } + } + } + mysql_mutex_unlock(&LOCK_thread_count); + + if(!threads_tmp.is_empty()) + { + I_List_iterator it_tmp(threads_tmp); + while ((thd_tmp=it_tmp++)){ + tmp=thd_tmp->ptr; + + if ((tmp)&&((thd->security_ctx->master_access & SUPER_ACL) || + thd->security_ctx->user_matches(tmp->security_ctx))) + { + tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION); + error=0; + } + else + error=ER_KILL_DENIED_ERROR; + mysql_mutex_unlock(&tmp->LOCK_thd_data); + } + free_list(&threads_tmp); + threads_tmp.empty(); + } + DBUG_PRINT("exit", ("%d", error)); + DBUG_RETURN(error); +} + +uint kill_user_thread_lve(THD *thd, char *user, bool only_kill_query) +{ + + DBUG_ENTER("kill_user_thread_lve"); + THD *tmp; + i_thd *thd_tmp; + I_List threads_tmp; + threads_tmp.empty(); + uint error=0;//ER_NO_SUCH_THREAD_USER; + mysql_mutex_lock(&LOCK_thread_count); // For unlink from list + I_List_iterator it(threads); + while ((tmp=it++)) + { + if((tmp)&&(user)&&(tmp->get_user_connect())&&(tmp->get_user_connect()->user)){ + if (!strncmp(tmp->get_user_connect()->user,user,16)) + { + mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete + thd_tmp = new i_thd(tmp); + if (thd_tmp) threads_tmp.append(thd_tmp); + else mysql_mutex_unlock(&tmp->LOCK_thd_data); + } + } + } + mysql_mutex_unlock(&LOCK_thread_count); + + if(!threads_tmp.is_empty()){ + I_List_iterator it_tmp(threads_tmp); + while ((thd_tmp=it_tmp++)){ + tmp=thd_tmp->ptr; + if ((tmp)&&((thd->security_ctx->master_access & SUPER_ACL) || + thd->security_ctx->user_matches(tmp->security_ctx))) + { + if(tmp->thread_tid_cll){ + governor_setlve_mysql_thread_info(tmp->thread_tid_cll); + } + } else { + error=ER_KILL_DENIED_ERROR; + } + mysql_mutex_unlock(&tmp->LOCK_thd_data); + + } + free_list(&threads_tmp); + threads_tmp.empty(); + } + + DBUG_RETURN(error); + +} + + + + diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 9a55174..b2871fd 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -50,6 +50,8 @@ bool parse_sql(THD *thd, Parser_state *parser_state, Object_creation_ctx *creation_ctx); +uint kill_user_thread(THD *thd, char *user, bool only_kill_query); +uint kill_user_thread_lve(THD *thd, char *user, bool only_kill_query); uint kill_one_thread(THD *thd, ulong id, bool only_kill_query); void free_items(Item *item); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 06a89c0..39fe9c7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2086,6 +2086,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) case SQLCOM_GRANT: case SQLCOM_REVOKE: case SQLCOM_KILL: + case SQLCOM_LVECMD: break; case SQLCOM_PREPARE: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 181fa6e..14cb51f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11284,6 +11284,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, save_proc_info=thd->proc_info; thd_proc_info(thd, "converting HEAP to MyISAM"); + my_reserve_slot(); if (create_myisam_tmp_table(&new_table, param, thd->lex->select_lex.options | thd->variables.option_bits, @@ -11350,10 +11351,12 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, if (save_proc_info) thd_proc_info(thd, (!strcmp(save_proc_info,"Copying to tmp table") ? "Copying to tmp table on disk" : save_proc_info)); + my_release_slot(); DBUG_RETURN(0); err: DBUG_PRINT("error",("Got error: %d",write_err)); + my_release_slot(); table->file->print_error(write_err, MYF(0)); (void) table->file->ha_rnd_end(); (void) new_table.file->close(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index af19762..f64f29c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -946,6 +946,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ELSE /* SQL-2003-R */ %token ELSEIF_SYM %token ENABLE_SYM +%token ENABLE_GOVERNOR_SYM +%token ENABLE_GOVERNOR_RECONN_SYM +%token ENABLE_GOVERNOR_LVE_SYM +%token ENABLE_GOVERNOR_RECONN_LVE_SYM %token ENCLOSED %token END /* SQL-2003-R */ %token ENDS_SYM @@ -1074,6 +1078,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token LOOP_SYM %token LOW_PRIORITY %token LT /* OPERATOR */ +%token LVECMD_SYM %token MASTER_CONNECT_RETRY_SYM %token MASTER_HOST_SYM %token MASTER_LOG_FILE_SYM @@ -1559,7 +1564,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); reset purge begin commit rollback savepoint release slave master_def master_defs master_file_def slave_until_opts repair analyze check start checksum - field_list field_list_item field_spec kill column_def key_def + field_list field_list_item field_spec kill lvecmd column_def key_def keycache_list keycache_list_or_parts assign_to_keycache assign_to_keycache_parts preload_list preload_list_or_parts preload_keys preload_keys_parts @@ -1728,6 +1733,10 @@ statement: | describe | do | drop + | enable_governor + | enable_governor_reconn + | enable_governor_lve + | enable_governor_reconn_lve | execute | flush | grant @@ -1738,6 +1747,7 @@ statement: | kill | load | lock + | lvecmd | optimize | keycache | partition_entry @@ -7053,6 +7063,21 @@ mi_check_type: | CHANGED { Lex->check_opt.flags|= T_CHECK_ONLY_CHANGED; } | FOR_SYM UPGRADE_SYM { Lex->check_opt.sql_flags|= TT_FOR_UPGRADE; } ; + +lvecmd: + LVECMD_SYM lvecmd_option expr + { + LEX *lex=Lex; + lex->value_list.empty(); + lex->value_list.push_front($3); + lex->sql_command= SQLCOM_LVECMD; + } + ; + +lvecmd_option: + /* empty */ { Lex->type= ONLY_KILL_QUERY; } + ; + optimize: OPTIMIZE opt_no_write_to_binlog table_or_tables @@ -10894,6 +10919,41 @@ opt_profile_args: } ; +enable_governor: + ENABLE_GOVERNOR_SYM + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_ENABLE_GOVERNOR; + set_governor_variable(); + } + ; + +enable_governor_reconn: + ENABLE_GOVERNOR_RECONN_SYM + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_ENABLE_RECONN_GOVERNOR; + set_governor_variable_reconn(); + } + ; +enable_governor_lve: + ENABLE_GOVERNOR_LVE_SYM + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_ENABLE_GOVERNOR_LVE; + set_governor_variable_lve(); + } + ; + +enable_governor_reconn_lve: + ENABLE_GOVERNOR_RECONN_LVE_SYM + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_ENABLE_RECONN_GOVERNOR_LVE; + set_governor_variable_reconn_lve(); + } + ; + /* Show things */ show: diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 8ef0906..f3d3b98 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -204,8 +204,9 @@ used to register actual file read, write and flush */ # define register_pfs_file_open_begin(state, locker, key, op, name, \ src_file, src_line) \ do { \ + my_reserve_slot(); \ if (PSI_server) { \ - locker = PSI_server->get_thread_file_name_locker( \ + locker = PSI_server->get_thread_file_name_locker( \ state, key, op, name, &locker); \ if (locker) { \ PSI_server->start_file_open_wait( \ @@ -220,11 +221,13 @@ do { \ PSI_server->end_file_open_wait_and_bind_to_descriptor( \ locker, file); \ } \ + my_release_slot(); \ } while (0) # define register_pfs_file_io_begin(state, locker, file, count, op, \ src_file, src_line) \ do { \ + my_reserve_slot(); \ if (PSI_server) { \ locker = PSI_server->get_thread_file_descriptor_locker( \ state, file, op); \ @@ -240,6 +243,7 @@ do { \ if (locker) { \ PSI_server->end_file_wait(locker, count); \ } \ + my_release_slot(); \ } while (0) #endif /* UNIV_PFS_IO */ diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index db777f0..77ab113 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -3752,6 +3752,7 @@ os_aio_array_reserve_slot( offset */ ulint len) /*!< in: length of the block to read or write */ { + my_reserve_slot(); os_aio_slot_t* slot = NULL; #ifdef WIN_ASYNC_IO OVERLAPPED* control; @@ -3895,6 +3896,7 @@ os_aio_array_free_slot( os_aio_array_t* array, /*!< in: aio array */ os_aio_slot_t* slot) /*!< in: pointer to slot */ { + my_release_slot(); ut_ad(array); ut_ad(slot); diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 5872ff2..d3a949e 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -1144,6 +1144,7 @@ srv_conc_enter_innodb( ibool has_slept = FALSE; srv_conc_slot_t* slot = NULL; ulint i; + my_reserve_slot(); #ifdef UNIV_SYNC_DEBUG ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); @@ -1158,7 +1159,6 @@ srv_conc_enter_innodb( return; } - /* If trx has 'free tickets' to enter the engine left, then use one such ticket */ @@ -1311,6 +1311,7 @@ srv_conc_force_enter_innodb( trx_t* trx) /*!< in: transaction object associated with the thread */ { + my_reserve_slot(); #ifdef UNIV_SYNC_DEBUG ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); #endif /* UNIV_SYNC_DEBUG */ @@ -1342,6 +1343,7 @@ srv_conc_force_exit_innodb( thread */ { srv_conc_slot_t* slot = NULL; + my_release_slot(); if (trx->mysql_thd != NULL && thd_is_replication_slave_thread(trx->mysql_thd)) { @@ -1401,6 +1403,7 @@ srv_conc_exit_innodb( trx_t* trx) /*!< in: transaction object associated with the thread */ { + my_release_slot(); #ifdef UNIV_SYNC_DEBUG ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch)); #endif /* UNIV_SYNC_DEBUG */ diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index b5115a5..f955e50 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -59,6 +59,33 @@ lock_file_path="$lockdir/mysql" # The following variables are only set for letting mysql.server find things. +cpu_limit= +io_limit= + +get_limit(){ + if [ -e /usr/sbin/lvectl ]; then + LVE_VER=`/usr/sbin/lvectl --lve-version` + if [ "$LVE_VER" == "4" ]; then + io_limit=`/usr/sbin/lvectl limits 3 | awk 'NR == 2' | awk '{print $6}'` + else + io_limit=`/usr/sbin/lvectl limits 3 | awk 'NR == 2' | awk '{print $8}'` + fi + cpu_limit=`/usr/sbin/lvectl limits 3 | awk 'NR == 2' | awk '{print $2}'` + fi +} + +set_big_limit(){ + if [ -e /usr/sbin/lvectl ]; then + /usr/sbin/lvectl set 3 --cpu=100 --io=0 --save-all-parameters + fi +} + +set_old_limit(){ + if [ -e /usr/sbin/lvectl ]; then + /usr/sbin/lvectl set 3 --cpu=$cpu_limit --io=$io_limit --save-all-parameters + fi +} + # Set some defaults mysqld_pid_file_path= if test -z "$basedir" @@ -298,6 +325,11 @@ case "$mode" in 'stop') # Stop daemon. We use a signal here to avoid having to know the # root password. + + get_limit + set_big_limit + sleep 2 + if test -s "$mysqld_pid_file_path" then @@ -319,10 +351,12 @@ case "$mode" in then rm -f "$lock_file_path" fi + set_old_limit exit $return_value else log_failure_msg "MySQL server PID file could not be found!" fi + set_old_limit ;; 'restart') @@ -337,14 +371,19 @@ case "$mode" in ;; 'reload'|'force-reload') + get_limit + set_big_limit + sleep 2 if test -s "$mysqld_pid_file_path" ; then read mysqld_pid < "$mysqld_pid_file_path" kill -HUP $mysqld_pid && log_success_msg "Reloading service MySQL" touch "$mysqld_pid_file_path" else log_failure_msg "MySQL PID file could not be found!" + set_old_limit exit 1 fi + set_old_limit ;; 'status') # First, check to see if pid file exists