diff options
Diffstat (limited to 'sql/ddl_log.cc')
-rw-r--r-- | sql/ddl_log.cc | 110 |
1 files changed, 60 insertions, 50 deletions
diff --git a/sql/ddl_log.cc b/sql/ddl_log.cc index 65a02914866..45677fe2f30 100644 --- a/sql/ddl_log.cc +++ b/sql/ddl_log.cc @@ -453,7 +453,7 @@ bool ddl_log_disable_execute_entry(DDL_LOG_MEMORY_ENTRY **active_entry) static bool is_execute_entry_active(uint entry_pos) { uchar buff[1]; - DBUG_ENTER("disable_execute_entry"); + DBUG_ENTER("is_execute_entry_active"); if (mysql_file_pread(global_ddl_log.file_id, buff, sizeof(buff), global_ddl_log.io_size * entry_pos + @@ -1297,9 +1297,8 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, mysql_mutex_assert_owner(&LOCK_gdl); DBUG_PRINT("ddl_log", - ("pos: %u=>%u->%u type: %u action: %u (%s) phase: %u " + ("pos: %u->%u type: %u action: %u (%s) phase: %u " "handler: '%s' name: '%s' from_name: '%s' tmp_name: '%s'", - recovery_state.execute_entry_pos, ddl_log_entry->entry_pos, ddl_log_entry->next_entry, (uint) ddl_log_entry->entry_type, @@ -1510,6 +1509,20 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, case DDL_LOG_DROP_INIT_ACTION: { LEX_CSTRING *comment= &ddl_log_entry->tmp_name; + const uint master_chain_pos= (uint) ddl_log_entry->unique_id; + /* + This drop table was depending on another chain and should only be executed + if the other chain is not active. + One such case is CREATE OR REPLACE TABLE ... which renamed the original table + and created this DROP TABLE event to be able to DROP the backup table if we + have a crash directly after closing of the CREATE event. + */ + if (master_chain_pos && is_execute_entry_active(master_chain_pos)) + { + DBUG_ASSERT(ddl_log_entry->next_entry); + error= disable_execute_entry(ddl_log_entry->next_entry); + break; + } recovery_state.drop_table.length(0); recovery_state.drop_table.set_charset(system_charset_info); recovery_state.drop_table.append(STRING_WITH_LEN("DROP TABLE IF EXISTS ")); @@ -1568,22 +1581,27 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, break; /* Fall through */ case DDL_DROP_PHASE_BINLOG: - if (strcmp(recovery_state.current_db, db.str)) + if (!(ddl_log_entry->flags & DDL_LOG_FLAG_DROP_SKIP_BINLOG)) { - append_identifier(thd, &recovery_state.drop_table, &db); - recovery_state.drop_table.append('.'); - } - append_identifier(thd, &recovery_state.drop_table, &table); - recovery_state.drop_table.append(','); - /* We don't increment phase as we want to retry this in case of crash */ + if (strcmp(recovery_state.current_db, db.str)) + { + append_identifier(thd, &recovery_state.drop_table, &db); + recovery_state.drop_table.append('.'); + } + append_identifier(thd, &recovery_state.drop_table, &table); + recovery_state.drop_table.append(','); + /* We don't increment phase as we want to retry this in case of crash */ - if (ddl_log_drop_to_binary_log(thd, ddl_log_entry, - &recovery_state.drop_table)) - { - if (increment_phase(entry_pos)) - break; + if (ddl_log_drop_to_binary_log(thd, ddl_log_entry, + &recovery_state.drop_table)) + { + if (increment_phase(entry_pos)) + break; + } + break; } - break; + (void) increment_phase(entry_pos); + /* Fall through */ case DDL_DROP_PHASE_RESET: /* We have already logged all previous drop's. Clear the query */ recovery_state.drop_table.length(recovery_state.drop_table_init_length); @@ -1758,31 +1776,6 @@ static int ddl_log_execute_action(THD *thd, MEM_ROOT *mem_root, } strxnmov(to_path, sizeof(to_path)-1, path.str, reg_ext, NullS); mysql_file_delete(key_file_frm, to_path, MYF(MY_WME|MY_IGNORE_ENOENT)); - if (ddl_log_entry->phase == DDL_CREATE_TABLE_PHASE_LOG) - { - /* - The server logged CREATE TABLE ... SELECT into binary log - before crashing. As the commit failed and we have delete the - table above, we have now to log the DROP of the created table. - */ - - String *query= &recovery_state.drop_table; - query->length(0); - query->append(STRING_WITH_LEN("DROP TABLE IF EXISTS ")); - append_identifier(thd, query, &db); - query->append('.'); - append_identifier(thd, query, &table); - query->append(&end_comment); - - if (mysql_bin_log.is_open()) - { - mysql_mutex_unlock(&LOCK_gdl); - (void) thd->binlog_query(THD::STMT_QUERY_TYPE, - query->ptr(), query->length(), - TRUE, FALSE, FALSE, 0); - mysql_mutex_lock(&LOCK_gdl); - } - } (void) update_phase(entry_pos, DDL_LOG_FINAL_PHASE); error= 0; break; @@ -2749,7 +2742,7 @@ int ddl_log_execute_recovery() if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE) { /* - Remeber information about executive ddl log entry, + Remember information about executive ddl log entry, used for binary logging during recovery */ recovery_state.execute_entry_pos= i; @@ -3101,18 +3094,18 @@ bool ddl_log_rename_view(THD *thd, DDL_LOG_STATE *ddl_state, */ static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state, - ddl_log_action_code action_code, const LEX_CSTRING *db, const LEX_CSTRING *comment) { DDL_LOG_ENTRY ddl_log_entry; - DBUG_ENTER("ddl_log_drop_file"); + DBUG_ENTER("ddl_log_drop_init"); bzero(&ddl_log_entry, sizeof(ddl_log_entry)); - ddl_log_entry.action_type= action_code; + ddl_log_entry.action_type= DDL_LOG_DROP_INIT_ACTION; ddl_log_entry.from_db= *const_cast<LEX_CSTRING*>(db); ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(comment); + ddl_log_entry.unique_id= ddl_state->master_chain_pos; DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry)); } @@ -3120,17 +3113,17 @@ static bool ddl_log_drop_init(THD *thd, DDL_LOG_STATE *ddl_state, bool ddl_log_drop_table_init(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db, - const LEX_CSTRING *comment) + const LEX_CSTRING *comment, + bool skip_binlog) { - return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_INIT_ACTION, - db, comment); + ddl_state->skip_binlog= skip_binlog; + return ddl_log_drop_init(thd, ddl_state, db, comment); } bool ddl_log_drop_view_init(THD *thd, DDL_LOG_STATE *ddl_state, const LEX_CSTRING *db) { - return ddl_log_drop_init(thd, ddl_state, DDL_LOG_DROP_INIT_ACTION, - db, &empty_clex_str); + return ddl_log_drop_init(thd, ddl_state, db, &empty_clex_str); } @@ -3166,6 +3159,8 @@ static bool ddl_log_drop(THD *thd, DDL_LOG_STATE *ddl_state, ddl_log_entry.name= *const_cast<LEX_CSTRING*>(table); ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(path); ddl_log_entry.phase= (uchar) phase; + if (ddl_state->skip_binlog) + ddl_log_entry.flags= DDL_LOG_FLAG_DROP_SKIP_BINLOG; mysql_mutex_lock(&LOCK_gdl); if (ddl_log_write_entry(&ddl_log_entry, &log_entry)) @@ -3304,6 +3299,7 @@ bool ddl_log_create_table(THD *thd, DDL_LOG_STATE *ddl_state, ddl_log_entry.name= *const_cast<LEX_CSTRING*>(table); ddl_log_entry.tmp_name= *const_cast<LEX_CSTRING*>(path); ddl_log_entry.flags= only_frm ? DDL_LOG_FLAG_ONLY_FRM : 0; + ddl_log_entry.next_entry= ddl_state->list ? ddl_state->list->entry_pos : 0; DBUG_RETURN(ddl_log_write(ddl_state, &ddl_log_entry)); } @@ -3528,3 +3524,17 @@ err: mysql_mutex_unlock(&LOCK_gdl); DBUG_RETURN(1); } + + +/* + Link the ddl_log_state to another (master) chain. If the master + chain is active during DDL recovery, this event will not be executed. + + This is used for DROP TABLE of the original table when + CREATE OR REPLACE ... is used. +*/ +void ddl_log_link_events(DDL_LOG_STATE *state, DDL_LOG_STATE *master_state) +{ + DBUG_ASSERT(master_state->execute_entry); + state->master_chain_pos= master_state->execute_entry->entry_pos; +} |