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"
|
"CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n"
|
||||||
"COMMIT WORK;\n"
|
"COMMIT WORK;\n"
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
fprintf(stderr, "InnoDB: error %lu in creation\n",
|
fprintf(stderr, "InnoDB: error %lu in creation\n",
|
||||||
@@ -1242,7 +1242,7 @@ dict_foreign_eval_sql(
|
|||||||
ulint error;
|
ulint error;
|
||||||
FILE* ef = dict_foreign_err_file;
|
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) {
|
if (error == DB_DUPLICATE_KEY) {
|
||||||
mutex_enter(&dict_foreign_err_mutex);
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
|||||||
@@ -143,14 +143,12 @@ que_thr_stop_for_mysql(
|
|||||||
/*===================*/
|
/*===================*/
|
||||||
que_thr_t* thr); /* in: query thread */
|
que_thr_t* thr); /* in: query thread */
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
Runs query threads. Note that the individual query thread which is run
|
Run a query thread. Handles lock waits. */
|
||||||
within this function may change if, e.g., the OS thread executing this
|
|
||||||
function uses a threshold amount of resources. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
que_run_threads(
|
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
|
After signal handling is finished, returns control to a query graph error
|
||||||
handling routine. (Currently, just returns the control to the root of the
|
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
|
que_t* fork); /* in: query graph which was run before signal
|
||||||
handling started, NULL not allowed */
|
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
|
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
|
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
|
the wait state of a query thread waiting for a lock or a stored procedure
|
||||||
@@ -337,9 +322,14 @@ Evaluate the given SQL */
|
|||||||
ulint
|
ulint
|
||||||
que_eval_sql(
|
que_eval_sql(
|
||||||
/*=========*/
|
/*=========*/
|
||||||
pars_info_t* info, /* out: error code or DB_SUCCESS */
|
/* out: error code or DB_SUCCESS */
|
||||||
const char* sql, /* in: info struct, or NULL */
|
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 */
|
trx_t* trx); /* in: trx */
|
||||||
|
|
||||||
/* Query graph query thread node: the fields are protected by the kernel
|
/* Query graph query thread node: the fields are protected by the kernel
|
||||||
mutex with the exceptions named below */
|
mutex with the exceptions named below */
|
||||||
|
|
||||||
|
|||||||
140
que/que0que.c
140
que/que0que.c
@@ -715,27 +715,6 @@ que_graph_try_free(
|
|||||||
return(FALSE);
|
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. */
|
Performs an execution step on a thr node. */
|
||||||
static
|
static
|
||||||
@@ -813,11 +792,10 @@ que_thr_move_to_run_state(
|
|||||||
Decrements the query thread reference counts in the query graph and the
|
Decrements the query thread reference counts in the query graph and the
|
||||||
transaction. May start signal handling, e.g., a rollback.
|
transaction. May start signal handling, e.g., a rollback.
|
||||||
*** NOTE ***:
|
*** NOTE ***:
|
||||||
This and que_thr_stop_for_mysql are
|
This and que_thr_stop_for_mysql are the only functions where the reference
|
||||||
the only functions where the reference count can be decremented and
|
count can be decremented and this function may only be called from inside
|
||||||
this function may only be called from inside que_run_threads or
|
que_run_threads or que_thr_check_if_switch! These restrictions exist to make
|
||||||
que_thr_check_if_switch! These restrictions exist to make the rollback code
|
the rollback code easier to maintain. */
|
||||||
easier to maintain. */
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
que_thr_dec_refer_count(
|
que_thr_dec_refer_count(
|
||||||
@@ -836,7 +814,7 @@ que_thr_dec_refer_count(
|
|||||||
ibool stopped;
|
ibool stopped;
|
||||||
|
|
||||||
fork = thr->common.parent;
|
fork = thr->common.parent;
|
||||||
trx = thr->graph->trx;
|
trx = thr_get_trx(thr);
|
||||||
sess = trx->sess;
|
sess = trx->sess;
|
||||||
|
|
||||||
mutex_enter(&kernel_mutex);
|
mutex_enter(&kernel_mutex);
|
||||||
@@ -856,6 +834,12 @@ que_thr_dec_refer_count(
|
|||||||
stderr); */
|
stderr); */
|
||||||
|
|
||||||
if (next_thr && *next_thr == NULL) {
|
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;
|
*next_thr = thr;
|
||||||
} else {
|
} else {
|
||||||
ut_a(0);
|
ut_a(0);
|
||||||
@@ -1200,7 +1184,10 @@ que_thr_step(
|
|||||||
trx_t* trx;
|
trx_t* trx;
|
||||||
ulint type;
|
ulint type;
|
||||||
|
|
||||||
|
trx = thr_get_trx(thr);
|
||||||
|
|
||||||
ut_ad(thr->state == QUE_THR_RUNNING);
|
ut_ad(thr->state == QUE_THR_RUNNING);
|
||||||
|
ut_a(trx->error_state == DB_SUCCESS);
|
||||||
|
|
||||||
thr->resource++;
|
thr->resource++;
|
||||||
|
|
||||||
@@ -1236,7 +1223,6 @@ que_thr_step(
|
|||||||
threads doing updating or inserting at the moment! */
|
threads doing updating or inserting at the moment! */
|
||||||
|
|
||||||
if (thr->prev_node == que_node_get_parent(node)) {
|
if (thr->prev_node == que_node_get_parent(node)) {
|
||||||
trx = thr_get_trx(thr);
|
|
||||||
trx->last_sql_stat_start.least_undo_no
|
trx->last_sql_stat_start.least_undo_no
|
||||||
= trx->undo_no;
|
= trx->undo_no;
|
||||||
}
|
}
|
||||||
@@ -1298,24 +1284,28 @@ que_thr_step(
|
|||||||
old_thr->prev_node = node;
|
old_thr->prev_node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thr) {
|
||||||
|
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
return(thr);
|
return(thr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
Runs query threads. Note that the individual query thread which is run
|
Run a query thread until it finishes or encounters e.g. a lock wait. */
|
||||||
within this function may change if, e.g., the OS thread executing this
|
static
|
||||||
function uses a threshold amount of resources. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
que_run_threads(
|
que_run_threads_low(
|
||||||
/*============*/
|
/*================*/
|
||||||
que_thr_t* thr) /* in: query thread which is run initially */
|
que_thr_t* thr) /* in: query thread */
|
||||||
{
|
{
|
||||||
que_thr_t* next_thr;
|
que_thr_t* next_thr;
|
||||||
ulint cumul_resource;
|
ulint cumul_resource;
|
||||||
ulint loop_count;
|
ulint loop_count;
|
||||||
|
|
||||||
ut_ad(thr->state == QUE_THR_RUNNING);
|
ut_ad(thr->state == QUE_THR_RUNNING);
|
||||||
|
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
|
||||||
|
|
||||||
#ifdef UNIV_SYNC_DEBUG
|
#ifdef UNIV_SYNC_DEBUG
|
||||||
ut_ad(!mutex_own(&kernel_mutex));
|
ut_ad(!mutex_own(&kernel_mutex));
|
||||||
#endif /* UNIV_SYNC_DEBUG */
|
#endif /* UNIV_SYNC_DEBUG */
|
||||||
@@ -1340,10 +1330,15 @@ loop:
|
|||||||
next_thr = que_thr_step(thr);
|
next_thr = que_thr_step(thr);
|
||||||
/*-------------------------*/
|
/*-------------------------*/
|
||||||
|
|
||||||
|
ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS));
|
||||||
|
|
||||||
loop_count++;
|
loop_count++;
|
||||||
|
|
||||||
if (next_thr != thr) {
|
if (next_thr != thr) {
|
||||||
ut_a(next_thr == NULL);
|
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);
|
que_thr_dec_refer_count(thr, &next_thr);
|
||||||
|
|
||||||
if (next_thr == NULL) {
|
if (next_thr == NULL) {
|
||||||
@@ -1359,20 +1354,89 @@ loop:
|
|||||||
goto 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
|
ulint
|
||||||
que_eval_sql(
|
que_eval_sql(
|
||||||
/*=========*/
|
/*=========*/
|
||||||
pars_info_t* info, /* out: error code or DB_SUCCESS */
|
/* out: error code or DB_SUCCESS */
|
||||||
const char* sql, /* in: info struct, or NULL */
|
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 */
|
trx_t* trx) /* in: trx */
|
||||||
{
|
{
|
||||||
que_thr_t* thr;
|
que_thr_t* thr;
|
||||||
que_t* graph;
|
que_t* graph;
|
||||||
|
|
||||||
|
ut_a(trx->error_state == DB_SUCCESS);
|
||||||
|
|
||||||
|
if (reserve_dict_mutex) {
|
||||||
|
mutex_enter(&dict_sys->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
graph = pars_sql(info, sql);
|
graph = pars_sql(info, sql);
|
||||||
|
|
||||||
|
if (reserve_dict_mutex) {
|
||||||
|
mutex_exit(&dict_sys->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
ut_a(graph);
|
ut_a(graph);
|
||||||
|
|
||||||
graph->trx = trx;
|
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"
|
" WHERE TABLE_ID = old_id;\n"
|
||||||
"COMMIT WORK;\n"
|
"COMMIT WORK;\n"
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
trx->error_state = 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"
|
" WHERE TABLE_ID = :old_id;\n"
|
||||||
"COMMIT WORK;\n"
|
"COMMIT WORK;\n"
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
trx->error_state = 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"
|
"DELETE FROM SYS_TABLES WHERE ID = table_id;\n"
|
||||||
"COMMIT WORK;\n"
|
"COMMIT WORK;\n"
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
ut_a(err == DB_OUT_OF_FILE_SPACE);
|
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_COLS WHERE ID = :id;\n"
|
||||||
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
|
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, trx));
|
, FALSE, trx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
@@ -3609,7 +3609,7 @@ row_rename_table_for_mysql(
|
|||||||
"UPDATE SYS_TABLES SET NAME = :new_table_name\n"
|
"UPDATE SYS_TABLES SET NAME = :new_table_name\n"
|
||||||
" WHERE NAME = :old_table_name;\n"
|
" WHERE NAME = :old_table_name;\n"
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
@@ -3683,7 +3683,7 @@ row_rename_table_for_mysql(
|
|||||||
"WHERE REF_NAME = :old_table_name\n"
|
"WHERE REF_NAME = :old_table_name\n"
|
||||||
" AND TO_BINARY(REF_NAME) = TO_BINARY(:old_table_name);\n"
|
" AND TO_BINARY(REF_NAME) = TO_BINARY(:old_table_name);\n"
|
||||||
"END;\n"
|
"END;\n"
|
||||||
, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
} else if (n_constraints_to_drop > 0) {
|
} else if (n_constraints_to_drop > 0) {
|
||||||
/* Drop some constraints of tmp tables. */
|
/* Drop some constraints of tmp tables. */
|
||||||
|
|||||||
@@ -1920,9 +1920,8 @@ row_sel_step(
|
|||||||
err = lock_table(0, table_node->table,
|
err = lock_table(0, table_node->table,
|
||||||
i_lock_mode, thr);
|
i_lock_mode, thr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
|
thr_get_trx(thr)->error_state = err;
|
||||||
|
|
||||||
que_thr_handle_error(thr, DB_ERROR,
|
|
||||||
NULL, 0);
|
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1958,17 +1957,8 @@ row_sel_step(
|
|||||||
|
|
||||||
thr->graph->last_sel_node = node;
|
thr->graph->last_sel_node = node;
|
||||||
|
|
||||||
if (err == DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
/* Ok: do nothing */
|
thr_get_trx(thr)->error_state = err;
|
||||||
|
|
||||||
} 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);
|
|
||||||
|
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
@@ -2029,7 +2019,7 @@ fetch_step(
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: fetch called on a closed cursor\n");
|
"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);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1984,12 +1984,7 @@ row_upd_step(
|
|||||||
error_handling:
|
error_handling:
|
||||||
trx->error_state = err;
|
trx->error_state = err;
|
||||||
|
|
||||||
if (err == DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
/* Ok: do nothing */
|
|
||||||
} else if (err == DB_LOCK_WAIT) {
|
|
||||||
|
|
||||||
return(NULL);
|
|
||||||
} else {
|
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user