Commit 26fb3606 authored by unknown's avatar unknown

WL#3234 Maria control file manager.

Fitting ma_control_file_test into the mytap unittest framework:
new directories:
- unittest/storage/ for unit tests of any storage engine
- unittest/storage/maria for ... Maria, containing ma_control_file-t.
Later, older tests like ma_test*, ma_test_all (but which is Unix
dependent in its current form) could move here too.
The plugins macro enable building of unittest/storage/X for any
enabled engine X which has such a directory.
If Falcon wants to have unit tests there too, I may have to merge
this patch into 5.x one day.


config/ac-macros/plugins.m4:
  If a storage engine has a directory in unittest/storage, build this
  directory.
configure.in:
  build storage engines' unit tests.
storage/maria/Makefile.am:
  ma_control_file_test moves to unittest/storage/maria
storage/maria/ma_control_file.c:
  more error codes when opening the control file fails.
  ma_control_file_end() may now return an error if my_close() failed.
storage/maria/ma_control_file.h:
  more error codes when opening the control file fails.
unittest/Makefile.am:
  adding unit tests for storage engines.
  Note that unit.pl simply recurses into "storage", so if a unit test for
  storage engine X has been built previously, and now you re-configure
  (without making clean) to disable this engine, then the unit test of
  X will not be rebuilt but will still be present in storage/X, so will
  be run.
unittest/storage/maria/ma_control_file-t.c:
  Making the test fit the mytap framework (return all the way up
  the stack instead of assert(); use the mytap functions plan(), ok() etc).
  Adding test of file too short/long.
unittest/storage/maria/Makefile.am:
  a_control_file-t is added to the Maria unit tests.
  Later, older tests (ma_test1 etc) could also move here.
unittest/storage/Makefile.am:
  New BitKeeper file ``unittest/storage/Makefile.am''
