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:
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,6 +394,9 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
DBUG_POP();
|
||||
if (!error)
|
||||
DBUG_PRINT("mutex", ("%s (0x%lx) locked", mp->name, (ulong) mp));
|
||||
return error;
|
||||
}
|
||||
|
@ -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)
|
||||
|
49
sql/lock.cc
49
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,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
10
sql/lock.h
10
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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2359,9 +2359,10 @@ 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,
|
||||
(void) mysql_unlock_some_tables(thd, table, const_tables,
|
||||
GET_LOCK_SKIP_SEQUENCES);
|
||||
}
|
||||
if (!conds && outer_join)
|
||||
|
@ -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=
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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())
|
||||
|
Reference in New Issue
Block a user