diff options
Diffstat (limited to 'storage/maria')
-rw-r--r-- | storage/maria/ma_blockrec.c | 40 | ||||
-rw-r--r-- | storage/maria/ma_blockrec.h | 3 | ||||
-rw-r--r-- | storage/maria/ma_commit.c | 11 | ||||
-rw-r--r-- | storage/maria/ma_loghandler.c | 4 | ||||
-rw-r--r-- | storage/maria/ma_recovery.c | 14 | ||||
-rw-r--r-- | storage/maria/trnman.c | 1 |
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")); |