parent e321f8eb
...@@ -280,6 +280,7 @@ AC_DEFUN([MYSQL_CONFIGURE_PLUGINS],[ ...@@ -280,6 +280,7 @@ AC_DEFUN([MYSQL_CONFIGURE_PLUGINS],[
_MYSQL_EMIT_PLUGIN_ACTIONS(m4_bpatsubst(__mysql_plugin_list__, :, [,])) _MYSQL_EMIT_PLUGIN_ACTIONS(m4_bpatsubst(__mysql_plugin_list__, :, [,]))
AC_SUBST([mysql_se_dirs]) AC_SUBST([mysql_se_dirs])
AC_SUBST([mysql_pg_dirs]) AC_SUBST([mysql_pg_dirs])
AC_SUBST([mysql_se_unittest_dirs])
]) ])
]) ])
]) ])
...@@ -315,6 +316,7 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[ ...@@ -315,6 +316,7 @@ AC_DEFUN([__MYSQL_EMIT_CHECK_PLUGIN],[
]) ])
AC_MSG_CHECKING([whether to use ]$3) AC_MSG_CHECKING([whether to use ]$3)
mysql_use_plugin_dir="" mysql_use_plugin_dir=""
mysql_use_plugin_unittest_dir=""
m4_ifdef([$10],[ m4_ifdef([$10],[
if test "X[$mysql_plugin_]$2" = Xyes -a \ if test "X[$mysql_plugin_]$2" = Xyes -a \
"X[$with_plugin_]$2" != Xno -o \ "X[$with_plugin_]$2" != Xno -o \
...@@ -407,10 +409,24 @@ dnl Although this is "pretty", it breaks libmysqld build ...@@ -407,10 +409,24 @@ dnl Although this is "pretty", it breaks libmysqld build
m4_syscmd(test -f "$6/configure") m4_syscmd(test -f "$6/configure")
ifelse(m4_sysval, 0, ifelse(m4_sysval, 0,
[AC_CONFIG_SUBDIRS($6)], [AC_CONFIG_SUBDIRS($6)],
[AC_CONFIG_FILES($6/Makefile)] [
AC_CONFIG_FILES($6/Makefile)
m4_syscmd(test -d "unittest/$6")
ifelse(m4_sysval, 0,
[
mysql_use_plugin_unittest_dir="$6"
AC_CONFIG_FILES(unittest/$6/Makefile)
], [])
]
) )
ifelse(m4_substr($6, 0, 8), [storage/], ifelse(m4_substr($6, 0, 8), [storage/],
[mysql_se_dirs="$mysql_se_dirs ]m4_substr($6, 8)", [
[mysql_se_name="]m4_substr($6, 8)"
mysql_se_dirs="$mysql_se_dirs $mysql_se_name"
if test -n "$mysql_use_plugin_unittest_dir" ; then
mysql_se_unittest_dirs="$mysql_se_unitest_dirs $mysql_se_name"
fi
],
m4_substr($6, 0, 7), [plugin/], m4_substr($6, 0, 7), [plugin/],
[mysql_pg_dirs="$mysql_pg_dirs ]m4_substr($6, 7)", [mysql_pg_dirs="$mysql_pg_dirs ]m4_substr($6, 7)",
[AC_FATAL([don't know how to handle plugin dir ]$6)]) [AC_FATAL([don't know how to handle plugin dir ]$6)])
......
...@@ -2482,6 +2482,7 @@ AC_SUBST(MAKE_BINARY_DISTRIBUTION_OPTIONS) ...@@ -2482,6 +2482,7 @@ AC_SUBST(MAKE_BINARY_DISTRIBUTION_OPTIONS)
AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl
unittest/Makefile unittest/mytap/Makefile unittest/mytap/t/Makefile dnl unittest/Makefile unittest/mytap/Makefile unittest/mytap/t/Makefile dnl
unittest/mysys/Makefile unittest/examples/Makefile dnl unittest/mysys/Makefile unittest/examples/Makefile dnl
unittest/storage/Makefile dnl
strings/Makefile regex/Makefile storage/Makefile dnl strings/Makefile regex/Makefile storage/Makefile dnl
man/Makefile BUILD/Makefile vio/Makefile dnl man/Makefile BUILD/Makefile vio/Makefile dnl
libmysql/Makefile client/Makefile dnl libmysql/Makefile client/Makefile dnl
......
...@@ -47,7 +47,7 @@ maria_pack_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \ ...@@ -47,7 +47,7 @@ maria_pack_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
$(top_builddir)/mysys/libmysys.a \ $(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \ $(top_builddir)/dbug/libdbug.a \
$(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
noinst_PROGRAMS = ma_test1 ma_test2 ma_test3 ma_rt_test ma_sp_test ma_control_file_test noinst_PROGRAMS = ma_test1 ma_test2 ma_test3 ma_rt_test ma_sp_test
noinst_HEADERS = maria_def.h ma_rt_index.h ma_rt_key.h ma_rt_mbr.h \ 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_sp_defs.h ma_fulltext.h ma_ftdefs.h ma_ft_test1.h ma_ft_eval.h \
ma_control_file.h ha_maria.h ma_control_file.h ha_maria.h
...@@ -89,12 +89,6 @@ ma_sp_test_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \ ...@@ -89,12 +89,6 @@ ma_sp_test_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
$(top_builddir)/mysys/libmysys.a \ $(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \ $(top_builddir)/dbug/libdbug.a \
$(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
ma_control_file_test_DEPENDENCIES= $(LIBRARIES)
ma_control_file_test_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
$(top_builddir)/storage/myisam/libmyisam.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
ma_rnext.c ma_rnext_same.c \ ma_rnext.c ma_rnext_same.c \
ma_search.c ma_page.c ma_key.c ma_locking.c \ ma_search.c ma_page.c ma_key.c ma_locking.c \
...@@ -113,7 +107,7 @@ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \ ...@@ -113,7 +107,7 @@ libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
ha_maria.cc \ ha_maria.cc \
ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c \ ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c \
ma_sp_key.c ma_control_file.c 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 CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA?
SUFFIXES = .sh SUFFIXES = .sh
......
...@@ -41,7 +41,7 @@ uint32 last_logno; ...@@ -41,7 +41,7 @@ uint32 last_logno;
Control file is less then 512 bytes (a disk sector), Control file is less then 512 bytes (a disk sector),
to be as atomic as possible to be as atomic as possible
*/ */
static int control_file_fd; static int control_file_fd= -1;
static void lsn8store(char *buffer, const LSN *lsn) static void lsn8store(char *buffer, const LSN *lsn)
{ {
...@@ -87,15 +87,16 @@ static char simple_checksum(char *buffer, uint size) ...@@ -87,15 +87,16 @@ static char simple_checksum(char *buffer, uint size)
RETURN RETURN
0 - OK 0 - OK
1 - Error 1 - Error (in which case the file is left closed)
*/ */
int ma_control_file_create_or_open() CONTROL_FILE_ERROR ma_control_file_create_or_open()
{ {
char buffer[CONTROL_FILE_SIZE]; char buffer[CONTROL_FILE_SIZE];
char name[FN_REFLEN]; char name[FN_REFLEN];
MY_STAT stat_buff; MY_STAT stat_buff;
my_bool create_file; my_bool create_file;
int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR; int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR;
int error= CONTROL_FILE_UNKNOWN_ERROR;
DBUG_ENTER("ma_control_file_create_or_open"); DBUG_ENTER("ma_control_file_create_or_open");
/* /*
...@@ -106,16 +107,19 @@ int ma_control_file_create_or_open() ...@@ -106,16 +107,19 @@ int ma_control_file_create_or_open()
DBUG_ASSERT(CONTROL_FILE_LSN_SIZE == (4+4)); DBUG_ASSERT(CONTROL_FILE_LSN_SIZE == (4+4));
DBUG_ASSERT(CONTROL_FILE_FILENO_SIZE == 4); DBUG_ASSERT(CONTROL_FILE_FILENO_SIZE == 4);
/* name is concatenation of Maria's home dir and "control" */ if (control_file_fd >= 0) /* already open */
if (fn_format(name, "control", maria_data_root, "", MYF(MY_WME)) == NullS) DBUG_RETURN(0);
DBUG_RETURN(1);
if (fn_format(name, CONTROL_FILE_BASE_NAME,
maria_data_root, "", MYF(MY_WME)) == NullS)
DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
create_file= test(my_access(name,F_OK)); create_file= test(my_access(name,F_OK));
if (create_file) if (create_file)
{ {
if ((control_file_fd= my_create(name, 0, open_flags, MYF(0))) < 0) if ((control_file_fd= my_create(name, 0, open_flags, MYF(0))) < 0)
DBUG_RETURN(1); DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
/* /*
TODO: from "man fsync" on Linux: TODO: from "man fsync" on Linux:
"fsync does not necessarily ensure that the entry in the directory "fsync does not necessarily ensure that the entry in the directory
...@@ -147,12 +151,12 @@ int ma_control_file_create_or_open() ...@@ -147,12 +151,12 @@ int ma_control_file_create_or_open()
/* Otherwise, file exists */ /* Otherwise, file exists */
if ((control_file_fd= my_open(name, open_flags, MYF(MY_WME))) < 0) if ((control_file_fd= my_open(name, open_flags, MYF(MY_WME))) < 0)
DBUG_RETURN(1); goto err;
if (my_stat(name, &stat_buff, MYF(MY_WME)) == NULL) if (my_stat(name, &stat_buff, MYF(MY_WME)) == NULL)
DBUG_RETURN(1); goto err;
if ((uint)stat_buff.st_size != CONTROL_FILE_SIZE) if ((uint)stat_buff.st_size < CONTROL_FILE_SIZE)
{ {
/* /*
Given that normally we write only a sector and it's atomic, the only Given that normally we write only a sector and it's atomic, the only
...@@ -165,31 +169,43 @@ int ma_control_file_create_or_open() ...@@ -165,31 +169,43 @@ int ma_control_file_create_or_open()
disk/filesystem has a problem. disk/filesystem has a problem.
So let's be rigid. So let's be rigid.
*/ */
my_message(0, "wrong file size", MYF(0)); /* TODO: improve errors */ my_message(0, "too small file", MYF(0)); /* TODO: improve errors */
my_error(HA_ERR_CRASHED, MYF(0), name); error= CONTROL_FILE_TOO_SMALL;
DBUG_RETURN(1); goto err;
}
if ((uint)stat_buff.st_size > CONTROL_FILE_SIZE)
{
my_message(0, "too big file", MYF(0)); /* TODO: improve errors */
error= CONTROL_FILE_TOO_BIG;
goto err;
} }
if (my_read(control_file_fd, buffer, CONTROL_FILE_SIZE, if (my_read(control_file_fd, buffer, CONTROL_FILE_SIZE,
MYF(MY_FNABP | MY_WME))) MYF(MY_FNABP | MY_WME)))
DBUG_RETURN(1); goto err;
if (memcmp(buffer + CONTROL_FILE_MAGIC_STRING_OFFSET, if (memcmp(buffer + CONTROL_FILE_MAGIC_STRING_OFFSET,
CONTROL_FILE_MAGIC_STRING, CONTROL_FILE_MAGIC_STRING_SIZE)) CONTROL_FILE_MAGIC_STRING, CONTROL_FILE_MAGIC_STRING_SIZE))
{ {
my_message(0, "bad magic string", MYF(0)); my_message(0, "bad magic string", MYF(0));
DBUG_RETURN(1); error= CONTROL_FILE_BAD_MAGIC_STRING;
goto err;
} }
if (simple_checksum(buffer + CONTROL_FILE_LSN_OFFSET, if (simple_checksum(buffer + CONTROL_FILE_LSN_OFFSET,
CONTROL_FILE_SIZE - CONTROL_FILE_LSN_OFFSET) != CONTROL_FILE_SIZE - CONTROL_FILE_LSN_OFFSET) !=
buffer[CONTROL_FILE_CHECKSUM_OFFSET]) buffer[CONTROL_FILE_CHECKSUM_OFFSET])
{ {
my_message(0, "checksum mismatch", MYF(0)); my_message(0, "checksum mismatch", MYF(0));
DBUG_RETURN(1); error= CONTROL_FILE_BAD_CHECKSUM;
goto err;
} }
last_checkpoint_lsn= lsn8korr(buffer + CONTROL_FILE_LSN_OFFSET); last_checkpoint_lsn= lsn8korr(buffer + CONTROL_FILE_LSN_OFFSET);
last_logno= uint4korr(buffer + CONTROL_FILE_FILENO_OFFSET); last_logno= uint4korr(buffer + CONTROL_FILE_FILENO_OFFSET);
DBUG_RETURN(0); DBUG_RETURN(0);
err:
ma_control_file_end();
DBUG_RETURN(error);
} }
...@@ -227,6 +243,8 @@ int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno, ...@@ -227,6 +243,8 @@ int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno,
my_bool update_checkpoint_lsn= FALSE, update_logno= FALSE; my_bool update_checkpoint_lsn= FALSE, update_logno= FALSE;
DBUG_ENTER("ma_control_file_write_and_force"); DBUG_ENTER("ma_control_file_write_and_force");
DBUG_ASSERT(control_file_fd >= 0); /* must be open */
memcpy(buffer + CONTROL_FILE_MAGIC_STRING_OFFSET, memcpy(buffer + CONTROL_FILE_MAGIC_STRING_OFFSET,
CONTROL_FILE_MAGIC_STRING, CONTROL_FILE_MAGIC_STRING_SIZE); CONTROL_FILE_MAGIC_STRING, CONTROL_FILE_MAGIC_STRING_SIZE);
...@@ -277,15 +295,26 @@ int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno, ...@@ -277,15 +295,26 @@ int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno,
ma_control_file_end() ma_control_file_end()
*/ */
void ma_control_file_end() int ma_control_file_end()
{ {
int close_error;
DBUG_ENTER("ma_control_file_end"); DBUG_ENTER("ma_control_file_end");
my_close(control_file_fd, MYF(MY_WME));
if (control_file_fd < 0) /* already closed */
DBUG_RETURN(0);
close_error= my_close(control_file_fd, MYF(MY_WME));
/*
As my_close() frees structures even if close() fails, we do the same,
i.e. we mark the file as closed in all cases.
*/
control_file_fd= -1;
/* /*
As this module owns these variables, closing the module forbids access to As this module owns these variables, closing the module forbids access to
them (just a safety): them (just a safety):
*/ */
last_checkpoint_lsn= CONTROL_FILE_IMPOSSIBLE_LSN; last_checkpoint_lsn= CONTROL_FILE_IMPOSSIBLE_LSN;
last_logno= CONTROL_FILE_IMPOSSIBLE_FILENO; last_logno= CONTROL_FILE_IMPOSSIBLE_FILENO;
DBUG_VOID_RETURN;
DBUG_RETURN(close_error);
} }
...@@ -24,6 +24,7 @@ typedef struct st_lsn { ...@@ -24,6 +24,7 @@ typedef struct st_lsn {
#define maria_data_root "." #define maria_data_root "."
#endif #endif
#define CONTROL_FILE_BASE_NAME "maria_control"
/* /*
indicate absence of the log file number; first log is always number 1, 0 is indicate absence of the log file number; first log is always number 1, 0 is
impossible. impossible.
...@@ -55,7 +56,15 @@ extern uint32 last_logno; ...@@ -55,7 +56,15 @@ extern uint32 last_logno;
If present, read it to find out last checkpoint's LSN and last log. If present, read it to find out last checkpoint's LSN and last log.
Called at engine's start. Called at engine's start.
*/ */
int ma_control_file_create_or_open(); typedef enum enum_control_file_error {
CONTROL_FILE_OK= 0,
CONTROL_FILE_TOO_SMALL,
CONTROL_FILE_TOO_BIG,
CONTROL_FILE_BAD_MAGIC_STRING,
CONTROL_FILE_BAD_CHECKSUM,
CONTROL_FILE_UNKNOWN_ERROR /* any other error */
} CONTROL_FILE_ERROR;
CONTROL_FILE_ERROR ma_control_file_create_or_open();
/* /*
Write information durably to the control file. Write information durably to the control file.
...@@ -70,6 +79,6 @@ int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno, ...@@ -70,6 +79,6 @@ int ma_control_file_write_and_force(const LSN *checkpoint_lsn, uint32 logno,
/* Free resources taken by control file subsystem */ /* Free resources taken by control file subsystem */
void ma_control_file_end(); int ma_control_file_end();
#endif #endif
This diff is collapsed.
SUBDIRS = mytap . mysys examples SUBDIRS = mytap . mysys storage examples
noinst_SCRIPTS = unit noinst_SCRIPTS = unit
EXTRA_DIST = unit.pl EXTRA_DIST = unit.pl
CLEANFILES = unit CLEANFILES = unit
unittests = mytap mysys unittests = mytap mysys storage
test: unit test: unit
./unit run $(unittests) ./unit run $(unittests)
......
# Copyright (C) 2000 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
# Process this file with automake to create Makefile.in
AUTOMAKE_OPTIONS = foreign
# These are built from source in the Docs directory
EXTRA_DIST =
# Cannot use @mysql_se_dirs@ as not all engines have unit tests here
SUBDIRS = @mysql_se_unittest_dirs@
# Don't update the files from bitkeeper
%::SCCS/s.%
# Copyright (C) 2000 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
AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include
AM_CPPFLAGS += -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
# Only reason to link with libmyisam.a here is that it's where some fulltext
# pieces are (but soon we'll remove fulltext dependencies from Maria).
LDADD= $(top_builddir)/unittest/mytap/libmytap.a \
$(top_builddir)/storage/maria/libmaria.a \
$(top_builddir)/storage/myisam/libmyisam.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
noinst_PROGRAMS = ma_control_file-t
CLEANFILES = maria_control
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment