mirror of
https://github.com/MariaDB/server.git
synced 2025-12-10 19:44:09 +03:00
Add support for lock waits in the SQL parser.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
140
que/que0que.c
140
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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user