summaryrefslogtreecommitdiff
path: root/storage/maria
diff options
context:
space:
mode:
Diffstat (limited to 'storage/maria')
-rw-r--r--storage/maria/ma_blockrec.c40
-rw-r--r--storage/maria/ma_blockrec.h3
-rw-r--r--storage/maria/ma_commit.c11
-rw-r--r--storage/maria/ma_loghandler.c4
-rw-r--r--storage/maria/ma_recovery.c14
-rw-r--r--storage/maria/trnman.c1
6 files changed, 65 insertions, 8 deletions
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index ed4d98015b1..2709a2bba5c 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -5914,7 +5914,7 @@ my_bool write_hook_for_file_id(enum translog_record_type type
TRN *trn
__attribute__ ((unused)),
MARIA_HA *tbl_info,
- LSN *lsn __attribute__ ((unused)),
+ LSN *lsn,
void *hook_arg
__attribute__ ((unused)))
{
@@ -5923,6 +5923,44 @@ my_bool write_hook_for_file_id(enum translog_record_type type
return 0;
}
+
+/**
+ Updates transaction's rec_lsn when committing.
+
+ A transaction writes its commit record before being committed in trnman, so
+ if Checkpoint happens just between the COMMIT record log write and the
+ commit in trnman, it will record that transaction is not committed. Assume
+ the transaction (trn1) did an INSERT; after the checkpoint, a second
+ transaction (trn2) does a DELETE of what trn1 has inserted. Then crash,
+ Checkpoint record says that trn1 was not committed, and REDO phase starts
+ from Checkpoint record's LSN. So it will not find the COMMIT record of
+ trn1, will want to roll back trn1, which will fail because the row/key
+ which it wants to delete does not exist anymore.
+ To avoid this, Checkpoint needs to know that the REDO phase must start
+ before this COMMIT record, so transaction sets its rec_lsn to the COMMIT's
+ record LSN, and as Checkpoint reads the transaction's rec_lsn, Checkpoint
+ will know.
+
+ @note so after commit trn->rec_lsn is a "commit LSN", which could be of
+ use later.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_commit(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn,
+ MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn,
+ void *hook_arg
+ __attribute__ ((unused)))
+{
+ trn->rec_lsn= *lsn;
+ return 0;
+}
+
+
/***************************************************************************
Applying of REDO log records
***************************************************************************/
diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h
index 34f6a3e3008..9b373d1d0ea 100644
--- a/storage/maria/ma_blockrec.h
+++ b/storage/maria/ma_blockrec.h
@@ -271,6 +271,9 @@ my_bool write_hook_for_undo_bulk_insert(enum translog_record_type type,
my_bool write_hook_for_file_id(enum translog_record_type type,
TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
void *hook_arg);
+my_bool write_hook_for_commit(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
void _ma_block_get_status(void* param, my_bool concurrent_insert);
void _ma_block_update_status(void *param);
void _ma_block_restore_status(void *param);
diff --git a/storage/maria/ma_commit.c b/storage/maria/ma_commit.c
index 1066eb15e11..951de1beeff 100644
--- a/storage/maria/ma_commit.c
+++ b/storage/maria/ma_commit.c
@@ -33,6 +33,7 @@ int ma_commit(TRN *trn)
LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS];
DBUG_ENTER("ma_commit");
+ DBUG_ASSERT(trn->rec_lsn == LSN_IMPOSSIBLE);
if (trn->undo_lsn == 0) /* no work done, rollback (cheaper than commit) */
DBUG_RETURN(trnman_rollback_trn(trn));
/*
@@ -61,8 +62,14 @@ int ma_commit(TRN *trn)
trn, NULL, 0,
sizeof(log_array)/sizeof(log_array[0]),
log_array, NULL, NULL) |
- translog_flush(commit_lsn) |
- trnman_commit_trn(trn));
+ translog_flush(commit_lsn));
+
+ DBUG_EXECUTE_IF("maria_sleep_in_commit",
+ {
+ DBUG_PRINT("info", ("maria_sleep_in_commit"));
+ sleep(3);
+ });
+ res|= trnman_commit_trn(trn);
/*
diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c
index cc8c7898d84..93bb6e32418 100644
--- a/storage/maria/ma_loghandler.c
+++ b/storage/maria/ma_loghandler.c
@@ -618,11 +618,11 @@ static LOG_DESC INIT_LOGREC_PREPARE_WITH_UNDO_PURGE=
static LOG_DESC INIT_LOGREC_COMMIT=
{LOGRECTYPE_FIXEDLENGTH, 0, 0, NULL,
- NULL, NULL, 0, "commit", LOGREC_IS_GROUP_ITSELF, NULL,
+ write_hook_for_commit, NULL, 0, "commit", LOGREC_IS_GROUP_ITSELF, NULL,
NULL};
static LOG_DESC INIT_LOGREC_COMMIT_WITH_UNDO_PURGE=
-{LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, NULL, NULL, 1,
+{LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, write_hook_for_commit, NULL, 1,
"commit_with_undo_purge", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
static LOG_DESC INIT_LOGREC_CHECKPOINT=
diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c
index 51eedf157c5..baebdcf2eb4 100644
--- a/storage/maria/ma_recovery.c
+++ b/storage/maria/ma_recovery.c
@@ -555,8 +555,9 @@ static void new_transaction(uint16 sid, TrID long_id, LSN undo_lsn,
char llbuf[22];
all_active_trans[sid].long_trid= long_id;
llstr(long_id, llbuf);
- tprint(tracef, "Transaction long_trid %s short_trid %u starts\n",
- llbuf, sid);
+ tprint(tracef, "Transaction long_trid %s short_trid %u starts,"
+ " undo_lsn (%lu,0x%lx) first_undo_lsn (%lu,0x%lx)\n",
+ llbuf, sid, LSN_IN_PARTS(undo_lsn), LSN_IN_PARTS(first_undo_lsn));
all_active_trans[sid].undo_lsn= undo_lsn;
all_active_trans[sid].first_undo_lsn= first_undo_lsn;
set_if_bigger(max_long_trid, long_id);
@@ -2968,6 +2969,8 @@ static LSN parse_checkpoint_record(LSN lsn)
ptr= log_record_buffer.str;
start_address= lsn_korr(ptr);
ptr+= LSN_STORE_SIZE;
+ tprint(tracef, "Checkpoint record has start_horizon at (%lu,0x%lx)\n",
+ LSN_IN_PARTS(start_address));
/* transactions */
nb_active_transactions= uint2korr(ptr);
@@ -2983,6 +2986,9 @@ static LSN parse_checkpoint_record(LSN lsn)
line. It may make start_address slightly decrease (only by the time it
takes to write one or a few rows, roughly).
*/
+ tprint(tracef, "Checkpoint record has min_rec_lsn of active transactions"
+ " at (%lu,0x%lx)\n",
+ LSN_IN_PARTS(minimum_rec_lsn_of_active_transactions));
set_if_smaller(start_address, minimum_rec_lsn_of_active_transactions);
for (i= 0; i < nb_active_transactions; i++)
@@ -3086,6 +3092,8 @@ static LSN parse_checkpoint_record(LSN lsn)
*/
start_address= checkpoint_start=
translog_next_LSN(start_address, LSN_IMPOSSIBLE);
+ tprint(tracef, "Checkpoint record start_horizon now adjusted to"
+ " LSN (%lu,0x%lx)\n", LSN_IN_PARTS(start_address));
if (checkpoint_start == LSN_IMPOSSIBLE)
{
/*
@@ -3095,6 +3103,8 @@ static LSN parse_checkpoint_record(LSN lsn)
return LSN_ERROR;
}
/* now, where the REDO phase should start reading log: */
+ tprint(tracef, "Checkpoint has min_rec_lsn of dirty pages at"
+ " LSN (%lu,0x%lx)\n", LSN_IN_PARTS(minimum_rec_lsn_of_dirty_pages));
set_if_smaller(start_address, minimum_rec_lsn_of_dirty_pages);
DBUG_PRINT("info",
("checkpoint_start: (%lu,0x%lx) start_address: (%lu,0x%lx)",
diff --git a/storage/maria/trnman.c b/storage/maria/trnman.c
index 538dc75b663..51940705952 100644
--- a/storage/maria/trnman.c
+++ b/storage/maria/trnman.c
@@ -389,7 +389,6 @@ my_bool trnman_end_trn(TRN *trn, my_bool commit)
LF_PINS *pins= trn->pins;
DBUG_ENTER("trnman_end_trn");
- DBUG_ASSERT(trn->rec_lsn == 0);
/* if a rollback, all UNDO records should have been executed */
DBUG_ASSERT(commit || trn->undo_lsn == 0);
DBUG_PRINT("info", ("pthread_mutex_lock LOCK_trn_list"));