📄 trx0roll.c
字号:
mutex_exit(&kernel_mutex); if (trx == NULL) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Rollback of non-prepared transactions completed\n"); mem_heap_free(heap); goto leave_function; } trx->sess = trx_dummy_sess; if (trx->conc_state == TRX_COMMITTED_IN_MEMORY) { fprintf(stderr, "InnoDB: Cleaning up trx with id %lu %lu\n", (ulong) ut_dulint_get_high(trx->id), (ulong) ut_dulint_get_low(trx->id)); trx_cleanup_at_db_startup(trx); mem_heap_free(heap); goto loop; } fork = que_fork_create(NULL, NULL, QUE_FORK_RECOVERY, heap); fork->trx = trx; thr = que_thr_create(fork, heap); roll_node = roll_node_create(heap); thr->child = roll_node; roll_node->common.parent = thr; mutex_enter(&kernel_mutex); trx->graph = fork; ut_a(thr == que_fork_start_command(fork)); trx_roll_crash_recv_trx = trx; trx_roll_max_undo_no = ut_conv_dulint_to_longlong(trx->undo_no); trx_roll_progress_printed_pct = 0; rows_to_undo = trx_roll_max_undo_no; if (rows_to_undo > 1000000000) { rows_to_undo = rows_to_undo / 1000000; unit = "M"; } ut_print_timestamp(stderr); fprintf(stderr," InnoDB: Rolling back trx with id %lu %lu, %lu%s rows to undo\n", (ulong) ut_dulint_get_high(trx->id), (ulong) ut_dulint_get_low(trx->id), (ulong) rows_to_undo, unit); mutex_exit(&kernel_mutex); trx->mysql_thread_id = os_thread_get_curr_id(); trx->mysql_process_no = os_proc_get_number(); if (trx->dict_operation) { row_mysql_lock_data_dictionary(trx); } que_run_threads(thr); mutex_enter(&kernel_mutex); while (trx->que_state != TRX_QUE_RUNNING) { mutex_exit(&kernel_mutex); fprintf(stderr, "InnoDB: Waiting for rollback of trx id %lu to end\n", (ulong) ut_dulint_get_low(trx->id)); os_thread_sleep(100000); mutex_enter(&kernel_mutex); } mutex_exit(&kernel_mutex); if (trx->dict_operation) { /* If the transaction was for a dictionary operation, we drop the relevant table, if it still exists */ fprintf(stderr,"InnoDB: Dropping table with id %lu %lu in recovery if it exists\n", (ulong) ut_dulint_get_high(trx->table_id), (ulong) ut_dulint_get_low(trx->table_id)); table = dict_table_get_on_id_low(trx->table_id, trx); if (table) { fputs("InnoDB: Table found: dropping table ", stderr); ut_print_name(stderr, trx, table->name); fputs(" in recovery\n", stderr); err = row_drop_table_for_mysql(table->name, trx, TRUE); ut_a(err == (int) DB_SUCCESS); } } if (trx->dict_operation) { row_mysql_unlock_data_dictionary(trx); } fprintf(stderr, "\nInnoDB: Rolling back of trx id %lu %lu completed\n", (ulong) ut_dulint_get_high(trx->id), (ulong) ut_dulint_get_low(trx->id)); mem_heap_free(heap); trx_roll_crash_recv_trx = NULL; goto loop;leave_function: /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ os_thread_exit(NULL); /* The following is dummy code to keep the compiler happy: */#ifndef __WIN__ return(NULL);#else return(0);#endif} /***********************************************************************Creates an undo number array. */trx_undo_arr_t*trx_undo_arr_create(void)/*=====================*/{ trx_undo_arr_t* arr; mem_heap_t* heap; ulint i; heap = mem_heap_create(1024); arr = mem_heap_alloc(heap, sizeof(trx_undo_arr_t)); arr->infos = mem_heap_alloc(heap, sizeof(trx_undo_inf_t) * UNIV_MAX_PARALLELISM); arr->n_cells = UNIV_MAX_PARALLELISM; arr->n_used = 0; arr->heap = heap; for (i = 0; i < UNIV_MAX_PARALLELISM; i++) { (trx_undo_arr_get_nth_info(arr, i))->in_use = FALSE; } return(arr);}/***********************************************************************Frees an undo number array. */voidtrx_undo_arr_free(/*==============*/ trx_undo_arr_t* arr) /* in: undo number array */{ ut_ad(arr->n_used == 0); mem_heap_free(arr->heap);}/***********************************************************************Stores info of an undo log record to the array if it is not stored yet. */staticibooltrx_undo_arr_store_info(/*====================*/ /* out: FALSE if the record already existed in the array */ trx_t* trx, /* in: transaction */ dulint undo_no)/* in: undo number */{ trx_undo_inf_t* cell; trx_undo_inf_t* stored_here; trx_undo_arr_t* arr; ulint n_used; ulint n; ulint i; n = 0; arr = trx->undo_no_arr; n_used = arr->n_used; stored_here = NULL; for (i = 0;; i++) { cell = trx_undo_arr_get_nth_info(arr, i); if (!cell->in_use) { if (!stored_here) { /* Not in use, we may store here */ cell->undo_no = undo_no; cell->in_use = TRUE; arr->n_used++; stored_here = cell; } } else { n++; if (0 == ut_dulint_cmp(cell->undo_no, undo_no)) { if (stored_here) { stored_here->in_use = FALSE; ut_ad(arr->n_used > 0); arr->n_used--; } ut_ad(arr->n_used == n_used); return(FALSE); } } if (n == n_used && stored_here) { ut_ad(arr->n_used == 1 + n_used); return(TRUE); } }}/***********************************************************************Removes an undo number from the array. */staticvoidtrx_undo_arr_remove_info(/*=====================*/ trx_undo_arr_t* arr, /* in: undo number array */ dulint undo_no)/* in: undo number */{ trx_undo_inf_t* cell; ulint n_used; ulint n; ulint i; n_used = arr->n_used; n = 0; for (i = 0;; i++) { cell = trx_undo_arr_get_nth_info(arr, i); if (cell->in_use && 0 == ut_dulint_cmp(cell->undo_no, undo_no)) { cell->in_use = FALSE; ut_ad(arr->n_used > 0); arr->n_used--; return; } }}/***********************************************************************Gets the biggest undo number in an array. */staticdulinttrx_undo_arr_get_biggest(/*=====================*/ /* out: biggest value, ut_dulint_zero if the array is empty */ trx_undo_arr_t* arr) /* in: undo number array */{ trx_undo_inf_t* cell; ulint n_used; dulint biggest; ulint n; ulint i; n = 0; n_used = arr->n_used; biggest = ut_dulint_zero; for (i = 0;; i++) { cell = trx_undo_arr_get_nth_info(arr, i); if (cell->in_use) { n++; if (ut_dulint_cmp(cell->undo_no, biggest) > 0) { biggest = cell->undo_no; } } if (n == n_used) { return(biggest); } }}/***************************************************************************Tries truncate the undo logs. */voidtrx_roll_try_truncate(/*==================*/ trx_t* trx) /* in: transaction */{ trx_undo_arr_t* arr; dulint limit; dulint biggest; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(trx->undo_mutex))); ut_ad(mutex_own(&((trx->rseg)->mutex)));#endif /* UNIV_SYNC_DEBUG */ trx->pages_undone = 0; arr = trx->undo_no_arr; limit = trx->undo_no; if (arr->n_used > 0) { biggest = trx_undo_arr_get_biggest(arr); if (ut_dulint_cmp(biggest, limit) >= 0) { limit = ut_dulint_add(biggest, 1); } } if (trx->insert_undo) { trx_undo_truncate_end(trx, trx->insert_undo, limit); } if (trx->update_undo) { trx_undo_truncate_end(trx, trx->update_undo, limit); }}/***************************************************************************Pops the topmost undo log record in a single undo log and updates the infoabout the topmost record in the undo log memory struct. */statictrx_undo_rec_t*trx_roll_pop_top_rec(/*=================*/ /* out: undo log record, the page s-latched */ trx_t* trx, /* in: transaction */ trx_undo_t* undo, /* in: undo log */ mtr_t* mtr) /* in: mtr */{ page_t* undo_page; ulint offset; trx_undo_rec_t* prev_rec; page_t* prev_rec_page;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(trx->undo_mutex)));#endif /* UNIV_SYNC_DEBUG */ undo_page = trx_undo_page_get_s_latched(undo->space, undo->top_page_no, mtr); offset = undo->top_offset;/* fprintf(stderr, "Thread %lu undoing trx %lu undo record %lu\n", os_thread_get_curr_id(), ut_dulint_get_low(trx->id), ut_dulint_get_low(undo->top_undo_no)); */ prev_rec = trx_undo_get_prev_rec(undo_page + offset, undo->hdr_page_no, undo->hdr_offset, mtr); if (prev_rec == NULL) { undo->empty = TRUE; } else { prev_rec_page = buf_frame_align(prev_rec); if (prev_rec_page != undo_page) { trx->pages_undone++; } undo->top_page_no = buf_frame_get_page_no(prev_rec_page); undo->top_offset = prev_rec - prev_rec_page; undo->top_undo_no = trx_undo_rec_get_undo_no(prev_rec); } return(undo_page + offset);}/************************************************************************Pops the topmost record when the two undo logs of a transaction are seenas a single stack of records ordered by their undo numbers. Inserts theundo number of the popped undo record to the array of currently processedundo numbers in the transaction. When the query thread finishes processingof this undo record, it must be released with trx_undo_rec_release. */trx_undo_rec_t*trx_roll_pop_top_rec_of_trx(/*========================*/ /* out: undo log record copied to heap, NULL if none left, or if the undo number of the top record would be less than the limit */ trx_t* trx, /* in: transaction */ dulint limit, /* in: least undo number we need */ dulint* roll_ptr,/* out: roll pointer to undo record */ mem_heap_t* heap) /* in: memory heap where copied */{ trx_undo_t* undo; trx_undo_t* ins_undo; trx_undo_t* upd_undo; trx_undo_rec_t* undo_rec; trx_undo_rec_t* undo_rec_copy; dulint undo_no; ibool is_insert; trx_rseg_t* rseg; ulint progress_pct; mtr_t mtr; rseg = trx->rseg;try_again: mutex_enter(&(trx->undo_mutex)); if (trx->pages_undone >= TRX_ROLL_TRUNC_THRESHOLD) { mutex_enter(&(rseg->mutex)); trx_roll_try_truncate(trx); mutex_exit(&(rseg->mutex)); } ins_undo = trx->insert_undo; upd_undo = trx->update_undo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -