mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
importing Sanja's changes to the control file, with my changes on them.
mysys/my_pread.c: print errno in case of error storage/maria/control_file.c: importing Sanja's changes, with my minor changes on them :) storage/maria/control_file.h: importing Sanja's changes, with my minor changes on them :)
This commit is contained in:
parent
1c25f0ce5b
commit
52191ea4d8
3 changed files with 147 additions and 36 deletions
|
@ -155,7 +155,8 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
|
|||
Count-=writenbytes;
|
||||
offset+=writenbytes;
|
||||
}
|
||||
DBUG_PRINT("error",("Write only %d bytes",writenbytes));
|
||||
DBUG_PRINT("error",("Write only %d bytes, error: %d",
|
||||
writenbytes, my_errno));
|
||||
#ifndef NO_BACKGROUND
|
||||
#ifdef THREAD
|
||||
if (my_thread_var->abort)
|
||||
|
|
|
@ -4,74 +4,162 @@
|
|||
Does not compile yet.
|
||||
*/
|
||||
|
||||
#include "maria_def.h"
|
||||
|
||||
|
||||
/* Here is the implementation of this module */
|
||||
|
||||
/* Control file is 512 bytes (a disk sector), to be as atomic as possible */
|
||||
/* should be sector size for atomic write operation */
|
||||
#define STAT_FILE_FILENO_SIZE 4
|
||||
#define STAT_FILE_FILEOFFSET_SIZE 4
|
||||
#define STAT_FILE_LSN_SIZE (STAT_FILE_FILENO_SIZE + STAT_FILE_FILEOFFSET_SIZE)
|
||||
#define STAT_FILE_MAX_SIZE (STAT_FILE_LSN_SIZE + STAT_FILE_FILENO_SIZE)
|
||||
|
||||
|
||||
LSN last_checkpoint_lsn_at_startup;
|
||||
uint32 last_logno_at_startup;
|
||||
|
||||
int control_file_fd;
|
||||
|
||||
/*
|
||||
Control file is less then 512 bytes (a disk sector),
|
||||
to be as atomic as possible
|
||||
*/
|
||||
static int control_file_fd;
|
||||
|
||||
|
||||
/*
|
||||
Initialize control file subsystem
|
||||
|
||||
SYNOPSIS
|
||||
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.
|
||||
Called at engine's start.
|
||||
|
||||
RETURN
|
||||
0 - OK
|
||||
1 - Error
|
||||
*/
|
||||
int control_file_create_or_open()
|
||||
{
|
||||
char buffer[4];
|
||||
char buffer[STAT_FILE_MAX_SIZE];
|
||||
char name[FN_REFLEN];
|
||||
MY_STAT stat_buff;
|
||||
|
||||
/* name is concatenation of Maria's home dir and "control" */
|
||||
if ((control_file_fd= my_open(name, O_RDWR)) < 0)
|
||||
if (fn_format(name, "control", maria_data_root, "", MYF(MY_WME)) == NullS)
|
||||
return 1;
|
||||
|
||||
if ((control_file_fd= my_open(name,
|
||||
O_CREAT | O_BINARY | /*O_DIRECT |*/ O_RDWR,
|
||||
MYF(MY_WME))) < 0)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
TODO: from "man fsync" on Linux:
|
||||
"fsync does not necessarily ensure that the entry in the direc- tory
|
||||
containing the file has also reached disk. For that an explicit
|
||||
fsync on the file descriptor of the directory is also needed."
|
||||
So if we just created the file we should sync the directory.
|
||||
Maybe there should be a flag of my_create() to do this.
|
||||
*/
|
||||
|
||||
if (my_stat(name, &stat_buff, MYF(MY_WME)) == NULL)
|
||||
return 1;
|
||||
|
||||
if (stat_buff.st_size < STAT_FILE_MAX_SIZE)
|
||||
{
|
||||
/* failure, try to create it */
|
||||
if ((control_file_fd= my_create(name, O_RDWR)) < 0)
|
||||
return 1;
|
||||
/*
|
||||
So this is a start from scratch, 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.
|
||||
For now we trust (this is alpha version), but for beta if would be great
|
||||
to verify.
|
||||
File shorter than expected (either we just created it, or a previous run
|
||||
crashed between creation and first write); do first write.
|
||||
*/
|
||||
char buffer[STAT_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).
|
||||
|
||||
TODO: For now we trust (this is alpha version), but for beta if would
|
||||
be great to verify.
|
||||
|
||||
We could have a tool which can rebuild the control file, by reading the
|
||||
directory of logs, finding the newest log, reading it to find last
|
||||
checkpoint... Slow but can save your db.
|
||||
*/
|
||||
last_checkpoint_lsn_at_startup= 0;
|
||||
last_log_name_at_startup= NULL;
|
||||
return 0;
|
||||
last_checkpoint_lsn_at_startup.file_no= CONTROL_FILE_IMPOSSIBLE_LOGNO;
|
||||
last_checkpoint_lsn_at_startup.rec_offset= 0;
|
||||
last_logno_at_startup= CONTROL_FILE_IMPOSSIBLE_LOGNO;
|
||||
|
||||
/* init the file with these "undefined" values */
|
||||
return control_file_write_and_force(last_checkpoint_lsn_at_startup,
|
||||
last_logno_at_startup);
|
||||
}
|
||||
/* Already existing file, read it */
|
||||
if (my_read(control_file_fd, buffer, 8, MYF(MY_FNABP)))
|
||||
if (my_read(control_file_fd, buffer, STAT_FILE_MAX_SIZE,
|
||||
MYF(MY_FNABP | MY_WME)))
|
||||
return 1;
|
||||
last_checkpoint_lsn_at_startup= uint8korr(buffer);
|
||||
if (last_log_name_at_startup= my_malloc(512-8+1))
|
||||
return 1;
|
||||
if (my_read(control_file_fd, last_log_name_at_startup, 512-8), MYF(MY_FNABP))
|
||||
return 1;
|
||||
last_log_name[512-8]= 0; /* end zero to be nice */
|
||||
last_checkpoint_lsn_at_startup.file_no= uint4korr(buffer);
|
||||
last_checkpoint_lsn_at_startup.rec_offset= uint4korr(buffer +
|
||||
STAT_FILE_FILENO_SIZE);
|
||||
last_logno_at_startup= uint4korr(buffer + STAT_FILE_LSN_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Write information durably to the control file.
|
||||
|
||||
SYNOPSIS
|
||||
control_file_write_and_force()
|
||||
checkpoint_lsn LSN of checkpoint
|
||||
log_no last log file number
|
||||
args_to_write bitmap of 1 (write the LSN) and 2 (write the LOGNO)
|
||||
|
||||
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).
|
||||
|
||||
RETURN
|
||||
0 - OK
|
||||
1 - Error
|
||||
*/
|
||||
int control_file_write_and_force(LSN lsn, char *log_name)
|
||||
|
||||
int control_file_write_and_force(LSN *checkpoint_lsn, uint32 log_no,
|
||||
uint args_to_write)
|
||||
{
|
||||
char buffer[512];
|
||||
uint start=8,end=8;
|
||||
if (lsn != 0) /* LSN was specified */
|
||||
char buffer[STAT_FILE_MAX_SIZE];
|
||||
uint start= STAT_FILE_LSN_SIZE, end= STAT_FILE_LSN_SIZE;
|
||||
/*
|
||||
If LSN was specified...
|
||||
|
||||
rec_offset can't be 0 in real LSN, because all files have header page
|
||||
*/
|
||||
if ((args_to_write & 1) && checkpoint_lsn) /* write checkpoint LSN */
|
||||
{
|
||||
start= 0;
|
||||
int8store(buffer, lsn);
|
||||
int4store(buffer, checkpoint_lsn->file_no);
|
||||
int4store(buffer + STAT_FILE_FILENO_SIZE, checkpoint_lsn->rec_offset);
|
||||
}
|
||||
if (log_name != NULL) /* log name was specified */
|
||||
if (args_to_write & 2) /* write logno */
|
||||
{
|
||||
end= 512;
|
||||
memcpy(buffer+8, log_name, 512-8);
|
||||
end= STAT_FILE_MAX_SIZE;
|
||||
int4store(buffer + STAT_FILE_LSN_SIZE, log_no);
|
||||
}
|
||||
DBUG_ASSERT(start != end);
|
||||
return (my_pwrite(control_file_fd, buffer, end-start, start, MYF(MY_FNABP)) ||
|
||||
my_sync(control_file_fd))
|
||||
return (my_pwrite(control_file_fd, buffer + start, end - start, start,
|
||||
MYF(MY_FNABP | MY_WME)) ||
|
||||
my_sync(control_file_fd, MYF(MY_WME)));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Free resources taken by control file subsystem
|
||||
|
||||
SYNOPSIS
|
||||
control_file_end()
|
||||
*/
|
||||
|
||||
void control_file_end()
|
||||
{
|
||||
my_close(control_file_fd, MYF(MY_WME));
|
||||
}
|
||||
|
|
|
@ -4,10 +4,25 @@
|
|||
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;
|
||||
extern char *last_log_name_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.
|
||||
|
@ -21,4 +36,11 @@ int control_file_create_or_open();
|
|||
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 lsn, char *log_name);
|
||||
int control_file_write_and_force(LSN *checkpoint_lsn, uint32 log_no,
|
||||
uint args_to_write);
|
||||
|
||||
|
||||
/* Free resources taken by control file subsystem */
|
||||
void control_file_end();
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue