diff --git a/dict/dict0crea.c b/dict/dict0crea.c index a41c90261d8..dd2e205a735 100644 --- a/dict/dict0crea.c +++ b/dict/dict0crea.c @@ -1193,7 +1193,7 @@ dict_create_or_check_foreign_constraint_tables(void) "CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n" "COMMIT WORK;\n" "END;\n" - , trx); + , FALSE, trx); if (error != DB_SUCCESS) { fprintf(stderr, "InnoDB: error %lu in creation\n", @@ -1242,7 +1242,7 @@ dict_foreign_eval_sql( ulint error; FILE* ef = dict_foreign_err_file; - error = que_eval_sql(info, sql, trx); + error = que_eval_sql(info, sql, FALSE, trx); if (error == DB_DUPLICATE_KEY) { mutex_enter(&dict_foreign_err_mutex); diff --git a/include/que0que.h b/include/que0que.h index c3314a1167b..8fbf5330c89 100644 --- a/include/que0que.h +++ b/include/que0que.h @@ -143,14 +143,12 @@ que_thr_stop_for_mysql( /*===================*/ que_thr_t* thr); /* in: query thread */ /************************************************************************** -Runs query threads. Note that the individual query thread which is run -within this function may change if, e.g., the OS thread executing this -function uses a threshold amount of resources. */ +Run a query thread. Handles lock waits. */ void que_run_threads( /*============*/ - que_thr_t* thr); /* in: query thread which is run initially */ + que_thr_t* thr); /* in: query thread */ /************************************************************************** After signal handling is finished, returns control to a query graph error handling routine. (Currently, just returns the control to the root of the @@ -163,19 +161,6 @@ que_fork_error_handle( que_t* fork); /* in: query graph which was run before signal handling started, NULL not allowed */ /************************************************************************** -Handles an SQL error noticed during query thread execution. At the moment, -does nothing! */ - -void -que_thr_handle_error( -/*=================*/ - que_thr_t* thr, /* in: query thread */ - ulint err_no, /* in: error number */ - byte* err_str,/* in, own: error string or NULL; NOTE: the - function will take care of freeing of the - string! */ - ulint err_len);/* in: error string length */ -/************************************************************************** Moves a suspended query thread to the QUE_THR_RUNNING state and releases a single worker thread to execute it. This function should be used to end the wait state of a query thread waiting for a lock or a stored procedure @@ -337,9 +322,14 @@ Evaluate the given SQL */ ulint que_eval_sql( /*=========*/ - pars_info_t* info, /* out: error code or DB_SUCCESS */ - const char* sql, /* in: info struct, or NULL */ + /* out: error code or DB_SUCCESS */ + pars_info_t* info, /* in: info struct, or NULL */ + const char* sql, /* in: SQL string */ + ibool reserve_dict_mutex, + /* in: if TRUE, acquire/release + dict_sys->mutex around call to pars_sql. */ trx_t* trx); /* in: trx */ + /* Query graph query thread node: the fields are protected by the kernel mutex with the exceptions named below */ diff --git a/que/que0que.c b/que/que0que.c index c6d287276c7..74f331c29f2 100644 --- a/que/que0que.c +++ b/que/que0que.c @@ -715,27 +715,6 @@ que_graph_try_free( return(FALSE); } -/************************************************************************** -Handles an SQL error noticed during query thread execution. Currently, -does nothing! */ - -void -que_thr_handle_error( -/*=================*/ - que_thr_t* thr __attribute__((unused)), - /* in: query thread */ - ulint err_no __attribute__((unused)), - /* in: error number */ - byte* err_str __attribute__((unused)), - /* in, own: error string or NULL; NOTE: the - function will take care of freeing of the - string! */ - ulint err_len __attribute__((unused))) - /* in: error string length */ -{ - /* Does nothing */ -} - /******************************************************************** Performs an execution step on a thr node. */ static @@ -813,11 +792,10 @@ que_thr_move_to_run_state( Decrements the query thread reference counts in the query graph and the transaction. May start signal handling, e.g., a rollback. *** NOTE ***: -This and que_thr_stop_for_mysql are -the only functions where the reference count can be decremented and -this function may only be called from inside que_run_threads or -que_thr_check_if_switch! These restrictions exist to make the rollback code -easier to maintain. */ +This and que_thr_stop_for_mysql are the only functions where the reference +count can be decremented and this function may only be called from inside +que_run_threads or que_thr_check_if_switch! These restrictions exist to make +the rollback code easier to maintain. */ static void que_thr_dec_refer_count( @@ -836,7 +814,7 @@ que_thr_dec_refer_count( ibool stopped; fork = thr->common.parent; - trx = thr->graph->trx; + trx = thr_get_trx(thr); sess = trx->sess; mutex_enter(&kernel_mutex); @@ -856,6 +834,12 @@ que_thr_dec_refer_count( stderr); */ if (next_thr && *next_thr == NULL) { + /* Normally srv_suspend_mysql_thread resets + the state to DB_SUCCESS before waiting, but + in this case we have to do it here, + otherwise nobody does it. */ + trx->error_state = DB_SUCCESS; + *next_thr = thr; } else { ut_a(0); @@ -1200,7 +1184,10 @@ que_thr_step( trx_t* trx; ulint type; + trx = thr_get_trx(thr); + ut_ad(thr->state == QUE_THR_RUNNING); + ut_a(trx->error_state == DB_SUCCESS); thr->resource++; @@ -1236,7 +1223,6 @@ que_thr_step( threads doing updating or inserting at the moment! */ if (thr->prev_node == que_node_get_parent(node)) { - trx = thr_get_trx(thr); trx->last_sql_stat_start.least_undo_no = trx->undo_no; } @@ -1298,24 +1284,28 @@ que_thr_step( old_thr->prev_node = node; } + if (thr) { + ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS); + } + return(thr); } /************************************************************************** -Runs query threads. Note that the individual query thread which is run -within this function may change if, e.g., the OS thread executing this -function uses a threshold amount of resources. */ - +Run a query thread until it finishes or encounters e.g. a lock wait. */ +static void -que_run_threads( -/*============*/ - que_thr_t* thr) /* in: query thread which is run initially */ +que_run_threads_low( +/*================*/ + que_thr_t* thr) /* in: query thread */ { que_thr_t* next_thr; ulint cumul_resource; ulint loop_count; ut_ad(thr->state == QUE_THR_RUNNING); + ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS); + #ifdef UNIV_SYNC_DEBUG ut_ad(!mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ @@ -1340,10 +1330,15 @@ loop: next_thr = que_thr_step(thr); /*-------------------------*/ + ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS)); + loop_count++; if (next_thr != thr) { ut_a(next_thr == NULL); + + /* This can change next_thr to a non-NULL value if there was + a lock wait that already completed. */ que_thr_dec_refer_count(thr, &next_thr); if (next_thr == NULL) { @@ -1359,20 +1354,89 @@ loop: goto loop; } +/************************************************************************** +Run a query thread. Handles lock waits. */ +void +que_run_threads( +/*============*/ + que_thr_t* thr) /* in: query thread */ +{ +loop: + ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS); + que_run_threads_low(thr); + + mutex_enter(&kernel_mutex); + + switch (thr->state) { + + case QUE_THR_RUNNING: + /* There probably was a lock wait, but it already ended + before we came here: continue running thr */ + + mutex_exit(&kernel_mutex); + + goto loop; + + case QUE_THR_LOCK_WAIT: + mutex_exit(&kernel_mutex); + + /* The ..._mysql_... function works also for InnoDB's + internal threads. Let us wait that the lock wait ends. */ + + srv_suspend_mysql_thread(thr); + + if (thr_get_trx(thr)->error_state != DB_SUCCESS) { + /* thr was chosen as a deadlock victim or there was + a lock wait timeout */ + + que_thr_dec_refer_count(thr, NULL); + + return; + } + + goto loop; + + case QUE_THR_COMPLETED: + case QUE_THR_COMMAND_WAIT: + /* Do nothing */ + break; + + default: + ut_error; + } + + mutex_exit(&kernel_mutex); +} + /************************************************************************* -Evaluate the given SQL */ +Evaluate the given SQL. */ ulint que_eval_sql( /*=========*/ - pars_info_t* info, /* out: error code or DB_SUCCESS */ - const char* sql, /* in: info struct, or NULL */ + /* out: error code or DB_SUCCESS */ + pars_info_t* info, /* in: info struct, or NULL */ + const char* sql, /* in: SQL string */ + ibool reserve_dict_mutex, + /* in: if TRUE, acquire/release + dict_sys->mutex around call to pars_sql. */ trx_t* trx) /* in: trx */ { que_thr_t* thr; que_t* graph; + ut_a(trx->error_state == DB_SUCCESS); + + if (reserve_dict_mutex) { + mutex_enter(&dict_sys->mutex); + } + graph = pars_sql(info, sql); + + if (reserve_dict_mutex) { + mutex_exit(&dict_sys->mutex); + } + ut_a(graph); graph->trx = trx; diff --git a/row/row0mysql.c b/row/row0mysql.c index 6fcaac68d3b..602e46f0998 100644 --- a/row/row0mysql.c +++ b/row/row0mysql.c @@ -2517,7 +2517,7 @@ do not allow the discard. We also reserve the data dictionary latch. */ " WHERE TABLE_ID = old_id;\n" "COMMIT WORK;\n" "END;\n" - , trx); + , FALSE, trx); if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; @@ -2913,7 +2913,7 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */ " WHERE TABLE_ID = :old_id;\n" "COMMIT WORK;\n" "END;\n" - , trx); + , FALSE, trx); if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; @@ -3234,7 +3234,7 @@ fputs(" InnoDB: You are trying to drop table ", stderr); "DELETE FROM SYS_TABLES WHERE ID = table_id;\n" "COMMIT WORK;\n" "END;\n" - , trx); + , FALSE, trx); if (err != DB_SUCCESS) { ut_a(err == DB_OUT_OF_FILE_SPACE); @@ -3443,7 +3443,7 @@ row_delete_constraint_low( "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n" "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n" "END;\n" - , trx)); + , FALSE, trx)); } /******************************************************************** @@ -3609,7 +3609,7 @@ row_rename_table_for_mysql( "UPDATE SYS_TABLES SET NAME = :new_table_name\n" " WHERE NAME = :old_table_name;\n" "END;\n" - , trx); + , FALSE, trx); if (err != DB_SUCCESS) { @@ -3683,7 +3683,7 @@ row_rename_table_for_mysql( "WHERE REF_NAME = :old_table_name\n" " AND TO_BINARY(REF_NAME) = TO_BINARY(:old_table_name);\n" "END;\n" - , trx); + , FALSE, trx); } else if (n_constraints_to_drop > 0) { /* Drop some constraints of tmp tables. */ diff --git a/row/row0sel.c b/row/row0sel.c index 3f42222ca2e..5b6b3232754 100644 --- a/row/row0sel.c +++ b/row/row0sel.c @@ -1920,9 +1920,8 @@ row_sel_step( err = lock_table(0, table_node->table, i_lock_mode, thr); if (err != DB_SUCCESS) { + thr_get_trx(thr)->error_state = err; - que_thr_handle_error(thr, DB_ERROR, - NULL, 0); return(NULL); } @@ -1958,17 +1957,8 @@ row_sel_step( thr->graph->last_sel_node = node; - if (err == DB_SUCCESS) { - /* Ok: do nothing */ - - } else if (err == DB_LOCK_WAIT) { - - return(NULL); - } else { - /* SQL error detected */ - fprintf(stderr, "SQL error %lu\n", (ulong) err); - - que_thr_handle_error(thr, DB_ERROR, NULL, 0); + if (err != DB_SUCCESS) { + thr_get_trx(thr)->error_state = err; return(NULL); } @@ -2029,7 +2019,7 @@ fetch_step( fprintf(stderr, "InnoDB: Error: fetch called on a closed cursor\n"); - que_thr_handle_error(thr, DB_ERROR, NULL, 0); + thr_get_trx(thr)->error_state = DB_ERROR; return(NULL); } diff --git a/row/row0upd.c b/row/row0upd.c index 7be2fb17a07..783a01bcaa0 100644 --- a/row/row0upd.c +++ b/row/row0upd.c @@ -1984,12 +1984,7 @@ row_upd_step( error_handling: trx->error_state = err; - if (err == DB_SUCCESS) { - /* Ok: do nothing */ - } else if (err == DB_LOCK_WAIT) { - - return(NULL); - } else { + if (err != DB_SUCCESS) { return(NULL); }