summaryrefslogtreecommitdiff
path: root/storage/maria
diff options
context:
space:
mode:
authorunknown <guilhem@gbichot3.local>2006-09-01 17:53:10 +0200
committerunknown <guilhem@gbichot3.local>2006-09-01 17:53:10 +0200
commita1f25544d531b8909e58d36734ee6f65c1e189d5 (patch)
treef4a0d677568823d8784eda7d5d823fe417926a4a /storage/maria
parent8a2901a7584a87a326eee67b00ccb9eb8519ea03 (diff)
downloadmariadb-git-a1f25544d531b8909e58d36734ee6f65c1e189d5.tar.gz
WL#3234 "Maria - control file manager"
- fixes to the control file module - unit test for it - renames of all Maria files I created to start with ma_ storage/maria/ma_checkpoint.c: Rename: storage/maria/checkpoint.c -> storage/maria/ma_checkpoint.c storage/maria/ma_checkpoint.h: Rename: storage/maria/checkpoint.h -> storage/maria/ma_checkpoint.h storage/maria/ma_least_recently_dirtied.c: Rename: storage/maria/least_recently_dirtied.c -> storage/maria/ma_least_recently_dirtied.c storage/maria/ma_least_recently_dirtied.h: Rename: storage/maria/least_recently_dirtied.h -> storage/maria/ma_least_recently_dirtied.h storage/maria/ma_recovery.c: Rename: storage/maria/recovery.c -> storage/maria/ma_recovery.c storage/maria/ma_recovery.h: Rename: storage/maria/recovery.h -> storage/maria/ma_recovery.h storage/maria/Makefile.am: control file module and its unit test program storage/maria/ma_control_file.c: DBUG_ tags. Fix for gcc warnings. log_no -> logno (I felt "_no" sounded like a standalone "No" word). ma_ prefix for some functions. last_checkpoint_lsn_at_startup -> last_checkpoint_lsn (no need to make special vars for the values at startup). Same for last_logno. ma_control_file_write_and_force() now updates last_checkpoint_lsn and last_logno, the idea being that they belong to the module, others should not update them. And thus when the module shuts down, it zeroes those vars. storage/maria/ma_control_file.h: importing structs from Sanja to get the control file module to compile; we'll remove that when Sanja pushes the log handler. CONTROL_FILE_IMPOSSIBLE_LOGNO is 0, not FFFFFFFF. storage/maria/ma_control_file_test.c: Unit test program for the Maria control file module. Modelled after other ma_test* files in this directory (so, does not follow the unit test framework recently introduced with libtap; TODO as a task on all ma_test* programs). We test that writing to the control file works, and re-reading from it too, we check (by reading the file by ourselves) that its content on disk is correct, and check that a corrupted control file is detected.
Diffstat (limited to 'storage/maria')
-rw-r--r--storage/maria/Makefile.am7
-rw-r--r--storage/maria/control_file.h46
-rw-r--r--storage/maria/ma_checkpoint.c (renamed from storage/maria/checkpoint.c)0
-rw-r--r--storage/maria/ma_checkpoint.h (renamed from storage/maria/checkpoint.h)0
-rw-r--r--storage/maria/ma_control_file.c (renamed from storage/maria/control_file.c)105
-rw-r--r--storage/maria/ma_control_file.h75
-rw-r--r--storage/maria/ma_control_file_test.c290
-rw-r--r--storage/maria/ma_least_recently_dirtied.c (renamed from storage/maria/least_recently_dirtied.c)0
-rw-r--r--storage/maria/ma_least_recently_dirtied.h (renamed from storage/maria/least_recently_dirtied.h)0
-rw-r--r--storage/maria/ma_recovery.c (renamed from storage/maria/recovery.c)0
-rw-r--r--storage/maria/ma_recovery.h (renamed from storage/maria/recovery.h)0
11 files changed, 433 insertions, 90 deletions
diff --git a/storage/maria/Makefile.am b/storage/maria/Makefile.am
index d4315b4d446..e2689698d62 100644
--- a/storage/maria/Makefile.am
+++ b/storage/maria/Makefile.am
@@ -27,7 +27,7 @@ pkglib_LIBRARIES = libmaria.a
bin_PROGRAMS = maria_chk maria_pack maria_ftdump
maria_chk_DEPENDENCIES= $(LIBRARIES)
maria_pack_DEPENDENCIES=$(LIBRARIES)
-noinst_PROGRAMS = ma_test1 ma_test2 ma_test3 ma_rt_test ma_sp_test
+noinst_PROGRAMS = ma_test1 ma_test2 ma_test3 ma_rt_test ma_sp_test ma_control_file_test
noinst_HEADERS = maria_def.h ma_rt_index.h ma_rt_key.h ma_rt_mbr.h ma_sp_defs.h ma_fulltext.h ma_ftdefs.h ma_ft_test1.h ma_ft_eval.h
ma_test1_DEPENDENCIES= $(LIBRARIES)
ma_test2_DEPENDENCIES= $(LIBRARIES)
@@ -53,8 +53,9 @@ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
ma_ft_update.c ma_ft_boolean_search.c \
ma_ft_nlq_search.c ft_maria.c ma_sort.c \
ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c \
- ma_sp_key.c
-CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA?
+ ma_sp_key.c \
+ ma_control_file.c
+CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA? maria_control
DEFS =
SUFFIXES = .sh
diff --git a/storage/maria/control_file.h b/storage/maria/control_file.h
deleted file mode 100644
index 66a1f225cd8..00000000000
--- a/storage/maria/control_file.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- WL#3234 Maria control file
- First version written by Guilhem Bichot on 2006-04-27.
- Does not compile yet.
-*/
-
-#ifndef _control_file_h
-#define _control_file_h
-
-/* indicate absence of the log file number */
-#define CONTROL_FILE_IMPOSSIBLE_LOGNO 0xFFFFFFFF
-
-/* Here is the interface of this module */
-
-/*
- LSN of the last checkoint
- (if last_checkpoint_lsn_at_startup.file_no == CONTROL_FILE_IMPOSSIBLE_LOGNO
- then there was never a checkpoint)
-*/
-extern LSN last_checkpoint_lsn_at_startup;
-/*
- Last log number at startup time (if last_logno_at_startup ==
- CONTROL_FILE_IMPOSSIBLE_LOGNO then there is no log file yet)
-*/
-extern uint32 last_logno_at_startup;
-
-/*
- Looks for the control file. If absent, it's a fresh start, create file.
- If present, read it to find out last checkpoint's LSN and last log.
- Called at engine's start.
-*/
-int control_file_create_or_open();
-
-/*
- Write information durably to the control file.
- Called when we have created a new log (after syncing this log's creation)
- and when we have written a checkpoint (after syncing this log record).
-*/
-int control_file_write_and_force(LSN *checkpoint_lsn, uint32 log_no,
- uint objs_to_write);
-
-
-/* Free resources taken by control file subsystem */
-void control_file_end();
-
-#endif
diff --git a/storage/maria/checkpoint.c b/storage/maria/ma_checkpoint.c
index 22e7b93d2f4..22e7b93d2f4 100644
--- a/storage/maria/checkpoint.c
+++ b/storage/maria/ma_checkpoint.c
diff --git a/storage/maria/checkpoint.h b/storage/maria/ma_checkpoint.h
index a9de18c695f..a9de18c695f 100644
--- a/storage/maria/checkpoint.h
+++ b/storage/maria/ma_checkpoint.h
diff --git a/storage/maria/control_file.c b/storage/maria/ma_control_file.c
index 70eb62c645b..d36e1c04c0c 100644
--- a/storage/maria/control_file.c
+++ b/storage/maria/ma_control_file.c
@@ -5,7 +5,7 @@
*/
#include "maria_def.h"
-
+#include "ma_control_file.h"
/* Here is the implementation of this module */
@@ -17,16 +17,22 @@
/* total size should be < sector size for atomic write operation */
#define CONTROL_FILE_MAGIC_STRING "MACF"
#define CONTROL_FILE_MAGIC_STRING_OFFSET 0
-#define CONTROL_FILE_MAGIC_STRING_SIZE sizeof(CONTROL_FILE_MAGIC_STRING)
+#define CONTROL_FILE_MAGIC_STRING_SIZE 4
#define CONTROL_FILE_LSN_OFFSET (CONTROL_FILE_MAGIC_STRING_OFFSET + CONTROL_FILE_MAGIC_STRING_SIZE)
#define CONTROL_FILE_LSN_SIZE (4+4)
#define CONTROL_FILE_FILENO_OFFSET (CONTROL_FILE_LSN_OFFSET + CONTROL_FILE_LSN_SIZE)
#define CONTROL_FILE_FILENO_SIZE 4
#define CONTROL_FILE_MAX_SIZE (CONTROL_FILE_FILENO_OFFSET + CONTROL_FILE_FILENO_SIZE)
-
-LSN last_checkpoint_lsn_at_startup;
-uint32 last_logno_at_startup;
+/*
+ This module owns these two vars.
+ uint32 is always atomically updated, but LSN is 8 bytes, we will need
+ provisions to ensure that it's updated atomically in
+ ma_control_file_write_and_force(). Probably the log mutex could be
+ used. TODO.
+*/
+LSN last_checkpoint_lsn;
+uint32 last_logno;
/*
@@ -35,7 +41,7 @@ uint32 last_logno_at_startup;
*/
static int control_file_fd;
-static void lsn8store(char *buffer, LSN *lsn)
+static void lsn8store(char *buffer, const LSN *lsn)
{
int4store(buffer, lsn->file_no);
int4store(buffer + CONTROL_FILE_FILENO_SIZE, lsn->rec_offset);
@@ -53,21 +59,23 @@ static LSN lsn8korr(char *buffer)
Initialize control file subsystem
SYNOPSIS
- control_file_create_or_open()
+ ma_control_file_create_or_open()
- Looks for the control file. If absent, it's a fresh start, create file.
- If present, read it to find out last checkpoint's LSN and last log.
+ Looks for the control file. If absent, it's a fresh start, creates file.
+ If present, reads it to find out last checkpoint's LSN and last log, updates
+ the last_checkpoint_lsn and last_logno global variables.
Called at engine's start.
RETURN
0 - OK
1 - Error
*/
-int control_file_create_or_open()
+int ma_control_file_create_or_open()
{
char buffer[CONTROL_FILE_MAX_SIZE];
char name[FN_REFLEN];
MY_STAT stat_buff;
+ DBUG_ENTER("ma_control_file_create_or_open");
/*
If you change sizes in the #defines, you at least have to change the
@@ -79,12 +87,12 @@ int control_file_create_or_open()
/* name is concatenation of Maria's home dir and "control" */
if (fn_format(name, "control", maria_data_root, "", MYF(MY_WME)) == NullS)
- return 1;
+ DBUG_RETURN(1);
if ((control_file_fd= my_open(name,
O_CREAT | O_BINARY | /*O_DIRECT |*/ O_RDWR,
MYF(MY_WME))) < 0)
- return 1;
+ DBUG_RETURN(1);
/*
TODO: from "man fsync" on Linux:
@@ -96,16 +104,14 @@ int control_file_create_or_open()
*/
if (my_stat(name, &stat_buff, MYF(MY_WME)) == NULL)
- return 1;
+ DBUG_RETURN(1);
- if (stat_buff.st_size < CONTROL_FILE_MAX_SIZE)
+ if ((uint)stat_buff.st_size < CONTROL_FILE_MAX_SIZE)
{
/*
File shorter than expected (either we just created it, or a previous run
crashed between creation and first write); do first write.
- */
- char buffer[CONTROL_FILE_MAX_SIZE];
- /*
+
To be safer we should make sure that there are no logs or data/index
files around (indeed it could be that the control file alone was deleted
or not restored, and we should not go on with life at this point).
@@ -117,38 +123,41 @@ int control_file_create_or_open()
directory of logs, finding the newest log, reading it to find last
checkpoint... Slow but can save your db.
*/
- last_checkpoint_lsn_at_startup.file_no= CONTROL_FILE_IMPOSSIBLE_FILENO;
- last_checkpoint_lsn_at_startup.rec_offset= 0;
- last_logno_at_startup= CONTROL_FILE_IMPOSSIBLE_FILENO;
+ LSN imposs_lsn= CONTROL_FILE_IMPOSSIBLE_LSN;
+ uint32 imposs_logno= CONTROL_FILE_IMPOSSIBLE_FILENO;
/* init the file with these "undefined" values */
- return control_file_write_and_force(last_checkpoint_lsn_at_startup,
- last_logno_at_startup,
- CONTROL_FILE_WRITE_ALL);
+ DBUG_RETURN(ma_control_file_write_and_force(&imposs_lsn, imposs_logno,
+ CONTROL_FILE_WRITE_ALL));
}
/* Already existing file, read it */
if (my_read(control_file_fd, buffer, CONTROL_FILE_MAX_SIZE,
MYF(MY_FNABP | MY_WME)))
- return 1;
+ DBUG_RETURN(1);
if (memcmp(buffer + CONTROL_FILE_MAGIC_STRING_OFFSET,
CONTROL_FILE_MAGIC_STRING, CONTROL_FILE_MAGIC_STRING_SIZE))
- return 1;
- last_checkpoint_lsn_at_startup= lsn8korr(buffer + CONTROL_FILE_LSN_OFFSET);
- last_logno_at_startup= uint4korr(buffer + CONTROL_FILE_FILENO_OFFSET);
- return 0;
+ {
+ /*
+ TODO: what is the good way to report the error? Knowing that this
+ happens at startup, probably stderr.
+ */
+ DBUG_PRINT("error", ("bad magic string"));
+ DBUG_RETURN(1);
+ }
+ last_checkpoint_lsn= lsn8korr(buffer + CONTROL_FILE_LSN_OFFSET);
+ last_logno= uint4korr(buffer + CONTROL_FILE_FILENO_OFFSET);
+ DBUG_RETURN(0);
}
-#define CONTROL_FILE_WRITE_ALL 0 /* write all 3 objects */
-#define CONTROL_FILE_WRITE_ONLY_LSN 1
-#define CONTROL_FILE_WRITE_ONLY_LOGNO 2
/*
- Write information durably to the control file.
+ Write information durably to the control file; stores this information into
+ the last_checkpoint_lsn and last_logno global variables.
SYNOPSIS
- control_file_write_and_force()
+ ma_control_file_write_and_force()
checkpoint_lsn LSN of last checkpoint
- log_no last log file number
+ logno last log file number
objs_to_write what we should write
Called when we have created a new log (after syncing this log's creation)
@@ -163,38 +172,44 @@ int control_file_create_or_open()
1 - Error
*/
-int control_file_write_and_force(LSN *checkpoint_lsn, uint32 log_no,
+int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno,
uint objs_to_write)
{
char buffer[CONTROL_FILE_MAX_SIZE];
uint start, size;
+ DBUG_ENTER("ma_control_file_write_and_force");
+
memcpy(buffer + CONTROL_FILE_MAGIC_STRING_OFFSET,
CONTROL_FILE_MAGIC_STRING, CONTROL_FILE_MAGIC_STRING_SIZE);
/* write checkpoint LSN */
if (checkpoint_lsn)
lsn8store(buffer + CONTROL_FILE_LSN_OFFSET, checkpoint_lsn);
/* write logno */
- int4store(buffer + CONTROL_FILE_FILENO_OFFSET, log_no);
+ int4store(buffer + CONTROL_FILE_FILENO_OFFSET, logno);
if (objs_to_write == CONTROL_FILE_WRITE_ALL)
{
start= CONTROL_FILE_MAGIC_STRING_OFFSET;
size= CONTROL_FILE_MAX_SIZE;
+ last_checkpoint_lsn= *checkpoint_lsn;
+ last_logno= logno;
}
else if (objs_to_write == CONTROL_FILE_WRITE_ONLY_LSN)
{
start= CONTROL_FILE_LSN_OFFSET;
size= CONTROL_FILE_LSN_SIZE;
+ last_checkpoint_lsn= *checkpoint_lsn;
}
else if (objs_to_write == CONTROL_FILE_WRITE_ONLY_LOGNO)
{
start= CONTROL_FILE_FILENO_OFFSET;
size= CONTROL_FILE_FILENO_SIZE;
+ last_logno= logno;
}
else /* incorrect value of objs_to_write */
DBUG_ASSERT(0);
- return (my_pwrite(control_file_fd, buffer + start, size,
- start, MYF(MY_FNABP | MY_WME)) ||
- my_sync(control_file_fd, MYF(MY_WME)));
+ DBUG_RETURN(my_pwrite(control_file_fd, buffer + start, size,
+ start, MYF(MY_FNABP | MY_WME)) ||
+ my_sync(control_file_fd, MYF(MY_WME)));
}
@@ -202,10 +217,18 @@ int control_file_write_and_force(LSN *checkpoint_lsn, uint32 log_no,
Free resources taken by control file subsystem
SYNOPSIS
- control_file_end()
+ ma_control_file_end()
*/
-void control_file_end()
+void ma_control_file_end()
{
+ DBUG_ENTER("ma_control_file_end");
my_close(control_file_fd, MYF(MY_WME));
+ /*
+ As this module owns these variables, closing the module forbids access to
+ them (just a safety):
+ */
+ last_checkpoint_lsn= CONTROL_FILE_IMPOSSIBLE_LSN;
+ last_logno= CONTROL_FILE_IMPOSSIBLE_FILENO;
+ DBUG_VOID_RETURN;
}
diff --git a/storage/maria/ma_control_file.h b/storage/maria/ma_control_file.h
new file mode 100644
index 00000000000..d081718b919
--- /dev/null
+++ b/storage/maria/ma_control_file.h
@@ -0,0 +1,75 @@
+/*
+ WL#3234 Maria control file
+ First version written by Guilhem Bichot on 2006-04-27.
+ Does not compile yet.
+*/
+
+#ifndef _control_file_h
+#define _control_file_h
+
+/*
+ Not everybody needs to call the control file that's why control_file.h is
+ not in maria_def.h. However, policy or habit may want to change this.
+*/
+
+#ifndef REMOVE_WHEN_SANJA_PUSHES_LOG_HANDLER
+/*
+ this is to get the control file to compile, until Sanja pushes the log
+ handler which will supersede those definitions.
+*/
+typedef struct st_lsn {
+ uint32 file_no;
+ uint32 rec_offset;
+} LSN;
+#define maria_data_root "."
+#endif
+
+/*
+ indicate absence of the log file number; first log is always number 1, 0 is
+ impossible.
+*/
+#define CONTROL_FILE_IMPOSSIBLE_FILENO 0
+/* logs always have a header */
+#define CONTROL_FILE_IMPOSSIBLE_LOG_OFFSET 0
+/*
+ indicate absence of LSN.
+*/
+#define CONTROL_FILE_IMPOSSIBLE_LSN ((LSN){CONTROL_FILE_IMPOSSIBLE_FILENO,CONTROL_FILE_IMPOSSIBLE_LOG_OFFSET})
+
+/* Here is the interface of this module */
+
+/*
+ LSN of the last checkoint
+ (if last_checkpoint_lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO
+ then there was never a checkpoint)
+*/
+extern LSN last_checkpoint_lsn;
+/*
+ Last log number (if last_logno ==
+ CONTROL_FILE_IMPOSSIBLE_FILENO then there is no log file yet)
+*/
+extern uint32 last_logno;
+
+/*
+ Looks for the control file. If absent, it's a fresh start, create file.
+ If present, read it to find out last checkpoint's LSN and last log.
+ Called at engine's start.
+*/
+int ma_control_file_create_or_open();
+
+/*
+ Write information durably to the control file.
+ Called when we have created a new log (after syncing this log's creation)
+ and when we have written a checkpoint (after syncing this log record).
+*/
+#define CONTROL_FILE_WRITE_ALL 0 /* write all 3 objects */
+#define CONTROL_FILE_WRITE_ONLY_LSN 1
+#define CONTROL_FILE_WRITE_ONLY_LOGNO 2
+int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno,
+ uint objs_to_write);
+
+
+/* Free resources taken by control file subsystem */
+void ma_control_file_end();
+
+#endif
diff --git a/storage/maria/ma_control_file_test.c b/storage/maria/ma_control_file_test.c
new file mode 100644
index 00000000000..b3ba27c8e4b
--- /dev/null
+++ b/storage/maria/ma_control_file_test.c
@@ -0,0 +1,290 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Unit test of the control file module of the Maria engine */
+
+/* TODO: make it fit the mytap framework */
+
+/*
+ Note that it is not possible to test the durability of the write (can't
+ pull the plug programmatically :)
+*/
+
+#include "maria.h"
+#include "ma_control_file.h"
+#include <my_getopt.h>
+
+char file_name[FN_REFLEN];
+int fd= -1;
+
+static void clean_files();
+static void run_test_normal();
+static void run_test_abnormal();
+static void usage();
+static void get_options(int argc, char *argv[]);
+
+int main(int argc,char *argv[])
+{
+ MY_INIT(argv[0]);
+
+ get_options(argc,argv);
+
+ clean_files();
+ run_test_normal();
+ run_test_abnormal();
+
+ exit(0); /* all ok, if some test failed, we will have aborted */
+}
+
+/*
+ Abort unless given expression is non-zero.
+
+ SYNOPSIS
+ DIE_UNLESS(expr)
+
+ DESCRIPTION
+ We can't use any kind of system assert as we need to
+ preserve tested invariants in release builds as well.
+
+ NOTE
+ This is infamous copy-paste from mysql_client_test.c;
+ we should instead put it in some include in one single place.
+*/
+
+#define DIE_UNLESS(expr) \
+ ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0)))
+#define DIE_IF(expr) \
+ ((void) (!(expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0)))
+#define DIE(expr) \
+ die(__FILE__, __LINE__, #expr)
+
+void die(const char *file, int line, const char *expr)
+{
+ fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr);
+ abort();
+}
+
+
+static void clean_files()
+{
+ DIE_IF(fn_format(file_name, "control", maria_data_root, "", MYF(MY_WME)) ==
+ NullS);
+ my_delete(file_name, MYF(0)); /* maybe file does not exist, ignore error */
+}
+
+
+static void run_test_normal()
+{
+ LSN checkpoint_lsn;
+ uint32 logno;
+ uint objs_to_write;
+ uint i;
+ char buffer[4];
+
+ /* TEST0: Instance starts from scratch (control file does not exist) */
+ DIE_UNLESS(ma_control_file_create_or_open() == 0);
+ /* Check that the module reports no information */
+ DIE_UNLESS(last_logno == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset == CONTROL_FILE_IMPOSSIBLE_LOG_OFFSET);
+
+ /* TEST1: Simulate creation of one log */
+
+ objs_to_write= CONTROL_FILE_WRITE_ONLY_LOGNO;
+ logno= 123;
+ DIE_UNLESS(ma_control_file_write_and_force(NULL, logno,
+ objs_to_write) == 0);
+ /* Check that last_logno was updated */
+ DIE_UNLESS(last_logno == logno);
+ /* Simulate shutdown */
+ ma_control_file_end();
+ /* Verify amnesia */
+ DIE_UNLESS(last_logno == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset == CONTROL_FILE_IMPOSSIBLE_LOG_OFFSET);
+ /* And restart */
+ DIE_UNLESS(ma_control_file_create_or_open() == 0);
+ DIE_UNLESS(last_logno == logno);
+
+ /* TEST2: Simulate creation of 5 logs */
+
+ objs_to_write= CONTROL_FILE_WRITE_ONLY_LOGNO;
+ logno= 100;
+ for (i= 0; i<5; i++)
+ {
+ logno*= 3;
+ DIE_UNLESS(ma_control_file_write_and_force(NULL, logno,
+ objs_to_write) == 0);
+ }
+ ma_control_file_end();
+ DIE_UNLESS(last_logno == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset == CONTROL_FILE_IMPOSSIBLE_LOG_OFFSET);
+ DIE_UNLESS(ma_control_file_create_or_open() == 0);
+ DIE_UNLESS(last_logno == logno);
+
+ /*
+ TEST3: Simulate one checkpoint, one log creation, two checkpoints, one
+ log creation.
+ */
+
+ objs_to_write= CONTROL_FILE_WRITE_ONLY_LSN;
+ checkpoint_lsn= (LSN){5, 10000};
+ logno= 10;
+ DIE_UNLESS(ma_control_file_write_and_force(&checkpoint_lsn, logno,
+ objs_to_write) == 0);
+ /* check that last_logno was not updated */
+ DIE_UNLESS(last_logno != logno);
+ /* Check that last_checkpoint_lsn was updated */
+ DIE_UNLESS(last_checkpoint_lsn.file_no == checkpoint_lsn.file_no);
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset == checkpoint_lsn.rec_offset);
+
+ objs_to_write= CONTROL_FILE_WRITE_ONLY_LOGNO;
+ checkpoint_lsn= (LSN){5, 20000};
+ logno= 17;
+ DIE_UNLESS(ma_control_file_write_and_force(&checkpoint_lsn, logno,
+ objs_to_write) == 0);
+ /* Check that checkpoint LSN was not updated */
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset != checkpoint_lsn.rec_offset);
+ objs_to_write= CONTROL_FILE_WRITE_ONLY_LSN;
+ checkpoint_lsn= (LSN){17, 20000};
+ DIE_UNLESS(ma_control_file_write_and_force(&checkpoint_lsn, logno,
+ objs_to_write) == 0);
+ objs_to_write= CONTROL_FILE_WRITE_ONLY_LSN;
+ checkpoint_lsn= (LSN){17, 45000};
+ DIE_UNLESS(ma_control_file_write_and_force(&checkpoint_lsn, logno,
+ objs_to_write) == 0);
+ objs_to_write= CONTROL_FILE_WRITE_ONLY_LOGNO;
+ logno= 19;
+ DIE_UNLESS(ma_control_file_write_and_force(&checkpoint_lsn, logno,
+ objs_to_write) == 0);
+
+ ma_control_file_end();
+ DIE_UNLESS(last_logno == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.file_no == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset == CONTROL_FILE_IMPOSSIBLE_LOG_OFFSET);
+ DIE_UNLESS(ma_control_file_create_or_open() == 0);
+ DIE_UNLESS(last_logno == logno);
+ DIE_UNLESS(last_checkpoint_lsn.file_no == checkpoint_lsn.file_no);
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset == checkpoint_lsn.rec_offset);
+
+ /*
+ TEST4: actually check by ourselves the content of the file.
+ Note that constants (offsets) are hard-coded here, precisely to prevent
+ someone from changing them in the control file module and breaking
+ backward-compatibility.
+ */
+
+ DIE_IF((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) < 0);
+ DIE_IF(my_read(fd, buffer, 16, MYF(MY_FNABP | MY_WME)) != 0);
+ DIE_IF(my_close(fd, MYF(MY_WME)) != 0);
+ i= uint4korr(buffer+4);
+ DIE_UNLESS(i == last_checkpoint_lsn.file_no);
+ i= uint4korr(buffer+8);
+ DIE_UNLESS(i == last_checkpoint_lsn.rec_offset);
+ i= uint4korr(buffer+12);
+ DIE_UNLESS(i == last_logno);
+
+
+ /* TEST5: Simulate stop/start/nothing/stop/start */
+
+ ma_control_file_end();
+ DIE_UNLESS(last_logno == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(ma_control_file_create_or_open() == 0);
+ ma_control_file_end();
+ DIE_UNLESS(last_logno == CONTROL_FILE_IMPOSSIBLE_FILENO);
+ DIE_UNLESS(ma_control_file_create_or_open() == 0);
+ DIE_UNLESS(last_logno == logno);
+ DIE_UNLESS(last_checkpoint_lsn.file_no == checkpoint_lsn.file_no);
+ DIE_UNLESS(last_checkpoint_lsn.rec_offset == checkpoint_lsn.rec_offset);
+
+}
+
+static void run_test_abnormal()
+{
+ /* Corrupt the control file */
+ DIE_IF((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) < 0);
+ DIE_IF(my_write(fd, "papa", 4, MYF(MY_FNABP | MY_WME)) != 0);
+ DIE_IF(my_close(fd, MYF(MY_WME)) != 0);
+
+ /* Check that control file module sees the problem */
+ DIE_IF(ma_control_file_create_or_open() == 0);
+}
+
+
+static struct my_option my_long_options[] =
+{
+#ifndef DBUG_OFF
+ {"debug", '#', "Debug log.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"help", '?', "Display help and exit",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version number and exit",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+static void version()
+{
+ printf("ma_control_file_test: unit test for the control file "
+ "module of the Maria storage engine. Ver 1.0 \n");
+}
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument)
+{
+ switch(optid) {
+ case 'V':
+ version();
+ exit(0);
+ case '#':
+ DBUG_PUSH (argument);
+ break;
+ case '?':
+ version();
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+
+/* Read options */
+
+static void get_options(int argc, char *argv[])
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ return;
+} /* get options */
+
+
+static void usage()
+{
+ printf("Usage: %s [options]\n\n", my_progname);
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
diff --git a/storage/maria/least_recently_dirtied.c b/storage/maria/ma_least_recently_dirtied.c
index c6285fe47cd..c6285fe47cd 100644
--- a/storage/maria/least_recently_dirtied.c
+++ b/storage/maria/ma_least_recently_dirtied.c
diff --git a/storage/maria/least_recently_dirtied.h b/storage/maria/ma_least_recently_dirtied.h
index 6a30db4b5f0..6a30db4b5f0 100644
--- a/storage/maria/least_recently_dirtied.h
+++ b/storage/maria/ma_least_recently_dirtied.h
diff --git a/storage/maria/recovery.c b/storage/maria/ma_recovery.c
index babf7507ef1..babf7507ef1 100644
--- a/storage/maria/recovery.c
+++ b/storage/maria/ma_recovery.c
diff --git a/storage/maria/recovery.h b/storage/maria/ma_recovery.h
index b85ffdeef59..b85ffdeef59 100644
--- a/storage/maria/recovery.h
+++ b/storage/maria/ma_recovery.h