diff options
author | Monty <monty@mariadb.org> | 2020-03-30 20:12:02 +0300 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2020-04-19 17:33:51 +0300 |
commit | f9f33b85be6b5006f0ecd0de7961c71d415a9d73 (patch) | |
tree | ae547acc02c05876ccc9f54a3c7be614af206425 | |
parent | 7866b723048d1d0f4a202d5a1e5475420b1dda64 (diff) | |
download | mariadb-git-f9f33b85be6b5006f0ecd0de7961c71d415a9d73.tar.gz |
Handle errors from external_unlock & mysql_unlock_tables
Other things:
- Handler errors from ha_maria::implict_commit
- Disable DBUG in safe_mutex_lock to get trace file easier to read
-rw-r--r-- | mysql-test/main/myisam_debug.result | 4 | ||||
-rw-r--r-- | mysql-test/main/myisam_debug.test | 2 | ||||
-rw-r--r-- | mysys/thr_mutex.c | 8 | ||||
-rw-r--r-- | sql/handler.cc | 8 | ||||
-rw-r--r-- | sql/lock.cc | 53 | ||||
-rw-r--r-- | sql/lock.h | 10 | ||||
-rw-r--r-- | sql/sql_base.cc | 26 | ||||
-rw-r--r-- | sql/sql_base.h | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_parse.cc | 6 | ||||
-rw-r--r-- | sql/sql_partition.cc | 9 | ||||
-rw-r--r-- | sql/sql_select.cc | 7 | ||||
-rw-r--r-- | sql/sql_table.cc | 12 | ||||
-rw-r--r-- | sql/transaction.cc | 3 | ||||
-rw-r--r-- | sql/wsrep_client_service.cc | 3 |
15 files changed, 101 insertions, 56 deletions
diff --git a/mysql-test/main/myisam_debug.result b/mysql-test/main/myisam_debug.result index 650a3bcb787..10208a936a0 100644 --- a/mysql-test/main/myisam_debug.result +++ b/mysql-test/main/myisam_debug.result @@ -38,7 +38,9 @@ insert t1 values (1),(2),(1); set @old_dbug=@@debug_dbug; SET debug_dbug='+d,mi_lock_database_failure'; unlock tables; -Warnings: +ERROR HY000: Index for table './test/t1.MYI' is corrupt; try to repair it +SHOW WARNINGS; +Level Code Message Error 126 Index for table './test/t1.MYI' is corrupt; try to repair it Error 1030 Got error 22 "Invalid argument" from storage engine MyISAM SET debug_dbug=@old_dbug; diff --git a/mysql-test/main/myisam_debug.test b/mysql-test/main/myisam_debug.test index 2861c344b10..fcb134c0400 100644 --- a/mysql-test/main/myisam_debug.test +++ b/mysql-test/main/myisam_debug.test @@ -67,6 +67,8 @@ lock tables t1 write; insert t1 values (1),(2),(1); set @old_dbug=@@debug_dbug; SET debug_dbug='+d,mi_lock_database_failure'; +--error HA_ERR_CRASHED unlock tables; +SHOW WARNINGS; SET debug_dbug=@old_dbug; drop table t1; diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index 4f495048f63..9db1e0efabf 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -233,6 +233,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file, int error; DBUG_PRINT("mutex", ("%s (0x%lx) locking", mp->name ? mp->name : "Null", (ulong) mp)); + DBUG_PUSH(""); pthread_mutex_lock(&mp->global); if (!mp->file) @@ -283,7 +284,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file, { error= pthread_mutex_trylock(&mp->mutex); if (error == EBUSY) - return error; + goto end; } else error= pthread_mutex_lock(&mp->mutex); @@ -393,7 +394,10 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file, } } - DBUG_PRINT("mutex", ("%s (0x%lx) locked", mp->name, (ulong) mp)); +end: + DBUG_POP(); + if (!error) + DBUG_PRINT("mutex", ("%s (0x%lx) locked", mp->name, (ulong) mp)); return error; } diff --git a/sql/handler.cc b/sql/handler.cc index 5156ef6bb8e..2d3f64a7d2b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1532,7 +1532,13 @@ int ha_commit_trans(THD *thd, bool all) } #ifdef WITH_ARIA_STORAGE_ENGINE - ha_maria::implicit_commit(thd, TRUE); + if ((error= ha_maria::implicit_commit(thd, TRUE))) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); + ha_rollback_trans(thd, all); + DBUG_RETURN(1); + } + #endif if (!ha_info) diff --git a/sql/lock.cc b/sql/lock.cc index 7f69946c35e..487f2c3115f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -409,17 +409,18 @@ static int lock_external(THD *thd, TABLE **tables, uint count) } -void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock) +int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock) { - mysql_unlock_tables(thd, sql_lock, - (thd->variables.option_bits & OPTION_TABLE_LOCK) || - !(sql_lock->flags & GET_LOCK_ON_THD)); + return mysql_unlock_tables(thd, sql_lock, + (thd->variables.option_bits & OPTION_TABLE_LOCK) || + !(sql_lock->flags & GET_LOCK_ON_THD)); } -void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) +int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) { bool errors= thd->is_error(); + int error= 0; PSI_stage_info org_stage; DBUG_ENTER("mysql_unlock_tables"); @@ -427,7 +428,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) THD_STAGE_INFO(thd, stage_unlocking_tables); if (sql_lock->table_count) - unlock_external(thd, sql_lock->table, sql_lock->table_count); + error= unlock_external(thd, sql_lock->table, sql_lock->table_count); if (sql_lock->lock_count) thr_multi_unlock(sql_lock->locks, sql_lock->lock_count, 0); if (free_lock) @@ -435,10 +436,12 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) DBUG_ASSERT(!(sql_lock->flags & GET_LOCK_ON_THD)); my_free(sql_lock); } - if (likely(!errors)) + if (likely(!errors && !error)) thd->clear_error(); THD_STAGE_INFO(thd, org_stage); - DBUG_VOID_RETURN; + if (error) + DBUG_PRINT("exit", ("error: %d", error)); + DBUG_RETURN(error); } /** @@ -447,12 +450,16 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock) This will work even if get_lock_data fails (next unlock will free all) */ -void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag) +int mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag) { - MYSQL_LOCK *sql_lock= - get_lock_data(thd, table, count, GET_LOCK_UNLOCK | GET_LOCK_ON_THD | flag); - if (sql_lock) - mysql_unlock_tables(thd, sql_lock, 0); + int error; + MYSQL_LOCK *sql_lock; + if (!(sql_lock= get_lock_data(thd, table, count, + GET_LOCK_UNLOCK | GET_LOCK_ON_THD | flag))) + error= ER_OUTOFMEMORY; + else + error= mysql_unlock_tables(thd, sql_lock, 0); + return error; } @@ -460,9 +467,10 @@ void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag) unlock all tables locked for read. */ -void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) +int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) { uint i,found; + int error= 0; DBUG_ENTER("mysql_unlock_read_tables"); /* Call external lock for all tables to be unlocked */ @@ -482,7 +490,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) /* Unlock all read locked tables */ if (i != found) { - (void) unlock_external(thd,table,i-found); + error= unlock_external(thd,table,i-found); sql_lock->table_count=found; } @@ -517,7 +525,7 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) found+= tbl->lock_count; table++; } - DBUG_VOID_RETURN; + DBUG_RETURN(error); } @@ -531,8 +539,9 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock) @param table the table to unlock */ -void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) +int mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) { + int error= 0; if (locked) { uint i; @@ -541,13 +550,20 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) if (locked->table[i] == table) { uint j, removed_locks, old_tables; + int tmp_error; TABLE *tbl; uint lock_data_end; DBUG_ASSERT(table->lock_position == i); /* Unlock the table. */ - mysql_unlock_some_tables(thd, &table, /* table count */ 1, 0); + if ((tmp_error= mysql_unlock_some_tables(thd, &table, + /* table count */ 1, 0))) + { + table->file->print_error(tmp_error, MYF(0)); + if (!error) + error= tmp_error; + } /* Decrement table_count in advance, making below expressions easier */ old_tables= --locked->table_count; @@ -589,6 +605,7 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) } } } + return error; } diff --git a/sql/lock.h b/sql/lock.h index e5036ea032c..0b23ddd3846 100644 --- a/sql/lock.h +++ b/sql/lock.h @@ -28,11 +28,11 @@ typedef struct st_mysql_lock MYSQL_LOCK; MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags); bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags); -void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock); -void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); -void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); -void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag); -void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); +int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock); +int mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); +int mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); +int mysql_unlock_some_tables(THD *thd, TABLE **table,uint count, uint flag); +int mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); /* Lock based on name */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 31e8fe45a5a..1b6d8834e7e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -772,9 +772,10 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, leave prelocked mode if needed. */ -void close_thread_tables(THD *thd) +int close_thread_tables(THD *thd) { TABLE *table; + int error= 0; DBUG_ENTER("close_thread_tables"); THD_STAGE_INFO(thd, stage_closing_tables); @@ -874,7 +875,7 @@ void close_thread_tables(THD *thd) we will exit this function a few lines below. */ if (! thd->lex->requires_prelocking()) - DBUG_VOID_RETURN; + DBUG_RETURN(0); /* We are in the top-level statement of a prelocked statement, @@ -885,7 +886,7 @@ void close_thread_tables(THD *thd) thd->locked_tables_mode= LTM_LOCK_TABLES; if (thd->locked_tables_mode == LTM_LOCK_TABLES) - DBUG_VOID_RETURN; + DBUG_RETURN(0); thd->leave_locked_tables_mode(); @@ -904,7 +905,7 @@ void close_thread_tables(THD *thd) binlog_query()) or when preparing a pending event. */ (void)thd->binlog_flush_pending_rows_event(TRUE); - mysql_unlock_tables(thd, thd->lock); + error= mysql_unlock_tables(thd, thd->lock); thd->lock=0; } /* @@ -914,7 +915,7 @@ void close_thread_tables(THD *thd) while (thd->open_tables) (void) close_thread_table(thd, &thd->open_tables); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } @@ -2320,9 +2321,10 @@ Locked_tables_list::init_locked_tables(THD *thd) @note This function is a no-op if we're not in LOCK TABLES. */ -void +int Locked_tables_list::unlock_locked_tables(THD *thd) { + int error; DBUG_ASSERT(!thd->in_sub_stmt && !(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); /* @@ -2332,7 +2334,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd) open tables, e.g. from begin_trans(). */ if (thd->locked_tables_mode != LTM_LOCK_TABLES) - return; + return 0; for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list= table_list->next_global) @@ -2349,7 +2351,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd) TRANSACT_TRACKER(clear_trx_state(thd, TX_LOCKED_TABLES)); DBUG_ASSERT(thd->transaction.stmt.is_empty()); - close_thread_tables(thd); + error= close_thread_tables(thd); /* We rely on the caller to implicitly commit the @@ -2361,6 +2363,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd) request for metadata locks and TABLE_LIST elements. */ reset(); + return error; } @@ -2369,7 +2372,7 @@ Locked_tables_list::unlock_locked_tables(THD *thd) table mode if there is no locked tables anymore */ -void +int Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket) { /* @@ -2378,7 +2381,7 @@ Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket) to check this condition here than in the caller. */ if (thd->locked_tables_mode != LTM_LOCK_TABLES) - return; + return 0; if (mdl_ticket) { @@ -2391,7 +2394,8 @@ Locked_tables_list::unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket) } if (thd->lock->table_count == 0) - unlock_locked_tables(thd); + return unlock_locked_tables(thd); + return 0; } diff --git a/sql/sql_base.h b/sql/sql_base.h index 773b95b8317..0fdb2599ce4 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -160,7 +160,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, TABLE_LIST *TABLE_LIST::*link, const LEX_CSTRING *db_name, const LEX_CSTRING *table_name); -void close_thread_tables(THD *thd); +int close_thread_tables(THD *thd); void switch_to_nullable_trigger_fields(List<Item> &items, TABLE *); void switch_defaults_to_nullable_trigger_fields(TABLE *table); bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, diff --git a/sql/sql_class.h b/sql/sql_class.h index 72a4722afbf..816935ba2ce 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1969,8 +1969,8 @@ public: init_sql_alloc(key_memory_locked_table_list, &m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC)); } - void unlock_locked_tables(THD *thd); - void unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket); + int unlock_locked_tables(THD *thd); + int unlock_locked_table(THD *thd, MDL_ticket *mdl_ticket); ~Locked_tables_list() { reset(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fb7002f701a..53ccdb5d4c3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5003,7 +5003,8 @@ mysql_execute_command(THD *thd) if (thd->variables.option_bits & OPTION_TABLE_LOCK) { res= trans_commit_implicit(thd); - thd->locked_tables_list.unlock_locked_tables(thd); + if (thd->locked_tables_list.unlock_locked_tables(thd)) + res= 1; thd->mdl_context.release_transactional_locks(); thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); } @@ -5017,7 +5018,8 @@ mysql_execute_command(THD *thd) case SQLCOM_LOCK_TABLES: /* We must end the transaction first, regardless of anything */ res= trans_commit_implicit(thd); - thd->locked_tables_list.unlock_locked_tables(thd); + if (thd->locked_tables_list.unlock_locked_tables(thd)) + res= 1; /* Release transactional metadata locks. */ thd->mdl_context.release_transactional_locks(); if (res) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ff1ddd200d0..d5915f65998 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6778,20 +6778,21 @@ static bool alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) @param lpt Struct carrying parameters - @return Always 0. + @return error code if external_unlock fails */ static int alter_close_table(ALTER_PARTITION_PARAM_TYPE *lpt) { + int error; DBUG_ENTER("alter_close_table"); if (lpt->table->db_stat) { - mysql_lock_remove(lpt->thd, lpt->thd->lock, lpt->table); - lpt->table->file->ha_close(); + error= mysql_lock_remove(lpt->thd, lpt->thd->lock, lpt->table); + error= lpt->table->file->ha_close(); lpt->table->db_stat= 0; // Mark file closed } - DBUG_RETURN(0); + DBUG_RETURN(error); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1f05156b96f..da30fda40f7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2359,10 +2359,11 @@ int JOIN::optimize_stage2() { /* Unlock all tables, except sequences, as accessing these may still - require table updates + require table updates. It's safe to ignore result code as all + tables where opened for read only. */ - mysql_unlock_some_tables(thd, table, const_tables, - GET_LOCK_SKIP_SEQUENCES); + (void) mysql_unlock_some_tables(thd, table, const_tables, + GET_LOCK_SKIP_SEQUENCES); } if (!conds && outer_join) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7c2875acda3..10f5e1f397e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2699,7 +2699,8 @@ err: if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0 && !dont_free_locks) { - thd->locked_tables_list.unlock_locked_tables(thd); + if (thd->locked_tables_list.unlock_locked_tables(thd)) + error= 1; goto end; } for (table= tables; table; table= table->next_local) @@ -5406,7 +5407,7 @@ err: Possible locked table was dropped. We should remove meta data locks associated with it and do UNLOCK_TABLES if no more locked tables. */ - thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket); + (void) thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket); } else if (likely(!result) && create_info->table) { @@ -10608,8 +10609,10 @@ do_continue:; if (thd->locked_tables_mode != LTM_LOCK_TABLES && thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES) { - mysql_unlock_tables(thd, thd->lock); + int tmp_error= mysql_unlock_tables(thd, thd->lock); thd->lock= NULL; + if (tmp_error) + goto err_new_table_cleanup; } else { @@ -10617,7 +10620,8 @@ do_continue:; If LOCK TABLES list is not empty and contains this table, unlock the table and remove the table from this list. */ - mysql_lock_remove(thd, thd->lock, table); + if (mysql_lock_remove(thd, thd->lock, table)) + goto err_new_table_cleanup; } } new_table->s->table_creation_was_logged= diff --git a/sql/transaction.cc b/sql/transaction.cc index db40bd6177b..c9fd211c1f8 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -103,7 +103,8 @@ bool trans_begin(THD *thd, uint flags) if (trans_check(thd)) DBUG_RETURN(TRUE); - thd->locked_tables_list.unlock_locked_tables(thd); + if (thd->locked_tables_list.unlock_locked_tables(thd)) + DBUG_RETURN(true); DBUG_ASSERT(!thd->locked_tables_mode); diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc index 696a097db21..b9c59623e6c 100644 --- a/sql/wsrep_client_service.cc +++ b/sql/wsrep_client_service.cc @@ -320,7 +320,8 @@ int Wsrep_client_service::bf_rollback() int ret= (trans_rollback_stmt(m_thd) || trans_rollback(m_thd)); if (m_thd->locked_tables_mode && m_thd->lock) { - m_thd->locked_tables_list.unlock_locked_tables(m_thd); + if (m_thd->locked_tables_list.unlock_locked_tables(m_thd)) + ret= 1; m_thd->variables.option_bits&= ~OPTION_TABLE_LOCK; } if (m_thd->global_read_lock.is_acquired()) |