Store maximum transaction id into control file at clean shutdown.
This can serve to maria_chk to check that trids found in rows and keys are not too big. Also used by Recovery when logs are lost. Options --require-control-file, --datadir, --log-dir (yes, the dashes are inconsistent but I imitated mysqld --datadir and --maria-log-dir) for maria_chk. Lock control file _before_ reading its content. storage/maria/ha_maria.cc: new prototype storage/maria/ma_check.c: A function to find the max trid in the system (consults transaction manager and control file), to check tables. storage/maria/ma_checkpoint.c: new prototype storage/maria/ma_control_file.c: Store max trid into control file, in a backward-compatible way (can still read old control files). Parameter to ma_control_file_open(), to not create the log if it's missing (maria_chk needs that). Lock control file _before_ reading its content. Fix for a segfault when reading an old control file (bzero() with a negative second argument) storage/maria/ma_control_file.h: changes to the control file module's API storage/maria/ma_init.c: When Maria shuts down cleanly, store max trid into control file. storage/maria/ma_loghandler.c: new prototype storage/maria/ma_recovery.c: During recovery, consult max trid stored in control file, in case it is bigger than what we found in log (case of logs manually removed by user). storage/maria/ma_test1.c: new prototype storage/maria/ma_test2.c: new prototype storage/maria/maria_chk.c: New option --require-control-file (abort if control file not found), --datadir (path for control file (and for logs if --log-dir not specified)), --log-dir (path for logs). Try to open control file when maria_chk starts. storage/maria/maria_read_log.c: new prototype storage/maria/trnman.c: A new function to know max trid in transaction manager storage/maria/trnman_public.h: New function storage/maria/unittest/ma_control_file-t.c: new prototypes. Testing storing and retrieving the max trid to/from control file storage/maria/unittest/ma_test_loghandler-t.c: new prototype storage/maria/unittest/ma_test_loghandler_first_lsn-t.c: new prototype storage/maria/unittest/ma_test_loghandler_max_lsn-t.c: new prototype storage/maria/unittest/ma_test_loghandler_multigroup-t.c: new prototype storage/maria/unittest/ma_test_loghandler_multithread-t.c: new prototype storage/maria/unittest/ma_test_loghandler_noflush-t.c: new prototype storage/maria/unittest/ma_test_loghandler_nologs-t.c: new prototype storage/maria/unittest/ma_test_loghandler_pagecache-t.c: new prototype storage/maria/unittest/ma_test_loghandler_purge-t.c: new prototype
This commit is contained in:
parent
42f970de3c
commit
722a8ebe5b
@ -2768,7 +2768,7 @@ static int ha_maria_init(void *p)
|
||||
maria_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
|
||||
bzero(maria_log_pagecache, sizeof(*maria_log_pagecache));
|
||||
maria_tmpdir= &mysql_tmpdir_list; /* For REDO */
|
||||
res= maria_init() || ma_control_file_create_or_open() ||
|
||||
res= maria_init() || ma_control_file_open(TRUE) ||
|
||||
!init_pagecache(maria_pagecache,
|
||||
(size_t) pagecache_buffer_size, pagecache_division_limit,
|
||||
pagecache_age_threshold, maria_block_size, 0) ||
|
||||
|
@ -98,6 +98,7 @@ static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
|
||||
static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file);
|
||||
static my_bool _ma_flush_table_files_before_swap(HA_CHECK *param,
|
||||
MARIA_HA *info);
|
||||
static TrID max_trid_in_system(void);
|
||||
|
||||
|
||||
void maria_chk_init(HA_CHECK *param)
|
||||
@ -6444,3 +6445,21 @@ static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
|
||||
"error: %d",
|
||||
llstr(position / block_size, buff), my_errno);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
When we want to check a table, we verify that the transaction ids of rows
|
||||
and keys are not bigger than the biggest id generated by Maria so far, which
|
||||
is returned by the function below.
|
||||
|
||||
@note If control file is not open, 0 may be returned; to not confuse
|
||||
this with a valid max trid of 0, the caller should notice that it failed to
|
||||
open the control file (ma_control_file_inited() can serve for that).
|
||||
*/
|
||||
|
||||
static TrID max_trid_in_system(void)
|
||||
{
|
||||
TrID id= trnman_get_max_trid(); /* 0 if transac manager not initialized */
|
||||
/* 'id' may be far bigger, if last shutdown is old */
|
||||
return max(id, max_trid_in_control_file);
|
||||
}
|
||||
|
@ -244,8 +244,8 @@ static int really_execute_checkpoint(void)
|
||||
such hook would be called before translog_flush (and we must be sure
|
||||
that log was flushed before we write to the control file).
|
||||
*/
|
||||
if (unlikely(ma_control_file_write_and_force(lsn, FILENO_IMPOSSIBLE,
|
||||
CONTROL_FILE_UPDATE_ONLY_LSN)))
|
||||
if (unlikely(ma_control_file_write_and_force(lsn, last_logno,
|
||||
max_trid_in_control_file)))
|
||||
{
|
||||
translog_unlock();
|
||||
goto err;
|
||||
|
@ -77,8 +77,9 @@ one should increment the control file version number.
|
||||
#define CF_LSN_SIZE LSN_STORE_SIZE
|
||||
#define CF_FILENO_OFFSET (CF_LSN_OFFSET + CF_LSN_SIZE)
|
||||
#define CF_FILENO_SIZE 4
|
||||
|
||||
#define CF_CHANGEABLE_TOTAL_SIZE (CF_FILENO_OFFSET + CF_FILENO_SIZE)
|
||||
#define CF_MAX_TRID_OFFSET (CF_FILENO_OFFSET + CF_FILENO_SIZE)
|
||||
#define CF_MAX_TRID_SIZE TRANSID_SIZE
|
||||
#define CF_CHANGEABLE_TOTAL_SIZE (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE)
|
||||
|
||||
/*
|
||||
The following values should not be changed, except when changing version
|
||||
@ -100,6 +101,11 @@ one should increment the control file version number.
|
||||
*/
|
||||
LSN last_checkpoint_lsn= LSN_IMPOSSIBLE;
|
||||
uint32 last_logno= FILENO_IMPOSSIBLE;
|
||||
/**
|
||||
The maximum transaction id given to a transaction. It is only updated at
|
||||
clean shutdown (in case of crash, logs have better information).
|
||||
*/
|
||||
TrID max_trid_in_control_file= 0;
|
||||
|
||||
/**
|
||||
@brief If log's lock should be asserted when writing to control file.
|
||||
@ -131,9 +137,6 @@ static CONTROL_FILE_ERROR create_control_file(const char *name,
|
||||
uchar buffer[CF_CREATE_TIME_TOTAL_SIZE];
|
||||
DBUG_ENTER("maria_create_control_file");
|
||||
|
||||
/* in a recovery, we expect to find a control file */
|
||||
if (maria_in_recovery)
|
||||
DBUG_RETURN(CONTROL_FILE_MISSING);
|
||||
if ((control_file_fd= my_create(name, 0,
|
||||
open_flags,
|
||||
MYF(MY_SYNC_DIR | MY_WME))) < 0)
|
||||
@ -164,7 +167,7 @@ static CONTROL_FILE_ERROR create_control_file(const char *name,
|
||||
|
||||
if (my_pwrite(control_file_fd, buffer, cf_create_time_size,
|
||||
0, MYF(MY_FNABP | MY_WME)))
|
||||
DBUG_RETURN(1);
|
||||
DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
|
||||
|
||||
/*
|
||||
To be safer we should make sure that there are no logs or data/index
|
||||
@ -184,10 +187,50 @@ static CONTROL_FILE_ERROR create_control_file(const char *name,
|
||||
|
||||
/* init the file with these "undefined" values */
|
||||
DBUG_RETURN(ma_control_file_write_and_force(LSN_IMPOSSIBLE,
|
||||
FILENO_IMPOSSIBLE,
|
||||
CONTROL_FILE_UPDATE_ALL));
|
||||
FILENO_IMPOSSIBLE, 0));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Locks control file exclusively. This is kept for the duration of the engine
|
||||
process, to prevent another Maria instance to write to our logs or control
|
||||
file.
|
||||
*/
|
||||
|
||||
static int lock_control_file(const char *name)
|
||||
{
|
||||
uint retry= 0;
|
||||
/*
|
||||
On Windows, my_lock() uses locking() which is mandatory locking and so
|
||||
prevents maria-recovery.test from copying the control file. And in case of
|
||||
crash, it may take a while for Windows to unlock file, causing downtime.
|
||||
*/
|
||||
/**
|
||||
@todo BUG We should explore my_sopen(_SH_DENYWRD) to open or create the
|
||||
file under Windows.
|
||||
*/
|
||||
#ifndef __WIN__
|
||||
/*
|
||||
We can't here use the automatic wait in my_lock() as the alarm thread
|
||||
may not yet exists.
|
||||
*/
|
||||
while (my_lock(control_file_fd, F_WRLCK, 0L, F_TO_EOF,
|
||||
MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK | MY_NO_WAIT)))
|
||||
{
|
||||
if (retry == 0)
|
||||
my_printf_error(HA_ERR_INITIALIZATION,
|
||||
"Can't lock maria control file '%s' for exclusive use, "
|
||||
"error: %d. Will retry for %d seconds", 0,
|
||||
name, my_errno, MARIA_MAX_CONTROL_FILE_LOCK_RETRY);
|
||||
if (retry++ > MARIA_MAX_CONTROL_FILE_LOCK_RETRY)
|
||||
return 1;
|
||||
sleep(1);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@brief Initialize control file subsystem
|
||||
|
||||
@ -200,24 +243,24 @@ static CONTROL_FILE_ERROR create_control_file(const char *name,
|
||||
The format of the control file is defined in the comments and defines
|
||||
at the start of this file.
|
||||
|
||||
@note If in recovery, file is not created
|
||||
@param create_if_missing create file if not found
|
||||
|
||||
@return Operation status
|
||||
@retval 0 OK
|
||||
@retval 1 Error (in which case the file is left closed)
|
||||
*/
|
||||
|
||||
CONTROL_FILE_ERROR ma_control_file_create_or_open()
|
||||
CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing)
|
||||
{
|
||||
uchar buffer[CF_MAX_SIZE];
|
||||
char name[FN_REFLEN], errmsg_buff[256];
|
||||
const char *errmsg;
|
||||
const char *errmsg, *lock_failed_errmsg= "Could not get an exclusive lock;"
|
||||
" file is probably in use by another process";
|
||||
uint new_cf_create_time_size, new_cf_changeable_size, new_block_size;
|
||||
uint retry;
|
||||
my_off_t file_size;
|
||||
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_open");
|
||||
|
||||
/*
|
||||
If you change sizes in the #defines, you at least have to change the
|
||||
@ -236,12 +279,25 @@ CONTROL_FILE_ERROR ma_control_file_create_or_open()
|
||||
|
||||
if (my_access(name,F_OK))
|
||||
{
|
||||
if (create_control_file(name, open_flags))
|
||||
CONTROL_FILE_ERROR create_error;
|
||||
if (!create_if_missing)
|
||||
{
|
||||
error= CONTROL_FILE_MISSING;
|
||||
errmsg= "Can't find file";
|
||||
goto err;
|
||||
}
|
||||
if ((create_error= create_control_file(name, open_flags)))
|
||||
{
|
||||
error= create_error;
|
||||
errmsg= "Can't create file";
|
||||
goto err;
|
||||
}
|
||||
goto lock_file;
|
||||
if (lock_control_file(name))
|
||||
{
|
||||
errmsg= lock_failed_errmsg;
|
||||
goto err;
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
|
||||
/* Otherwise, file exists */
|
||||
@ -252,6 +308,12 @@ CONTROL_FILE_ERROR ma_control_file_create_or_open()
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (lock_control_file(name)) /* lock it before reading content */
|
||||
{
|
||||
errmsg= lock_failed_errmsg;
|
||||
goto err;
|
||||
}
|
||||
|
||||
file_size= my_seek(control_file_fd, 0, SEEK_END, MYF(MY_WME));
|
||||
if (file_size == MY_FILEPOS_ERROR)
|
||||
{
|
||||
@ -343,7 +405,7 @@ CONTROL_FILE_ERROR ma_control_file_create_or_open()
|
||||
uint4korr(buffer + new_cf_create_time_size))
|
||||
{
|
||||
error= CONTROL_FILE_BAD_CHECKSUM;
|
||||
errmsg= "Changeable part (end of control file) checksum missmatch";
|
||||
errmsg= "Changeable part (end of control file) checksum mismatch";
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -353,57 +415,29 @@ CONTROL_FILE_ERROR ma_control_file_create_or_open()
|
||||
last_checkpoint_lsn= lsn_korr(buffer + new_cf_create_time_size +
|
||||
CF_LSN_OFFSET);
|
||||
last_logno= uint4korr(buffer + new_cf_create_time_size + CF_FILENO_OFFSET);
|
||||
if (new_cf_changeable_size >= (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE))
|
||||
max_trid_in_control_file=
|
||||
transid_korr(buffer + new_cf_create_time_size + CF_MAX_TRID_OFFSET);
|
||||
|
||||
lock_file:
|
||||
retry= 0;
|
||||
|
||||
/*
|
||||
On Windows, my_lock() uses locking() which is mandatory locking and so
|
||||
prevents maria-recovery.test from copying the control file. And in case of
|
||||
crash, it may take a while for Windows to unlock file, causing downtime.
|
||||
*/
|
||||
/**
|
||||
@todo BUG We should explore my_sopen(_SH_DENYWRD) to open or create the
|
||||
file under Windows.
|
||||
*/
|
||||
#ifndef __WIN__
|
||||
/*
|
||||
We can't here use the automatic wait in my_lock() as the alarm thread
|
||||
may not yet exists.
|
||||
*/
|
||||
while (my_lock(control_file_fd, F_WRLCK, 0L, F_TO_EOF,
|
||||
MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK | MY_NO_WAIT)))
|
||||
{
|
||||
if (retry == 0)
|
||||
my_printf_error(HA_ERR_INITIALIZATION,
|
||||
"Can't lock maria control file '%s' for exclusive use, "
|
||||
"error: %d. Will retry for %d seconds", 0,
|
||||
name, my_errno, MARIA_MAX_CONTROL_FILE_LOCK_RETRY);
|
||||
if (retry++ > MARIA_MAX_CONTROL_FILE_LOCK_RETRY)
|
||||
{
|
||||
errmsg= "Could not get an exclusive lock; file is probably in use by another process";
|
||||
goto err;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
ok:
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
my_printf_error(HA_ERR_INITIALIZATION,
|
||||
"Error when trying to use maria control file '%s': %s", 0,
|
||||
name, errmsg);
|
||||
ma_control_file_end();
|
||||
ma_control_file_end(); /* will unlock file if needed */
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Write information durably to the control file; stores this information into
|
||||
the last_checkpoint_lsn and last_logno global variables.
|
||||
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).
|
||||
the last_checkpoint_lsn, last_logno, max_trid_in_control_file global
|
||||
variables.
|
||||
Called when we have created a new log (after syncing this log's creation),
|
||||
when we have written a checkpoint (after syncing this log record), and at
|
||||
shutdown (for storing trid in case logs are soon removed by user).
|
||||
Variables last_checkpoint_lsn and last_logno must be protected by caller
|
||||
using log's lock, unless this function is called at startup.
|
||||
|
||||
@ -411,13 +445,7 @@ err:
|
||||
ma_control_file_write_and_force()
|
||||
checkpoint_lsn LSN of last checkpoint
|
||||
logno last log file number
|
||||
objs_to_write which of the arguments should be used as new values
|
||||
(for example, CF_UPDATE_ONLY_LSN will not
|
||||
write the logno argument to the control file and will
|
||||
not update the last_logno global variable); can be:
|
||||
CF_UPDATE_ALL
|
||||
CF_UPDATE_ONLY_LSN
|
||||
CF_UPDATE_ONLY_LOGNO.
|
||||
trid maximum transaction longid.
|
||||
|
||||
NOTE
|
||||
We always want to do one single my_pwrite() here to be as atomic as
|
||||
@ -428,11 +456,10 @@ err:
|
||||
1 - Error
|
||||
*/
|
||||
|
||||
int ma_control_file_write_and_force(const LSN checkpoint_lsn, uint32 logno,
|
||||
uint objs_to_write)
|
||||
int ma_control_file_write_and_force(LSN checkpoint_lsn, uint32 logno,
|
||||
TrID trid)
|
||||
{
|
||||
char buffer[CF_MAX_SIZE];
|
||||
my_bool update_checkpoint_lsn= FALSE, update_logno= FALSE;
|
||||
uchar buffer[CF_MAX_SIZE];
|
||||
uint32 sum;
|
||||
DBUG_ENTER("ma_control_file_write_and_force");
|
||||
|
||||
@ -442,48 +469,38 @@ int ma_control_file_write_and_force(const LSN checkpoint_lsn, uint32 logno,
|
||||
translog_lock_handler_assert_owner();
|
||||
#endif
|
||||
|
||||
if (objs_to_write == CONTROL_FILE_UPDATE_ONLY_LSN)
|
||||
update_checkpoint_lsn= TRUE;
|
||||
else if (objs_to_write == CONTROL_FILE_UPDATE_ONLY_LOGNO)
|
||||
update_logno= TRUE;
|
||||
else if (objs_to_write == CONTROL_FILE_UPDATE_ALL)
|
||||
update_checkpoint_lsn= update_logno= TRUE;
|
||||
else /* incorrect value of objs_to_write */
|
||||
DBUG_ASSERT(0);
|
||||
|
||||
if (update_checkpoint_lsn)
|
||||
lsn_store(buffer + CF_LSN_OFFSET, checkpoint_lsn);
|
||||
else /* store old value == change nothing */
|
||||
lsn_store(buffer + CF_LSN_OFFSET, last_checkpoint_lsn);
|
||||
|
||||
if (update_logno)
|
||||
int4store(buffer + CF_FILENO_OFFSET, logno);
|
||||
else
|
||||
int4store(buffer + CF_FILENO_OFFSET, last_logno);
|
||||
lsn_store(buffer + CF_LSN_OFFSET, checkpoint_lsn);
|
||||
int4store(buffer + CF_FILENO_OFFSET, logno);
|
||||
transid_store(buffer + CF_MAX_TRID_OFFSET, trid);
|
||||
|
||||
/*
|
||||
Clear unknown part of changeable part.
|
||||
Clear unknown part of changeable part, if bigger than ours.
|
||||
Other option would be to remember the original values in the file
|
||||
and copy them here, but this should be safer.
|
||||
*/
|
||||
bzero(buffer + CF_CHANGEABLE_TOTAL_SIZE,
|
||||
cf_changeable_size - CF_CHANGEABLE_TOTAL_SIZE);
|
||||
if (cf_changeable_size > CF_CHANGEABLE_TOTAL_SIZE)
|
||||
bzero(buffer + CF_CHANGEABLE_TOTAL_SIZE,
|
||||
cf_changeable_size - CF_CHANGEABLE_TOTAL_SIZE);
|
||||
|
||||
/* Checksum is stored first */
|
||||
compile_time_assert(CF_CHECKSUM_OFFSET == 0);
|
||||
sum= my_checksum(0, (const uchar *) buffer + CF_CHECKSUM_SIZE,
|
||||
sum= my_checksum(0, buffer + CF_CHECKSUM_SIZE,
|
||||
cf_changeable_size - CF_CHECKSUM_SIZE);
|
||||
int4store(buffer, sum);
|
||||
|
||||
if (my_pwrite(control_file_fd, (uchar *) buffer, cf_changeable_size,
|
||||
/**
|
||||
@todo BUG by reusing the cf_changeable_size of the old control file (from
|
||||
an old server), it does not write the new parts featured by the running
|
||||
server (like max_trid), is it expected?
|
||||
*/
|
||||
if (my_pwrite(control_file_fd, buffer, cf_changeable_size,
|
||||
cf_create_time_size, MYF(MY_FNABP | MY_WME)) ||
|
||||
my_sync(control_file_fd, MYF(MY_WME)))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (update_checkpoint_lsn)
|
||||
last_checkpoint_lsn= checkpoint_lsn;
|
||||
if (update_logno)
|
||||
last_logno= logno;
|
||||
last_checkpoint_lsn= checkpoint_lsn;
|
||||
last_logno= logno;
|
||||
max_trid_in_control_file= trid;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -496,7 +513,7 @@ int ma_control_file_write_and_force(const LSN checkpoint_lsn, uint32 logno,
|
||||
ma_control_file_end()
|
||||
*/
|
||||
|
||||
int ma_control_file_end()
|
||||
int ma_control_file_end(void)
|
||||
{
|
||||
int close_error;
|
||||
DBUG_ENTER("ma_control_file_end");
|
||||
@ -521,8 +538,19 @@ int ma_control_file_end()
|
||||
*/
|
||||
last_checkpoint_lsn= LSN_IMPOSSIBLE;
|
||||
last_logno= FILENO_IMPOSSIBLE;
|
||||
max_trid_in_control_file= 0;
|
||||
|
||||
DBUG_RETURN(close_error);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Tells if control file is initialized.
|
||||
*/
|
||||
|
||||
my_bool ma_control_file_inited(void)
|
||||
{
|
||||
return (control_file_fd >= 0);
|
||||
}
|
||||
|
||||
#endif /* EXTRACT_DEFINITIONS */
|
||||
|
@ -42,6 +42,8 @@ extern LSN last_checkpoint_lsn;
|
||||
*/
|
||||
extern uint32 last_logno;
|
||||
|
||||
extern TrID max_trid_in_control_file;
|
||||
|
||||
extern my_bool maria_multi_threaded, maria_in_recovery;
|
||||
|
||||
typedef enum enum_control_file_error {
|
||||
@ -58,33 +60,10 @@ typedef enum enum_control_file_error {
|
||||
CONTROL_FILE_UNKNOWN_ERROR /* any other error */
|
||||
} CONTROL_FILE_ERROR;
|
||||
|
||||
#define CONTROL_FILE_UPDATE_ALL 0
|
||||
#define CONTROL_FILE_UPDATE_ONLY_LSN 1
|
||||
#define CONTROL_FILE_UPDATE_ONLY_LOGNO 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Looks for the control file. If none and creation was requested, creates file.
|
||||
If present, reads it to find out last checkpoint's LSN and last log.
|
||||
Called at engine's start.
|
||||
*/
|
||||
CONTROL_FILE_ERROR 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).
|
||||
*/
|
||||
int ma_control_file_write_and_force(const LSN checkpoint_lsn, uint32 logno,
|
||||
uint objs_to_write);
|
||||
|
||||
|
||||
/* Free resources taken by control file subsystem */
|
||||
int ma_control_file_end();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
C_MODE_START
|
||||
CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing);
|
||||
int ma_control_file_write_and_force(LSN checkpoint_lsn, uint32 logno, TrID trid);
|
||||
int ma_control_file_end(void);
|
||||
my_bool ma_control_file_inited(void);
|
||||
C_MODE_END
|
||||
#endif
|
||||
|
@ -52,9 +52,20 @@ void maria_end(void)
|
||||
{
|
||||
if (maria_inited)
|
||||
{
|
||||
TrID trid;
|
||||
maria_inited= maria_multi_threaded= FALSE;
|
||||
ft_free_stopwords();
|
||||
ma_checkpoint_end();
|
||||
if (ma_control_file_inited() &&
|
||||
((trid= trnman_get_max_trid()) > max_trid_in_control_file))
|
||||
{
|
||||
/*
|
||||
Store max transaction id into control file, in case logs are removed
|
||||
by user, or maria_chk wants to check tables (it cannot access max trid
|
||||
from the log, as it cannot process REDOs).
|
||||
*/
|
||||
ma_control_file_write_and_force(last_checkpoint_lsn, last_logno, trid);
|
||||
}
|
||||
trnman_destroy();
|
||||
if (translog_status == TRANSLOG_OK)
|
||||
translog_destroy();
|
||||
|
@ -1519,8 +1519,8 @@ static my_bool translog_create_new_file()
|
||||
if (translog_write_file_header())
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (ma_control_file_write_and_force(LSN_IMPOSSIBLE, file_no,
|
||||
CONTROL_FILE_UPDATE_ONLY_LOGNO))
|
||||
if (ma_control_file_write_and_force(last_checkpoint_lsn, file_no,
|
||||
max_trid_in_control_file))
|
||||
{
|
||||
translog_stop_writing();
|
||||
DBUG_RETURN(1);
|
||||
@ -3697,7 +3697,7 @@ my_bool translog_init_with_table(const char *directory,
|
||||
log_descriptor.open_files.elements);
|
||||
|
||||
if (ma_control_file_write_and_force(checkpoint_lsn, start_file_num,
|
||||
CONTROL_FILE_UPDATE_ALL))
|
||||
max_trid_in_control_file))
|
||||
DBUG_RETURN(1);
|
||||
/* assign buffer 0 */
|
||||
translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
|
||||
|
@ -2509,6 +2509,14 @@ static uint end_of_redo_phase(my_bool prepare_for_undo_phase)
|
||||
|
||||
llstr(max_long_trid, llbuf);
|
||||
tprint(tracef, "Maximum transaction long id seen: %s\n", llbuf);
|
||||
llstr(max_trid_in_control_file, llbuf);
|
||||
tprint(tracef, "Maximum transaction long id seen in control file: %s\n",
|
||||
llbuf);
|
||||
/*
|
||||
If logs were deleted, or lost, trid in control file is needed to set
|
||||
trnman's generator:
|
||||
*/
|
||||
set_if_bigger(max_long_trid, max_trid_in_control_file);
|
||||
if (prepare_for_undo_phase && trnman_init(max_long_trid))
|
||||
return -1;
|
||||
|
||||
|
@ -77,7 +77,7 @@ int main(int argc,char *argv[])
|
||||
if (maria_init() ||
|
||||
(init_pagecache(maria_pagecache, maria_block_size * 16, 0, 0,
|
||||
maria_block_size, MY_WME) == 0) ||
|
||||
ma_control_file_create_or_open() ||
|
||||
ma_control_file_open(TRUE) ||
|
||||
(init_pagecache(maria_log_pagecache,
|
||||
TRANSLOG_PAGECACHE_SIZE, 0, 0,
|
||||
TRANSLOG_PAGE_SIZE, MY_WME) == 0) ||
|
||||
|
@ -83,7 +83,7 @@ int main(int argc, char *argv[])
|
||||
if (maria_init() ||
|
||||
(init_pagecache(maria_pagecache, pagecache_size, 0, 0,
|
||||
maria_block_size, MY_WME) == 0) ||
|
||||
ma_control_file_create_or_open() ||
|
||||
ma_control_file_open(TRUE) ||
|
||||
(init_pagecache(maria_log_pagecache,
|
||||
TRANSLOG_PAGECACHE_SIZE, 0, 0,
|
||||
TRANSLOG_PAGE_SIZE, MY_WME) == 0) ||
|
||||
|
@ -37,11 +37,11 @@ SET_STACK_SIZE(9000) /* Minimum stack size for program */
|
||||
static uint decode_bits;
|
||||
static char **default_argv;
|
||||
static const char *load_default_groups[]= { "maria_chk", 0 };
|
||||
static const char *set_collation_name, *opt_tmpdir;
|
||||
static const char *set_collation_name, *opt_tmpdir, *opt_log_dir;
|
||||
static CHARSET_INFO *set_collation;
|
||||
static int stopwords_inited= 0;
|
||||
static MY_TMPDIR maria_chk_tmpdir;
|
||||
static my_bool opt_transaction_logging, opt_debug;
|
||||
static my_bool opt_transaction_logging, opt_debug, opt_require_control_file;
|
||||
|
||||
static const char *type_names[]=
|
||||
{
|
||||
@ -97,7 +97,7 @@ int main(int argc, char **argv)
|
||||
int error;
|
||||
MY_INIT(argv[0]);
|
||||
|
||||
maria_data_root= (char *)".";
|
||||
opt_log_dir= maria_data_root= (char *)".";
|
||||
maria_chk_init(&check_param);
|
||||
check_param.opt_lock_memory= 1; /* Lock memory if possible */
|
||||
check_param.using_global_keycache = 0;
|
||||
@ -110,20 +110,30 @@ int main(int argc, char **argv)
|
||||
If we are doing a repair, user may want to store this repair into the log
|
||||
so that the log has a complete history and can be used to replay.
|
||||
*/
|
||||
if (opt_transaction_logging && (check_param.testflag & T_REP_ANY) &&
|
||||
(ma_control_file_create_or_open() ||
|
||||
init_pagecache(maria_log_pagecache,
|
||||
TRANSLOG_PAGECACHE_SIZE, 0, 0,
|
||||
TRANSLOG_PAGE_SIZE, MY_WME) == 0 ||
|
||||
translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
|
||||
0, 0, maria_log_pagecache,
|
||||
TRANSLOG_DEFAULT_FLAGS, 0)))
|
||||
if (opt_transaction_logging && (check_param.testflag & T_REP_ANY))
|
||||
{
|
||||
_ma_check_print_error(&check_param,
|
||||
"Can't initialize transaction logging. Run "
|
||||
"recovery with switch --skip-transaction-log");
|
||||
error= 1;
|
||||
argc= 1; /* Force loop out */
|
||||
if (ma_control_file_open(FALSE) ||
|
||||
init_pagecache(maria_log_pagecache,
|
||||
TRANSLOG_PAGECACHE_SIZE, 0, 0,
|
||||
TRANSLOG_PAGE_SIZE, MY_WME) == 0 ||
|
||||
translog_init(opt_log_dir, TRANSLOG_FILE_SIZE,
|
||||
0, 0, maria_log_pagecache,
|
||||
TRANSLOG_DEFAULT_FLAGS, 0))
|
||||
{
|
||||
_ma_check_print_error(&check_param,
|
||||
"Can't initialize transaction logging. Run "
|
||||
"recovery with switch --skip-transaction-log");
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ma_control_file_open(FALSE) && opt_require_control_file)
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
while (--argc >= 0)
|
||||
@ -156,6 +166,7 @@ int main(int argc, char **argv)
|
||||
VOID(fflush(stdout));
|
||||
}
|
||||
}
|
||||
end:
|
||||
if (check_param.total_files > 1)
|
||||
{ /* Only if descript */
|
||||
char buff[22],buff2[22];
|
||||
@ -183,7 +194,8 @@ enum options_mc {
|
||||
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
|
||||
OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
|
||||
OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG,
|
||||
OPT_SKIP_SAFEMALLOC, OPT_ZEROFILL_KEEP_LSN
|
||||
OPT_SKIP_SAFEMALLOC, OPT_ZEROFILL_KEEP_LSN, OPT_REQUIRE_CONTROL_FILE,
|
||||
OPT_LOG_DIR, OPT_DATADIR
|
||||
};
|
||||
|
||||
static struct my_option my_long_options[] =
|
||||
@ -249,6 +261,13 @@ static struct my_option my_long_options[] =
|
||||
(uchar**) &check_param.keys_in_use,
|
||||
(uchar**) &check_param.keys_in_use,
|
||||
0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
|
||||
{"datadir", OPT_DATADIR,
|
||||
"Path for control file (and logs if --log-dir not used).",
|
||||
(uchar**) &maria_data_root, 0, 0, GET_STR, REQUIRED_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"log-dir", OPT_LOG_DIR,
|
||||
"Path for log files.",
|
||||
(uchar**) &opt_log_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"max-record-length", OPT_MAX_RECORD_LENGTH,
|
||||
"Skip rows bigger than this if maria_chk can't allocate memory to hold it",
|
||||
(uchar**) &check_param.max_record_length,
|
||||
@ -274,6 +293,10 @@ static struct my_option my_long_options[] =
|
||||
{"sort-recover", 'n',
|
||||
"Force recovering with sorting even if the temporary file was very big.",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{ "require-control-file", OPT_REQUIRE_CONTROL_FILE,
|
||||
"Abort if cannot find control file",
|
||||
(uchar**)&opt_require_control_file, 0, 0, GET_BOOL, NO_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
#ifdef DEBUG
|
||||
{"start-check-pos", OPT_START_CHECK_POS,
|
||||
"No help available.",
|
||||
|
@ -56,7 +56,7 @@ int main(int argc, char **argv)
|
||||
goto err;
|
||||
}
|
||||
/* we don't want to create a control file, it MUST exist */
|
||||
if (ma_control_file_create_or_open())
|
||||
if (ma_control_file_open(FALSE))
|
||||
{
|
||||
fprintf(stderr, "Can't open control file (%d)\n", errno);
|
||||
goto err;
|
||||
|
@ -745,3 +745,18 @@ TRN *trnman_get_any_trn()
|
||||
TRN *trn= active_list_min.next;
|
||||
return (trn != &active_list_max) ? trn : NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns maximum transaction id given to a transaction so far.
|
||||
*/
|
||||
TrID trnman_get_max_trid()
|
||||
{
|
||||
TrID id;
|
||||
if (short_trid_to_active_trn == NULL)
|
||||
return 0;
|
||||
pthread_mutex_lock(&LOCK_trn_list);
|
||||
id= global_trid_generator;
|
||||
pthread_mutex_unlock(&LOCK_trn_list);
|
||||
return id;
|
||||
}
|
||||
|
@ -54,7 +54,8 @@ uint trnman_decrement_locked_tables(TRN *trn);
|
||||
uint trnman_has_locked_tables(TRN *trn);
|
||||
void trnman_reset_locked_tables(TRN *trn, uint locked_tables);
|
||||
TRN *trnman_recreate_trn_from_recovery(uint16 shortid, TrID longid);
|
||||
TRN *trnman_get_any_trn();
|
||||
TRN *trnman_get_any_trn(void);
|
||||
TrID trnman_get_max_trid(void);
|
||||
#define TRANSID_SIZE 6
|
||||
#define transid_store(dst, id) int6store(dst,id)
|
||||
#define transid_korr(P) uint6korr(P)
|
||||
|
@ -42,36 +42,39 @@
|
||||
char file_name[FN_REFLEN];
|
||||
|
||||
/* The values we'll set and expect the control file module to return */
|
||||
LSN expect_checkpoint_lsn;
|
||||
LSN expect_checkpoint_lsn;
|
||||
uint32 expect_logno;
|
||||
TrID expect_max_trid;
|
||||
|
||||
static int delete_file(myf my_flags);
|
||||
/*
|
||||
Those are test-specific wrappers around the module's API functions: after
|
||||
calling the module's API functions they perform checks on the result.
|
||||
*/
|
||||
static int close_file(); /* wraps ma_control_file_end */
|
||||
static int create_or_open_file(); /* wraps ma_control_file_open_or_create */
|
||||
static int write_file(); /* wraps ma_control_file_write_and_force */
|
||||
static int close_file(void); /* wraps ma_control_file_end */
|
||||
/* wraps ma_control_file_open_or_create */
|
||||
static int open_file(void);
|
||||
/* wraps ma_control_file_write_and_force */
|
||||
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid);
|
||||
|
||||
/* Tests */
|
||||
static int test_one_log();
|
||||
static int test_five_logs();
|
||||
static int test_3_checkpoints_and_2_logs();
|
||||
static int test_binary_content();
|
||||
static int test_start_stop();
|
||||
static int test_2_open_and_2_close();
|
||||
static int test_bad_magic_string();
|
||||
static int test_bad_checksum();
|
||||
static int test_bad_hchecksum();
|
||||
static int test_future_size();
|
||||
static int test_bad_blocksize();
|
||||
static int test_bad_size();
|
||||
static int test_one_log(void);
|
||||
static int test_five_logs_and_max_trid(void);
|
||||
static int test_3_checkpoints_and_2_logs(void);
|
||||
static int test_binary_content(void);
|
||||
static int test_start_stop(void);
|
||||
static int test_2_open_and_2_close(void);
|
||||
static int test_bad_magic_string(void);
|
||||
static int test_bad_checksum(void);
|
||||
static int test_bad_hchecksum(void);
|
||||
static int test_future_size(void);
|
||||
static int test_bad_blocksize(void);
|
||||
static int test_bad_size(void);
|
||||
|
||||
/* Utility */
|
||||
static int verify_module_values_match_expected();
|
||||
static int verify_module_values_are_impossible();
|
||||
static void usage();
|
||||
static int verify_module_values_match_expected(void);
|
||||
static int verify_module_values_are_impossible(void);
|
||||
static void usage(void);
|
||||
static void get_options(int argc, char *argv[]);
|
||||
|
||||
/*
|
||||
@ -83,10 +86,10 @@ static void get_options(int argc, char *argv[]);
|
||||
*/
|
||||
|
||||
#define RET_ERR_UNLESS(expr) \
|
||||
{if (!(expr)) {diag("line %d: failure: '%s'", __LINE__, #expr); return 1;}}
|
||||
{if (!(expr)) {diag("line %d: failure: '%s'", __LINE__, #expr); assert(0);return 1;}}
|
||||
|
||||
|
||||
/* Used to ignore error messages from ma_control_file_create_or_open */
|
||||
/* Used to ignore error messages from ma_control_file_open() */
|
||||
|
||||
static int my_ignore_message(uint error __attribute__((unused)),
|
||||
const char *str __attribute__((unused)),
|
||||
@ -101,13 +104,13 @@ int (*default_error_handler_hook)(uint my_err, const char *str,
|
||||
myf MyFlags) = 0;
|
||||
|
||||
|
||||
/* like ma_control_file_create_or_open(), but without error messages */
|
||||
/* like ma_control_file_open(), but without error messages */
|
||||
|
||||
static CONTROL_FILE_ERROR local_ma_control_file_create_or_open(void)
|
||||
static CONTROL_FILE_ERROR local_ma_control_file_open(void)
|
||||
{
|
||||
CONTROL_FILE_ERROR error;
|
||||
error_handler_hook= my_ignore_message;
|
||||
error= ma_control_file_create_or_open();
|
||||
error= ma_control_file_open(TRUE);
|
||||
error_handler_hook= default_error_handler_hook;
|
||||
return error;
|
||||
}
|
||||
@ -133,7 +136,8 @@ int main(int argc,char *argv[])
|
||||
|
||||
diag("Tests of normal conditions");
|
||||
ok(0 == test_one_log(), "test of creating one log");
|
||||
ok(0 == test_five_logs(), "test of creating five logs");
|
||||
ok(0 == test_five_logs_and_max_trid(),
|
||||
"test of creating five logs and many transactions");
|
||||
ok(0 == test_3_checkpoints_and_2_logs(),
|
||||
"test of creating three checkpoints and two logs");
|
||||
ok(0 == test_binary_content(), "test of the binary content of the file");
|
||||
@ -163,19 +167,20 @@ static int delete_file(myf my_flags)
|
||||
my_delete(file_name, my_flags);
|
||||
expect_checkpoint_lsn= LSN_IMPOSSIBLE;
|
||||
expect_logno= FILENO_IMPOSSIBLE;
|
||||
expect_max_trid= 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Verifies that global values last_checkpoint_lsn and last_logno (belonging
|
||||
to the module) match what we expect.
|
||||
Verifies that global values last_checkpoint_lsn, last_logno,
|
||||
max_trid_in_control_file (belonging to the module) match what we expect.
|
||||
*/
|
||||
static int verify_module_values_match_expected()
|
||||
static int verify_module_values_match_expected(void)
|
||||
{
|
||||
RET_ERR_UNLESS(last_logno == expect_logno);
|
||||
RET_ERR_UNLESS(last_checkpoint_lsn ==
|
||||
expect_checkpoint_lsn);
|
||||
RET_ERR_UNLESS(last_checkpoint_lsn == expect_checkpoint_lsn);
|
||||
RET_ERR_UNLESS(max_trid_in_control_file == expect_max_trid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -184,16 +189,16 @@ static int verify_module_values_match_expected()
|
||||
Verifies that global values last_checkpoint_lsn and last_logno (belonging
|
||||
to the module) are impossible (this is used when the file has been closed).
|
||||
*/
|
||||
static int verify_module_values_are_impossible()
|
||||
static int verify_module_values_are_impossible(void)
|
||||
{
|
||||
RET_ERR_UNLESS(last_logno == FILENO_IMPOSSIBLE);
|
||||
RET_ERR_UNLESS(last_checkpoint_lsn ==
|
||||
LSN_IMPOSSIBLE);
|
||||
RET_ERR_UNLESS(last_checkpoint_lsn == LSN_IMPOSSIBLE);
|
||||
RET_ERR_UNLESS(max_trid_in_control_file == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int close_file()
|
||||
static int close_file(void)
|
||||
{
|
||||
/* Simulate shutdown */
|
||||
ma_control_file_end();
|
||||
@ -202,94 +207,81 @@ static int close_file()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_or_open_file()
|
||||
static int open_file(void)
|
||||
{
|
||||
RET_ERR_UNLESS(local_ma_control_file_create_or_open() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(local_ma_control_file_open() == CONTROL_FILE_OK);
|
||||
/* Check that the module reports expected information */
|
||||
RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_file(const LSN checkpoint_lsn,
|
||||
uint32 logno,
|
||||
uint objs_to_write)
|
||||
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid)
|
||||
{
|
||||
RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno,
|
||||
objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno, trid)
|
||||
== 0);
|
||||
/* Check that the module reports expected information */
|
||||
RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_one_log()
|
||||
static int test_one_log(void)
|
||||
{
|
||||
uint objs_to_write;
|
||||
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
objs_to_write= CONTROL_FILE_UPDATE_ONLY_LOGNO;
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
expect_logno= 123;
|
||||
RET_ERR_UNLESS(write_file(LSN_IMPOSSIBLE,
|
||||
expect_logno,
|
||||
objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
|
||||
max_trid_in_control_file) == 0);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_five_logs()
|
||||
static int test_five_logs_and_max_trid(void)
|
||||
{
|
||||
uint objs_to_write;
|
||||
uint i;
|
||||
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
objs_to_write= CONTROL_FILE_UPDATE_ONLY_LOGNO;
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
expect_logno= 100;
|
||||
expect_max_trid= ULL(14111978111);
|
||||
for (i= 0; i<5; i++)
|
||||
{
|
||||
expect_logno*= 3;
|
||||
RET_ERR_UNLESS(write_file(LSN_IMPOSSIBLE, expect_logno,
|
||||
objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
|
||||
expect_max_trid) == 0);
|
||||
}
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_3_checkpoints_and_2_logs()
|
||||
static int test_3_checkpoints_and_2_logs(void)
|
||||
{
|
||||
uint objs_to_write;
|
||||
/*
|
||||
Simulate one checkpoint, one log creation, two checkpoints, one
|
||||
log creation.
|
||||
*/
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
objs_to_write= CONTROL_FILE_UPDATE_ONLY_LSN;
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
expect_checkpoint_lsn= MAKE_LSN(5, 10000);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn,
|
||||
expect_logno, objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||
max_trid_in_control_file) == 0);
|
||||
|
||||
objs_to_write= CONTROL_FILE_UPDATE_ONLY_LOGNO;
|
||||
expect_logno= 17;
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn,
|
||||
expect_logno, objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||
max_trid_in_control_file) == 0);
|
||||
|
||||
objs_to_write= CONTROL_FILE_UPDATE_ONLY_LSN;
|
||||
expect_checkpoint_lsn= MAKE_LSN(17, 20000);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn,
|
||||
expect_logno, objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||
max_trid_in_control_file) == 0);
|
||||
|
||||
objs_to_write= CONTROL_FILE_UPDATE_ONLY_LSN;
|
||||
expect_checkpoint_lsn= MAKE_LSN(17, 45000);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn,
|
||||
expect_logno, objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||
max_trid_in_control_file) == 0);
|
||||
|
||||
objs_to_write= CONTROL_FILE_UPDATE_ONLY_LOGNO;
|
||||
expect_logno= 19;
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn,
|
||||
expect_logno, objs_to_write) == 0);
|
||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||
max_trid_in_control_file) == 0);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_binary_content()
|
||||
static int test_binary_content(void)
|
||||
{
|
||||
uint i;
|
||||
int fd;
|
||||
@ -310,7 +302,7 @@ static int test_binary_content()
|
||||
MYF(MY_WME))) >= 0);
|
||||
RET_ERR_UNLESS(my_read(fd, buffer, 45, MYF(MY_FNABP | MY_WME)) == 0);
|
||||
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
i= uint3korr(buffer + 34 );
|
||||
RET_ERR_UNLESS(i == LSN_FILE_NO(last_checkpoint_lsn));
|
||||
i= uint4korr(buffer + 37);
|
||||
@ -321,35 +313,35 @@ static int test_binary_content()
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_start_stop()
|
||||
static int test_start_stop(void)
|
||||
{
|
||||
/* TEST5: Simulate start/nothing/stop/start/nothing/stop/start */
|
||||
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_2_open_and_2_close()
|
||||
static int test_2_open_and_2_close(void)
|
||||
{
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int test_bad_magic_string()
|
||||
static int test_bad_magic_string(void)
|
||||
{
|
||||
uchar buffer[4];
|
||||
int fd;
|
||||
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
|
||||
/* Corrupt magic string */
|
||||
@ -361,22 +353,22 @@ static int test_bad_magic_string()
|
||||
MYF(MY_FNABP | MY_WME)) == 0);
|
||||
|
||||
/* Check that control file module sees the problem */
|
||||
RET_ERR_UNLESS(local_ma_control_file_create_or_open() ==
|
||||
RET_ERR_UNLESS(local_ma_control_file_open() ==
|
||||
CONTROL_FILE_BAD_MAGIC_STRING);
|
||||
/* Restore magic string */
|
||||
RET_ERR_UNLESS(my_pwrite(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0);
|
||||
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_bad_checksum()
|
||||
static int test_bad_checksum(void)
|
||||
{
|
||||
uchar buffer[4];
|
||||
int fd;
|
||||
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
|
||||
/* Corrupt checksum */
|
||||
@ -387,7 +379,7 @@ static int test_bad_checksum()
|
||||
buffer[0]+= 3; /* mangle checksum */
|
||||
RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
|
||||
/* Check that control file module sees the problem */
|
||||
RET_ERR_UNLESS(local_ma_control_file_create_or_open() ==
|
||||
RET_ERR_UNLESS(local_ma_control_file_open() ==
|
||||
CONTROL_FILE_BAD_CHECKSUM);
|
||||
/* Restore checksum */
|
||||
buffer[0]-= 3;
|
||||
@ -398,22 +390,22 @@ static int test_bad_checksum()
|
||||
}
|
||||
|
||||
|
||||
static int test_bad_blocksize()
|
||||
static int test_bad_blocksize(void)
|
||||
{
|
||||
maria_block_size<<= 1;
|
||||
/* Check that control file module sees the problem */
|
||||
RET_ERR_UNLESS(local_ma_control_file_create_or_open() ==
|
||||
RET_ERR_UNLESS(local_ma_control_file_open() ==
|
||||
CONTROL_FILE_WRONG_BLOCKSIZE);
|
||||
/* Restore blocksize */
|
||||
maria_block_size>>= 1;
|
||||
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int test_future_size()
|
||||
static int test_future_size(void)
|
||||
{
|
||||
/*
|
||||
Here we check ability to add fields only so we can use
|
||||
@ -455,18 +447,18 @@ static int test_future_size()
|
||||
CF_CHANGEABLE_TOTAL_SIZE + 2,
|
||||
0, MYF(MY_FNABP | MY_WME)) == 0);
|
||||
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int test_bad_hchecksum()
|
||||
static int test_bad_hchecksum(void)
|
||||
{
|
||||
uchar buffer[4];
|
||||
int fd;
|
||||
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
|
||||
/* Corrupt checksum */
|
||||
@ -477,7 +469,7 @@ static int test_bad_hchecksum()
|
||||
buffer[0]+= 3; /* mangle checksum */
|
||||
RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
|
||||
/* Check that control file module sees the problem */
|
||||
RET_ERR_UNLESS(local_ma_control_file_create_or_open() ==
|
||||
RET_ERR_UNLESS(local_ma_control_file_open() ==
|
||||
CONTROL_FILE_BAD_HEAD_CHECKSUM);
|
||||
/* Restore checksum */
|
||||
buffer[0]-= 3;
|
||||
@ -488,7 +480,7 @@ static int test_bad_hchecksum()
|
||||
}
|
||||
|
||||
|
||||
static int test_bad_size()
|
||||
static int test_bad_size(void)
|
||||
{
|
||||
uchar buffer[]=
|
||||
"123456789012345678901234567890123456789012345678901234567890123456";
|
||||
@ -501,20 +493,20 @@ static int test_bad_size()
|
||||
MYF(MY_WME))) >= 0);
|
||||
RET_ERR_UNLESS(my_write(fd, buffer, 10, MYF(MY_FNABP | MY_WME)) == 0);
|
||||
/* Check that control file module sees the problem */
|
||||
RET_ERR_UNLESS(local_ma_control_file_create_or_open() ==
|
||||
RET_ERR_UNLESS(local_ma_control_file_open() ==
|
||||
CONTROL_FILE_TOO_SMALL);
|
||||
for (i= 0; i < 8; i++)
|
||||
{
|
||||
RET_ERR_UNLESS(my_write(fd, buffer, 66, MYF(MY_FNABP | MY_WME)) == 0);
|
||||
}
|
||||
/* Check that control file module sees the problem */
|
||||
RET_ERR_UNLESS(local_ma_control_file_create_or_open() ==
|
||||
RET_ERR_UNLESS(local_ma_control_file_open() ==
|
||||
CONTROL_FILE_TOO_BIG);
|
||||
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
|
||||
|
||||
/* Leave a correct control file */
|
||||
RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0);
|
||||
RET_ERR_UNLESS(create_or_open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||
RET_ERR_UNLESS(close_file() == 0);
|
||||
|
||||
return 0;
|
||||
@ -535,7 +527,7 @@ static struct my_option my_long_options[] =
|
||||
};
|
||||
|
||||
|
||||
static void version()
|
||||
static void version(void)
|
||||
{
|
||||
printf("ma_control_file_test: unit test for the control file "
|
||||
"module of the Maria storage engine. Ver 1.0 \n");
|
||||
@ -575,7 +567,7 @@ static void get_options(int argc, char *argv[])
|
||||
} /* get options */
|
||||
|
||||
|
||||
static void usage()
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: %s [options]\n\n", my_progname);
|
||||
my_print_help(my_long_options);
|
||||
|
@ -196,7 +196,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -67,7 +67,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -64,7 +64,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -184,7 +184,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
@ -348,7 +348,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
end_pagecache(&pagecache, 1);
|
||||
ma_control_file_end();
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "pass2: Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -283,7 +283,7 @@ int main(int argc __attribute__((unused)),
|
||||
|
||||
my_thread_global_init();
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -70,7 +70,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -67,7 +67,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
@ -140,7 +140,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -95,7 +95,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
@ -67,7 +67,7 @@ int main(int argc __attribute__((unused)), char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
if (ma_control_file_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user