Skip to content

Commit c532cf7

Browse files
committed
WL#15129 - Enable DDL Statements in HeatWave
Enh#34350907 - [Nvidia] Allow DDLs when tables are loaded to HeatWave Bug#34433145 - WL#15129: mysqld crash Assertion `column_count == static_cast<int64_t>(cp_table- Bug#34446287 - WL#15129: mysqld crash at rapid::data::RapidNetChunkCtx::consolidateEncodingsDic Bug#34520634 - MYSQLD CRASH : Sql_cmd_secondary_load_unload::mysql_secondary_load_or_unload Bug#34520630 - Failed Condition: "table_id != InvalidTableId" Currently, DDL statements such as ALTER TABLE*, RENAME TABLE, and TRUNCATE TABLE are not allowed if a table has a secondary engine defined. The statements fail with the following error: "DDLs on a table with a secondary engine defined are not allowed." This worklog lifts this restriction for tables whose secondary engine is RAPID. A secondary engine hook is called in the beginning (pre-hook) and in the end (post-hook) of a DDL statement execution. If the DDL statement succeeds, the post-hook will direct the recovery framework to reload the table in order to reflect that change in HeatWave. Currently all DDL statements that were previously disallowed will trigger a reload. This can be improved in the future by checking whether the DDL operation has an impact on HeatWave or not. However detecting all edge-cases in this behavior is not straightforward so this improvement has been left as a future improvement. Additionally, if a DDL modifies the table schema in a way that makes it incompatible with HeatWave (e.g., dropping a primary key column) the reload will fail silently. There is no easy way to recognize whether the table schema will become incompatible with HeatWave in a pre-hook. List of changes: 1) [MySQL] Add new HTON_SECONDARY_ENGINE_SUPPORTS_DDL flag to indicate whether a secondary engine supports DDLs. 2) [MySQL] Add RAII hooks for RENAME TABLE and TRUNCATE TABLE, modeled on the ALTER TABLE hook. 3) Define HeatWave hooks for ALTER TABLE, RENAME TABLE, and TRUNCATE TABLE statements. 4) If a table reload is necessary, trigger it by marking the table as stale (WL#14914). 4) Move all change propagation & DDL hooks to ha_rpd_hooks.cc. 5) Adjust existing tests to support table reload upon DDL execution. 6) Extract code related to RapidOpSyncCtx in ha_rpd_sync_ctx.cc, and the PluginState enum to ha_rpd_fsm.h. * Note: ALTER TABLE statements related to secondary engine setting and loading were allowed before: - ALTER TABLE <TABLE> SECONDARY_UNLOAD, - ALTER TABLE SECONDARY_ENGINE = NULL. -- Bug#34433145 -- -- Bug#34446287 -- --Problem #1-- Crashes in Change Propagation when the CP thread tries to apply DMLs of tables with new schema to the not-yet-reloaded table in HeatWave. --Solution #1-- Remove table from Change Propagation before marking it as stale and revert the original change from rpd_binlog_parser.cc where we were checking if the table was stale before continuing with binlog parsing. The original change is no longer necessary since the table is removed from CP before being marked as stale. --Problem #2-- In case of a failed reload, tables are not removed from Global State. --Solution #2-- Keep track of whether the table was reloaded because it was marked as STALE. In that case we do not want the Recovery Framework to retry the reload and therefore we can remove the table from the Global State. -- Bug#34520634 -- Problem: Allowing the change of primary engine for tables with a defined secondary engine hits an assertion in mysql_secondary_load_or_unload(). Example: CREATE TABLE t1 (col1 INT PRIMARY KEY) SECONDARY_ENGINE = RAPID; ALTER TABLE t1 ENGINE = BLACKHOLE; ALTER TABLE t1 SECONDARY_LOAD; <- assertion hit here Solution: Disallow changing the primary engine for tables with a defined secondary engine. -- Bug#34520630 -- Problem: A debug assert is being hit in rapid_gs_is_table_reloading_from_stale because the table was dropped in the meantime. Solution: Instead of asserting, just return false if table is not present in the Global State. This patch also changes rapid_gs_is_table_reloading_from_stale to a more specific check (inlined the logic in load_table()). This check now also covers the case when a table was dropped/unloaded before the Recovery Framework marked it as INRECOVERY. In that case, if the reload fails we should not have an entry for that table in the Global State. The patch also adjusts dict_types MTR test, where we no longer expect for tables to be in UNAVAIL state after a failed reload. Additionally, recovery2_ddls.test is adjusted to not try to offload queries running on Performance Schema. Change-Id: I6ee390b1f418120925f5359d5e9365f0a6a415ee
1 parent 7dc6dff commit c532cf7

