Commit 3e90f0d8 authored by unknown's avatar unknown

Added variable to control log directory syncs.

Part of postreview fixes added.


mysql-test/r/maria.result:
  Added variable to control log directory syncs.
storage/maria/ha_maria.cc:
  Added variable to control log directory syncs.
storage/maria/ma_loghandler.h:
  Added variable to control log directory syncs.
storage/maria/ma_loghandler_lsn.h:
  postreview fix
storage/maria/unittest/Makefile.am:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler_first_lsn-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler_max_lsn-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler_multigroup-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler_multithread-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler_noflush-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler_pagecache-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_test_loghandler_purge-t.c:
  New file with logrecord descriptors for tests.
storage/maria/unittest/ma_loghandler_examples.c:
  New BitKeeper file ``storage/maria/unittest/ma_loghandler_examples.c''
parent 1e865f0a
......@@ -2055,6 +2055,7 @@ maria_pagecache_division_limit 100
maria_repair_threads 1
maria_sort_buffer_size 8388608
maria_stats_method nulls_unequal
maria_sync_log_dir NEWFILE
show status like 'maria%';
Variable_name Value
Maria_pagecache_blocks_not_flushed #
......
......@@ -81,6 +81,17 @@ TYPELIB maria_stats_method_typelib=
maria_stats_method_names, NULL
};
const char *maria_sync_log_dir_names[]=
{
"NEVER", "NEWFILE", "ALWAYS", NullS
};
TYPELIB maria_sync_log_dir_typelib=
{
array_elements(maria_sync_log_dir_names) - 1, "",
maria_sync_log_dir_names, NULL
};
/** @brief Interval between background checkpoints in seconds */
static ulong checkpoint_interval;
static void update_checkpoint_interval(MYSQL_THD thd,
......@@ -140,6 +151,12 @@ static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG,
"NULLs. Possible values of name are \"nulls_unequal\", \"nulls_equal\", "
"and \"nulls_ignored\".", 0, 0, 0, &maria_stats_method_typelib);
static MYSQL_SYSVAR_ENUM(sync_log_dir, sync_log_dir, PLUGIN_VAR_RQCMDARG,
"Controls syncing directory after log file growth and new file "
"creation. Possible values of are \"never\", \"newfile\" and "
"\"always\")", NULL, NULL, TRANSLOG_SYNC_DIR_NEWFILE,
&maria_sync_log_dir_typelib);
/*****************************************************************************
** MARIA tables
*****************************************************************************/
......@@ -2512,6 +2529,7 @@ static struct st_mysql_sys_var* system_variables[]= {
MYSQL_SYSVAR(repair_threads),
MYSQL_SYSVAR(sort_buffer_size),
MYSQL_SYSVAR(stats_method),
MYSQL_SYSVAR(sync_log_dir),
NULL
};
......
......@@ -23,6 +23,7 @@
@brief Module which writes and reads to a transaction log
*/
/* 0xFF can never be valid first byte of a chunk */
#define TRANSLOG_FILLER 0xFF
/* number of opened log files in the pagecache (should be at least 2) */
......@@ -66,18 +67,18 @@
static int translog_mutex_lock(pthread_mutex_t *M)
{
int rc;
DBUG_PRINT("info", ("Going lock mutex 0x%lx", (ulong)(M)));
DBUG_PRINT("info", ("Going to lock mutex 0x%lx", (ulong)M));
rc= pthread_mutex_lock(M);
DBUG_PRINT("info", ("Mutex locked 0x%lx rc: %d", (ulong)(M), rc));
DBUG_PRINT("info", ("Mutex locked 0x%lx rc: %d", (ulong)M, rc));
return (rc);
}
static int translog_mutex_unlock(pthread_mutex_t *M)
{
int rc;
DBUG_PRINT("info", ("Going unlock mutex 0x%lx", (ulong)(M)));
DBUG_PRINT("info", ("Going to unlock mutex 0x%lx", (ulong)M));
rc= pthread_mutex_unlock(M);
DBUG_PRINT("info", ("Mutex unlocked 0x%lx rc: %d", (ulong)(M), rc));
DBUG_PRINT("info", ("Mutex unlocked 0x%lx rc: %d", (ulong)M, rc));
return(rc);
}
......@@ -99,7 +100,7 @@ struct st_translog_buffer
*/
TRANSLOG_ADDRESS next_buffer_offset;
/*
How much written (or will be written when copy_to_buffer_in_progress
How much is written (or will be written when copy_to_buffer_in_progress
become 0) to this buffer
*/
translog_size_t size;
......@@ -107,36 +108,57 @@ struct st_translog_buffer
File file;
/* Threads which are waiting for buffer filling/freeing */
WQUEUE waiting_filling_buffer;
/* Number of record which are in copy progress */
/* Number of records which are in copy progress */
uint copy_to_buffer_in_progress;
/* list of waiting buffer ready threads */
struct st_my_thread_var *waiting_flush;
/*
Pointer on the buffer which overlap with this one (due to flush of
loghandler) and have to be written first (because contain old content of
page which present in both buffers)
*/
struct st_translog_buffer *overlay;
#ifndef DBUG_OFF
uint buffer_no;
#endif
/* lock for the buffer. Current buffer also lock the handler */
/*
Lock for the buffer.
Current buffer also lock the whole handler (if one want lock the handler
one should lock the current buffer)
*/
pthread_mutex_t mutex;
/* IO cache for current log */
/* Cache for current log. */
uchar buffer[TRANSLOG_WRITE_BUFFER];
};
struct st_buffer_cursor
{
/* pointer on the buffer */
/* pointer into the buffer */
uchar *ptr;
/* current buffer */
struct st_translog_buffer *buffer;
/* current page fill */
/* How many bytes we wrote on the current page */
uint16 current_page_fill;
/* how many times we finish this page to write it (for sector protection) */
/*
How many times we write the page on the disk during flushing process
(for sector protection).
*/
uint16 write_counter;
/* previous write offset */
uint16 previous_offset;
/* Number of current buffer */
uint8 buffer_no;
my_bool chaser, protected;
/*
True if it is just filling buffer after advancing the pointer to
the horizon.
*/
my_bool chaser;
/*
Is current page of the cursor already finished (sector protection
should be applied if it is needed)
*/
my_bool protected;
};
......@@ -146,28 +168,38 @@ struct st_translog_descriptor
/* Page cache for the log reads */
PAGECACHE *pagecache;
/* Flags */
uint flags;
/* max size of one log size (for new logs creation) */
uint32 log_file_max_size;
/* server version */
uint32 server_version;
/* server ID */
/* server ID (used for replication) */
uint32 server_id;
/* Loghandler's buffer capacity in case of chunk 2 filling */
uint32 buffer_capacity_chunk_2;
/* Half of the buffer capacity in case of chunk 2 filling */
/*
Half of the buffer capacity in case of chunk 2 filling,
used to decide will we write a record in one group or many.
It is written to the variable just to avoid devision every
time we need it.
*/
uint32 half_buffer_capacity_chunk_2;
/* Page overhead calculated by flags */
/* Page overhead calculated by flags (whether CRC is enabled, etc) */
uint16 page_overhead;
/* Page capacity calculated by flags (TRANSLOG_PAGE_SIZE-page_overhead-1) */
/*
Page capacity ("useful load") calculated by flags
(TRANSLOG_PAGE_SIZE - page_overhead-1)
*/
uint16 page_capacity_chunk_2;
/* Directory to store files */
/* Path to the directory where we store log store files */
char directory[FN_REFLEN];
/* *** Current state of the log handler *** */
/* Current and (OPENED_FILES_NUM-1) last logs number in page cache */
/* Current and (OPENED_FILES_NUM-1) last logs number in the page cache */
File log_file_num[OPENED_FILES_NUM];
/*
File descriptor of the directory where we store log files for syncing
it.
*/
File directory_fd;
/* buffers for log writing */
struct st_translog_buffer buffers[TRANSLOG_BUFFERS_NO];
......@@ -181,13 +213,18 @@ struct st_translog_descriptor
/* maximum LSN of the current (not finished) file */
LSN max_lsn;
/* Last flushed LSN (protected by log_flush_lock) */
/*
Last flushed LSN (protected by log_flush_lock).
Pointers in the log ordered like this:
last_lsn_checked <= flushed <= sent_to_disk <= in_buffers_only <=
max_lsn <= horizon
*/
LSN flushed;
/* Last LSN sent to the disk (but maybe not written yet) */
LSN sent_to_file;
LSN sent_to_disk;
/* All what is after this address is not sent to disk yet */
TRANSLOG_ADDRESS in_buffers_only;
pthread_mutex_t sent_to_file_lock;
pthread_mutex_t sent_to_disk_lock;
pthread_mutex_t log_flush_lock;
/* Protects changing of headers of finished files (max_lsn) */
......@@ -210,6 +247,8 @@ struct st_translog_descriptor
static struct st_translog_descriptor log_descriptor;
ulong sync_log_dir= TRANSLOG_SYNC_DIR_NEWFILE;
/* Marker for end of log */
static uchar end_of_log= 0;
#define END_OF_LOG &end_of_log
......@@ -241,8 +280,6 @@ static my_bool translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner);
/*
Initialize log_record_type_descriptors
NOTE that after first public Maria release, these can NOT be changed
*/
LOG_DESC log_record_type_descriptor[LOGREC_NUMBER_OF_TYPES];
......@@ -251,7 +288,7 @@ LOG_DESC log_record_type_descriptor[LOGREC_NUMBER_OF_TYPES];
#ifndef DBUG_OFF
#define translog_buffer_lock_assert_owner(B) \
safe_mutex_assert_owner(&B->mutex);
safe_mutex_assert_owner(&(B)->mutex);
void translog_lock_assert_owner()
{
translog_buffer_lock_assert_owner(log_descriptor.bc.buffer);
......@@ -323,55 +360,6 @@ static void check_translog_description_table(int num)
#define translog_lock_assert_owner()
#endif
static LOG_DESC INIT_LOGREC_FIXED_RECORD_0LSN_EXAMPLE=
{LOGRECTYPE_FIXEDLENGTH, 6, 6, NULL, NULL, NULL, 0,
"fixed0example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE=
{LOGRECTYPE_VARIABLE_LENGTH, 0, 9, NULL, NULL, NULL, 0,
"variable0example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_FIXED_RECORD_1LSN_EXAMPLE=
{LOGRECTYPE_PSEUDOFIXEDLENGTH, 7, 7, NULL, NULL, NULL, 1,
"fixed1example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE=
{LOGRECTYPE_VARIABLE_LENGTH, 0, 12, NULL, NULL, NULL, 1,
"variable1example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_FIXED_RECORD_2LSN_EXAMPLE=
{LOGRECTYPE_PSEUDOFIXEDLENGTH, 23, 23, NULL, NULL, NULL, 2,
"fixed2example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE=
{LOGRECTYPE_VARIABLE_LENGTH, 0, 19, NULL, NULL, NULL, 2,
"variable2example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
void example_loghandler_init()
{
int i;
log_record_type_descriptor[LOGREC_FIXED_RECORD_0LSN_EXAMPLE]=
INIT_LOGREC_FIXED_RECORD_0LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE]=
INIT_LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_FIXED_RECORD_1LSN_EXAMPLE]=
INIT_LOGREC_FIXED_RECORD_1LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE]=
INIT_LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_FIXED_RECORD_2LSN_EXAMPLE]=
INIT_LOGREC_FIXED_RECORD_2LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE]=
INIT_LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE;
for (i= LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE + 1;
i < LOGREC_NUMBER_OF_TYPES;
i++)
log_record_type_descriptor[i].class= LOGRECTYPE_NOT_ALLOWED;
DBUG_EXECUTE("info",
check_translog_description_table(LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE););
}
static LOG_DESC INIT_LOGREC_RESERVED_FOR_CHUNKS23=
{LOGRECTYPE_NOT_ALLOWED, 0, 0, NULL, NULL, NULL, 0,
"reserved", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL };
......@@ -394,7 +382,7 @@ static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_BLOB=
"redo_insert_row_blob", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
/** @todo RECOVERY BUG handle it in recovery */
/*QQQ:TODO:header???*/
/*QQ:TODO:header???*/
static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_BLOBS=
{LOGRECTYPE_VARIABLE_LENGTH, 0, FILEID_STORE_SIZE, NULL,
write_hook_for_redo, NULL, 0,
......@@ -716,16 +704,46 @@ static char *translog_filename_by_fileno(uint32 file_no, char *path)
}
/*
Open log file with given number without cache
/**
@brief Create log file with given number without cache
SYNOPSIS
open_logfile_by_number_no_cache()
file_no Number of the log we want to open
@param file_no Number of the log we want to open
RETURN
-1 error
# file descriptor number
retval -1 error
retval # file descriptor number
*/
static File create_logfile_by_number_no_cache(uint32 file_no)
{
File file;
char path[FN_REFLEN];
DBUG_ENTER("create_logfile_by_number_no_cache");
/* TODO: add O_DIRECT to open flags (when buffer is aligned) */
if ((file= my_create(translog_filename_by_fileno(file_no, path),
0, O_BINARY | O_RDWR, MYF(MY_WME))) < 0)
{
UNRECOVERABLE_ERROR(("Error %d during creating file '%s'", errno, path));
DBUG_RETURN(-1);
}
if (sync_log_dir >= TRANSLOG_SYNC_DIR_NEWFILE &&
my_sync(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD)))
{
UNRECOVERABLE_ERROR(("Error %d during syncing directory '%s'",
errno, log_descriptor.directory));
DBUG_RETURN(-1);
}
DBUG_PRINT("info", ("File: '%s' handler: %d", path, file));
DBUG_RETURN(file);
}
/**
@brief Open (not create) log file with given number without cache
@param file_no Number of the log we want to open
retval -1 error
retval # file descriptor number
*/
static File open_logfile_by_number_no_cache(uint32 file_no)
......@@ -737,7 +755,7 @@ static File open_logfile_by_number_no_cache(uint32 file_no)
/* TODO: add O_DIRECT to open flags (when buffer is aligned) */
/* TODO: use my_create() */
if ((file= my_open(translog_filename_by_fileno(file_no, path),
O_CREAT | O_BINARY | O_RDWR,
O_BINARY | O_RDWR,
MYF(MY_WME))) < 0)
{
UNRECOVERABLE_ERROR(("Error %d during opening file '%s'", errno, path));
......@@ -748,6 +766,14 @@ static File open_logfile_by_number_no_cache(uint32 file_no)
}
uchar NEAR maria_trans_file_magic[]=
{ (uchar) 254, (uchar) 254, (uchar) 11, '\001', 'M', 'A', 'R', 'I', 'A',
'L', 'O', 'G' };
#define LOG_HEADER_DATA_SIZE (sizeof(maria_trans_file_magic) + \
8 + 4 + 4 + 4 + 2 + 3 + \
LSN_STORE_SIZE)
/*
Write log file page header in the just opened new log file
......@@ -762,10 +788,6 @@ static File open_logfile_by_number_no_cache(uint32 file_no)
1 ERROR
*/
uchar NEAR maria_trans_file_magic[]=
{ (uchar) 254, (uchar) 254, (uchar) 11, '\001', 'M', 'A', 'R', 'I', 'A',
'L', 'O', 'G' };
static my_bool translog_write_file_header()
{
ulonglong timestamp;
......@@ -825,8 +847,7 @@ static my_bool translog_max_lsn_to_header(File file, LSN lsn)
DBUG_RETURN(my_pwrite(file, lsn_buff,
LSN_STORE_SIZE,
(sizeof(maria_trans_file_magic) +
8 + 4 + 4 + 4 + 2 + 3),
(LOG_HEADER_DATA_SIZE - LSN_STORE_SIZE),
log_write_flags) != 0 ||
my_sync(file, MYF(MY_WME)) != 0);
}
......@@ -839,13 +860,14 @@ static my_bool translog_max_lsn_to_header(File file, LSN lsn)
typedef struct st_loghandler_file_info
{
/*
LSN_IMPOSSIBLE for current file and max LSN which parts stored in the
file for all other (finished) files.
LSN_IMPOSSIBLE for current file (not finished file).
Maximum LSN of the record which parts stored in the
file.
*/
LSN max_lsn;
ulonglong timestamp; /* Time stamp */
ulong maria_version; /* Version of maria loghandler */
ulong mysql_versiob; /* Version of mysql server */
ulong mysql_version; /* Version of mysql server */
ulong server_id; /* Server ID */
uint page_size; /* Loghandler page size */
uint file_number; /* Number of the file (from the file header) */
......@@ -861,10 +883,6 @@ typedef struct st_loghandler_file_info
@retval 1 Error
*/
#define LOG_HEADER_DATA_SIZE (sizeof(maria_trans_file_magic) + \
8 + 4 + 4 + 4 + 2 + 3 + \
LSN_STORE_SIZE)
my_bool translog_read_file_header(LOGHANDLER_FILE_INFO *desc, File file)
{
uchar page_buff[LOG_HEADER_DATA_SIZE], *ptr;
......@@ -881,7 +899,7 @@ my_bool translog_read_file_header(LOGHANDLER_FILE_INFO *desc, File file)
ptr+= 8;
desc->maria_version= uint4korr(ptr);
ptr+= 4;
desc->mysql_versiob= uint4korr(ptr);
desc->mysql_version= uint4korr(ptr);
ptr+= 4;
desc->server_id= uint4korr(ptr);
ptr+= 4;
......@@ -1147,13 +1165,13 @@ static my_bool translog_buffer_init(struct st_translog_buffer *buffer)
/* This Buffer File */
buffer->file= -1;
buffer->overlay= 0;
/* IO cache for current log */
/* cache for current log */
memset(buffer->buffer, TRANSLOG_FILLER, TRANSLOG_WRITE_BUFFER);
/* Buffer size */
buffer->size= 0;
/* cond of thread which is waiting for buffer filling */
buffer->waiting_filling_buffer.last_thread= 0;
/* Number of record which are in copy progress */
/* Number of records which are in copy progress */
buffer->copy_to_buffer_in_progress= 0;
/* list of waiting buffer ready threads */
buffer->waiting_flush= 0;
......@@ -1192,15 +1210,16 @@ static my_bool translog_close_log_file(File file)
}
/*
Create and fill header of new file
/**
@brief Create and fill header of new file.
SYNOPSIS
translog_create_new_file()
@note the caller must call it right after it has increased
log_descriptor.horizon to the new file
(log_descriptor.horizon+= LSN_ONE_FILE)
RETURN
0 OK
1 Error
@retval 0 OK
@retval 1 Error
*/
static my_bool translog_create_new_file()
......@@ -1210,8 +1229,10 @@ static my_bool translog_create_new_file()
DBUG_ENTER("translog_create_new_file");
/*
Writes max_lsn to the file header before finishing it (it is no need to
lock file header buffer because it is still unfinished file)
Writes max_lsn to the file header before finishing it (there is no need
to lock file header buffer because it is still unfinished file, so only
one thread can finish the file and nobody interested of LSN of current
(unfinished) file, because no one can purge it).
*/
translog_max_lsn_to_header(log_descriptor.log_file_num[0],
log_descriptor.max_lsn);
......@@ -1225,7 +1246,7 @@ static my_bool translog_create_new_file()
log_descriptor.log_file_num[i]= log_descriptor.log_file_num[i - 1];
if ((log_descriptor.log_file_num[0]=
open_logfile_by_number_no_cache(file_no)) == -1 ||
create_logfile_by_number_no_cache(file_no)) == -1 ||
translog_write_file_header())
DBUG_RETURN(1);
......@@ -1346,14 +1367,18 @@ static void translog_new_page_header(TRANSLOG_ADDRESS *horizon,
}
if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
{
time_t tm;
uint16 tmp_time= time(&tm);
/*
The time() works like "random" values producer because it is enough to
have such "random" for this purpose and it will not interfere with
higher level pseudo random value generator
*/
uint16 tmp_time= time(NULL);
int2store(ptr, tmp_time);
ptr+= (TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE) * 2;
}
{
uint len= (ptr - cursor->ptr);
(*horizon)+= len; /* it is increasing of offset part of the address */
(*horizon)+= len; /* increasing the offset part of the address */
cursor->current_page_fill= len;
if (!cursor->chaser)
cursor->buffer->size+= len;
......@@ -1491,10 +1516,11 @@ static void translog_finish_page(TRANSLOG_ADDRESS *horizon,
{
DBUG_PRINT("info", ("left: %u", (uint) left));
memset(cursor->ptr, TRANSLOG_FILLER, left);
cursor->ptr +=left;
cursor->ptr+= left;
(*horizon)+= left; /* offset increasing */
if (!cursor->chaser)
cursor->buffer->size+= left;
/* We are finishing the page so reset the counter */
cursor->current_page_fill= 0;
DBUG_PRINT("info", ("Finish Page buffer #%u: 0x%lx "
"chaser: %d Size: %lu (%lu)",
......@@ -1506,8 +1532,8 @@ static void translog_finish_page(TRANSLOG_ADDRESS *horizon,
}
/*
When we are finishing the page other thread might not finish the page
header yet so we have to read log_descriptor.flags but not the flags
from the page
header yet (in case if we started from the middle of the page) so we
have to read log_descriptor.flags but not the flags from the page.
*/
if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
{
......@@ -1530,14 +1556,9 @@ static void translog_finish_page(TRANSLOG_ADDRESS *horizon,
/*
Wait until all thread finish filling this buffer
@brief Wait until all threads have finished filling this buffer.
SYNOPSIS
translog_wait_for_writers()
buffer This buffer should be check
NOTE
This buffer should be locked
@param buffer This buffer should be check
*/
static void translog_wait_for_writers(struct st_translog_buffer *buffer)
......@@ -1547,6 +1568,7 @@ static void translog_wait_for_writers(struct st_translog_buffer *buffer)
DBUG_PRINT("enter", ("Buffer #%u 0x%lx copies in progress: %u",
(uint) buffer->buffer_no, (ulong) buffer,
(int) buffer->copy_to_buffer_in_progress));
translog_buffer_lock_assert_owner(buffer);
while (buffer->copy_to_buffer_in_progress)
{
......@@ -1641,13 +1663,11 @@ static void translog_cursor_init(struct st_buffer_cursor *cursor,
/*
Initialize buffer for current file
@brief Initialize buffer for the current file, and a cursor for this buffer.
SYNOPSIS
translog_start_buffer()
buffer The buffer
cursor It's cursor
buffer_no Number of buffer
@param buffer The buffer
@param cursor It's cursor
@param buffer_no Number of buffer
*/
static void translog_start_buffer(struct st_translog_buffer *buffer,
......@@ -1679,21 +1699,18 @@ static void translog_start_buffer(struct st_translog_buffer *buffer,
/*
Switch to the next buffer in a chain
@brief Switch to the next buffer in a chain.
SYNOPSIS
translog_buffer_next()
horizon \ Pointers on current position in file and buffer
cursor /
next_file Also start new file
@param horizon \ Pointers on current position in file and buffer
@param cursor /
@param new_file Also start new file
NOTE:
@note
- loghandler should be locked
- after return new and old buffer still are locked
RETURN
0 OK
1 Error
@retval 0 OK
@retval 1 Error
*/
static my_bool translog_buffer_next(TRANSLOG_ADDRESS *horizon,
......@@ -1718,10 +1735,9 @@ static my_bool translog_buffer_next(TRANSLOG_ADDRESS *horizon,
translog_buffer_lock(new_buffer);
translog_wait_for_buffer_free(new_buffer);
}
#ifndef DBUG_OFF
else
DBUG_ASSERT(new_buffer->file != 0);
#endif
if (new_file)
{
......@@ -1752,31 +1768,31 @@ static my_bool translog_buffer_next(TRANSLOG_ADDRESS *horizon,
Sets max LSN sent to file, and address from which data is only in the buffer
SYNOPSIS
translog_set_sent_to_file()
translog_set_sent_to_disk()
lsn LSN to assign
in_buffers to assign to in_buffers_only
TODO: use atomic operations if possible (64bit architectures?)
*/
static void translog_set_sent_to_file(LSN lsn, TRANSLOG_ADDRESS in_buffers)
static void translog_set_sent_to_disk(LSN lsn, TRANSLOG_ADDRESS in_buffers)
{
DBUG_ENTER("translog_set_sent_to_file");
translog_mutex_lock(&log_descriptor.sent_to_file_lock);
DBUG_ENTER("translog_set_sent_to_disk");
translog_mutex_lock(&log_descriptor.sent_to_disk_lock);
DBUG_PRINT("enter", ("lsn: (%lu,0x%lx) in_buffers: (%lu,0x%lx) "
"in_buffers_only: (%lu,0x%lx)",
LSN_IN_PARTS(lsn),
LSN_IN_PARTS(in_buffers),
LSN_IN_PARTS(log_descriptor.in_buffers_only)));
DBUG_ASSERT(cmp_translog_addr(lsn, log_descriptor.sent_to_file) >= 0);
log_descriptor.sent_to_file= lsn;
DBUG_ASSERT(cmp_translog_addr(lsn, log_descriptor.sent_to_disk) >= 0);
log_descriptor.sent_to_disk= lsn;
/* LSN_IMPOSSIBLE == 0 => it will work for very first time */
if (cmp_translog_addr(in_buffers, log_descriptor.in_buffers_only) > 0)
{
log_descriptor.in_buffers_only= in_buffers;
DBUG_PRINT("info", ("set new in_buffers_only"));
}
translog_mutex_unlock(&log_descriptor.sent_to_file_lock);
translog_mutex_unlock(&log_descriptor.sent_to_disk_lock);
DBUG_VOID_RETURN;
}
......@@ -1793,7 +1809,7 @@ static void translog_set_sent_to_file(LSN lsn, TRANSLOG_ADDRESS in_buffers)
static void translog_set_only_in_buffers(TRANSLOG_ADDRESS in_buffers)
{
DBUG_ENTER("translog_set_only_in_buffers");
translog_mutex_lock(&log_descriptor.sent_to_file_lock);
translog_mutex_lock(&log_descriptor.sent_to_disk_lock);
DBUG_PRINT("enter", ("in_buffers: (%lu,0x%lx) "
"in_buffers_only: (%lu,0x%lx)",
LSN_IN_PARTS(in_buffers),
......@@ -1804,7 +1820,7 @@ static void translog_set_only_in_buffers(TRANSLOG_ADDRESS in_buffers)
log_descriptor.in_buffers_only= in_buffers;
DBUG_PRINT("info", ("set new in_buffers_only"));
}
translog_mutex_unlock(&log_descriptor.sent_to_file_lock);
translog_mutex_unlock(&log_descriptor.sent_to_disk_lock);
DBUG_VOID_RETURN;
}
......@@ -1823,9 +1839,9 @@ static TRANSLOG_ADDRESS translog_only_in_buffers()
{
register TRANSLOG_ADDRESS addr;
DBUG_ENTER("translog_only_in_buffers");
translog_mutex_lock(&log_descriptor.sent_to_file_lock);
translog_mutex_lock(&log_descriptor.sent_to_disk_lock);
addr= log_descriptor.in_buffers_only;
translog_mutex_unlock(&log_descriptor.sent_to_file_lock);
translog_mutex_unlock(&log_descriptor.sent_to_disk_lock);
DBUG_RETURN(addr);
}
......@@ -1834,19 +1850,19 @@ static TRANSLOG_ADDRESS translog_only_in_buffers()
Get max LSN sent to file
SYNOPSIS
translog_get_sent_to_file()
translog_get_sent_to_disk()
RETURN
max LSN send to file
*/
static LSN translog_get_sent_to_file()
static LSN translog_get_sent_to_disk()
{
register LSN lsn;
DBUG_ENTER("translog_get_sent_to_file");
translog_mutex_lock(&log_descriptor.sent_to_file_lock);
lsn= log_descriptor.sent_to_file;
translog_mutex_unlock(&log_descriptor.sent_to_file_lock);
DBUG_ENTER("translog_get_sent_to_disk");
translog_mutex_lock(&log_descriptor.sent_to_disk_lock);
lsn= log_descriptor.sent_to_disk;
translog_mutex_unlock(&log_descriptor.sent_to_disk_lock);
DBUG_RETURN(lsn);
}
......@@ -1864,14 +1880,9 @@ static LSN translog_get_sent_to_file()
static my_bool translog_get_first_chunk_offset(uchar *page)
{
uint16 page_header= 7;
DBUG_ENTER("translog_get_first_chunk_offset");
if (page[TRANSLOG_PAGE_FLAGS] & TRANSLOG_PAGE_CRC)
page_header+= 4;
if (page[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION)
page_header+= (TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE) * 2;
DBUG_RETURN(page_header);
DBUG_ASSERT(page[TRANSLOG_PAGE_FLAGS] < TRANSLOG_FLAGS_NUM);
DBUG_RETURN(page_overhead[page[TRANSLOG_PAGE_FLAGS]]);
}
......@@ -1972,7 +1983,7 @@ static uint16 translog_get_total_chunk_length(uchar *page, uint16 offset)
/* 0 chunk referred as LSN (head or tail) */
translog_size_t rec_len;
uchar *start= page + offset;
uchar *ptr= start + 1 + 2;
uchar *ptr= start + 1 + 2; /* chunk type and short trid */
uint16 chunk_len, header_len, page_rest;
DBUG_PRINT("info", ("TRANSLOG_CHUNK_LSN"));
rec_len= translog_variable_record_1group_decode_len(&ptr);
......@@ -2018,11 +2029,11 @@ static uint16 translog_get_total_chunk_length(uchar *page, uint16 offset)
for (i= 0; i < log_record_type_descriptor[type].compressed_LSN; i++)
{
/* first 2 bits is length - 2 */
uint len= ((((uint8) (*ptr)) & TRANSLOG_CLSN_LEN_BITS) >> 6) + 2;
uint len= (((uint8) (*ptr)) >> 6) + 2;
if (ptr[0] == 0 && ((uint8) ptr[1]) == 1)
len+= LSN_STORE_SIZE; /* case of full LSN storing */
ptr+= len;
/* subtract economized bytes */
/* subtract saved bytes */
length-= (LSN_STORE_SIZE - len);
}
DBUG_PRINT("info", ("Pseudo-fixed length: %u", length));
......@@ -2121,7 +2132,7 @@ static my_bool translog_buffer_flush(struct st_translog_buffer *buffer)
}
if (LSN_OFFSET(buffer->last_lsn) != 0) /* if buffer->last_lsn is set */
translog_set_sent_to_file(buffer->last_lsn,
translog_set_sent_to_disk(buffer->last_lsn,
buffer->next_buffer_offset);
else
translog_set_only_in_buffers(buffer->next_buffer_offset);
......@@ -2415,7 +2426,7 @@ static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer,
{
/*
if the page is in the buffer and it is the last version of the
page (in case of devision the page bu buffer flush
page (in case of division the page by buffer flush)
*/
if (curr_buffer->file != -1 &&
cmp_translog_addr(addr, curr_buffer->offset) >= 0 &&
......@@ -2481,7 +2492,10 @@ static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer,
supposed to be correct.
*/
if (translog_page_validator((uchar*) buffer, (uchar*) data))
{
buffer= NULL;
DBUG_ASSERT(FALSE);
}
}
DBUG_RETURN(buffer);
}
......@@ -2804,7 +2818,7 @@ my_bool translog_init(const char *directory,
loghandler_init(); /* Safe to do many times */
if (pthread_mutex_init(&log_descriptor.sent_to_file_lock,
if (pthread_mutex_init(&log_descriptor.sent_to_disk_lock,
MY_MUTEX_INIT_FAST) ||
pthread_mutex_init(&log_descriptor.file_header_lock,
MY_MUTEX_INIT_FAST) ||
......@@ -3075,7 +3089,7 @@ my_bool translog_init(const char *directory,
log_descriptor.horizon= MAKE_LSN(1, TRANSLOG_PAGE_SIZE); /* header page */
/* Current logs file number in page cache */
if ((log_descriptor.log_file_num[0]=
open_logfile_by_number_no_cache(1)) == -1 ||
create_logfile_by_number_no_cache(1)) == -1 ||
translog_write_file_header())
DBUG_RETURN(1);
if (ma_control_file_write_and_force(LSN_IMPOSSIBLE, 1,
......@@ -3103,7 +3117,7 @@ my_bool translog_init(const char *directory,
}
/* all LSNs that are on disk are flushed */
log_descriptor.sent_to_file=
log_descriptor.sent_to_disk=
log_descriptor.flushed= log_descriptor.horizon;
log_descriptor.in_buffers_only= log_descriptor.bc.buffer->offset;
log_descriptor.max_lsn= LSN_IMPOSSIBLE; /* set to 0 */
......@@ -3112,7 +3126,7 @@ my_bool translog_init(const char *directory,
it to signal that all LSNs before it are flushed
*/
log_descriptor.flushed--; /* offset decreased */
log_descriptor.sent_to_file--; /* offset decreased */
log_descriptor.sent_to_disk--; /* offset decreased */
/*
Log records will refer to a MARIA_SHARE by a unique 2-byte id; set up
structures for generating 2-byte ids:
......@@ -3330,7 +3344,7 @@ void translog_destroy()
if (log_descriptor.log_file_num[i] != -1)
translog_close_log_file(log_descriptor.log_file_num[i]);
}
pthread_mutex_destroy(&log_descriptor.sent_to_file_lock);
pthread_mutex_destroy(&log_descriptor.sent_to_disk_lock);
pthread_mutex_destroy(&log_descriptor.file_header_lock);
pthread_mutex_destroy(&log_descriptor.unfinished_files_lock);
pthread_mutex_destroy(&log_descriptor.purger_lock);
......@@ -6565,13 +6579,14 @@ static void translog_force_current_buffer_to_finish()
my_bool translog_flush(LSN lsn)
{
LSN old_flushed, sent_to_file;
LSN old_flushed, sent_to_disk;
int rc= 0;
uint i;
my_bool full_circle= 0;
DBUG_ENTER("translog_flush");
DBUG_PRINT("enter", ("Flush up to LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
DBUG_ASSERT(translog_inited == 1);
LINT_INIT(sent_to_disk);
translog_mutex_lock(&log_descriptor.log_flush_lock);
translog_lock();
......@@ -6592,8 +6607,8 @@ my_bool translog_flush(LSN lsn)
goto sync;
}
/* send to the file if it is not sent */
sent_to_file= translog_get_sent_to_file();
if (cmp_translog_addr(sent_to_file, lsn) >= 0)
sent_to_disk= translog_get_sent_to_disk();
if (cmp_translog_addr(sent_to_disk, lsn) >= 0)
break;
do
......@@ -6630,7 +6645,10 @@ my_bool translog_flush(LSN lsn)
sync:
translog_unlock();
for (i= LSN_FILE_NO(old_flushed); i <= LSN_FILE_NO(lsn); i++)
for (i= (LSN_FILE_NO(old_flushed) ? LSN_FILE_NO(old_flushed) : 1);
i <= LSN_FILE_NO(lsn);
i++)
{
uint cache_index;
File file;
......@@ -6653,8 +6671,8 @@ sync:
}
/* We sync file when we are closing it => do nothing if file closed */
}
log_descriptor.flushed= sent_to_file;
/** @todo LOG decide if syncing of directory is needed */
log_descriptor.flushed= sent_to_disk;
if (sync_log_dir >= TRANSLOG_SYNC_DIR_ALWAYS)
rc|= my_sync(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD));
out:
translog_mutex_unlock(&log_descriptor.log_flush_lock);
......
......@@ -253,8 +253,6 @@ C_MODE_START
#define LOGREC_FIXED_RECORD_2LSN_EXAMPLE 5
#define LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE 6
extern void example_loghandler_init();
extern my_bool translog_init(const char *directory, uint32 log_file_max_size,
uint32 server_version, uint32 server_id,
PAGECACHE *pagecache, uint flags);
......@@ -402,5 +400,13 @@ typedef struct st_log_record_type_descriptor
extern LOG_DESC log_record_type_descriptor[LOGREC_NUMBER_OF_TYPES];
#endif
typedef enum
{
TRANSLOG_SYNC_DIR_NEVER,
TRANSLOG_SYNC_DIR_NEWFILE,
TRANSLOG_SYNC_DIR_ALWAYS
} enum_maria_sync_log_dir;
extern ulong sync_log_dir;
C_MODE_END
#endif
......@@ -32,7 +32,12 @@ typedef int64 TRANSLOG_ADDRESS;
*/
#define cmp_translog_addr(A1,A2) ((A1) - (A2))
/* LSN type (address of certain log record chank */
/*
TRANSLOG_ADDRESS is just address of some byte in the log (usually some
chunk)
LSN used where address of some record in the log needed (not just any
address)
*/
typedef TRANSLOG_ADDRESS LSN;
/* Gets file number part of a LSN/log address */
......
......@@ -48,16 +48,16 @@ noinst_PROGRAMS = ma_control_file-t trnman-t lockman2-t \
ma_test_loghandler_max_lsn-t \
ma_test_loghandler_purge-t
ma_test_loghandler_t_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c
ma_test_loghandler_multigroup_t_SOURCES = ma_test_loghandler_multigroup-t.c ma_maria_log_cleanup.c
ma_test_loghandler_multithread_t_SOURCES = ma_test_loghandler_multithread-t.c ma_maria_log_cleanup.c
ma_test_loghandler_pagecache_t_SOURCES = ma_test_loghandler_pagecache-t.c ma_maria_log_cleanup.c
ma_test_loghandler_long_t_big_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c
ma_test_loghandler_t_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_multigroup_t_SOURCES = ma_test_loghandler_multigroup-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_multithread_t_SOURCES = ma_test_loghandler_multithread-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_pagecache_t_SOURCES = ma_test_loghandler_pagecache-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_long_t_big_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_long_t_big_CPPFLAGS = -DLONG_LOG_TEST
ma_test_loghandler_noflush_t_SOURCES = ma_test_loghandler_noflush-t.c ma_maria_log_cleanup.c
ma_test_loghandler_first_lsn_t_SOURCES = ma_test_loghandler_first_lsn-t.c ma_maria_log_cleanup.c
ma_test_loghandler_max_lsn_t_SOURCES = ma_test_loghandler_max_lsn-t.c ma_maria_log_cleanup.c
ma_test_loghandler_purge_t_SOURCES = ma_test_loghandler_purge-t.c ma_maria_log_cleanup.c
ma_test_loghandler_noflush_t_SOURCES = ma_test_loghandler_noflush-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_first_lsn_t_SOURCES = ma_test_loghandler_first_lsn-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_max_lsn_t_SOURCES = ma_test_loghandler_max_lsn-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_test_loghandler_purge_t_SOURCES = ma_test_loghandler_purge-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
ma_pagecache_single_src = ma_pagecache_single.c test_file.c test_file.h
ma_pagecache_consist_src = ma_pagecache_consist.c test_file.c test_file.h
......
/* TODO: copyright */
#include "../maria_def.h"
static LOG_DESC INIT_LOGREC_FIXED_RECORD_0LSN_EXAMPLE=
{LOGRECTYPE_FIXEDLENGTH, 6, 6, NULL, NULL, NULL, 0,
"fixed0example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE=
{LOGRECTYPE_VARIABLE_LENGTH, 0, 9, NULL, NULL, NULL, 0,
"variable0example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_FIXED_RECORD_1LSN_EXAMPLE=
{LOGRECTYPE_PSEUDOFIXEDLENGTH, 7, 7, NULL, NULL, NULL, 1,
"fixed1example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE=
{LOGRECTYPE_VARIABLE_LENGTH, 0, 12, NULL, NULL, NULL, 1,
"variable1example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_FIXED_RECORD_2LSN_EXAMPLE=
{LOGRECTYPE_PSEUDOFIXEDLENGTH, 23, 23, NULL, NULL, NULL, 2,
"fixed2example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE=
{LOGRECTYPE_VARIABLE_LENGTH, 0, 19, NULL, NULL, NULL, 2,
"variable2example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
void example_loghandler_init()
{
int i;
log_record_type_descriptor[LOGREC_FIXED_RECORD_0LSN_EXAMPLE]=
INIT_LOGREC_FIXED_RECORD_0LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE]=
INIT_LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_FIXED_RECORD_1LSN_EXAMPLE]=
INIT_LOGREC_FIXED_RECORD_1LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE]=
INIT_LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_FIXED_RECORD_2LSN_EXAMPLE]=
INIT_LOGREC_FIXED_RECORD_2LSN_EXAMPLE;
log_record_type_descriptor[LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE]=
INIT_LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE;
for (i= LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE + 1;
i < LOGREC_NUMBER_OF_TYPES;
i++)
log_record_type_descriptor[i].class= LOGRECTYPE_NOT_ALLOWED;
}
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
......@@ -5,6 +5,7 @@
#include "../trnman.h"
extern my_bool maria_log_remove();
extern void example_loghandler_init();
#ifndef DBUG_OFF
static const char *default_dbug_option;
......
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