void que_thr_end_wait_no_next_thr( /*=========================*/ que_thr_t* thr) /* in: query thread in the QUE_THR_LOCK_WAIT, or QUE_THR_PROCEDURE_WAIT, or QUE_THR_SIG_REPLY_WAIT state */ { ibool was_active; ut_a(thr->state == QUE_THR_LOCK_WAIT); /* In MySQL this is the only possible state here */ #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(thr); ut_ad((thr->state == QUE_THR_LOCK_WAIT) || (thr->state == QUE_THR_PROCEDURE_WAIT) || (thr->state == QUE_THR_SIG_REPLY_WAIT)); was_active = thr->is_active; que_thr_move_to_run_state(thr); if (was_active) { return; } /* In MySQL we let the OS thread (not just the query thread) to wait for the lock to be released: */ srv_release_mysql_thread_if_suspended(thr); /* srv_que_task_enqueue_low(thr); */ }
/************************************************************************** Inits a query thread for a command. */ UNIV_INLINE void que_thr_init_command( /*=================*/ que_thr_t* thr) /* in: query thread */ { thr->run_node = thr; thr->prev_node = thr->common.parent; que_thr_move_to_run_state(thr); }
void que_thr_end_wait( /*=============*/ que_thr_t* thr, /* in: query thread in the QUE_THR_LOCK_WAIT, or QUE_THR_PROCEDURE_WAIT, or QUE_THR_SIG_REPLY_WAIT state */ que_thr_t** next_thr) /* in/out: next query thread to run; if the value which is passed in is a pointer to a NULL pointer, then the calling function can start running a new query thread; if NULL is passed as the parameter, it is ignored */ { ibool was_active; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(thr); ut_ad((thr->state == QUE_THR_LOCK_WAIT) || (thr->state == QUE_THR_PROCEDURE_WAIT) || (thr->state == QUE_THR_SIG_REPLY_WAIT)); ut_ad(thr->run_node); thr->prev_node = thr->run_node; was_active = thr->is_active; que_thr_move_to_run_state(thr); if (was_active) { return; } if (next_thr && *next_thr == NULL) { *next_thr = thr; } else { ut_a(0); srv_que_task_enqueue_low(thr); } }
que_thr_t* que_fork_start_command( /*===================*/ /* out: a query thread of the graph moved to QUE_THR_RUNNING state, or NULL; the query thread should be executed by que_run_threads by the caller */ que_fork_t* fork) /* in: a query fork */ { que_thr_t* thr; fork->state = QUE_FORK_ACTIVE; fork->last_sel_node = NULL; /* Choose the query thread to run: usually there is just one thread, but in a parallelized select, which necessarily is non-scrollable, there may be several to choose from */ /*--------------------------------------------------------------- First we try to find a query thread in the QUE_THR_COMMAND_WAIT state */ thr = UT_LIST_GET_FIRST(fork->thrs); while (thr != NULL) { if (thr->state == QUE_THR_COMMAND_WAIT) { /* We have to send the initial message to query thread to start it */ que_thr_init_command(thr); return(thr); } ut_ad(thr->state != QUE_THR_LOCK_WAIT); thr = UT_LIST_GET_NEXT(thrs, thr); } /*---------------------------------------------------------------- Then we try to find a query thread in the QUE_THR_SUSPENDED state */ thr = UT_LIST_GET_FIRST(fork->thrs); while (thr != NULL) { if (thr->state == QUE_THR_SUSPENDED) { /* In this case the execution of the thread was suspended: no initial message is needed because execution can continue from where it was left */ que_thr_move_to_run_state(thr); return(thr); } thr = UT_LIST_GET_NEXT(thrs, thr); } /*----------------------------------------------------------------- Then we try to find a query thread in the QUE_THR_COMPLETED state */ thr = UT_LIST_GET_FIRST(fork->thrs); while (thr != NULL) { if (thr->state == QUE_THR_COMPLETED) { que_thr_init_command(thr); return(thr); } thr = UT_LIST_GET_NEXT(thrs, thr); } /* Else we return NULL */ return(NULL); }
enum db_err ib_trx_lock_table_with_retry( /*=========================*/ trx_t* trx, /*!< in/out: transaction */ dict_table_t* table, /*!< in: table to lock */ enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */ { que_thr_t* thr; enum db_err err; mem_heap_t* heap; sel_node_t* node; ut_ad(trx->client_thread_id == os_thread_get_curr_id()); heap = mem_heap_create(512); trx->op_info = "setting table lock"; node = sel_node_create(heap); thr = pars_complete_graph_for_exec(node, trx, heap); thr->graph->state = QUE_FORK_ACTIVE; /* We use the select query graph as the dummy graph needed in the lock module call */ thr = que_fork_get_first_thr(que_node_get_parent(thr)); que_thr_move_to_run_state(thr); run_again: thr->run_node = thr; thr->prev_node = thr->common.parent; err = lock_table(0, table, mode, thr); trx->error_state = err; if (UNIV_LIKELY(err == DB_SUCCESS)) { que_thr_stop_for_client_no_error(thr, trx); } else { que_thr_stop_client(thr); if (err != DB_QUE_THR_SUSPENDED) { ibool was_lock_wait; was_lock_wait = ib_handle_errors(&err, trx, thr, NULL); if (was_lock_wait) { goto run_again; } } else { que_thr_t* run_thr; que_node_t* parent; parent = que_node_get_parent(thr); run_thr = que_fork_start_command(parent); ut_a(run_thr == thr); /* There was a lock wait but the thread was not in a ready to run or running state. */ trx->error_state = DB_LOCK_WAIT; goto run_again; } } que_graph_free(thr->graph); trx->op_info = ""; return(err); }
/**********************************************************************//** Starts execution of a command in a query fork. Picks a query thread which is not in the QUE_THR_RUNNING state and moves it to that state. If none can be chosen, a situation which may arise in parallelized fetches, NULL is returned. @return a query thread of the graph moved to QUE_THR_RUNNING state, or NULL; the query thread should be executed by que_run_threads by the caller */ UNIV_INTERN que_thr_t* que_fork_start_command( /*===================*/ que_fork_t* fork) /*!< in: a query fork */ { que_thr_t* thr; que_thr_t* suspended_thr = NULL; que_thr_t* completed_thr = NULL; fork->state = QUE_FORK_ACTIVE; fork->last_sel_node = NULL; suspended_thr = NULL; completed_thr = NULL; /* Choose the query thread to run: usually there is just one thread, but in a parallelized select, which necessarily is non-scrollable, there may be several to choose from */ /* First we try to find a query thread in the QUE_THR_COMMAND_WAIT state. Then we try to find a query thread in the QUE_THR_SUSPENDED state, finally we try to find a query thread in the QUE_THR_COMPLETED state */ thr = UT_LIST_GET_FIRST(fork->thrs); /* We make a single pass over the thr list within which we note which threads are ready to run. */ while (thr) { switch (thr->state) { case QUE_THR_COMMAND_WAIT: /* We have to send the initial message to query thread to start it */ que_thr_init_command(thr); return(thr); case QUE_THR_SUSPENDED: /* In this case the execution of the thread was suspended: no initial message is needed because execution can continue from where it was left */ if (!suspended_thr) { suspended_thr = thr; } break; case QUE_THR_COMPLETED: if (!completed_thr) { completed_thr = thr; } break; case QUE_THR_LOCK_WAIT: ut_error; } thr = UT_LIST_GET_NEXT(thrs, thr); } if (suspended_thr) { thr = suspended_thr; que_thr_move_to_run_state(thr); } else if (completed_thr) { thr = completed_thr; que_thr_init_command(thr); } return(thr); }