List:Maria Storage Engine« Previous MessageNext Message »
From:Guilhem Bichot Date:December 5 2008 2:45pm
Subject:bzr commit into MySQL/Maria:mysql-maria branch (guilhem:2708) Bug#41037
View as plain text  
#At bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-maria/ based on revid:guilhem@stripped

 2708 Guilhem Bichot	2008-12-05
      Fix for BUG#41037 "Maria: recovery failure (pushbuild2)" (checkpoint bug). No testcase (maria-recovery* framework
      cannot do it without random test failures), it's already tested by pushbuild2's recovery tests.
modified:
  storage/maria/ma_blockrec.c
  storage/maria/ma_blockrec.h
  storage/maria/ma_commit.c
  storage/maria/ma_loghandler.c
  storage/maria/ma_recovery.c
  storage/maria/trnman.c

per-file messages:
  storage/maria/ma_blockrec.c
    set trn->rec_lsn to LSN of commit record, when writing it.
  storage/maria/ma_blockrec.h
    new function
  storage/maria/ma_commit.c
    when committing or rolling back, rec_lsn should be LSN_IMPOSSIBLE: assertion is moved here
    from trnman_end_trn(), because now ma_commit() can set rec_lsn and so when we reach trnman_end_trn()
    it's not LSN_IMPOSSIBLE anymore.
  storage/maria/ma_loghandler.c
    in-write hook for COMMIT records
  storage/maria/ma_recovery.c
    More debugging info in maria_recovery.trace, to see how the starting point of REDO phase is determined
  storage/maria/trnman.c
    assertion cannot be here anymore see ma_commit.c
=== modified file 'storage/maria/ma_blockrec.c'
--- a/storage/maria/ma_blockrec.c	2008-10-14 15:18:14 +0000
+++ b/storage/maria/ma_blockrec.c	2008-12-05 14:45:28 +0000
@@ -5914,7 +5914,7 @@ my_bool write_hook_for_file_id(enum tran
                                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 tran
   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
 ***************************************************************************/

=== modified file 'storage/maria/ma_blockrec.h'
--- a/storage/maria/ma_blockrec.h	2008-10-14 09:38:07 +0000
+++ b/storage/maria/ma_blockrec.h	2008-12-05 14:45:28 +0000
@@ -271,6 +271,9 @@ my_bool write_hook_for_undo_bulk_insert(
 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);

=== modified file 'storage/maria/ma_commit.c'
--- a/storage/maria/ma_commit.c	2008-10-09 20:03:54 +0000
+++ b/storage/maria/ma_commit.c	2008-12-05 14:45:28 +0000
@@ -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));
   /*

=== modified file 'storage/maria/ma_loghandler.c'
--- a/storage/maria/ma_loghandler.c	2008-12-02 22:02:52 +0000
+++ b/storage/maria/ma_loghandler.c	2008-12-05 14:45:28 +0000
@@ -618,11 +618,11 @@ static LOG_DESC INIT_LOGREC_PREPARE_WITH
 
 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=

=== modified file 'storage/maria/ma_recovery.c'
--- a/storage/maria/ma_recovery.c	2008-11-24 14:23:48 +0000
+++ b/storage/maria/ma_recovery.c	2008-12-05 14:45:28 +0000
@@ -555,8 +555,9 @@ static void new_transaction(uint16 sid, 
   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 l
   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 l
     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 l
   */
   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 l
     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)",

=== modified file 'storage/maria/trnman.c'
--- a/storage/maria/trnman.c	2008-11-20 14:11:00 +0000
+++ b/storage/maria/trnman.c	2008-12-05 14:45:28 +0000
@@ -389,7 +389,6 @@ my_bool trnman_end_trn(TRN *trn, my_bool
   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"));

Thread
bzr commit into MySQL/Maria:mysql-maria branch (guilhem:2708) Bug#41037Guilhem Bichot5 Dec