1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-17 12:02:09 +03:00

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
This commit is contained in:
Monty
2020-03-30 20:12:02 +03:00
parent 7866b72304
commit f9f33b85be
15 changed files with 101 additions and 56 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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,

View File

@ -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();

View File

@ -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)

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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=

View File

@ -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);

View File

@ -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())