summaryrefslogtreecommitdiff
path: root/innobase/trx
diff options
context:
space:
mode:
authorheikki@hundin.mysql.fi <>2002-06-22 20:41:14 +0300
committerheikki@hundin.mysql.fi <>2002-06-22 20:41:14 +0300
commit128e872f3cc19ec59cb6e07dbb638732797b3f15 (patch)
treecd94be28879d52101bd7438dc97dc04856d81739 /innobase/trx
parent8056af30e467350a3725c0324bd2142b8fd26801 (diff)
downloadmariadb-git-128e872f3cc19ec59cb6e07dbb638732797b3f15.tar.gz
Many files:
Merge 3.23.52
Diffstat (limited to 'innobase/trx')
-rw-r--r--innobase/trx/trx0roll.c29
-rw-r--r--innobase/trx/trx0sys.c121
-rw-r--r--innobase/trx/trx0trx.c86
-rw-r--r--innobase/trx/trx0undo.c4
4 files changed, 187 insertions, 53 deletions
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index 47fffea5e40..0a951484b59 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 ae607c33fbe..9c49abbd287 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -83,6 +83,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 +365,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 +414,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 +611,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 +655,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 +748,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 +771,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
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index b5341871228..dd249a7062a 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,