From db1d2f64d1b7f54b652a9c0b7778716a46599ec9 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Mar 2007 11:30:17 +0300 Subject: [PATCH 1/3] Fix for bug #25966 "2MB per second endless memory consumption after LOCK TABLE ... WRITE". CPU hogging occured when connection which had to wait for table lock was serviced by thread which previously serviced connection that was killed (note that connections can reuse threads if thread cache is enabled). One possible scenario which exposed this problem was when thread which provided binlog dump to replication slave was implicitly/automatically killed when the same slave reconnected and started pulling data through different thread/connection. In 5.* versions memory hogging was added to CPU hogging. Moreover in those versions the problem also occured when one killed particular query in connection (using KILL QUERY) and later this connection had to wait for some table lock. This problem was caused by the fact that thread-specific mysys_var::abort variable, which indicates that waiting operations on mysys layer should be aborted (this includes waiting for table locks), was set by kill operation but was never reset back. So this value was "inherited" by the following statements or even other connections (which reused the same physical thread). Such discrepancy between this variable and THD::killed flag broke logic on SQL-layer and caused CPU and memory hogging. This patch tries to fix this problem by properly resetting this member. There is no test-case associated with this patch since it is hard to test for memory/CPU hogging conditions in our test-suite. sql/mysqld.cc: We should not forget to reset THD::mysys_var::abort after kill operation if we are going to use thread to which this operation was applied for handling of other connections. --- sql/mysqld.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0efc1339467..20f20a0a86b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1572,6 +1572,12 @@ void end_thread(THD *thd, bool put_in_cache) thd=thread_cache.get(); thd->real_id=pthread_self(); (void) thd->store_globals(); + /* + THD::mysys_var::abort is associated with physical thread rather + than with THD object. So we need to reset this flag before using + this thread for handling of new THD object/connection. + */ + thd->mysys_var->abort= 0; thd->thr_create_time= time(NULL); threads.append(thd); pthread_mutex_unlock(&LOCK_thread_count); From cdd2a2e40d32a2ee4fc0f5be12092a90512e0618 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Mar 2007 11:51:35 +0300 Subject: [PATCH 2/3] Fix for bug #25966 "2MB per second endless memory consumption after LOCK TABLE ... WRITE". Memory and CPU hogging occured when connection which had to wait for table lock was serviced by thread which previously serviced connection that was killed (note that connections can reuse threads if thread cache is enabled). One possible scenario which exposed this problem was when thread which provided binlog dump to replication slave was implicitly/automatically killed when the same slave reconnected and started pulling data through different thread/connection. The problem also occured when one killed particular query in connection (using KILL QUERY) and later this connection had to wait for some table lock. This problem was caused by the fact that thread-specific mysys_var::abort variable, which indicates that waiting operations on mysys layer should be aborted (this includes waiting for table locks), was set by kill operation but was never reset back. So this value was "inherited" by the following statements or even other connections (which reused the same physical thread). Such discrepancy between this variable and THD::killed flag broke logic on SQL-layer and caused CPU and memory hogging. This patch tries to fix this problem by properly resetting this member. There is no test-case associated with this patch since it is hard to test for memory/CPU hogging conditions in our test-suite. sql/mysqld.cc: We should not forget to reset THD::mysys_var::abort after kill operation if we are going to use thread to which this operation was applied for handling of other connections. sql/sp_head.cc: We should not forget to reset THD::mysys_var::abort after kill operation if we are going to use thread to which this operation was applied for handling of further statements. sql/sql_parse.cc: We should not forget to reset THD::mysys_var::abort after kill operation if we are going to use thread to which this operation was applied for handling of further statements. --- sql/mysqld.cc | 6 ++++++ sql/sp_head.cc | 1 + sql/sql_parse.cc | 3 +++ 3 files changed, 10 insertions(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9a7928b214f..99d66134405 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1681,6 +1681,12 @@ void end_thread(THD *thd, bool put_in_cache) thd->real_id=pthread_self(); thd->thread_stack= (char*) &thd; // For store_globals (void) thd->store_globals(); + /* + THD::mysys_var::abort is associated with physical thread rather + than with THD object. So we need to reset this flag before using + this thread for handling of new THD object/connection. + */ + thd->mysys_var->abort= 0; thd->thr_create_time= time(NULL); threads.append(thd); pthread_mutex_unlock(&LOCK_thread_count); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index baeedc1c9b3..4cb56e003ee 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1087,6 +1087,7 @@ sp_head::execute(THD *thd) ctx->enter_handler(hip); thd->clear_error(); thd->killed= THD::NOT_KILLED; + thd->mysys_var->abort= 0; continue; } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b503e147624..6500def76f7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1604,7 +1604,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_ENTER("dispatch_command"); if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) + { thd->killed= THD::NOT_KILLED; + thd->mysys_var->abort= 0; + } thd->command=command; /* From 0d31e0f3cfab1f90b24fc0fa716ce590dd60cd91 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Mar 2007 22:28:31 +0100 Subject: [PATCH 3/3] Raise version number after cloning 5.0.38 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 53f666bad00..7867bf444ad 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.38) +AM_INIT_AUTOMAKE(mysql, 5.0.40) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=38 +NDB_VERSION_BUILD=40 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ?