From 98aad88f4d2d1baef97e9be4d26da0e850d121bc Mon Sep 17 00:00:00 2001
From: unknown <guilhem@gbichot4.local>
Date: Tue, 1 Jan 2008 22:30:49 +0100
Subject: [PATCH] after-merge fixes and comments

mysql-test/include/maria_empty_logs.inc:
  At one moment in maria-recovery.test the first log has number 2,
  because log 1 was manually deleted.
mysql-test/r/maria-recovery.result:
  after-merge fix
mysql-test/t/maria-recovery.test:
  after-merge fix
storage/maria/ma_bitmap.c:
  after-merge fix. The todo is implemented now.
storage/maria/ma_blockrec.c:
  comment
storage/maria/ma_open.c:
  after-merge fix. Set write_fail also for index file or a write error
  would crash.
storage/maria/ma_pagecache.c:
  comment
storage/maria/ma_pagecache.h:
  I prefer to use NULL for 'no callback' instead of a dummy callback
  in the special case of get_log_address; indeed for non-transactional
  tables it uses an if(), while if using a dummy callback, it would
  use a function call plus an if() (the dummy callback would need to
  return a magic value to say "don't flush" and that value would be
  tested in if()).
storage/maria/unittest/ma_test_all-t:
  fix if running from outside storage/maria
---
 mysql-test/include/maria_empty_logs.inc |  1 +
 mysql-test/r/maria-recovery.result      | 38 ++++++++++++++++++++-----
 mysql-test/t/maria-recovery.test        | 29 +++++++++++++++++++
 storage/maria/ma_bitmap.c               | 23 ++++++---------
 storage/maria/ma_blockrec.c             |  6 ++++
 storage/maria/ma_open.c                 | 12 +++++---
 storage/maria/ma_pagecache.c            | 10 +++++++
 storage/maria/ma_pagecache.h            |  2 +-
 storage/maria/unittest/ma_test_all-t    | 14 ++++-----
 9 files changed, 102 insertions(+), 33 deletions(-)

diff --git a/mysql-test/include/maria_empty_logs.inc b/mysql-test/include/maria_empty_logs.inc
index 64ea9e7a47..1849eaf82a 100644
--- a/mysql-test/include/maria_empty_logs.inc
+++ b/mysql-test/include/maria_empty_logs.inc
@@ -17,6 +17,7 @@ if (!$mel_keep_control_file)
 {
   remove_file $MYSQLTEST_VARDIR/master-data/maria_log_control;
 }
+-- error 0,1
 remove_file $MYSQLTEST_VARDIR/master-data/maria_log.00000001;
 -- error 0,1
 remove_file $MYSQLTEST_VARDIR/master-data/maria_log.00000002;
diff --git a/mysql-test/r/maria-recovery.result b/mysql-test/r/maria-recovery.result
index e37619dffc..6f75443a02 100644
--- a/mysql-test/r/maria-recovery.result
+++ b/mysql-test/r/maria-recovery.result
@@ -214,6 +214,9 @@ t1	CREATE TABLE `t1` (
   KEY `c` (`c`)
 ) ENGINE=MARIA AUTO_INCREMENT=16 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
 drop table t1;
+* TEST of removing logs manually
+* shut down mysqld, removed logs, restarted it
+use mysqltest;
 * TEST of UNDO_ROW_DELETE preserving rowid
 create table t1(a int) engine=maria;
 insert into t1 values(1),(2);
@@ -222,17 +225,38 @@ flush table t1;
 lock tables t1 write;
 insert into t1 values(3);
 delete from t1 where a in (1,2,3);
-drop table t1;
-* TEST of removing logs manually
-* shut down mysqld, removed logs, restarted it
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table	Op	Msg_type	Msg_text
+mysqltest.t1	check	status	OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
 use mysqltest;
-create table t1 (a varchar(1000)) engine=maria;
-insert into t1 values ("00000000");
+drop table t1;
+* TEST of checkpoint
+set global debug="+d,info,query,enter,exit,loop,maria_checkpoint_indirect";
+set global maria_checkpoint_interval=10000;
+create table t1(a int, b varchar(10), index(a,b)) engine=maria;
+insert into t1 values(1,"a"),(2,"b"),(3,"c");
+delete from t1 where b="b";
+update t1 set b="d" where a=1;
 flush table t1;
 * copied t1 for comparison
 lock tables t1 write;
-insert into t1 values ("aaaaaaaaa");
-SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+insert into t1 values(4,"e"),(5,"f"),(6,"g");
+update t1 set b="h" where a=5;
+delete from t1 where b="g";
+show status like "Maria_pagecache_blocks_not_flushed";
+Variable_name	Value
+Maria_pagecache_blocks_not_flushed	3
+set global maria_checkpoint_interval=10000;
+update t1 set b="i" where a=5;
+SET SESSION debug="+d,maria_crash";
 * crashing mysqld intentionally
 set global maria_checkpoint_interval=1;
 ERROR HY000: Lost connection to MySQL server during query
diff --git a/mysql-test/t/maria-recovery.test b/mysql-test/t/maria-recovery.test
index abd13ab364..f2d8d5b1e2 100644
--- a/mysql-test/t/maria-recovery.test
+++ b/mysql-test/t/maria-recovery.test
@@ -205,6 +205,35 @@ delete from t1 where a in (1,2,3);
 -- source include/maria_verify_recovery.inc
 drop table t1;
 
+# A basic checkpoint test
+--echo * TEST of checkpoint
+# Don't take a full checkpoints, we want to test checkpoint vs dirty pages
+set global debug="+d,info,query,enter,exit,loop,maria_checkpoint_indirect";
+# restart checkpoint thread for it to notice the above
+set global maria_checkpoint_interval=10000;
+create table t1(a int, b varchar(10), index(a,b)) engine=maria;
+insert into t1 values(1,"a"),(2,"b"),(3,"c");
+delete from t1 where b="b";
+update t1 set b="d" where a=1;
+-- source include/maria_make_snapshot_for_comparison.inc
+lock tables t1 write;
+insert into t1 values(4,"e"),(5,"f"),(6,"g");
+update t1 set b="h" where a=5;
+delete from t1 where b="g";
+show status like "Maria_pagecache_blocks_not_flushed";
+# force a checkpoint; there should be dirty pages and an open transaction
+set global maria_checkpoint_interval=10000;
+# do some more work
+update t1 set b="i" where a=5;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+# Now we have a recovery, which should use the checkpoint record
+# and its dirty pages list.
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
 # clean up everything
 let $mms_purpose=feeding_recovery;
 eval drop database mysqltest_for_$mms_purpose;
diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c
index 31cd2586d0..701518487b 100644
--- a/storage/maria/ma_bitmap.c
+++ b/storage/maria/ma_bitmap.c
@@ -161,18 +161,6 @@ static inline my_bool write_changed_bitmap(MARIA_SHARE *share,
   }
   else
   {
-    /**
-      @todo RECOVERY BUG
-      Not flushable: its content is not reflected by the log, to honour WAL we
-      must keep the bitmap page pinned. Scenario of INSERT:
-      REDO - UNDO (written to log but not forced)
-      bitmap goes to page cache (because other INSERT needs to)
-      and then to disk (pagecache eviction)
-      crash: recovery will not find REDO-UNDO, table is corrupted.
-      Solutions:
-      give LSNs to bitmap pages or change pagecache to flush all log when
-      flushing a bitmap page or keep bitmap page pinned until checkpoint.
-    */
     MARIA_PINNED_PAGE page_link;
     int res= pagecache_write(share->pagecache,
                              &bitmap->file, bitmap->page, 0,
@@ -221,7 +209,6 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file)
 
   bitmap->block_size= share->block_size;
   bitmap->file.file= file;
-  bitmap->file.write_fail= &maria_page_write_failure; aaaaa
   _ma_bitmap_set_pagecache_callbacks(&bitmap->file, share);
 
   /* Size needs to be aligned on 6 */
@@ -2196,6 +2183,11 @@ void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc)
     info->non_flushable_state= 0;
     if (--bitmap->non_flushable == 0)
     {
+      /*
+        We unlock and unpin pages locked and pinned by other threads. It does
+        not seem to be an issue as all bitmap changes are serialized with
+        the bitmap's mutex.
+      */
       _ma_bitmap_unpin_all(share);
       if (unlikely(bitmap->flush_all_requested))
       {
@@ -2610,12 +2602,15 @@ void _ma_bitmap_set_pagecache_callbacks(PAGECACHE_FILE *file,
 {
   if (share->temporary)
     pagecache_file_init(*file, &maria_page_crc_check_none,
-                        &maria_page_filler_set_none, NULL, share);
+                        &maria_page_filler_set_none,
+                        &maria_page_write_failure,
+                        NULL, share);
   else
     pagecache_file_init(*file, &maria_page_crc_check_bitmap,
                         ((share->options & HA_OPTION_PAGE_CHECKSUM) ?
                          &maria_page_crc_set_normal :
                          &maria_page_filler_set_bitmap),
+                        &maria_page_write_failure,
                         share->now_transactional ?
                         &_ma_bitmap_get_log_address : NULL, share);
 }
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index 31579db04a..ddf8e5069e 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -446,7 +446,13 @@ my_bool _ma_once_end_block_record(MARIA_SHARE *share)
     share->bitmap.file.file= -1;
   }
   if (share->id != 0)
+  {
+    /*
+      We de-assign the id even though index has not been flushed, this is ok
+      as intern_lock serializes us with a Checkpoint looking at our share.
+    */
     translog_deassign_id_from_share(share);
+  }
   return res;
 }
 
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index 6cd0e15d3b..31b2012801 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -1540,15 +1540,17 @@ void set_data_pagecache_callbacks(PAGECACHE_FILE *file, MARIA_SHARE *share)
     them. On the other hand, index file can always have page CRCs, for all
     data formats.
   */
