MXS-2325 Only enable events that were enabled on the master

The monitor now continuously updates a list of enabled server events. When
promoting a new master in failover/switchover, only events that were enabled
on the previous master are enabled on the new. This avoids enabling events
that may have been disabled on the master yet stayed in the SLAVESIDE_DISABLED-
state on the slave.

In the case of reset-replication command, events on the new master are only
enabled if the monitor had a master when the command was launched. Otherwise
all events remain disabled.
This commit is contained in:
Esa Korhonen
2019-02-27 13:24:37 +02:00
parent 8d6932abb2
commit 4fd4b726a1
7 changed files with 147 additions and 88 deletions

View File

@ -26,20 +26,12 @@ using maxscale::string_printf;
using maxbase::Duration;
using maxbase::StopWatch;
class MariaDBServer::EventInfo
{
public:
std::string database;
std::string name;
std::string definer;
std::string status;
};
MariaDBServer::MariaDBServer(MXS_MONITORED_SERVER* monitored_server, int config_index,
bool assume_unique_hostnames)
bool assume_unique_hostnames, bool query_events)
: m_server_base(monitored_server)
, m_config_index(config_index)
, m_assume_unique_hostnames(assume_unique_hostnames)
, m_query_events(query_events)
{
mxb_assert(monitored_server);
}
@ -839,6 +831,10 @@ void MariaDBServer::monitor_server()
{
query_ok = update_gtids(&errmsg);
}
if (query_ok && m_query_events)
{
query_ok = update_enabled_events();
}
}
else
{
@ -1222,22 +1218,24 @@ const SlaveStatus* MariaDBServer::slave_connection_status_host_port(const MariaD
return NULL;
}
bool MariaDBServer::enable_events(json_t** error_out)
bool MariaDBServer::enable_events(const EventNameSet& event_names, json_t** error_out)
{
int found_disabled_events = 0;
int events_enabled = 0;
// Helper function which enables a slaveside disabled event.
ManipulatorFunc enabler = [this, &found_disabled_events, &events_enabled](const EventInfo& event,
json_t** error_out) {
if (event.status == "SLAVESIDE_DISABLED")
// Helper function which enables a disabled event if that event name is found in the events-set.
ManipulatorFunc enabler = [this, event_names, &found_disabled_events, &events_enabled](
const EventInfo& event, json_t** error_out) {
if (event_names.count(event.name) > 0
&& (event.status == "SLAVESIDE_DISABLED" || event.status == "DISABLED"))
{
found_disabled_events++;
if (alter_event(event, "ENABLE", error_out))
{
found_disabled_events++;
if (alter_event(event, "ENABLE", error_out))
{
events_enabled++;
}
events_enabled++;
}
};
}
};
bool rval = false;
if (events_foreach(enabler, error_out))
@ -1361,8 +1359,7 @@ bool MariaDBServer::events_foreach(ManipulatorFunc& func, json_t** error_out)
while (event_info->next_row())
{
EventInfo event;
event.database = event_info->get_string(db_name_ind);
event.name = event_info->get_string(event_name_ind);
event.name = event_info->get_string(db_name_ind) + "." + event_info->get_string(event_name_ind);
event.definer = event_info->get_string(event_definer_ind);
event.status = event_info->get_string(event_status_ind);
func(event, error_out);
@ -1382,51 +1379,40 @@ bool MariaDBServer::alter_event(const EventInfo& event, const string& target_sta
{
bool rval = false;
string error_msg;
// First switch to the correct database.
string use_db_query = string_printf("USE %s;", event.database.c_str());
if (execute_cmd(use_db_query, &error_msg))
// An ALTER EVENT by default changes the definer (owner) of the event to the monitor user.
// This causes problems if the monitor user does not have privileges to run
// the event contents. Prevent this by setting definer explicitly.
// The definer may be of the form user@host. If host includes %, then it must be quoted.
// For simplicity, quote the host always.
string quoted_definer;
auto loc_at = event.definer.find('@');
if (loc_at != string::npos)
{
// An ALTER EVENT by default changes the definer (owner) of the event to the monitor user.
// This causes problems if the monitor user does not have privileges to run
// the event contents. Prevent this by setting definer explicitly.
// The definer may be of the form user@host. If host includes %, then it must be quoted.
// For simplicity, quote the host always.
string quoted_definer;
auto loc_at = event.definer.find('@');
if (loc_at != string::npos)
{
auto host_begin = loc_at + 1;
quoted_definer = event.definer.substr(0, loc_at + 1)
+ // host_begin may be the null-char if @ was the last char
"'" + event.definer.substr(host_begin, string::npos) + "'";
}
else
{
// Just the username
quoted_definer = event.definer;
}
string alter_event_query = string_printf("ALTER DEFINER = %s EVENT %s %s;",
quoted_definer.c_str(),
event.name.c_str(),
target_status.c_str());
if (execute_cmd(alter_event_query, &error_msg))
{
rval = true;
const char FMT[] = "Event '%s' of database '%s' on server '%s' set to '%s'.";
MXS_NOTICE(FMT, event.name.c_str(), event.database.c_str(), name(), target_status.c_str());
}
else
{
const char FMT[] = "Could not alter event '%s' of database '%s' on server '%s': %s";
PRINT_MXS_JSON_ERROR(error_out, FMT, event.name.c_str(), event.database.c_str(), name(),
error_msg.c_str());
}
auto host_begin = loc_at + 1;
quoted_definer = event.definer.substr(0, loc_at + 1)
+ // host_begin may be the null-char if @ was the last char
"'" + event.definer.substr(host_begin, string::npos) + "'";
}
else
{
const char FMT[] = "Could not switch to database '%s' on '%s': %s Event '%s' not altered.";
PRINT_MXS_JSON_ERROR(error_out, FMT, event.database.c_str(), name(), error_msg.c_str(),
event.name.c_str());
// Just the username
quoted_definer = event.definer;
}
string alter_event_query = string_printf("ALTER DEFINER = %s EVENT %s %s;",
quoted_definer.c_str(),
event.name.c_str(),
target_status.c_str());
if (execute_cmd(alter_event_query, &error_msg))
{
rval = true;
const char FMT[] = "Event '%s' on server '%s' set to '%s'.";
MXS_NOTICE(FMT, event.name.c_str(), name(), target_status.c_str());
}
else
{
const char FMT[] = "Could not alter event '%s' on server '%s': %s";
PRINT_MXS_JSON_ERROR(error_out, FMT, event.name.c_str(), name(), error_msg.c_str());
}
return rval;
}
@ -1510,7 +1496,7 @@ bool MariaDBServer::promote(GeneralOpData& general, ServerOperation& promotion,
if (promotion.handle_events)
{
// TODO: Add query replying to enable_events
bool events_enabled = enable_events(error_out);
bool events_enabled = enable_events(promotion.events_to_enable, error_out);
general.time_remaining -= timer.restart();
if (!events_enabled)
{
@ -2119,3 +2105,33 @@ bool MariaDBServer::redirect_existing_slave_conn(GeneralOpData& op, const SlaveS
} // 'stop_slave_conn' prints its own errors
return success;
}
bool MariaDBServer::update_enabled_events()
{
string error_msg;
// Get names of all enabled scheduled events on the server.
auto event_info = execute_query("SELECT Event_schema, Event_name FROM information_schema.EVENTS WHERE "
"Status = 'ENABLED';", &error_msg);
if (event_info.get() == NULL)
{
MXS_ERROR("Could not query events of '%s': %s Event handling can be disabled by "
"setting '%s' to false.",
name(), error_msg.c_str(), CN_HANDLE_EVENTS);
return false;
}
auto db_name_ind = 0;
auto event_name_ind = 1;
EventNameSet full_names;
full_names.reserve(event_info->get_row_count());
while (event_info->next_row())
{
string full_name = event_info->get_string(db_name_ind) + "." + event_info->get_string(event_name_ind);
full_names.insert(full_name); // Ignore duplicates, they shouldn't exists.
}
m_enabled_events = std::move(full_names);
return true;
}