📄 trx0trx.c
字号:
/******************************************************The transaction(c) 1996 Innobase OyCreated 3/26/1996 Heikki Tuuri*******************************************************/#include "trx0trx.h"#ifdef UNIV_NONINL#include "trx0trx.ic"#endif#include "trx0undo.h"#include "trx0rseg.h"#include "log0log.h"#include "que0que.h"#include "lock0lock.h"#include "trx0roll.h"#include "usr0sess.h"#include "read0read.h"#include "srv0srv.h"#include "thr0loc.h"#include "btr0sea.h"#include "os0proc.h"#include "trx0xa.h"/* Copy of the prototype for innobase_mysql_print_thd: thiscopy MUST be equal to the one in mysql/sql/ha_innodb.cc ! */void innobase_mysql_print_thd( FILE* f, void* thd, uint max_query_len);/* Dummy session used currently in MySQL interface */sess_t* trx_dummy_sess = NULL;/* Number of transactions currently allocated for MySQL: protected bythe kernel mutex */ulint trx_n_mysql_transactions = 0;/*****************************************************************Starts the transaction if it is not yet started. */voidtrx_start_if_not_started_noninline(/*===============================*/ trx_t* trx) /* in: transaction */{ trx_start_if_not_started(trx);}/*****************************************************************Set detailed error message for the transaction. */voidtrx_set_detailed_error(/*===================*/ trx_t* trx, /* in: transaction struct */ const char* msg) /* in: detailed error message */{ ut_strlcpy(trx->detailed_error, msg, sizeof(trx->detailed_error));}/*****************************************************************Set detailed error message for the transaction from a file. Note that thefile is rewinded before reading from it. */voidtrx_set_detailed_error_from_file(/*=============================*/ trx_t* trx, /* in: transaction struct */ FILE* file) /* in: file to read message from */{ os_file_read_string(file, trx->detailed_error, sizeof(trx->detailed_error));}/********************************************************************Retrieves the error_info field from a trx. */void*trx_get_error_info(/*===============*/ /* out: the error info */ trx_t* trx) /* in: trx object */{ return(trx->error_info);}/********************************************************************Creates and initializes a transaction object. */trx_t*trx_create(/*=======*/ /* out, own: the transaction */ sess_t* sess) /* in: session or NULL */{ trx_t* trx;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ trx = mem_alloc(sizeof(trx_t)); trx->magic_n = TRX_MAGIC_N; trx->op_info = ""; trx->type = TRX_USER; trx->conc_state = TRX_NOT_STARTED; trx->start_time = time(NULL); trx->isolation_level = TRX_ISO_REPEATABLE_READ; trx->id = ut_dulint_zero; trx->no = ut_dulint_max; trx->support_xa = TRUE; trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; trx->flush_log_later = FALSE; trx->must_flush_log_later = FALSE; trx->dict_operation = FALSE; trx->mysql_thd = NULL; trx->mysql_query_str = NULL; trx->n_mysql_tables_in_use = 0; trx->mysql_n_tables_locked = 0; trx->mysql_log_file_name = NULL; trx->mysql_log_offset = 0; trx->mysql_master_log_file_name = ""; trx->mysql_master_log_pos = 0; trx->repl_wait_binlog_name = NULL; trx->repl_wait_binlog_pos = 0; mutex_create(&(trx->undo_mutex)); mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO); trx->rseg = NULL; trx->undo_no = ut_dulint_zero; trx->last_sql_stat_start.least_undo_no = ut_dulint_zero; trx->insert_undo = NULL; trx->update_undo = NULL; trx->undo_no_arr = NULL; trx->error_state = DB_SUCCESS; trx->detailed_error[0] = '\0'; trx->sess = sess; trx->que_state = TRX_QUE_RUNNING; trx->n_active_thrs = 0; trx->handling_signals = FALSE; UT_LIST_INIT(trx->signals); UT_LIST_INIT(trx->reply_signals); trx->graph = NULL; trx->wait_lock = NULL; trx->was_chosen_as_deadlock_victim = FALSE; UT_LIST_INIT(trx->wait_thrs); trx->lock_heap = mem_heap_create_in_buffer(256); UT_LIST_INIT(trx->trx_locks); UT_LIST_INIT(trx->trx_savepoints); trx->dict_operation_lock_mode = 0; trx->has_search_latch = FALSE; trx->search_latch_timeout = BTR_SEA_TIMEOUT; trx->declared_to_be_inside_innodb = FALSE; trx->n_tickets_to_enter_innodb = 0; trx->auto_inc_lock = NULL; trx->global_read_view_heap = mem_heap_create(256); trx->global_read_view = NULL; trx->read_view = NULL; /* Set X/Open XA transaction identification to NULL */ memset(&trx->xid, 0, sizeof(trx->xid)); trx->xid.formatID = -1; trx_reset_new_rec_lock_info(trx); return(trx);}/************************************************************************Creates a transaction object for MySQL. */trx_t*trx_allocate_for_mysql(void)/*========================*/ /* out, own: transaction object */{ trx_t* trx; mutex_enter(&kernel_mutex); /* Open a dummy session */ if (!trx_dummy_sess) { trx_dummy_sess = sess_open(); } trx = trx_create(trx_dummy_sess); trx_n_mysql_transactions++; UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx); mutex_exit(&kernel_mutex); trx->mysql_thread_id = os_thread_get_curr_id(); trx->mysql_process_no = os_proc_get_number(); return(trx);}/************************************************************************Creates a transaction object for background operations by the master thread. */trx_t*trx_allocate_for_background(void)/*=============================*/ /* out, own: transaction object */{ trx_t* trx; mutex_enter(&kernel_mutex); /* Open a dummy session */ if (!trx_dummy_sess) { trx_dummy_sess = sess_open(); } trx = trx_create(trx_dummy_sess); mutex_exit(&kernel_mutex); return(trx);}/************************************************************************Releases the search latch if trx has reserved it. */voidtrx_search_latch_release_if_reserved(/*=================================*/ trx_t* trx) /* in: transaction */{ if (trx->has_search_latch) { rw_lock_s_unlock(&btr_search_latch); trx->has_search_latch = FALSE; }}/************************************************************************Frees a transaction object. */voidtrx_free(/*=====*/ trx_t* trx) /* in, own: trx object */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ if (trx->declared_to_be_inside_innodb) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: Freeing a trx which is declared to be processing\n""InnoDB: inside InnoDB.\n", stderr); trx_print(stderr, trx, 600); putc('\n', stderr); } if (trx->n_mysql_tables_in_use != 0 || trx->mysql_n_tables_locked != 0) { ut_print_timestamp(stderr); fprintf(stderr," InnoDB: Error: MySQL is freeing a thd\n""InnoDB: though trx->n_mysql_tables_in_use is %lu\n""InnoDB: and trx->mysql_n_tables_locked is %lu.\n", (ulong)trx->n_mysql_tables_in_use, (ulong)trx->mysql_n_tables_locked); trx_print(stderr, trx, 600); ut_print_buf(stderr, (byte*)trx, sizeof(trx_t)); } ut_a(trx->magic_n == TRX_MAGIC_N); trx->magic_n = 11112222; ut_a(trx->conc_state == TRX_NOT_STARTED); mutex_free(&(trx->undo_mutex)); ut_a(trx->insert_undo == NULL); ut_a(trx->update_undo == NULL); if (trx->undo_no_arr) { trx_undo_arr_free(trx->undo_no_arr); } if (trx->repl_wait_binlog_name != NULL) { mem_free(trx->repl_wait_binlog_name); } ut_a(UT_LIST_GET_LEN(trx->signals) == 0); ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0); ut_a(trx->wait_lock == NULL); ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0); ut_a(!trx->has_search_latch); ut_a(!trx->auto_inc_lock); ut_a(trx->dict_operation_lock_mode == 0); if (trx->lock_heap) { mem_heap_free(trx->lock_heap); } ut_a(UT_LIST_GET_LEN(trx->trx_locks) == 0); if (trx->global_read_view_heap) { mem_heap_free(trx->global_read_view_heap); } trx->global_read_view = NULL; ut_a(trx->read_view == NULL); mem_free(trx);}/************************************************************************Frees a transaction object for MySQL. */voidtrx_free_for_mysql(/*===============*/ trx_t* trx) /* in, own: trx object */{ thr_local_free(trx->mysql_thread_id); mutex_enter(&kernel_mutex); UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx); trx_free(trx); ut_a(trx_n_mysql_transactions > 0); trx_n_mysql_transactions--; mutex_exit(&kernel_mutex);}/************************************************************************Frees a transaction object of a background operation of the master thread. */voidtrx_free_for_background(/*====================*/ trx_t* trx) /* in, own: trx object */{ mutex_enter(&kernel_mutex); trx_free(trx); mutex_exit(&kernel_mutex);}/********************************************************************Inserts the trx handle in the trx system trx list in the right position.The list is sorted on the trx id so that the biggest id is at the liststart. This function is used at the database startup to insert incompletetransactions to the list. */staticvoidtrx_list_insert_ordered(/*====================*/ trx_t* trx) /* in: trx handle */{ trx_t* trx2;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ trx2 = UT_LIST_GET_FIRST(trx_sys->trx_list); while (trx2 != NULL) { if (ut_dulint_cmp(trx->id, trx2->id) >= 0) { ut_ad(ut_dulint_cmp(trx->id, trx2->id) == 1); break; } trx2 = UT_LIST_GET_NEXT(trx_list, trx2); } if (trx2 != NULL) { trx2 = UT_LIST_GET_PREV(trx_list, trx2); if (trx2 == NULL) { UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx); } else { UT_LIST_INSERT_AFTER(trx_list, trx_sys->trx_list, trx2, trx); } } else { UT_LIST_ADD_LAST(trx_list, trx_sys->trx_list, trx); } }/********************************************************************Creates trx objects for transactions and initializes the trx list oftrx_sys at database start. Rollback segment and undo log lists mustalready exist when this function is called, because the lists oftransactions to be rolled back or cleaned up are built based on theundo log lists. */voidtrx_lists_init_at_db_start(void)/*============================*/{ trx_rseg_t* rseg; trx_undo_t* undo; trx_t* trx; UT_LIST_INIT(trx_sys->trx_list); /* Look from the rollback segments if there exist undo logs for transactions */ rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); while (rseg != NULL) { undo = UT_LIST_GET_FIRST(rseg->insert_undo_list); while (undo != NULL) { trx = trx_create(NULL); trx->id = undo->trx_id; trx->xid = undo->xid; trx->insert_undo = undo; trx->rseg = rseg; if (undo->state != TRX_UNDO_ACTIVE) { /* Prepared transactions are left in the prepared state waiting for a commit or abort decision from MySQL */ if (undo->state == TRX_UNDO_PREPARED) { fprintf(stderr,"InnoDB: Transaction %lu %lu was in the XA prepared state.\n", ut_dulint_get_high(trx->id), ut_dulint_get_low(trx->id)); if (srv_force_recovery == 0) { trx->conc_state = TRX_PREPARED; } else { fprintf(stderr,"InnoDB: Since innodb_force_recovery > 0, we will rollback it anyway.\n"); trx->conc_state = TRX_ACTIVE; } } else { trx->conc_state = TRX_COMMITTED_IN_MEMORY; } /* We give a dummy value for the trx no; this should have no relevance since purge is not interested in committed transaction numbers, unless they are in the history list, in which case it looks the number from the disk based undo log structure */ trx->no = trx->id; } else { trx->conc_state = TRX_ACTIVE; /* A running transaction always has the number field inited to ut_dulint_max */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -