Skip to content

Commit 73fbd85

Browse files
author
Dmitry Lenev
committed
WL#7567 "Handlerton MDL callback".
Implemented support for notification of storage engines about acquisition and release of exclusive metadata locks, which allow metadata to be changed. Such support allows NDB SE to prevent concurrent changes to object metadata on different cluster nodes and opens path to implementation of proper cluster-wide metadata locking. Introduced new handlerton method which is called by MDL subsystem each time before X lock acquisition. This method gets MDL_key in order to be able to identify object on which lock is acquired. Lock acquisition can be refused by SE by returning error from this method. The same method (with a different notification_type argument) is called after release of X lock. Since in case of ALTER TABLE statement upgrade to X metadata lock happens late in the process of statement execution, it is expensive to abort statement execution as result of failed SE notification at upgrade time. To alleviate this issue we additionally notify SE at the start of ALTER TABLE on a base table and at its end. This gives SE chance to abort execution of ALTER TABLE early in the process without wasting precious resources.
1 parent 4b3453f commit 73fbd85

File tree

11 files changed

+979
-27
lines changed

11 files changed

+979
-27
lines changed

include/mysql/psi/mysql_mdl.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -81,7 +81,7 @@ inline_mysql_mdl_create(void *identity,
8181
const MDL_key *mdl_key,
8282
enum_mdl_type mdl_type,
8383
enum_mdl_duration mdl_duration,
84-
MDL_wait::enum_wait_status mdl_status,
84+
MDL_ticket::enum_psi_status mdl_status,
8585
const char *src_file, uint src_line)
8686
{
8787
PSI_metadata_lock *result;
@@ -100,7 +100,7 @@ inline_mysql_mdl_create(void *identity,
100100

101101
static inline void inline_mysql_mdl_set_status(
102102
PSI_metadata_lock *psi,
103-
MDL_wait::enum_wait_status mdl_status)
103+
MDL_ticket::enum_psi_status mdl_status)
104104
{
105105
if (psi != NULL)
106106
PSI_METADATA_CALL(set_metadata_lock_status)(psi, mdl_status);

sql/handler.cc

+145
Original file line numberDiff line numberDiff line change
@@ -8320,3 +8320,148 @@ bool handler::my_eval_gcolumn_expr(THD *thd,
83208320
DBUG_RETURN(res);
83218321
}
83228322

8323+
8324+
/**
8325+
Auxiliary structure for passing information to notify_*_helper()
8326+
functions.
8327+
*/
8328+
8329+
struct HTON_NOTIFY_PARAMS
8330+
{
8331+
const MDL_key *key;
8332+
const ha_notification_type notification_type;
8333+
bool some_htons_were_notified;
8334+
};
8335+
8336+
8337+
static my_bool
8338+
notify_exclusive_mdl_helper(THD *thd, plugin_ref plugin, void *arg)
8339+
{
8340+
handlerton *hton= plugin_data<handlerton*>(plugin);
8341+
if (hton->state == SHOW_OPTION_YES && hton->notify_exclusive_mdl)
8342+
{
8343+
HTON_NOTIFY_PARAMS *params= reinterpret_cast<HTON_NOTIFY_PARAMS*>(arg);
8344+
8345+
if (hton->notify_exclusive_mdl(thd, params->key,
8346+
params->notification_type))
8347+
{
8348+
// Ignore failures from post event notification.
8349+
if (params->notification_type == HA_NOTIFY_PRE_EVENT)
8350+
return TRUE;
8351+
}
8352+
else
8353+
params->some_htons_were_notified= true;
8354+
}
8355+
return FALSE;
8356+
}
8357+
8358+
8359+
/**
8360+
Notify/get permission from all interested storage engines before
8361+
acquisition or after release of exclusive metadata lock on object
8362+
represented by key.
8363+
8364+
@param thd Thread context.
8365+
@param mdl_key MDL key identifying object on which exclusive
8366+
lock is to be acquired/was released.
8367+
@param notification_type Indicates whether this is pre-acquire or
8368+
post-release notification.
8369+
8370+
@note @see handlerton::notify_exclusive_mdl for details about
8371+
calling convention and error reporting.
8372+
8373+
@return False - if notification was successful/lock can be acquired,
8374+
True - if it has failed/lock should not be acquired.
8375+
*/
8376+
8377+
bool ha_notify_exclusive_mdl(THD *thd, const MDL_key *mdl_key,
8378+
ha_notification_type notification_type)
8379+
{
8380+
HTON_NOTIFY_PARAMS params = {mdl_key, notification_type, false};
8381+
if (plugin_foreach(thd, notify_exclusive_mdl_helper,
8382+
MYSQL_STORAGE_ENGINE_PLUGIN, &params))
8383+
{
8384+
/*
8385+
If some SE hasn't given its permission to acquire lock and some SEs
8386+
has given their permissions, we need to notify the latter group about
8387+
failed lock acquisition. We do this by calling post-release notification
8388+
for all interested SEs unconditionally.
8389+
*/
8390+
if (notification_type == HA_NOTIFY_PRE_EVENT &&
8391+
params.some_htons_were_notified)
8392+
{
8393+
HTON_NOTIFY_PARAMS rollback_params = {mdl_key, HA_NOTIFY_POST_EVENT,
8394+
false};
8395+
(void) plugin_foreach(thd, notify_exclusive_mdl_helper,
8396+
MYSQL_STORAGE_ENGINE_PLUGIN, &rollback_params);
8397+
}
8398+
return true;
8399+
}
8400+
return false;
8401+
}
8402+
8403+
8404+
static my_bool
8405+
notify_alter_table_helper(THD *thd, plugin_ref plugin, void *arg)
8406+
{
8407+
handlerton *hton= plugin_data<handlerton*>(plugin);
8408+
if (hton->state == SHOW_OPTION_YES && hton->notify_alter_table)
8409+
{
8410+
HTON_NOTIFY_PARAMS *params= reinterpret_cast<HTON_NOTIFY_PARAMS*>(arg);
8411+
8412+
if (hton->notify_alter_table(thd, params->key, params->notification_type))
8413+
{
8414+
// Ignore failures from post event notification.
8415+
if (params->notification_type == HA_NOTIFY_PRE_EVENT)
8416+
return TRUE;
8417+
}
8418+
else
8419+
params->some_htons_were_notified= true;
8420+
}
8421+
return FALSE;
8422+
}
8423+
8424+
8425+
/**
8426+
Notify/get permission from all interested storage engines before
8427+
or after executed ALTER TABLE on the table identified by key.
8428+
8429+
@param thd Thread context.
8430+
@param mdl_key MDL key identifying table.
8431+
@param notification_type Indicates whether this is pre-ALTER or
8432+
post-ALTER notification.
8433+
8434+
@note @see handlerton::notify_alter_table for rationale,
8435+
details about calling convention and error reporting.
8436+
8437+
@return False - if notification was successful/ALTER TABLE can
8438+
proceed.
8439+
True - if it has failed/ALTER TABLE should fail.
8440+
*/
8441+
8442+
bool ha_notify_alter_table(THD *thd, const MDL_key *mdl_key,
8443+
ha_notification_type notification_type)
8444+
{
8445+
HTON_NOTIFY_PARAMS params = {mdl_key, notification_type, false};
8446+
8447+
if (plugin_foreach(thd, notify_alter_table_helper,
8448+
MYSQL_STORAGE_ENGINE_PLUGIN, &params))
8449+
{
8450+
/*
8451+
If some SE hasn't given its permission to do ALTER TABLE and some SEs
8452+
has given their permissions, we need to notify the latter group about
8453+
failed attemopt. We do this by calling post-ALTER TABLE notification
8454+
for all interested SEs unconditionally.
8455+
*/
8456+
if (notification_type == HA_NOTIFY_PRE_EVENT &&
8457+
params.some_htons_were_notified)
8458+
{
8459+
HTON_NOTIFY_PARAMS rollback_params = {mdl_key, HA_NOTIFY_POST_EVENT,
8460+
false};
8461+
(void) plugin_foreach(thd, notify_alter_table_helper,
8462+
MYSQL_STORAGE_ENGINE_PLUGIN, &rollback_params);
8463+
}
8464+
return true;
8465+
}
8466+
return false;
8467+
}

sql/handler.h

+72
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,8 @@ typedef bool (stat_print_fn)(THD *thd, const char *type, size_t type_len,
668668
const char *file, size_t file_len,
669669
const char *status, size_t status_len);
670670
enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX };
671+
enum ha_notification_type { HA_NOTIFY_PRE_EVENT, HA_NOTIFY_POST_EVENT };
672+
671673
extern st_plugin_int *hton2plugin[MAX_HA];
672674

673675
class handler;
@@ -901,6 +903,70 @@ struct handlerton
901903
void (*replace_native_transaction_in_thd)(THD *thd, void *new_trx_arg,
902904
void **ptr_trx_arg);
903905

906+
907+
/**
908+
Notify/get permission from storage engine before acquisition or after
909+
release of exclusive metadata lock on object represented by key.
910+
911+
@param thd Thread context.
912+
@param mdl_key MDL key identifying object on which exclusive
913+
lock is to be acquired/was released.
914+
@param notification_type Indicates whether this is pre-acquire or
915+
post-release notification.
916+
917+
@note Notification is done only for objects from TABLESPACE, SCHEMA,
918+
TABLE, FUNCTION, PROCEDURE, TRIGGER and EVENT namespaces.
919+
920+
@note Problems during notification are to be reported as warnings, MDL
921+
subsystem will report generic error if pre-acquire notification
922+
fails/SE refuses lock acquisition.
923+
@note Return value is ignored/error is not reported in case of
924+
post-release notification.
925+
926+
@note In some cases post-release notification might happen even if
927+
there were no prior pre-acquire notification. For example,
928+
when SE was loaded after exclusive lock acquisition, or when
929+
we need notify SEs which permitted lock acquisition that it
930+
didn't happen because one of SEs didn't allow it (in such case
931+
we will do post-release notification for all SEs for simplicity).
932+
933+
@return False - if notification was successful/lock can be acquired,
934+
True - if it has failed/lock should not be acquired.
935+
*/
936+
bool (*notify_exclusive_mdl)(THD *thd, const MDL_key *mdl_key,
937+
ha_notification_type notification_type);
938+
939+
/**
940+
Notify/get permission from storage engine before or after execution of
941+
ALTER TABLE operation on the table identified by the MDL key.
942+
943+
@param thd Thread context.
944+
@param mdl_key MDL key identifying table which is going to be
945+
or was ALTERed.
946+
@param notification_type Indicates whether this is pre-ALTER TABLE or
947+
post-ALTER TABLE notification.
948+
949+
@note This hook is necessary because for ALTER TABLE upgrade to X
950+
metadata lock happens fairly late during the execution process,
951+
so it can be expensive to abort ALTER TABLE operation at this
952+
stage by returning failure from notify_exclusive_mdl() hook.
953+
954+
@note This hook follows the same error reporting convention as
955+
@see notify_exclusive_mdl().
956+
957+
@note Similarly to notify_exclusive_mdl() in some cases post-ALTER
958+
notification might happen even if there were no prior pre-ALTER
959+
notification.
960+
961+
@note Post-ALTER notification can happen before post-release notification
962+
for exclusive metadata lock acquired by this ALTER TABLE.
963+
964+
@return False - if notification was successful/ALTER TABLE can proceed.
965+
True - if it has failed/ALTER TABLE should be aborted.
966+
*/
967+
bool (*notify_alter_table)(THD *thd, const MDL_key *mdl_key,
968+
ha_notification_type notification_type);
969+
904970
uint32 license; /* Flag for Engine License */
905971
void *data; /* Location for engines to keep personal structures */
906972
};
@@ -4013,4 +4079,10 @@ void print_keydup_error(TABLE *table, KEY *key, myf errflag);
40134079

40144080
void ha_set_normalized_disabled_se_str(const std::string &disabled_se_str);
40154081
bool ha_is_storage_engine_disabled(handlerton *se_engine);
4082+
4083+
bool ha_notify_exclusive_mdl(THD *thd, const MDL_key *mdl_key,
4084+
ha_notification_type notification_type);
4085+
bool ha_notify_alter_table(THD *thd, const MDL_key *mdl_key,
4086+
ha_notification_type notification_type);
4087+
40164088
#endif /* HANDLER_INCLUDED */

0 commit comments

Comments
 (0)