-  file->write_fail= &maria_page_write_failure;
   if (share->temporary)
     pagecache_file_init(*file, &maria_page_crc_check_none,
-                        &maria_page_filler_set_none, NULL, share);
+                        &maria_page_filler_set_none,
+                        &maria_page_write_failure,
+                        NULL, share);
   else
     pagecache_file_init(*file, &maria_page_crc_check_data,
                         ((share->options & HA_OPTION_PAGE_CHECKSUM) ?
                          &maria_page_crc_set_normal :
                          &maria_page_filler_set_normal),
+                        &maria_page_write_failure,
                         share->now_transactional ?
                         &maria_page_get_lsn : NULL, share);
 }
@@ -1556,15 +1558,17 @@ void set_data_pagecache_callbacks(PAGECACHE_FILE *file, MARIA_SHARE *share)
 
 void set_index_pagecache_callbacks(PAGECACHE_FILE *file, MARIA_SHARE *share)
 {
-  no write_fail set here?
   if (share->temporary)
     pagecache_file_init(*file, &maria_page_crc_check_none,
-                        &maria_page_filler_set_none, NULL, share);
+                        &maria_page_filler_set_none,
+                        &maria_page_write_failure,
+                        NULL, share);
   else
     pagecache_file_init(*file, &maria_page_crc_check_index,
                         ((share->options & HA_OPTION_PAGE_CHECKSUM) ?
                          &maria_page_crc_set_index :
                          &maria_page_filler_set_normal),
+                        &maria_page_write_failure,
                         share->now_transactional ?
                         &maria_page_get_lsn : NULL,
                         share);
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c
index 1f559e1f66..951d5263fc 100755
--- a/storage/maria/ma_pagecache.c
+++ b/storage/maria/ma_pagecache.c
@@ -3683,6 +3683,12 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
        @todo IO If page is contiguous with next page to flush, group flushes
        in one single my_pwrite().
     */
+    /*
+      It is important to use block->hash_link->file below and not 'file', as
+      the first one is right and the second may have different content (and
+      this matters for callbacks, bitmap pages and data pages have different
+      ones).
+    */
     error= pagecache_fwrite(pagecache, &block->hash_link->file,
                             block->buffer,
                             block->hash_link->pageno,
@@ -3741,6 +3747,10 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
    @param  filter_arg      an argument to pass to 'filter'. Information about
                            the block will be passed too.
 
+   @note
+     Flushes all blocks having the same OS file descriptor as 'file->file', so
+     can flush blocks having '*block->hash_link->file' != '*file'.
+
    @note
      This function doesn't do any mutex locks because it needs to be called
      both from flush_pagecache_blocks and flush_all_key_blocks (the later one
diff --git a/storage/maria/ma_pagecache.h b/storage/maria/ma_pagecache.h
index 78b7200bab..6671a3e998 100644
--- a/storage/maria/ma_pagecache.h
+++ b/storage/maria/ma_pagecache.h
@@ -88,7 +88,7 @@ typedef struct st_pagecache_file
   my_bool (*write_callback)(uchar *page, pgcache_page_no_t offset,
                             uchar *data);
   void (*write_fail)(uchar *data);
-  /** Can be NULL */ or use dummy
+  /** Can be NULL */
   TRANSLOG_ADDRESS (*get_log_address_callback)
     (uchar *page, pgcache_page_no_t offset, uchar *data);
   uchar *callback_data;
diff --git a/storage/maria/unittest/ma_test_all-t b/storage/maria/unittest/ma_test_all-t
index 7e5441172b..7a778aa998 100755
--- a/storage/maria/unittest/ma_test_all-t
+++ b/storage/maria/unittest/ma_test_all-t
@@ -352,14 +352,14 @@ sub run_tests_on_clrs
            "rm test2.MA?"
           );
 
-  my @t3= ("ma_test2 -s -L -K -W -P -M -T -c -b32768 -t4 -A1",
-           "maria_read_log -a -s",
-           "maria_chk -es test2",
-           "maria_read_log -a -s",
-           "maria_chk -es test2",
+  my @t3= ("$maria_path/ma_test2 -s -L -K -W -P -M -T -c -b32768 -t4 -A1",
+           "$maria_path/maria_read_log -a -s",
+           "$maria_path/maria_chk -es test2",
+           "$maria_path/maria_read_log -a -s",
+           "$maria_path/maria_chk -es test2",
            "rm test2.MA?",
-           "maria_read_log -a -s",
-           "maria_chk -es test2",
+           "$maria_path/maria_read_log -a -s",
+           "$maria_path/maria_chk -es test2",
            "rm test2.MA?"
           );
 
-- 
2.30.9