📄 trx0sys.c
字号:
fprintf(stderr, "InnoDB: Warning: database page corruption or a failed\n" "InnoDB: file read of page %lu.\n", (ulong) page_no); fprintf(stderr, "InnoDB: Trying to recover it from the doublewrite buffer.\n"); if (buf_page_is_corrupted(page)) { fprintf(stderr, "InnoDB: Dump of the page:\n"); buf_page_print(read_buf); fprintf(stderr, "InnoDB: Dump of corresponding page in doublewrite buffer:\n"); buf_page_print(page); fprintf(stderr, "InnoDB: Also the page in the doublewrite buffer is corrupt.\n" "InnoDB: Cannot continue operation.\n" "InnoDB: You can try to recover the database with the my.cnf\n" "InnoDB: option:\n" "InnoDB: set-variable=innodb_force_recovery=6\n"); exit(1); } /* Write the good page from the doublewrite buffer to the intended position */ fil_io(OS_FILE_WRITE, TRUE, space_id, page_no, 0, UNIV_PAGE_SIZE, page, NULL); fprintf(stderr, "InnoDB: Recovered the page from the doublewrite buffer.\n"); } } page += UNIV_PAGE_SIZE; } fil_flush_file_spaces(FIL_TABLESPACE); leave_func: ut_free(unaligned_read_buf);}/********************************************************************Checks that trx is in the trx list. */ibooltrx_in_trx_list(/*============*/ /* out: TRUE if is in */ trx_t* in_trx) /* in: trx */{ trx_t* trx;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(kernel_mutex)));#endif /* UNIV_SYNC_DEBUG */ trx = UT_LIST_GET_FIRST(trx_sys->trx_list); while (trx != NULL) { if (trx == in_trx) { return(TRUE); } trx = UT_LIST_GET_NEXT(trx_list, trx); } return(FALSE);}/*********************************************************************Writes the value of max_trx_id to the file based trx system header. */voidtrx_sys_flush_max_trx_id(void)/*==========================*/{ trx_sysf_t* sys_header; mtr_t mtr;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ mtr_start(&mtr); sys_header = trx_sysf_get(&mtr); mlog_write_dulint(sys_header + TRX_SYS_TRX_ID_STORE, trx_sys->max_trx_id, &mtr); mtr_commit(&mtr);}/*********************************************************************Updates the offset information about the end of the MySQL binlog entrywhich corresponds to the transaction just being committed. In a MySQLreplication slave updates the latest master binlog position up to whichreplication has proceeded. */voidtrx_sys_update_mysql_binlog_offset(/*===============================*/ const char* file_name,/* in: MySQL log file name */ ib_longlong offset, /* in: position in that log file */ ulint field, /* in: offset of the MySQL log info field in the trx sys header */ mtr_t* mtr) /* in: mtr */{ trx_sysf_t* sys_header; if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) { /* We cannot fit the name to the 512 bytes we have reserved */ return; } sys_header = trx_sysf_get(mtr); if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) != TRX_SYS_MYSQL_LOG_MAGIC_N) { mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD, TRX_SYS_MYSQL_LOG_MAGIC_N, MLOG_4BYTES, mtr); } if (0 != strcmp((char*) (sys_header + field + TRX_SYS_MYSQL_LOG_NAME), file_name)) { mlog_write_string(sys_header + field + TRX_SYS_MYSQL_LOG_NAME, (byte*) file_name, 1 + ut_strlen(file_name), mtr); } if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0 || (offset >> 32) > 0) { mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_LOG_OFFSET_HIGH, (ulint)(offset >> 32), MLOG_4BYTES, mtr); } mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_LOG_OFFSET_LOW, (ulint)(offset & 0xFFFFFFFFUL), MLOG_4BYTES, mtr);}/*********************************************************************Prints to stderr the MySQL binlog info in the system header if themagic number shows it valid. */voidtrx_sys_print_mysql_binlog_offset_from_page(/*========================================*/ byte* page) /* in: buffer containing the trx system header page, i.e., page number TRX_SYS_PAGE_NO in the tablespace */{ trx_sysf_t* sys_header; sys_header = page + TRX_SYS; if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) == TRX_SYS_MYSQL_LOG_MAGIC_N) { fprintf(stderr, "ibbackup: Last MySQL binlog file position %lu %lu, file name %s\n", (ulong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), (ulong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_LOW), sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME); }}/*********************************************************************Stores the MySQL binlog offset info in the trx system header ifthe magic number shows it valid, and print the info to stderr */voidtrx_sys_print_mysql_binlog_offset(void)/*===================================*/{ trx_sysf_t* sys_header; mtr_t mtr; ulint trx_sys_mysql_bin_log_pos_high; ulint trx_sys_mysql_bin_log_pos_low; mtr_start(&mtr); sys_header = trx_sysf_get(&mtr); if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) != TRX_SYS_MYSQL_LOG_MAGIC_N) { mtr_commit(&mtr); return; } trx_sys_mysql_bin_log_pos_high = mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_HIGH); trx_sys_mysql_bin_log_pos_low = mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_LOW); trx_sys_mysql_bin_log_pos = (((ib_longlong)trx_sys_mysql_bin_log_pos_high) << 32) + (ib_longlong)trx_sys_mysql_bin_log_pos_low; ut_memcpy(trx_sys_mysql_bin_log_name, sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME, TRX_SYS_MYSQL_LOG_NAME_LEN); fprintf(stderr, "InnoDB: Last MySQL binlog file position %lu %lu, file name %s\n", trx_sys_mysql_bin_log_pos_high, trx_sys_mysql_bin_log_pos_low, trx_sys_mysql_bin_log_name); mtr_commit(&mtr);}/*********************************************************************Prints to stderr the MySQL master log offset info in the trx system header ifthe magic number shows it valid. */voidtrx_sys_print_mysql_master_log_pos(void)/*====================================*/{ trx_sysf_t* sys_header; mtr_t mtr; mtr_start(&mtr); sys_header = trx_sysf_get(&mtr); if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) != TRX_SYS_MYSQL_LOG_MAGIC_N) { mtr_commit(&mtr); return; } fprintf(stderr,"InnoDB: In a MySQL replication slave the last master binlog file\n""InnoDB: position %lu %lu, file name %s\n", (ulong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), (ulong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_LOW), sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME); /* Copy the master log position info to global variables we can use in ha_innobase.cc to initialize glob_mi to right values */ ut_memcpy(trx_sys_mysql_master_log_name, sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME, TRX_SYS_MYSQL_LOG_NAME_LEN); trx_sys_mysql_master_log_pos = (((ib_longlong)mach_read_from_4( sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) + (ib_longlong) mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_LOW); mtr_commit(&mtr);}/********************************************************************Looks for a free slot for a rollback segment in the trx system file copy. */ulinttrx_sysf_rseg_find_free(/*====================*/ /* out: slot index or ULINT_UNDEFINED if not found */ mtr_t* mtr) /* in: mtr */{ trx_sysf_t* sys_header; ulint page_no; ulint i; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(kernel_mutex)));#endif /* UNIV_SYNC_DEBUG */ sys_header = trx_sysf_get(mtr); for (i = 0; i < TRX_SYS_N_RSEGS; i++) { page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr); if (page_no == FIL_NULL) { return(i); } } return(ULINT_UNDEFINED);} /*********************************************************************Creates the file page for the transaction system. This function is called onlyat the database creation, before trx_sys_init. */staticvoidtrx_sysf_create(/*============*/ mtr_t* mtr) /* in: mtr */{ trx_sysf_t* sys_header; ulint slot_no; page_t* page; ulint page_no; ulint i; ut_ad(mtr); /* Note that below we first reserve the file space x-latch, and then enter the kernel: we must do it in this order to conform to the latching order rules. */ mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE), mtr); mutex_enter(&kernel_mutex); /* Create the trx sys file block in a new allocated file segment */ page = fseg_create(TRX_SYS_SPACE, 0, TRX_SYS + TRX_SYS_FSEG_HEADER, mtr); ut_a(buf_frame_get_page_no(page) == TRX_SYS_PAGE_NO);#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_TRX_SYS_HEADER);#endif /* UNIV_SYNC_DEBUG */ sys_header = trx_sysf_get(mtr); /* Start counting transaction ids from number 1 up */ mlog_write_dulint(sys_header + TRX_SYS_TRX_ID_STORE, ut_dulint_create(0, 1), mtr); /* Reset the rollback segment slots */ for (i = 0; i < TRX_SYS_N_RSEGS; i++) { trx_sysf_rseg_set_page_no(sys_header, i, FIL_NULL, mtr); } /* Create the first rollback segment in the SYSTEM tablespace */ page_no = trx_rseg_header_create(TRX_SYS_SPACE, ULINT_MAX, &slot_no, mtr); ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID); ut_a(page_no != FIL_NULL); mutex_exit(&kernel_mutex);}/*********************************************************************Creates and initializes the central memory structures for the transactionsystem. This is called when the database is started. */voidtrx_sys_init_at_db_start(void)/*==========================*/{ trx_sysf_t* sys_header; ib_longlong rows_to_undo = 0; const char* unit = ""; trx_t* trx; mtr_t mtr; mtr_start(&mtr); ut_ad(trx_sys == NULL); mutex_enter(&kernel_mutex); trx_sys = mem_alloc(sizeof(trx_sys_t)); sys_header = trx_sysf_get(&mtr); trx_rseg_list_and_array_init(sys_header, &mtr); trx_sys->latest_rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); /* VERY important: after the database is started, max_trx_id value is divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the 'if' in trx_sys_get_new_trx_id will evaluate to TRUE when the function is first time called, and the value for trx id will be written to the disk-based header! Thus trx id values will not overlap when the database is repeatedly started! */ trx_sys->max_trx_id = ut_dulint_add( ut_dulint_align_up( mtr_read_dulint(sys_header + TRX_SYS_TRX_ID_STORE, &mtr), TRX_SYS_TRX_ID_WRITE_MARGIN), 2 * TRX_SYS_TRX_ID_WRITE_MARGIN); UT_LIST_INIT(trx_sys->mysql_trx_list); trx_lists_init_at_db_start(); if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { trx = UT_LIST_GET_FIRST(trx_sys->trx_list); for (;;) { if ( trx->conc_state != TRX_PREPARED) { rows_to_undo += ut_conv_dulint_to_longlong(trx->undo_no); } trx = UT_LIST_GET_NEXT(trx_list, trx); if (!trx) { break; } } if (rows_to_undo > 1000000000) { unit = "M"; rows_to_undo = rows_to_undo / 1000000; } fprintf(stderr,"InnoDB: %lu transaction(s) which must be rolled back or cleaned up\n""InnoDB: in total %lu%s row operations to undo\n", (ulong) UT_LIST_GET_LEN(trx_sys->trx_list), (ulong) rows_to_undo, unit); fprintf(stderr, "InnoDB: Trx id counter is %lu %lu\n", (ulong) ut_dulint_get_high(trx_sys->max_trx_id), (ulong) ut_dulint_get_low(trx_sys->max_trx_id)); } UT_LIST_INIT(trx_sys->view_list); trx_purge_sys_create(); mutex_exit(&kernel_mutex); mtr_commit(&mtr);}/*********************************************************************Creates and initializes the transaction system at the database creation. */voidtrx_sys_create(void)/*================*/{ mtr_t mtr; mtr_start(&mtr); trx_sysf_create(&mtr); mtr_commit(&mtr); trx_sys_init_at_db_start();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -