summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@sun.com>2010-03-15 14:52:25 +0100
committerJon Olav Hauglid <jon.hauglid@sun.com>2010-03-15 14:52:25 +0100
commitc7c1f2198fe96a67cd90a73ee0f844c4a83cf2fa (patch)
tree8059280cdc65626a37bbb400d6c77f8b81e83162
parentf007796bf4d4dff6353145a3cf2dff57e3819b20 (diff)
downloadmariadb-git-c7c1f2198fe96a67cd90a73ee0f844c4a83cf2fa.tar.gz
Bug #51160 Deadlock around SET GLOBAL EVENT_SCHEDULER = ON|OFF
This deadlock could occour betweeen one connection executing SET GLOBAL EVENT_SCHEDULER= ON and another executing SET GLOBAL EVENT_SCHEDULER= OFF. The bug was introduced by WL#4738. The first connection would hold LOCK_event_metadata (protecting the global variable) while trying to lock LOCK_global_system_variables starting the event scheduler thread (in THD:init()). The second connection would hold LOCK_global_system_variables while trying to get LOCK_event_scheduler after stopping the event scheduler inside event_scheduler_update(). This patch fixes the problem by not using LOCK_event_metadata to protect the event_scheduler variable. It is still protected using LOCK_global_system_variables. This fixes the deadlock as it removes one of the two mutexes used to produce it. However, this patch opens up the possibility that the event_scheduler variable and the real event_scheduler state can become out of sync (e.g. variable = OFF, but scheduler running). But this can only happen under very unlikely conditions - two concurrent SET GLOBAL statments, with one thread interrupted at the exact wrong moment. This is preferable to having the possibility of a deadlock. This patch also fixes a bug where it was possible to exit create_event() without releasing LOCK_event_metadata if running out of memory during its exection. No test case added since a repeatable test case would have required excessive use of new sync points. Instead we rely on the fact that this bug was easily reproduceable using RGQ tests.
-rw-r--r--sql/events.cc27
-rw-r--r--sql/events.h8
-rw-r--r--sql/sys_vars.cc24
3 files changed, 34 insertions, 25 deletions
diff --git a/sql/events.cc b/sql/events.cc
index d8bf549321e..a2375b1274b 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2004, 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
@@ -11,7 +11,7 @@
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "mysql_priv.h"
#include "events.h"
@@ -367,15 +367,14 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
{
sql_print_error("Event Error: An error occurred while creating query string, "
"before writing it into binary log.");
- /* Restore the state of binlog format */
- DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
- if (save_binlog_row_based)
- thd->set_current_stmt_binlog_format_row();
- DBUG_RETURN(TRUE);
+ ret= TRUE;
+ }
+ else
+ {
+ /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
+ will be written into the binary log as the definer for the SQL thread. */
+ ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
}
- /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
- will be written into the binary log as the definer for the SQL thread. */
- ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
}
}
mysql_mutex_unlock(&LOCK_event_metadata);
@@ -1017,7 +1016,11 @@ Events::dump_internal_status()
puts("LLA = Last Locked At LUA = Last Unlocked At");
puts("WOC = Waiting On Condition DL = Data Locked");
- mysql_mutex_lock(&LOCK_event_metadata);
+ /*
+ opt_event_scheduler should only be accessed while
+ holding LOCK_global_system_variables.
+ */
+ mysql_mutex_lock(&LOCK_global_system_variables);
if (opt_event_scheduler == EVENTS_DISABLED)
puts("The Event Scheduler is disabled");
else
@@ -1026,7 +1029,7 @@ Events::dump_internal_status()
event_queue->dump_internal_status();
}
- mysql_mutex_unlock(&LOCK_event_metadata);
+ mysql_mutex_unlock(&LOCK_global_system_variables);
DBUG_VOID_RETURN;
}
diff --git a/sql/events.h b/sql/events.h
index 881ade37cbf..380b0d97f0a 100644
--- a/sql/events.h
+++ b/sql/events.h
@@ -1,6 +1,6 @@
#ifndef _EVENT_H_
#define _EVENT_H_
-/* Copyright (C) 2004-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2004, 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
@@ -13,7 +13,7 @@
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/**
@defgroup Event_Scheduler Event Scheduler
@@ -83,6 +83,7 @@ public:
See sys_var.cc
*/
enum enum_opt_event_scheduler { EVENTS_OFF, EVENTS_ON, EVENTS_DISABLED };
+ /* Protected using LOCK_global_system_variables only. */
static uint opt_event_scheduler;
static mysql_mutex_t LOCK_event_metadata;
static bool check_if_system_tables_error();
@@ -107,9 +108,6 @@ public:
destroy_mutexes();
static bool
- switch_event_scheduler_state(enum enum_opt_event_scheduler new_state);
-
- static bool
create_event(THD *thd, Event_parse_data *parse_data, bool if_exists);
static bool
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 2e239a9161c..e14286210b4 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002-2006 MySQL AB, 2009-2010 Sun Microsystems, Inc.
+/* Copyright (c) 2002, 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
@@ -11,7 +11,7 @@
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
How to add new variables:
@@ -647,32 +647,40 @@ static bool event_scheduler_check(sys_var *self, THD *thd, set_var *var)
}
static bool event_scheduler_update(sys_var *self, THD *thd, enum_var_type type)
{
+ uint opt_event_scheduler_value= Events::opt_event_scheduler;
mysql_mutex_unlock(&LOCK_global_system_variables);
/*
Events::start() is heavyweight. In particular it creates a new THD,
which takes LOCK_global_system_variables internally.
Thus we have to release it here.
We need to re-take it before returning, though.
- And we need to take it *without* holding Events::LOCK_event_metadata.
+
+ Note that since we release LOCK_global_system_variables before calling
+ start/stop, there is a possibility that the server variable
+ can become out of sync with the real event scheduler state.
+
+ This can happen with two concurrent statments if the first gets
+ interrupted after start/stop but before retaking
+ LOCK_global_system_variables. However, this problem should be quite
+ rare and it's difficult to avoid it without opening up possibilities
+ for deadlocks. See bug#51160.
*/
- bool ret= Events::opt_event_scheduler == Events::EVENTS_ON
+ bool ret= opt_event_scheduler_value == Events::EVENTS_ON
? Events::start()
: Events::stop();
- mysql_mutex_unlock(&Events::LOCK_event_metadata);
mysql_mutex_lock(&LOCK_global_system_variables);
- mysql_mutex_lock(&Events::LOCK_event_metadata);
if (ret)
my_error(ER_EVENT_SET_VAR_ERROR, MYF(0));
return ret;
}
-static PolyLock_mutex PLock_event_metadata(&Events::LOCK_event_metadata);
+
static Sys_var_enum Sys_event_scheduler(
"event_scheduler", "Enable the event scheduler. Possible values are "
"ON, OFF, and DISABLED (keep the event scheduler completely "
"deactivated, it cannot be activated run-time)",
GLOBAL_VAR(Events::opt_event_scheduler), CMD_LINE(OPT_ARG),
event_scheduler_names, DEFAULT(Events::EVENTS_OFF),
- &PLock_event_metadata, NOT_IN_BINLOG,
+ NO_MUTEX_GUARD, NOT_IN_BINLOG,
ON_CHECK(event_scheduler_check), ON_UPDATE(event_scheduler_update));
#endif