diff options
author | monty@mashka.mysql.fi <> | 2002-07-25 22:46:28 +0300 |
---|---|---|
committer | monty@mashka.mysql.fi <> | 2002-07-25 22:46:28 +0300 |
commit | bc035c71f1d94649253e4dac5fb8e5c981c7d834 (patch) | |
tree | f38c137c73206e3d059517b2bcab6a4a43c957f9 /innobase/trx | |
parent | b126501bf3888b09fad83dbd2894709c45f009fc (diff) | |
parent | 3c9f1a9ae47e4fcbede526430b0171e8ba17d948 (diff) | |
download | mariadb-git-bc035c71f1d94649253e4dac5fb8e5c981c7d834.tar.gz |
Merge with 3.23.51
Fixed wrong usage of sprintf() in ha_innodb.cc
Diffstat (limited to 'innobase/trx')
-rw-r--r-- | innobase/trx/trx0roll.c | 29 | ||||
-rw-r--r-- | innobase/trx/trx0sys.c | 121 | ||||
-rw-r--r-- | innobase/trx/trx0trx.c | 135 | ||||
-rw-r--r-- | innobase/trx/trx0undo.c | 4 |
4 files changed, 217 insertions, 72 deletions
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c index 97cc2dbff1a..4c2ee5dc9be 100644 --- a/innobase/trx/trx0roll.c +++ b/innobase/trx/trx0roll.c @@ -160,11 +160,13 @@ trx_rollback_last_sql_stat_for_mysql( } /*********************************************************************** -Rollback uncommitted transactions which have no user session. */ +Rollback or clean up transactions which have no user session. If the +transaction already was committed, then we clean up a possible insert +undo log. If the transaction was not yet committed, then we roll it back. */ void -trx_rollback_all_without_sess(void) -/*===============================*/ +trx_rollback_or_clean_all_without_sess(void) +/*========================================*/ { mem_heap_t* heap; que_fork_t* fork; @@ -217,6 +219,19 @@ loop: trx->sess = trx_dummy_sess; + if (trx->conc_state == TRX_COMMITTED_IN_MEMORY) { + + fprintf(stderr, "InnoDB: Cleaning up trx with id %lu %lu\n", + ut_dulint_get_high(trx->id), + 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; @@ -264,9 +279,17 @@ loop: /* 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", + ut_dulint_get_high(trx->table_id), + ut_dulint_get_low(trx->table_id)); + table = dict_table_get_on_id_low(trx->table_id, trx); if (table) { + fprintf(stderr, +"InnoDB: Table found: dropping table %s in recovery\n", table->name); + err = row_drop_table_for_mysql(table->name, trx, TRUE); ut_a(err == (int) DB_SUCCESS); diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 32a1db48488..675cdf1b7e4 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -26,6 +26,14 @@ Created 3/26/1996 Heikki Tuuri trx_sys_t* trx_sys = NULL; trx_doublewrite_t* trx_doublewrite = NULL; +/* In a MySQL replication slave, in crash recovery we store the master log +file name and position here. We have successfully got the updates to InnoDB +up to this position. If .._pos is -1, it means no crash recovery was needed, +or there was no master log position info inside InnoDB. */ + +char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN]; +ib_longlong trx_sys_mysql_master_log_pos = -1; + /******************************************************************** Determines if a page number is located inside the doublewrite buffer. */ @@ -427,75 +435,62 @@ trx_sys_flush_max_trx_id(void) /********************************************************************* Updates the offset information about the end of the MySQL binlog entry -which corresponds to the transaction just being committed. */ +which corresponds to the transaction just being committed. In a MySQL +replication slave updates the latest master binlog position up to which +replication has proceeded. */ void trx_sys_update_mysql_binlog_offset( /*===============================*/ - trx_t* trx, /* in: transaction being committed */ - mtr_t* mtr) /* in: mtr */ + 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; - char namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN]; - - ut_ad(trx->mysql_log_file_name); - memset(namebuf, ' ', TRX_SYS_MYSQL_LOG_NAME_LEN - 1); - namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN - 1] = '\0'; + if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) { - /* Copy the whole MySQL log file name to the buffer, or only the - last characters, if it does not fit */ + /* We cannot fit the name to the 512 bytes we have reserved */ - if (ut_strlen(trx->mysql_log_file_name) - > TRX_SYS_MYSQL_LOG_NAME_LEN - 1) { - ut_memcpy(namebuf, trx->mysql_log_file_name - + ut_strlen(trx->mysql_log_file_name) - - (TRX_SYS_MYSQL_LOG_NAME_LEN - 1), - TRX_SYS_MYSQL_LOG_NAME_LEN - 1); - } else { - ut_memcpy(namebuf, trx->mysql_log_file_name, - 1 + ut_strlen(trx->mysql_log_file_name)); + return; } - namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN - 1] = '\0'; - sys_header = trx_sysf_get(mtr); - if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + 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 + TRX_SYS_MYSQL_LOG_INFO + mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD, TRX_SYS_MYSQL_LOG_MAGIC_N, MLOG_4BYTES, mtr); } - if (0 != ut_memcmp(sys_header + TRX_SYS_MYSQL_LOG_INFO - + TRX_SYS_MYSQL_LOG_NAME, - namebuf, TRX_SYS_MYSQL_LOG_NAME_LEN)) { + if (0 != ut_memcmp(sys_header + field + TRX_SYS_MYSQL_LOG_NAME, + file_name, 1 + ut_strlen(file_name))) { - mlog_write_string(sys_header + TRX_SYS_MYSQL_LOG_INFO + mlog_write_string(sys_header + field + TRX_SYS_MYSQL_LOG_NAME, - namebuf, TRX_SYS_MYSQL_LOG_NAME_LEN, mtr); + file_name, 1 + ut_strlen(file_name), mtr); } - if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0 - || (trx->mysql_log_offset >> 32) > 0) { + || (offset >> 32) > 0) { - mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO + mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_LOG_OFFSET_HIGH, - (ulint)(trx->mysql_log_offset >> 32), + (ulint)(offset >> 32), MLOG_4BYTES, mtr); } - mlog_write_ulint(sys_header + TRX_SYS_MYSQL_LOG_INFO + mlog_write_ulint(sys_header + field + TRX_SYS_MYSQL_LOG_OFFSET_LOW, - (ulint)(trx->mysql_log_offset & 0xFFFFFFFF), + (ulint)(offset & 0xFFFFFFFF), MLOG_4BYTES, mtr); - - trx->mysql_log_file_name = NULL; } /********************************************************************* @@ -533,6 +528,58 @@ trx_sys_print_mysql_binlog_offset(void) mtr_commit(&mtr); } +/********************************************************************* +Prints to stderr the MySQL master log offset info in the trx system header if +the magic number shows it valid. */ + +void +trx_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", + mach_read_from_4(sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), + 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. */ @@ -660,7 +707,7 @@ trx_sys_init_at_db_start(void) if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { fprintf(stderr, - "InnoDB: %lu uncommitted transaction(s) which must be rolled back\n", + "InnoDB: %lu transaction(s) which must be rolled back or cleaned up\n", UT_LIST_GET_LEN(trx_sys->trx_list)); fprintf(stderr, "InnoDB: Trx id counter is %lu %lu\n", diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 87b82cbee3a..8d84967a49d 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -26,9 +26,11 @@ Created 3/26/1996 Heikki Tuuri /* Copy of the prototype for innobase_mysql_print_thd: this -copy must be equal to the one in mysql/sql/ha_innobase.cc ! */ +copy MUST be equal to the one in mysql/sql/ha_innobase.cc ! */ -void innobase_mysql_print_thd(void* thd); +void innobase_mysql_print_thd( + char* buf, + void* thd); /* Dummy session used currently in MySQL interface */ sess_t* trx_dummy_sess = NULL; @@ -83,6 +85,8 @@ trx_create( trx->mysql_log_file_name = NULL; trx->mysql_log_offset = 0; + trx->mysql_master_log_file_name = ""; + trx->mysql_master_log_pos = 0; trx->ignore_duplicates_in_insert = FALSE; @@ -363,16 +367,31 @@ trx_lists_init_at_db_start(void) trx = trx_create(NULL); + trx->id = undo->trx_id; + + trx->insert_undo = undo; + trx->rseg = rseg; + if (undo->state != TRX_UNDO_ACTIVE) { 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; - } - trx->id = undo->trx_id; - trx->insert_undo = undo; - trx->rseg = rseg; + /* A running transaction always has the number + field inited to ut_dulint_max */ + + trx->no = ut_dulint_max; + } if (undo->dict_operation) { trx->dict_operation = undo->dict_operation; @@ -397,14 +416,25 @@ trx_lists_init_at_db_start(void) if (NULL == trx) { trx = trx_create(NULL); + trx->id = undo->trx_id; + if (undo->state != TRX_UNDO_ACTIVE) { trx->conc_state = TRX_COMMITTED_IN_MEMORY; + /* We give a dummy value for the trx + number */ + + trx->no = trx->id; } else { trx->conc_state = TRX_ACTIVE; + + /* A running transaction always has + the number field inited to + ut_dulint_max */ + + trx->no = ut_dulint_max; } - trx->id = undo->trx_id; trx->rseg = rseg; trx_list_insert_ordered(trx); @@ -583,7 +613,7 @@ trx_commit_off_kernel( if (undo) { mutex_enter(&kernel_mutex); #ifdef notdefined - /* ########## There is a bug here: purge and rollback + /* !!!!!!!!! There is a bug here: purge and rollback need the whole stack of old record versions even if no consistent read would need them!! This is because they decide on the basis of the old versions when we can @@ -627,12 +657,25 @@ trx_commit_off_kernel( mutex_exit(&(rseg->mutex)); /* Update the latest MySQL binlog name and offset info - in trx sys header if MySQL binlogging is on */ + in trx sys header if MySQL binlogging is on or the database + server is a MySQL replication slave */ if (trx->mysql_log_file_name) { - trx_sys_update_mysql_binlog_offset(trx, &mtr); + trx_sys_update_mysql_binlog_offset( + trx->mysql_log_file_name, + trx->mysql_log_offset, + TRX_SYS_MYSQL_LOG_INFO, &mtr); + trx->mysql_log_file_name = NULL; } - + + if (trx->mysql_master_log_file_name[0] != '\0') { + /* This database server is a MySQL replication slave */ + trx_sys_update_mysql_binlog_offset( + trx->mysql_master_log_file_name, + trx->mysql_master_log_pos, + TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); + } + /* If we did not take the shortcut, the following call commits the mini-transaction, making the whole transaction committed in the file-based world at this log sequence number; @@ -707,12 +750,12 @@ trx_commit_off_kernel( /*-------------------------------------*/ - /* Most MySQL users run with srv_flush.. set to FALSE: */ + /* Most MySQL users run with srv_flush_.. set to FALSE: */ if (srv_flush_log_at_trx_commit) { log_flush_up_to(lsn, LOG_WAIT_ONE_GROUP); - } + } /*-------------------------------------*/ @@ -730,6 +773,29 @@ trx_commit_off_kernel( UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx); } +/******************************************************************** +Cleans up a transaction at database startup. The cleanup is needed if +the transaction already got to the middle of a commit when the database +crashed, andf we cannot roll it back. */ + +void +trx_cleanup_at_db_startup( +/*======================*/ + trx_t* trx) /* in: transaction */ +{ + if (trx->insert_undo != NULL) { + + trx_undo_insert_cleanup(trx); + } + + trx->conc_state = TRX_NOT_STARTED; + trx->rseg = NULL; + trx->undo_no = ut_dulint_zero; + trx->last_sql_stat_start.least_undo_no = ut_dulint_zero; + + UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx); +} + /************************************************************************ Assigns a read view for a consistent read query. All the consistent reads within the same transaction will get the same read view, which is created @@ -1395,54 +1461,63 @@ own the kernel mutex. */ void trx_print( /*======*/ + char* buf, /* in/out: buffer where to print, must be at least + 500 bytes */ trx_t* trx) /* in: transaction */ { - printf("TRANSACTION %lu %lu, OS thread id %lu", + buf += sprintf(buf, "TRANSACTION %lu %lu, OS thread id %lu", ut_dulint_get_high(trx->id), ut_dulint_get_low(trx->id), (ulint)trx->mysql_thread_id); if (ut_strlen(trx->op_info) > 0) { - printf(" %s", trx->op_info); + buf += sprintf(buf, " %s", trx->op_info); } if (trx->type != TRX_USER) { - printf(" purge trx"); + buf += sprintf(buf, " purge trx"); } switch (trx->conc_state) { - case TRX_NOT_STARTED: printf(", not started"); break; - case TRX_ACTIVE: printf(", active"); break; - case TRX_COMMITTED_IN_MEMORY: printf(", committed in memory"); + case TRX_NOT_STARTED: buf += sprintf(buf, + ", not started"); break; + case TRX_ACTIVE: buf += sprintf(buf, + ", active"); break; + case TRX_COMMITTED_IN_MEMORY: buf += sprintf(buf, + ", committed in memory"); break; - default: printf(" state %lu", trx->conc_state); + default: buf += sprintf(buf, " state %lu", trx->conc_state); } switch (trx->que_state) { - case TRX_QUE_RUNNING: printf(", runs or sleeps"); break; - case TRX_QUE_LOCK_WAIT: printf(", lock wait"); break; - case TRX_QUE_ROLLING_BACK: printf(", rolling back"); break; - case TRX_QUE_COMMITTING: printf(", committing"); break; - default: printf(" que state %lu", trx->que_state); + case TRX_QUE_RUNNING: buf += sprintf(buf, + ", runs or sleeps"); break; + case TRX_QUE_LOCK_WAIT: buf += sprintf(buf, + ", lock wait"); break; + case TRX_QUE_ROLLING_BACK: buf += sprintf(buf, + ", rolling back"); break; + case TRX_QUE_COMMITTING: buf += sprintf(buf, + ", committing"); break; + default: buf += sprintf(buf, " que state %lu", trx->que_state); } if (0 < UT_LIST_GET_LEN(trx->trx_locks)) { - printf(", has %lu lock struct(s)", + buf += sprintf(buf, ", has %lu lock struct(s)", UT_LIST_GET_LEN(trx->trx_locks)); } if (trx->has_search_latch) { - printf(", holds adaptive hash latch"); + buf += sprintf(buf, ", holds adaptive hash latch"); } if (ut_dulint_cmp(trx->undo_no, ut_dulint_zero) != 0) { - printf(", undo log entries %lu", + buf += sprintf(buf, ", undo log entries %lu", ut_dulint_get_low(trx->undo_no)); } - printf("\n"); + buf += sprintf(buf, "\n"); if (trx->mysql_thd != NULL) { - innobase_mysql_print_thd(trx->mysql_thd); + innobase_mysql_print_thd(buf, trx->mysql_thd); } } diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c index aae31f3726b..6303c5bbcdd 100644 --- a/innobase/trx/trx0undo.c +++ b/innobase/trx/trx0undo.c @@ -1147,7 +1147,7 @@ trx_undo_mem_create_at_db_start( /* If the log segment is being freed, the page list is inconsistent! */ if (state == TRX_UNDO_TO_FREE) { - return(undo); + goto add_to_list; } last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr); @@ -1166,7 +1166,7 @@ trx_undo_mem_create_at_db_start( undo->top_offset = rec - last_page; undo->top_undo_no = trx_undo_rec_get_undo_no(rec); } - +add_to_list: if (type == TRX_UNDO_INSERT) { if (state != TRX_UNDO_CACHED) { UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list, |