diff options
author | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-03-15 14:52:25 +0100 |
---|---|---|
committer | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-03-15 14:52:25 +0100 |
commit | c7c1f2198fe96a67cd90a73ee0f844c4a83cf2fa (patch) | |
tree | 8059280cdc65626a37bbb400d6c77f8b81e83162 /sql/sys_vars.cc | |
parent | f007796bf4d4dff6353145a3cf2dff57e3819b20 (diff) | |
download | mariadb-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.
Diffstat (limited to 'sql/sys_vars.cc')
-rw-r--r-- | sql/sys_vars.cc | 24 |
1 files changed, 16 insertions, 8 deletions
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 |