File tree

6 files changed

+290
-87
lines changed

6 files changed

+290
-87
lines changed

sql/handler.cc

Lines changed: 106 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,22 @@ plugin_ref ha_resolve_by_name(THD *thd, const LEX_CSTRING *name,
434434
return nullptr;
435435
}
436436

437+
bool ha_secondary_engine_supports_ddl(
438+
THD *thd, const LEX_CSTRING &secondary_engine) noexcept {
439+
bool ret = false;
440+
auto *plugin = ha_resolve_by_name_raw(thd, secondary_engine);
441+
442+
if (plugin != nullptr) {
443+
const auto *se_hton = plugin_data<const handlerton *>(plugin);
444+
if (se_hton != nullptr) {
445+
ret = secondary_engine_supports_ddl(se_hton);
446+
}
447+
448+
plugin_unlock(thd, plugin);
449+
}
450+
return ret;
451+
}
452+
437453
/**
438454
Read a comma-separated list of storage engine names. Look up each in the
439455
known list of canonical and legacy names. In case of a match; add both the
@@ -8390,16 +8406,32 @@ Temp_table_handle::~Temp_table_handle() {
83908406
*/
83918407

83928408
struct HTON_NOTIFY_PARAMS {
8393-
HTON_NOTIFY_PARAMS(const MDL_key *mdl_key, ha_notification_type mdl_type)
8409+
HTON_NOTIFY_PARAMS(const MDL_key *mdl_key, ha_notification_type mdl_type,
8410+
ha_ddl_type ddl_type = HA_INVALID_DDL,
8411+
const char *old_db_name = nullptr,
8412+
const char *old_table_name = nullptr,
8413+
const char *new_db_name = nullptr,
8414+
const char *new_table_name = nullptr)
83948415
: key(mdl_key),
83958416
notification_type(mdl_type),
8417+
ddl_type{ddl_type},
83968418
some_htons_were_notified(false),
8397-
victimized(false) {}
8419+
victimized(false),
8420+
m_old_db_name(old_db_name),
8421+
m_old_table_name(old_table_name),
8422+
m_new_db_name(new_db_name),
8423+
m_new_table_name(new_table_name) {}
83988424

83998425
const MDL_key *key;
84008426
const ha_notification_type notification_type;
8427+
const ha_ddl_type ddl_type;
84018428
bool some_htons_were_notified;
84028429
bool victimized;
8430+
/* Only used in RENAME TABLE */
8431+
const char *m_old_db_name;
8432+
const char *m_old_table_name;
8433+
const char *m_new_db_name;
8434+
const char *m_new_table_name;
84038435
};
84048436

84058437
static bool notify_exclusive_mdl_helper(THD *thd, plugin_ref plugin,
@@ -8463,12 +8495,51 @@ bool ha_notify_exclusive_mdl(THD *thd, const MDL_key *mdl_key,
84638495
return false;
84648496
}
84658497

8466-
static bool notify_alter_table_helper(THD *thd, plugin_ref plugin, void *arg) {
8498+
static bool notify_table_ddl_helper(THD *thd, plugin_ref plugin, void *arg) {
84678499
handlerton *hton = plugin_data<handlerton *>(plugin);
8468-
if (hton->state == SHOW_OPTION_YES && hton->notify_alter_table) {
8500+
if (hton->state == SHOW_OPTION_YES &&
8501+
(hton->notify_alter_table || hton->notify_rename_table ||
8502+
hton->notify_truncate_table)) {
84698503
HTON_NOTIFY_PARAMS *params = reinterpret_cast<HTON_NOTIFY_PARAMS *>(arg);
84708504

8471-
if (hton->notify_alter_table(thd, params->key, params->notification_type)) {
8505+
bool notify_ret{false};
8506+
8507+
/* If the DDL is ALTER or TRUNCATE, it shouldn't have the names set. */
8508+
assert(((params->ddl_type == HA_ALTER_DDL ||
8509+
params->ddl_type == HA_TRUNCATE_DDL) &&
8510+
(params->m_old_db_name == nullptr &&
8511+
params->m_old_table_name == nullptr &&
8512+
params->m_new_db_name == nullptr &&
8513+
params->m_new_table_name == nullptr)) ||
8514+
(params->ddl_type == HA_RENAME_DDL));
8515+
8516+
switch (params->ddl_type) {
8517+
case HA_ALTER_DDL:
8518+
if (hton->notify_alter_table) {
8519+
notify_ret = hton->notify_alter_table(thd, params->key,
8520+
params->notification_type);
8521+
}
8522+
break;
8523+
case HA_TRUNCATE_DDL:
8524+
if (hton->notify_truncate_table) {
8525+
notify_ret = hton->notify_truncate_table(thd, params->key,
8526+
params->notification_type);
8527+
}
8528+
break;
8529+
case HA_RENAME_DDL:
8530+
if (hton->notify_rename_table) {
8531+
notify_ret = hton->notify_rename_table(
8532+
thd, params->key, params->notification_type,
8533+
params->m_old_db_name, params->m_old_table_name,
8534+
params->m_new_db_name, params->m_new_table_name);
8535+
}
8536+
break;
8537+
default:
8538+
assert(0);
8539+
return true;
8540+
}
8541+
8542+
if (notify_ret) {
84728543
// Ignore failures from post event notification.
84738544
if (params->notification_type == HA_NOTIFY_PRE_EVENT) return true;
84748545
} else
@@ -8478,38 +8549,41 @@ static bool notify_alter_table_helper(THD *thd, plugin_ref plugin, void *arg) {
84788549
}
84798550

84808551
/**
8481-
Notify/get permission from all interested storage engines before
8482-
or after executed ALTER TABLE on the table identified by key.
8552+
Notify/get permission from all interested storage engines before or after
8553+
executed DDL (ALTER TABLE, RENAME TABLE, TRUNCATE TABLE) on the table
8554+
identified by key.
84838555
84848556
@param thd Thread context.
84858557
@param mdl_key MDL key identifying table.
8486-
@param notification_type Indicates whether this is pre-ALTER or
8487-
post-ALTER notification.
8488-
8489-
See @sa handlerton::notify_alter_table for rationale,
8490-
details about calling convention and error reporting.
8491-
8492-
@return False - if notification was successful/ALTER TABLE can
8493-
proceed.
8494-
True - if it has failed/ALTER TABLE should fail.
8495-
*/
8496-
8497-
bool ha_notify_alter_table(THD *thd, const MDL_key *mdl_key,
8498-
ha_notification_type notification_type) {
8499-
HTON_NOTIFY_PARAMS params(mdl_key, notification_type);
8500-
8501-
if (plugin_foreach(thd, notify_alter_table_helper,
8502-
MYSQL_STORAGE_ENGINE_PLUGIN, &params)) {
8503-
/*
8504-
If some SE hasn't given its permission to do ALTER TABLE and some SEs
8505-
has given their permissions, we need to notify the latter group about
8506-
failed attemopt. We do this by calling post-ALTER TABLE notification
8507-
for all interested SEs unconditionally.
8508-
*/
8558+
@param notification_type Indicates whether this is pre-DDL or post-DDL
8559+
notification.
8560+
@param old_db_name Old db name, used in RENAME DDL
8561+
@param old_table_name Old table name, used in RENAME DDL
8562+
@param new_db_name New db name, used in RENAME DDL
8563+
@param new_table_name New table name, used in RENAME DDL
8564+
8565+
See @sa handlerton::notify_alter_table for rationale, details about calling
8566+
convention and error reporting.
8567+
8568+
@return False - if notification was successful/DDL can proceed.
8569+
True - if it has failed/DDL should fail.
8570+
*/
8571+
bool ha_notify_table_ddl(THD *thd, const MDL_key *mdl_key,
8572+
ha_notification_type notification_type,
8573+
ha_ddl_type ddl_type, const char *old_db_name,
8574+
const char *old_table_name, const char *new_db_name,
8575+
const char *new_table_name) {
8576+
HTON_NOTIFY_PARAMS params(mdl_key, notification_type, ddl_type, old_db_name,
8577+
old_table_name, new_db_name, new_table_name);
8578+
8579+
if (plugin_foreach(thd, notify_table_ddl_helper, MYSQL_STORAGE_ENGINE_PLUGIN,
8580+
&params)) {
85098581
if (notification_type == HA_NOTIFY_PRE_EVENT &&
85108582
params.some_htons_were_notified) {
8511-
HTON_NOTIFY_PARAMS rollback_params(mdl_key, HA_NOTIFY_POST_EVENT);
8512-
(void)plugin_foreach(thd, notify_alter_table_helper,
8583+
HTON_NOTIFY_PARAMS rollback_params(mdl_key, HA_NOTIFY_POST_EVENT,
8584+
ddl_type, old_db_name, old_table_name,
8585+
new_db_name, new_table_name);
8586+
(void)plugin_foreach(thd, notify_table_ddl_helper,
85138587
MYSQL_STORAGE_ENGINE_PLUGIN, &rollback_params);
85148588
}
85158589
return true;

sql/handler.h

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,12 @@ enum enum_schema_tables : int {
929929

930930
enum ha_stat_type { HA_ENGINE_STATUS, HA_ENGINE_LOGS, HA_ENGINE_MUTEX };
931931
enum ha_notification_type : int { HA_NOTIFY_PRE_EVENT, HA_NOTIFY_POST_EVENT };
932+
enum ha_ddl_type : int {
933+
HA_INVALID_DDL,
934+
HA_ALTER_DDL,
935+
HA_TRUNCATE_DDL,
936+
HA_RENAME_DDL
937+
};
932938

933939
/** Clone start operation mode */
934940
enum Ha_clone_mode {
@@ -2028,6 +2034,40 @@ typedef bool (*notify_exclusive_mdl_t)(THD *thd, const MDL_key *mdl_key,
20282034
typedef bool (*notify_alter_table_t)(THD *thd, const MDL_key *mdl_key,
20292035
ha_notification_type notification_type);
20302036

2037+
/**
2038+
Notify/get permission from storage engine before or after execution of
2039+
RENAME TABLE operation on the table identified by the MDL key.
2040+
2041+
@param thd Thread context.
2042+
@param mdl_key MDL key identifying table which is going to be
2043+
or was RENAMEd.
2044+
@param notification_type Indicates whether this is pre-RENAME TABLE or
2045+
post-RENAME TABLE notification.
2046+
@param old_db_name
2047+
@param old_table_name
2048+
@param new_db_name
2049+
@param new_table_name
2050+
*/
2051+
typedef bool (*notify_rename_table_t)(THD *thd, const MDL_key *mdl_key,
2052+
ha_notification_type notification_type,
2053+
const char *old_db_name,
2054+
const char *old_table_name,
2055+
const char *new_db_name,
2056+
const char *new_table_name);
2057+
2058+
/**
2059+
Notify/get permission from storage engine before or after execution of
2060+
TRUNCATE TABLE operation on the table identified by the MDL key.
2061+
2062+
@param thd Thread context.
2063+
@param mdl_key MDL key identifying table which is going to be
2064+
or was TRUNCATEd.
2065+
@param notification_type Indicates whether this is pre-TRUNCATE TABLE or
2066+
post-TRUNCATE TABLE notification.
2067+
*/
2068+
typedef bool (*notify_truncate_table_t)(THD *thd, const MDL_key *mdl_key,
2069+
ha_notification_type notification_type);
2070+
20312071
/**
20322072
@brief
20332073
Initiate master key rotation
@@ -2685,6 +2725,8 @@ struct handlerton {
26852725
replace_native_transaction_in_thd_t replace_native_transaction_in_thd;
26862726
notify_exclusive_mdl_t notify_exclusive_mdl;
26872727
notify_alter_table_t notify_alter_table;
2728+
notify_rename_table_t notify_rename_table;
2729+
notify_truncate_table_t notify_truncate_table;
26882730
rotate_encryption_master_key_t rotate_encryption_master_key;
26892731
redo_log_set_state_t redo_log_set_state;
26902732

@@ -2844,6 +2886,16 @@ constexpr const decltype(handlerton::flags) HTON_SUPPORTS_ENGINE_ATTRIBUTE{
28442886
constexpr const decltype(
28452887
handlerton::flags) HTON_SUPPORTS_GENERATED_INVISIBLE_PK{1 << 18};
28462888

2889+
/** Whether the secondary engine supports DDLs. No meaning if the engine is not
2890+
* secondary. */
2891+
#define HTON_SECONDARY_ENGINE_SUPPORTS_DDL (1 << 19)
2892+
2893+
inline bool secondary_engine_supports_ddl(const handlerton *hton) {
2894+
assert(hton->flags & HTON_IS_SECONDARY_ENGINE);
2895+
2896+
return (hton->flags & HTON_SECONDARY_ENGINE_SUPPORTS_DDL) != 0;
2897+
}
2898+
28472899
inline bool ddl_is_atomic(const handlerton *hton) {
28482900
return (hton->flags & HTON_SUPPORTS_ATOMIC_DDL) != 0;
28492901
}
@@ -7029,6 +7081,9 @@ handler *get_new_handler(TABLE_SHARE *share, bool partitioned, MEM_ROOT *alloc,
70297081
handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
70307082
bool no_substitute, bool report_error);
70317083

7084+
bool ha_secondary_engine_supports_ddl(
7085+
THD *thd, const LEX_CSTRING &secondary_engine) noexcept;
7086+
70327087
/**
70337088
Get default handlerton, if handler supplied is null.
70347089
@@ -7268,8 +7323,11 @@ bool ha_is_storage_engine_disabled(handlerton *se_engine);
72687323
bool ha_notify_exclusive_mdl(THD *thd, const MDL_key *mdl_key,
72697324
ha_notification_type notification_type,
72707325
bool *victimized);
7271-
bool ha_notify_alter_table(THD *thd, const MDL_key *mdl_key,
7272-
ha_notification_type notification_type);
7326+
bool ha_notify_table_ddl(THD *thd, const MDL_key *mdl_key,
7327+
ha_notification_type notification_type,
7328+
ha_ddl_type ddl_type, const char *old_db_name,
7329+
const char *old_table_name, const char *new_db_name,
7330+
const char *new_table_name);
72737331

72747332
std::pair<int, bool> commit_owned_gtids(THD *thd, bool all);
72757333
bool set_tx_isolation(THD *thd, enum_tx_isolation tx_isolation, bool one_shot);

sql/sql_partition_admin.cc

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -656,12 +656,20 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) {
656656
/* Table was successfully opened above. */
657657
assert(table_def != nullptr);
658658

659+
Table_ddl_hton_notification_guard notification_guard{
660+
thd, &first_table->mdl_request.key, ha_ddl_type::HA_TRUNCATE_DDL};
661+
662+
if (notification_guard.notify()) return true;
663+
659664
if (table_def->options().exists("secondary_engine")) {
660-
/* Truncate operation is not allowed for tables with secondary engine
661-
* since it's not currently supported by change propagation
662-
*/
663-
my_error(ER_SECONDARY_ENGINE_DDL, MYF(0));
664-
return true;
665+
LEX_CSTRING secondary_engine;
666+
table_def->options().get("secondary_engine", &secondary_engine,
667+
thd->mem_root);
668+
669+
if (!ha_secondary_engine_supports_ddl(thd, secondary_engine)) {
670+
my_error(ER_SECONDARY_ENGINE_DDL, MYF(0));
671+
return true;
672+
}
665673
}
666674

667675
if (hton->partition_flags() & HA_TRUNCATE_PARTITION_PRECLOSE) {

0 commit comments

Comments
 (0)