📄 trx0roll.c
字号:
/******************************************************Transaction rollback(c) 1996 Innobase OyCreated 3/26/1996 Heikki Tuuri*******************************************************/#include "trx0roll.h"#ifdef UNIV_NONINL#include "trx0roll.ic"#endif#include "fsp0fsp.h"#include "mach0data.h"#include "trx0rseg.h"#include "trx0trx.h"#include "trx0undo.h"#include "trx0rec.h"#include "que0que.h"#include "usr0sess.h"#include "srv0que.h"#include "srv0start.h"#include "row0undo.h"#include "row0mysql.h"#include "lock0lock.h"#include "pars0pars.h"/* This many pages must be undone before a truncate is tried within rollback */#define TRX_ROLL_TRUNC_THRESHOLD 1/* In crash recovery, the current trx to be rolled back */trx_t* trx_roll_crash_recv_trx = NULL;/* In crash recovery we set this to the undo n:o of the current trx to berolled back. Then we can print how many % the rollback has progressed. */ib_longlong trx_roll_max_undo_no;/* Auxiliary variable which tells the previous progress % we printed */ulint trx_roll_progress_printed_pct;/***********************************************************************Rollback a transaction used in MySQL. */inttrx_general_rollback_for_mysql(/*===========================*/ /* out: error code or DB_SUCCESS */ trx_t* trx, /* in: transaction handle */ ibool partial,/* in: TRUE if partial rollback requested */ trx_savept_t* savept) /* in: pointer to savepoint undo number, if partial rollback requested */{#ifndef UNIV_HOTBACKUP mem_heap_t* heap; que_thr_t* thr; roll_node_t* roll_node; /* Tell Innobase server that there might be work for utility threads: */ srv_active_wake_master_thread(); trx_start_if_not_started(trx); heap = mem_heap_create(512); roll_node = roll_node_create(heap); roll_node->partial = partial; if (partial) { roll_node->savept = *savept; } trx->error_state = DB_SUCCESS; thr = pars_complete_graph_for_exec(roll_node, trx, heap); ut_a(thr == que_fork_start_command(que_node_get_parent(thr))); que_run_threads(thr); mutex_enter(&kernel_mutex); while (trx->que_state != TRX_QUE_RUNNING) { mutex_exit(&kernel_mutex); os_thread_sleep(100000); mutex_enter(&kernel_mutex); } mutex_exit(&kernel_mutex); mem_heap_free(heap); ut_a(trx->error_state == DB_SUCCESS); /* Tell Innobase server that there might be work for utility threads: */ srv_active_wake_master_thread(); return((int) trx->error_state);#else /* UNIV_HOTBACKUP */ /* This function depends on MySQL code that is not included in InnoDB Hot Backup builds. Besides, this function should never be called in InnoDB Hot Backup. */ ut_error;#endif /* UNIV_HOTBACKUP */}/***********************************************************************Rollback a transaction used in MySQL. */inttrx_rollback_for_mysql(/*===================*/ /* out: error code or DB_SUCCESS */ trx_t* trx) /* in: transaction handle */{ int err; if (trx->conc_state == TRX_NOT_STARTED) { return(DB_SUCCESS); } trx->op_info = "rollback"; err = trx_general_rollback_for_mysql(trx, FALSE, NULL); trx->op_info = ""; return(err);} /***********************************************************************Rollback the latest SQL statement for MySQL. */inttrx_rollback_last_sql_stat_for_mysql(/*=================================*/ /* out: error code or DB_SUCCESS */ trx_t* trx) /* in: transaction handle */{ int err; if (trx->conc_state == TRX_NOT_STARTED) { return(DB_SUCCESS); } trx->op_info = "rollback of SQL statement"; err = trx_general_rollback_for_mysql(trx, TRUE, &(trx->last_sql_stat_start)); /* The following call should not be needed, but we play safe: */ trx_mark_sql_stat_end(trx); trx->op_info = ""; return(err);}/***********************************************************************Frees savepoint structs. */voidtrx_roll_savepoints_free(/*=====================*/ trx_t* trx, /* in: transaction handle */ trx_named_savept_t* savep) /* in: free all savepoints > this one; if this is NULL, free all savepoints of trx */{ trx_named_savept_t* next_savep; if (savep == NULL) { savep = UT_LIST_GET_FIRST(trx->trx_savepoints); } else { savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } while (savep != NULL) { next_savep = UT_LIST_GET_NEXT(trx_savepoints, savep); UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); mem_free(savep->name); mem_free(savep); savep = next_savep; }}/***********************************************************************Rolls back a transaction back to a named savepoint. Modifications after thesavepoint are undone but InnoDB does NOT release the corresponding lockswhich are stored in memory. If a lock is 'implicit', that is, a new insertedrow holds a lock where the lock information is carried by the trx id stored in the row, these locks are naturally released in the rollback. Savepoints whichwere set after this savepoint are deleted. */ulinttrx_rollback_to_savepoint_for_mysql(/*================================*/ /* out: if no savepoint of the name found then DB_NO_SAVEPOINT, otherwise DB_SUCCESS */ trx_t* trx, /* in: transaction handle */ const char* savepoint_name, /* in: savepoint name */ ib_longlong* mysql_binlog_cache_pos) /* out: the MySQL binlog cache position corresponding to this savepoint; MySQL needs this information to remove the binlog entries of the queries executed after the savepoint */{ trx_named_savept_t* savep; ulint err; savep = UT_LIST_GET_FIRST(trx->trx_savepoints); while (savep != NULL) { if (0 == ut_strcmp(savep->name, savepoint_name)) { /* Found */ break; } savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } if (savep == NULL) { return(DB_NO_SAVEPOINT); } if (trx->conc_state == TRX_NOT_STARTED) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: transaction has a savepoint ", stderr); ut_print_name(stderr, trx, savep->name); fputs(" though it is not started\n", stderr); return(DB_ERROR); } /* We can now free all savepoints strictly later than this one */ trx_roll_savepoints_free(trx, savep); *mysql_binlog_cache_pos = savep->mysql_binlog_cache_pos; trx->op_info = "rollback to a savepoint"; err = trx_general_rollback_for_mysql(trx, TRUE, &(savep->savept)); /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement: */ trx_mark_sql_stat_end(trx); trx->op_info = ""; return(err);}/***********************************************************************Creates a named savepoint. If the transaction is not yet started, starts it.If there is already a savepoint of the same name, this call erases that oldsavepoint and replaces it with a new. Savepoints are deleted in a transactioncommit or rollback. */ulinttrx_savepoint_for_mysql(/*====================*/ /* out: always DB_SUCCESS */ trx_t* trx, /* in: transaction handle */ const char* savepoint_name, /* in: savepoint name */ ib_longlong binlog_cache_pos) /* in: MySQL binlog cache position corresponding to this connection at the time of the savepoint */{ trx_named_savept_t* savep; ut_a(trx); ut_a(savepoint_name); trx_start_if_not_started(trx); savep = UT_LIST_GET_FIRST(trx->trx_savepoints); while (savep != NULL) { if (0 == ut_strcmp(savep->name, savepoint_name)) { /* Found */ break; } savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } if (savep) { /* There is a savepoint with the same name: free that */ UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); mem_free(savep->name); mem_free(savep); } /* Create a new savepoint and add it as the last in the list */ savep = mem_alloc(sizeof(trx_named_savept_t)); savep->name = mem_strdup(savepoint_name); savep->savept = trx_savept_take(trx); savep->mysql_binlog_cache_pos = binlog_cache_pos; UT_LIST_ADD_LAST(trx_savepoints, trx->trx_savepoints, savep); return(DB_SUCCESS);}/***********************************************************************Releases a named savepoint. Savepoints whichwere set after this savepoint are deleted. */ulinttrx_release_savepoint_for_mysql(/*============================*/ /* out: if no savepoint of the name found then DB_NO_SAVEPOINT, otherwise DB_SUCCESS */ trx_t* trx, /* in: transaction handle */ const char* savepoint_name) /* in: savepoint name */{ trx_named_savept_t* savep; savep = UT_LIST_GET_FIRST(trx->trx_savepoints); while (savep != NULL) { if (0 == ut_strcmp(savep->name, savepoint_name)) { /* Found */ break; } savep = UT_LIST_GET_NEXT(trx_savepoints, savep); } if (savep == NULL) { return(DB_NO_SAVEPOINT); } /* We can now free all savepoints strictly later than this one */ trx_roll_savepoints_free(trx, savep); /* Now we can free this savepoint too */ UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep); mem_free(savep->name); mem_free(savep); return(DB_SUCCESS);}/***********************************************************************Returns a transaction savepoint taken at this point in time. */trx_savept_ttrx_savept_take(/*============*/ /* out: savepoint */ trx_t* trx) /* in: transaction */{ trx_savept_t savept; savept.least_undo_no = trx->undo_no; return(savept);}/***********************************************************************Rollback or clean up transactions which have no user session. If thetransaction already was committed, then we clean up a possible insertundo log. If the transaction was not yet committed, then we roll it back. Note: this is done in a background thread. */#ifndef __WIN__void*#elseulint#endiftrx_rollback_or_clean_all_without_sess(/*===================================*/ /* out: a dummy parameter */ void* arg __attribute__((unused))) /* in: a dummy parameter required by os_thread_create */{ mem_heap_t* heap; que_fork_t* fork; que_thr_t* thr; roll_node_t* roll_node; trx_t* trx; dict_table_t* table; ib_longlong rows_to_undo; const char* unit = ""; int err; mutex_enter(&kernel_mutex); /* Open a dummy session */ if (!trx_dummy_sess) { trx_dummy_sess = sess_open(); } mutex_exit(&kernel_mutex); if (UT_LIST_GET_FIRST(trx_sys->trx_list)) { fprintf(stderr,"InnoDB: Starting in background the rollback of uncommitted transactions\n"); } else { goto leave_function; }loop: heap = mem_heap_create(512); mutex_enter(&kernel_mutex); trx = UT_LIST_GET_FIRST(trx_sys->trx_list); while (trx) { if ((trx->sess || (trx->conc_state == TRX_NOT_STARTED))) { trx = UT_LIST_GET_NEXT(trx_list, trx); } else if (trx->conc_state == TRX_PREPARED) { trx->sess = trx_dummy_sess; trx = UT_LIST_GET_NEXT(trx_list, trx); } else { break; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -