📄 trx0roll.c
字号:
if (!ins_undo || ins_undo->empty) { undo = upd_undo; } else if (!upd_undo || upd_undo->empty) { undo = ins_undo; } else if (ut_dulint_cmp(upd_undo->top_undo_no, ins_undo->top_undo_no) > 0) { undo = upd_undo; } else { undo = ins_undo; } if (!undo || undo->empty || (ut_dulint_cmp(limit, undo->top_undo_no) > 0)) { if ((trx->undo_no_arr)->n_used == 0) { /* Rollback is ending */ mutex_enter(&(rseg->mutex)); trx_roll_try_truncate(trx); mutex_exit(&(rseg->mutex)); } mutex_exit(&(trx->undo_mutex)); return(NULL); } if (undo == ins_undo) { is_insert = TRUE; } else { is_insert = FALSE; } *roll_ptr = trx_undo_build_roll_ptr(is_insert, (undo->rseg)->id, undo->top_page_no, undo->top_offset); mtr_start(&mtr); undo_rec = trx_roll_pop_top_rec(trx, undo, &mtr); undo_no = trx_undo_rec_get_undo_no(undo_rec); ut_ad(ut_dulint_cmp(ut_dulint_add(undo_no, 1), trx->undo_no) == 0); /* We print rollback progress info if we are in a crash recovery and the transaction has at least 1000 row operations to undo. */ if (trx == trx_roll_crash_recv_trx && trx_roll_max_undo_no > 1000) { progress_pct = 100 - (ulint) ((ut_conv_dulint_to_longlong(undo_no) * 100) / trx_roll_max_undo_no); if (progress_pct != trx_roll_progress_printed_pct) { if (trx_roll_progress_printed_pct == 0) { fprintf(stderr,"\nInnoDB: Progress in percents: %lu", (ulong) progress_pct); } else { fprintf(stderr, " %lu", (ulong) progress_pct); } fflush(stderr); trx_roll_progress_printed_pct = progress_pct; } } trx->undo_no = undo_no; if (!trx_undo_arr_store_info(trx, undo_no)) { /* A query thread is already processing this undo log record */ mutex_exit(&(trx->undo_mutex)); mtr_commit(&mtr); goto try_again; } undo_rec_copy = trx_undo_rec_copy(undo_rec, heap); mutex_exit(&(trx->undo_mutex)); mtr_commit(&mtr); return(undo_rec_copy);}/************************************************************************Reserves an undo log record for a query thread to undo. This should becalled if the query thread gets the undo log record not using the popfunction above. */ibooltrx_undo_rec_reserve(/*=================*/ /* out: TRUE if succeeded */ trx_t* trx, /* in: transaction */ dulint undo_no)/* in: undo number of the record */{ ibool ret; mutex_enter(&(trx->undo_mutex)); ret = trx_undo_arr_store_info(trx, undo_no); mutex_exit(&(trx->undo_mutex)); return(ret);}/***********************************************************************Releases a reserved undo record. */voidtrx_undo_rec_release(/*=================*/ trx_t* trx, /* in: transaction */ dulint undo_no)/* in: undo number */{ trx_undo_arr_t* arr; mutex_enter(&(trx->undo_mutex)); arr = trx->undo_no_arr; trx_undo_arr_remove_info(arr, undo_no); mutex_exit(&(trx->undo_mutex));}/*************************************************************************Starts a rollback operation. */ voidtrx_rollback(/*=========*/ trx_t* trx, /* in: transaction */ trx_sig_t* sig, /* in: signal starting the rollback */ 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 the passed value is NULL, the parameter is ignored */{ que_t* roll_graph; que_thr_t* thr;/* que_thr_t* thr2; */#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ ut_ad((trx->undo_no_arr == NULL) || ((trx->undo_no_arr)->n_used == 0)); /* Initialize the rollback field in the transaction */ if (sig->type == TRX_SIG_TOTAL_ROLLBACK) { trx->roll_limit = ut_dulint_zero; } else if (sig->type == TRX_SIG_ROLLBACK_TO_SAVEPT) { trx->roll_limit = (sig->savept).least_undo_no; } else if (sig->type == TRX_SIG_ERROR_OCCURRED) { trx->roll_limit = trx->last_sql_stat_start.least_undo_no; } else { ut_error; } ut_a(ut_dulint_cmp(trx->roll_limit, trx->undo_no) <= 0); trx->pages_undone = 0; if (trx->undo_no_arr == NULL) { trx->undo_no_arr = trx_undo_arr_create(); } /* Build a 'query' graph which will perform the undo operations */ roll_graph = trx_roll_graph_build(trx); trx->graph = roll_graph; trx->que_state = TRX_QUE_ROLLING_BACK; thr = que_fork_start_command(roll_graph); ut_ad(thr);/* thr2 = que_fork_start_command(roll_graph); ut_ad(thr2); */ if (next_thr && (*next_thr == NULL)) { *next_thr = thr;/* srv_que_task_enqueue_low(thr2); */ } else { srv_que_task_enqueue_low(thr);/* srv_que_task_enqueue_low(thr2); */ }}/********************************************************************Builds an undo 'query' graph for a transaction. The actual rollback isperformed by executing this query graph like a query subprocedure call.The reply about the completion of the rollback will be sent by thisgraph. */que_t*trx_roll_graph_build(/*=================*/ /* out, own: the query graph */ trx_t* trx) /* in: trx handle */{ mem_heap_t* heap; que_fork_t* fork; que_thr_t* thr;/* que_thr_t* thr2; */#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ heap = mem_heap_create(512); fork = que_fork_create(NULL, NULL, QUE_FORK_ROLLBACK, heap); fork->trx = trx; thr = que_thr_create(fork, heap);/* thr2 = que_thr_create(fork, heap); */ thr->child = row_undo_node_create(trx, thr, heap); /* thr2->child = row_undo_node_create(trx, thr2, heap); */ return(fork);}/*************************************************************************Finishes error processing after the necessary partial rollback has beendone. */staticvoidtrx_finish_error_processing(/*========================*/ trx_t* trx) /* in: transaction */{ trx_sig_t* sig; trx_sig_t* next_sig;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ sig = UT_LIST_GET_FIRST(trx->signals); while (sig != NULL) { next_sig = UT_LIST_GET_NEXT(signals, sig); if (sig->type == TRX_SIG_ERROR_OCCURRED) { trx_sig_remove(trx, sig); } sig = next_sig; } trx->que_state = TRX_QUE_RUNNING;}/*************************************************************************Finishes a partial rollback operation. */staticvoidtrx_finish_partial_rollback_off_kernel(/*===================================*/ trx_t* trx, /* in: transaction */ 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 this parameter is NULL, it is ignored */{ trx_sig_t* sig;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ sig = UT_LIST_GET_FIRST(trx->signals); /* Remove the signal from the signal queue and send reply message to it */ trx_sig_reply(sig, next_thr); trx_sig_remove(trx, sig); trx->que_state = TRX_QUE_RUNNING;}/********************************************************************Finishes a transaction rollback. */voidtrx_finish_rollback_off_kernel(/*===========================*/ que_t* graph, /* in: undo graph which can now be freed */ trx_t* trx, /* in: transaction */ 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 this parameter is NULL, it is ignored */{ trx_sig_t* sig; trx_sig_t* next_sig; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ ut_a(trx->undo_no_arr == NULL || trx->undo_no_arr->n_used == 0); /* Free the memory reserved by the undo graph */ que_graph_free(graph); sig = UT_LIST_GET_FIRST(trx->signals); if (sig->type == TRX_SIG_ROLLBACK_TO_SAVEPT) { trx_finish_partial_rollback_off_kernel(trx, next_thr); return; } else if (sig->type == TRX_SIG_ERROR_OCCURRED) { trx_finish_error_processing(trx); return; }#ifdef UNIV_DEBUG if (lock_print_waits) { fprintf(stderr, "Trx %lu rollback finished\n", (ulong) ut_dulint_get_low(trx->id)); }#endif /* UNIV_DEBUG */ trx_commit_off_kernel(trx); /* Remove all TRX_SIG_TOTAL_ROLLBACK signals from the signal queue and send reply messages to them */ trx->que_state = TRX_QUE_RUNNING; while (sig != NULL) { next_sig = UT_LIST_GET_NEXT(signals, sig); if (sig->type == TRX_SIG_TOTAL_ROLLBACK) { trx_sig_reply(sig, next_thr); trx_sig_remove(trx, sig); } sig = next_sig; }}/*************************************************************************Creates a rollback command node struct. */roll_node_t*roll_node_create(/*=============*/ /* out, own: rollback node struct */ mem_heap_t* heap) /* in: mem heap where created */{ roll_node_t* node; node = mem_heap_alloc(heap, sizeof(roll_node_t)); node->common.type = QUE_NODE_ROLLBACK; node->state = ROLL_NODE_SEND; node->partial = FALSE; return(node);}/***************************************************************Performs an execution step for a rollback command node in a query graph. */que_thr_t*trx_rollback_step(/*==============*/ /* out: query thread to run next, or NULL */ que_thr_t* thr) /* in: query thread */{ roll_node_t* node; ibool success; ulint sig_no; trx_savept_t* savept; node = thr->run_node; ut_ad(que_node_get_type(node) == QUE_NODE_ROLLBACK); if (thr->prev_node == que_node_get_parent(node)) { node->state = ROLL_NODE_SEND; } if (node->state == ROLL_NODE_SEND) { mutex_enter(&kernel_mutex); node->state = ROLL_NODE_WAIT; if (node->partial) { sig_no = TRX_SIG_ROLLBACK_TO_SAVEPT; savept = &(node->savept); } else { sig_no = TRX_SIG_TOTAL_ROLLBACK; savept = NULL; } /* Send a rollback signal to the transaction */ success = trx_sig_send(thr_get_trx(thr), sig_no, TRX_SIG_SELF, thr, savept, NULL); thr->state = QUE_THR_SIG_REPLY_WAIT; mutex_exit(&kernel_mutex); if (!success) { /* Error in delivering the rollback signal */ que_thr_handle_error(thr, DB_ERROR, NULL, 0); } return(NULL); } ut_ad(node->state == ROLL_NODE_WAIT); thr->run_node = que_node_get_parent(node); return(thr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -