mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
Ability to read unflushed data added (only problem with CRC left and have to be fixed).
Already written pages injection to the cache fixed. storage/maria/ma_loghandler.c: Ability to read unflushed data added. storage/maria/ma_page.c: Parameters added storage/maria/ma_pagecache.c: Already written pages injection to the cache fixed. Validator for case of page content injection added. storage/maria/ma_pagecache.h: Validator for case of page content injection added. storage/maria/unittest/Makefile.am: Test of reading unflushed data storage/maria/unittest/ma_test_loghandler-t.c: Define fixed. Restart of the log removed. storage/maria/unittest/ma_test_loghandler_noflush-t.c: New BitKeeper file ``storage/maria/unittest/ma_test_loghandler_noflush-t.c''
This commit is contained in:
parent
85510db991
commit
7c32eac40a
7 changed files with 432 additions and 106 deletions
|
@ -67,6 +67,11 @@ struct st_translog_buffer
|
|||
LSN last_lsn;
|
||||
/* This buffer offset in the file */
|
||||
TRANSLOG_ADDRESS offset;
|
||||
/*
|
||||
Next buffer offset in the file (it is not always offset + size,
|
||||
in case of flush by LSN it can be offset + size - TRANSLOG_PAGE_SIZE)
|
||||
*/
|
||||
TRANSLOG_ADDRESS next_buffer_offset;
|
||||
/*
|
||||
How much written (or will be written when copy_to_buffer_in_progress
|
||||
become 0) to this buffer
|
||||
|
@ -150,7 +155,10 @@ struct st_translog_descriptor
|
|||
|
||||
/* Last flushed LSN */
|
||||
LSN flushed;
|
||||
/* Last LSN sent to the disk (but maybe not written yet) */
|
||||
LSN sent_to_file;
|
||||
/* All what is after this addess is not sent to disk yet */
|
||||
TRANSLOG_ADDRESS in_buffers_only;
|
||||
pthread_mutex_t sent_to_file_lock;
|
||||
};
|
||||
|
||||
|
@ -187,6 +195,8 @@ static my_bool write_hook_for_undo(enum translog_record_type type,
|
|||
TRN *trn, LSN *lsn,
|
||||
struct st_translog_parts *parts);
|
||||
|
||||
static my_bool translog_page_validator(uchar *page_addr, uchar* data_ptr);
|
||||
|
||||
/*
|
||||
Initialize log_record_type_descriptors
|
||||
|
||||
|
@ -672,7 +682,6 @@ my_bool translog_read_file_header(LOGHANDLER_FILE_INFO *desc)
|
|||
static my_bool translog_buffer_init(struct st_translog_buffer *buffer)
|
||||
{
|
||||
DBUG_ENTER("translog_buffer_init");
|
||||
/* This buffer offset */
|
||||
buffer->last_lsn= LSN_IMPOSSIBLE;
|
||||
/* This Buffer File */
|
||||
buffer->file= -1;
|
||||
|
@ -966,7 +975,8 @@ static void translog_put_sector_protection(uchar *page,
|
|||
|
||||
static uint32 translog_crc(uchar *area, uint length)
|
||||
{
|
||||
return crc32(0L, (unsigned char*) area, length);
|
||||
DBUG_ENTER("translog_crc");
|
||||
DBUG_RETURN(crc32(0L, (unsigned char*) area, length));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1180,6 +1190,7 @@ static void translog_start_buffer(struct st_translog_buffer *buffer,
|
|||
DBUG_ASSERT(buffer_no == buffer->buffer_no);
|
||||
buffer->last_lsn= LSN_IMPOSSIBLE;
|
||||
buffer->offset= log_descriptor.horizon;
|
||||
buffer->next_buffer_offset= LSN_IMPOSSIBLE;
|
||||
buffer->file= log_descriptor.log_file_num[0];
|
||||
buffer->overlay= 0;
|
||||
buffer->size= 0;
|
||||
|
@ -1254,45 +1265,117 @@ static my_bool translog_buffer_next(TRANSLOG_ADDRESS *horizon,
|
|||
translog_cursor_init(cursor, new_buffer, new_buffer_no);
|
||||
else
|
||||
translog_start_buffer(new_buffer, cursor, new_buffer_no);
|
||||
log_descriptor.buffers[old_buffer_no].next_buffer_offset= new_buffer->offset;
|
||||
translog_new_page_header(horizon, cursor);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Set max LSN sent to file
|
||||
Sets max LSN sent to file, and address from which data is only in the buffer
|
||||
|
||||
SYNOPSIS
|
||||
translog_set_sent_to_file()
|
||||
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)
|
||||
static void translog_set_sent_to_file(LSN lsn, TRANSLOG_ADDRESS in_buffers)
|
||||
{
|
||||
DBUG_ENTER("translog_set_sent_to_file");
|
||||
pthread_mutex_lock(&log_descriptor.sent_to_file_lock);
|
||||
DBUG_ASSERT(cmp_translog_addr(*lsn, log_descriptor.sent_to_file) >= 0);
|
||||
log_descriptor.sent_to_file= *lsn;
|
||||
DBUG_PRINT("enter", ("lsn: (%lu,0x%lx) in_buffers: (%lu,0x%lx) "
|
||||
"in_buffers_only: (%lu,0x%lx)",
|
||||
(ulong) LSN_FILE_NO(lsn),
|
||||
(ulong) LSN_OFFSET(lsn),
|
||||
(ulong) LSN_FILE_NO(in_buffers),
|
||||
(ulong) LSN_OFFSET(in_buffers),
|
||||
(ulong) LSN_FILE_NO(log_descriptor.in_buffers_only),
|
||||
(ulong) LSN_OFFSET(log_descriptor.in_buffers_only)));
|
||||
DBUG_ASSERT(cmp_translog_addr(lsn, log_descriptor.sent_to_file) >= 0);
|
||||
log_descriptor.sent_to_file= 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"));
|
||||
}
|
||||
pthread_mutex_unlock(&log_descriptor.sent_to_file_lock);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get max LSN send to file
|
||||
Sets address from which data is only in the buffer
|
||||
|
||||
SYNOPSIS
|
||||
translog_set_only_in_buffers()
|
||||
lsn LSN to assign
|
||||
in_buffers to assign to in_buffers_only
|
||||
*/
|
||||
|
||||
static void translog_set_only_in_buffers(TRANSLOG_ADDRESS in_buffers)
|
||||
{
|
||||
DBUG_ENTER("translog_set_only_in_buffers");
|
||||
pthread_mutex_lock(&log_descriptor.sent_to_file_lock);
|
||||
DBUG_PRINT("enter", ("in_buffers: (%lu,0x%lx) "
|
||||
"in_buffers_only: (%lu,0x%lx)",
|
||||
(ulong) LSN_FILE_NO(in_buffers),
|
||||
(ulong) LSN_OFFSET(in_buffers),
|
||||
(ulong) LSN_FILE_NO(log_descriptor.in_buffers_only),
|
||||
(ulong) LSN_OFFSET(log_descriptor.in_buffers_only)));
|
||||
/* 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"));
|
||||
}
|
||||
pthread_mutex_unlock(&log_descriptor.sent_to_file_lock);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Gets address from which data is only in the buffer
|
||||
|
||||
SYNOPSIS
|
||||
translog_only_in_buffers()
|
||||
|
||||
RETURN
|
||||
address from which data is only in the buffer
|
||||
*/
|
||||
|
||||
static TRANSLOG_ADDRESS translog_only_in_buffers()
|
||||
{
|
||||
register TRANSLOG_ADDRESS addr;
|
||||
DBUG_ENTER("translog_only_in_buffers");
|
||||
pthread_mutex_lock(&log_descriptor.sent_to_file_lock);
|
||||
addr= log_descriptor.in_buffers_only;
|
||||
pthread_mutex_unlock(&log_descriptor.sent_to_file_lock);
|
||||
DBUG_RETURN(addr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get max LSN sent to file
|
||||
|
||||
SYNOPSIS
|
||||
translog_get_sent_to_file()
|
||||
lsn LSN to value
|
||||
|
||||
RETURN
|
||||
max LSN send to file
|
||||
*/
|
||||
|
||||
static void translog_get_sent_to_file(LSN *lsn)
|
||||
static LSN translog_get_sent_to_file()
|
||||
{
|
||||
register LSN lsn;
|
||||
DBUG_ENTER("translog_get_sent_to_file");
|
||||
pthread_mutex_lock(&log_descriptor.sent_to_file_lock);
|
||||
*lsn= log_descriptor.sent_to_file;
|
||||
lsn= log_descriptor.sent_to_file;
|
||||
pthread_mutex_unlock(&log_descriptor.sent_to_file_lock);
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(lsn);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1532,16 +1615,20 @@ static my_bool translog_buffer_flush(struct st_translog_buffer *buffer)
|
|||
file.file= buffer->file;
|
||||
for (i= 0; i < buffer->size; i+= TRANSLOG_PAGE_SIZE)
|
||||
{
|
||||
TRANSLOG_ADDRESS addr= (buffer->offset + i);
|
||||
TRANSLOG_VALIDATOR_DATA data;
|
||||
data.addr= &addr;
|
||||
DBUG_ASSERT(log_descriptor.pagecache->block_size == TRANSLOG_PAGE_SIZE);
|
||||
DBUG_ASSERT(i + TRANSLOG_PAGE_SIZE <= buffer->size);
|
||||
if (pagecache_write(log_descriptor.pagecache,
|
||||
if (pagecache_inject(log_descriptor.pagecache,
|
||||
&file,
|
||||
(LSN_OFFSET(buffer->offset) + i) / TRANSLOG_PAGE_SIZE,
|
||||
3,
|
||||
buffer->buffer + i,
|
||||
PAGECACHE_PLAIN_PAGE,
|
||||
PAGECACHE_LOCK_LEFT_UNLOCKED,
|
||||
PAGECACHE_PIN_LEFT_UNPINNED, PAGECACHE_WRITE_DONE, 0))
|
||||
PAGECACHE_PIN_LEFT_UNPINNED, 0,
|
||||
&translog_page_validator, (uchar*) &data))
|
||||
{
|
||||
UNRECOVERABLE_ERROR(("Can't write page (%lu,0x%lx) to pagecache",
|
||||
(ulong) buffer->file,
|
||||
|
@ -1559,9 +1646,12 @@ static my_bool translog_buffer_flush(struct st_translog_buffer *buffer)
|
|||
(ulong) buffer->size, errno));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (LSN_OFFSET(buffer->last_lsn) != 0) /* if buffer->last_lsn is set */
|
||||
translog_set_sent_to_file(&buffer->last_lsn);
|
||||
|
||||
if (LSN_OFFSET(buffer->last_lsn) != 0) /* if buffer->last_lsn is set */
|
||||
translog_set_sent_to_file(buffer->last_lsn,
|
||||
buffer->next_buffer_offset);
|
||||
else
|
||||
translog_set_only_in_buffers(buffer->next_buffer_offset);
|
||||
/* Free buffer */
|
||||
buffer->file= -1;
|
||||
buffer->overlay= 0;
|
||||
|
@ -1747,6 +1837,59 @@ static my_bool translog_page_validator(uchar *page_addr, uchar* data_ptr)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Lock the loghandler
|
||||
|
||||
SYNOPSIS
|
||||
translog_lock()
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
1 Error
|
||||
*/
|
||||
|
||||
my_bool translog_lock()
|
||||
{
|
||||
struct st_translog_buffer *current_buffer;
|
||||
DBUG_ENTER("translog_lock");
|
||||
|
||||
/*
|
||||
Locking the loghandler mean locking current buffer, but it can change
|
||||
during locking, so we should check it
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
current_buffer= log_descriptor.bc.buffer;
|
||||
if (translog_buffer_lock(current_buffer))
|
||||
DBUG_RETURN(1);
|
||||
if (log_descriptor.bc.buffer == current_buffer)
|
||||
break;
|
||||
translog_buffer_unlock(current_buffer);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Unlock the loghandler
|
||||
|
||||
SYNOPSIS
|
||||
translog_unlock()
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
1 Error
|
||||
*/
|
||||
|
||||
my_bool translog_unlock()
|
||||
{
|
||||
DBUG_ENTER("translog_unlock");
|
||||
translog_buffer_unlock(log_descriptor.bc.buffer);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get log page by file number and offset of the beginning of the page
|
||||
|
||||
|
@ -1763,7 +1906,7 @@ static my_bool translog_page_validator(uchar *page_addr, uchar* data_ptr)
|
|||
|
||||
static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer)
|
||||
{
|
||||
TRANSLOG_ADDRESS addr= *(data->addr);
|
||||
TRANSLOG_ADDRESS addr= *(data->addr), in_buffers;
|
||||
uint cache_index;
|
||||
uint32 file_no= LSN_FILE_NO(addr);
|
||||
DBUG_ENTER("translog_get_page");
|
||||
|
@ -1775,6 +1918,107 @@ static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer)
|
|||
/* it is really page address */
|
||||
DBUG_ASSERT(LSN_OFFSET(addr) % TRANSLOG_PAGE_SIZE == 0);
|
||||
|
||||
in_buffers= translog_only_in_buffers();
|
||||
DBUG_PRINT("info", ("in_buffers: (%lu,0x%lx)",
|
||||
(ulong) LSN_FILE_NO(in_buffers),
|
||||
(ulong) LSN_OFFSET(in_buffers)));
|
||||
if (in_buffers != LSN_IMPOSSIBLE &&
|
||||
cmp_translog_addr(addr, in_buffers) >= 0)
|
||||
{
|
||||
translog_lock();
|
||||
/* recheck with locked loghandler */
|
||||
in_buffers= translog_only_in_buffers();
|
||||
if (cmp_translog_addr(addr, in_buffers) >= 0)
|
||||
{
|
||||
uint16 buffer_no= log_descriptor.bc.buffer_no;
|
||||
uint16 buffer_start= buffer_no;
|
||||
struct st_translog_buffer *buffer_unlock= log_descriptor.bc.buffer;
|
||||
struct st_translog_buffer *curr_buffer= log_descriptor.bc.buffer;
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
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
|
||||
*/
|
||||
if (curr_buffer->file != -1 &&
|
||||
cmp_translog_addr(addr, curr_buffer->offset) >= 0 &&
|
||||
cmp_translog_addr(addr,
|
||||
(curr_buffer->next_buffer_offset ?
|
||||
curr_buffer->next_buffer_offset:
|
||||
curr_buffer->offset + curr_buffer->size)) < 0)
|
||||
{
|
||||
int is_last_unfinished_page;
|
||||
uint last_protected_sector= 0;
|
||||
uchar *from, *table;
|
||||
translog_wait_for_writers(curr_buffer);
|
||||
DBUG_ASSERT(LSN_FILE_NO(addr) == LSN_FILE_NO(curr_buffer->offset));
|
||||
from= curr_buffer->buffer + (addr - curr_buffer->offset);
|
||||
memcpy(buffer, from, TRANSLOG_PAGE_SIZE);
|
||||
is_last_unfinished_page= ((log_descriptor.bc.buffer ==
|
||||
curr_buffer) &&
|
||||
(log_descriptor.bc.ptr >= from) &&
|
||||
(log_descriptor.bc.ptr <
|
||||
from + TRANSLOG_PAGE_SIZE));
|
||||
if (is_last_unfinished_page &&
|
||||
(buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION))
|
||||
{
|
||||
last_protected_sector= ((log_descriptor.bc.previous_offset - 1) /
|
||||
DISK_DRIVE_SECTOR_SIZE);
|
||||
table= buffer + log_descriptor.page_overhead -
|
||||
(TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE) * 2;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(buffer_unlock == curr_buffer);
|
||||
translog_buffer_unlock(buffer_unlock);
|
||||
if (is_last_unfinished_page)
|
||||
{
|
||||
uint i;
|
||||
/*
|
||||
This is last unfinished page => we should not check CRC and
|
||||
remove only that protection which already installed (no need
|
||||
to check it)
|
||||
|
||||
We do not check the flag of sector protection, because if
|
||||
(buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION) is
|
||||
not set then last_protected_sector will be 0 so following loop
|
||||
will be never executed
|
||||
*/
|
||||
DBUG_PRINT("info", ("This is last unfinished page, "
|
||||
"last protected sector %u",
|
||||
last_protected_sector));
|
||||
for (i= 1; i <= last_protected_sector; i++)
|
||||
{
|
||||
uint index= i * 2;
|
||||
uint offset= i * DISK_DRIVE_SECTOR_SIZE;
|
||||
DBUG_PRINT("info", ("Sector %u: 0x%02x%02x <- 0x%02x%02x",
|
||||
i, buffer[offset], buffer[offset + 1],
|
||||
table[index], table[index + 1]));
|
||||
buffer[offset]= table[index];
|
||||
buffer[offset + 1]= table[index + 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
This IF should be true because we use in-memory data which
|
||||
supposed to be correct.
|
||||
*/
|
||||
if (translog_page_validator((uchar*) buffer, (uchar*) data))
|
||||
buffer= NULL;
|
||||
}
|
||||
DBUG_RETURN(buffer);
|
||||
}
|
||||
buffer_no= (buffer_no + 1) % TRANSLOG_BUFFERS_NO;
|
||||
curr_buffer= log_descriptor.buffers + buffer_no;
|
||||
translog_buffer_lock(curr_buffer);
|
||||
translog_buffer_unlock(buffer_unlock);
|
||||
buffer_unlock= curr_buffer;
|
||||
/* we can't make full circle */
|
||||
DBUG_ASSERT(buffer_start != buffer_no);
|
||||
}
|
||||
}
|
||||
translog_unlock();
|
||||
}
|
||||
if ((cache_index= LSN_FILE_NO(log_descriptor.horizon) - file_no) <
|
||||
OPENED_FILES_NUM)
|
||||
{
|
||||
|
@ -2000,6 +2244,7 @@ my_bool translog_init(const char *directory,
|
|||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
log_descriptor.in_buffers_only= LSN_IMPOSSIBLE;
|
||||
/* max size of one log size (for new logs creation) */
|
||||
log_descriptor.log_file_max_size=
|
||||
log_file_max_size - (log_file_max_size % TRANSLOG_PAGE_SIZE);
|
||||
|
@ -2269,7 +2514,9 @@ my_bool translog_init(const char *directory,
|
|||
}
|
||||
|
||||
/* all LSNs that are on disk are flushed */
|
||||
log_descriptor.sent_to_file= log_descriptor.flushed= log_descriptor.horizon;
|
||||
log_descriptor.sent_to_file=
|
||||
log_descriptor.flushed= log_descriptor.horizon;
|
||||
log_descriptor.in_buffers_only= log_descriptor.bc.buffer->offset;
|
||||
/*
|
||||
horizon is (potentially) address of the next LSN we need decrease
|
||||
it to signal that all LSNs before it are flushed
|
||||
|
@ -2366,57 +2613,6 @@ void translog_destroy()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Lock the loghandler
|
||||
|
||||
SYNOPSIS
|
||||
translog_lock()
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
1 Error
|
||||
*/
|
||||
|
||||
my_bool translog_lock()
|
||||
{
|
||||
struct st_translog_buffer *current_buffer;
|
||||
DBUG_ENTER("translog_lock");
|
||||
|
||||
/*
|
||||
Locking the loghandler mean locking current buffer, but it can change
|
||||
during locking, so we should check it
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
current_buffer= log_descriptor.bc.buffer;
|
||||
if (translog_buffer_lock(current_buffer))
|
||||
DBUG_RETURN(1);
|
||||
if (log_descriptor.bc.buffer == current_buffer)
|
||||
break;
|
||||
translog_buffer_unlock(current_buffer);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Unlock the loghandler
|
||||
|
||||
SYNOPSIS
|
||||
translog_unlock()
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
1 Error
|
||||
*/
|
||||
|
||||
my_bool translog_unlock()
|
||||
{
|
||||
DBUG_ENTER("translog_unlock");
|
||||
translog_buffer_unlock(log_descriptor.bc.buffer);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
#define translog_buffer_lock_assert_owner(B) \
|
||||
|
@ -2923,6 +3119,7 @@ static my_bool translog_advance_pointer(uint pages, uint16 last_page_data)
|
|||
log_descriptor.horizon+= min_offset; /* offset increasing */
|
||||
}
|
||||
translog_start_buffer(new_buffer, &log_descriptor.bc, new_buffer_no);
|
||||
old_buffer->next_buffer_offset= new_buffer->offset;
|
||||
if (translog_buffer_unlock(old_buffer))
|
||||
DBUG_RETURN(1);
|
||||
offset-= min_offset;
|
||||
|
@ -3523,7 +3720,7 @@ static my_bool translog_relative_LSN_encode(struct st_translog_parts *parts,
|
|||
uchar *dst_ptr= compressed_LSNs + (MAX_NUMBER_OF_LSNS_PER_RECORD *
|
||||
COMPRESSED_LSN_MAX_STORE_SIZE);
|
||||
for (src_ptr= buffer + lsns_len - LSN_STORE_SIZE;
|
||||
src_ptr >= buffer;
|
||||
src_ptr >= (uchar*) buffer;
|
||||
src_ptr-= LSN_STORE_SIZE)
|
||||
{
|
||||
ref= lsn_korr(src_ptr);
|
||||
|
@ -3536,7 +3733,7 @@ static my_bool translog_relative_LSN_encode(struct st_translog_parts *parts,
|
|||
dst_ptr);
|
||||
parts->record_length-= (economy= lsns_len - part->length);
|
||||
DBUG_PRINT("info", ("new length of LSNs: %u economy: %d",
|
||||
part->length, economy));
|
||||
(uint) part->length, economy));
|
||||
parts->total_record_length-= economy;
|
||||
part->str= (char*)dst_ptr;
|
||||
}
|
||||
|
@ -5363,7 +5560,7 @@ static void translog_force_current_buffer_to_finish()
|
|||
struct st_translog_buffer *new_buffer= (log_descriptor.buffers +
|
||||
new_buffer_no);
|
||||
struct st_translog_buffer *old_buffer= log_descriptor.bc.buffer;
|
||||
uchar *data= log_descriptor.bc.ptr -log_descriptor.bc.current_page_fill;
|
||||
uchar *data= log_descriptor.bc.ptr - log_descriptor.bc.current_page_fill;
|
||||
uint16 left= TRANSLOG_PAGE_SIZE - log_descriptor.bc.current_page_fill;
|
||||
uint16 current_page_fill, write_counter, previous_offset;
|
||||
DBUG_ENTER("translog_force_current_buffer_to_finish");
|
||||
|
@ -5458,13 +5655,14 @@ static void translog_force_current_buffer_to_finish()
|
|||
if (left)
|
||||
{
|
||||
memcpy(new_buffer->buffer, data, current_page_fill);
|
||||
log_descriptor.bc.ptr +=current_page_fill;
|
||||
log_descriptor.bc.ptr+= current_page_fill;
|
||||
log_descriptor.bc.buffer->size= log_descriptor.bc.current_page_fill=
|
||||
current_page_fill;
|
||||
new_buffer->overlay= old_buffer;
|
||||
}
|
||||
else
|
||||
translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
|
||||
old_buffer->next_buffer_offset= new_buffer->offset;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -5527,7 +5725,7 @@ my_bool translog_flush(LSN lsn)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
/* send to the file if it is not sent */
|
||||
translog_get_sent_to_file(&sent_to_file);
|
||||
sent_to_file= translog_get_sent_to_file();
|
||||
if (cmp_translog_addr(sent_to_file, lsn) >= 0)
|
||||
break;
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ int _ma_dispose(register MARIA_HA *info, MARIA_KEYDEF *keyinfo, my_off_t pos,
|
|||
PAGECACHE_LOCK_LEFT_UNLOCKED,
|
||||
PAGECACHE_PIN_LEFT_UNPINNED,
|
||||
PAGECACHE_WRITE_DELAY, 0,
|
||||
offset, sizeof(buff)));
|
||||
offset, sizeof(buff), 0, 0));
|
||||
} /* _ma_dispose */
|
||||
|
||||
|
||||
|
|
|
@ -3167,7 +3167,9 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
|
|||
enum pagecache_page_pin pin,
|
||||
enum pagecache_write_mode write_mode,
|
||||
PAGECACHE_PAGE_LINK *link,
|
||||
uint offset, uint size)
|
||||
uint offset, uint size,
|
||||
pagecache_disk_read_validator validator,
|
||||
uchar* validator_data)
|
||||
{
|
||||
PAGECACHE_BLOCK_LINK *block= NULL;
|
||||
PAGECACHE_PAGE_LINK fake_link;
|
||||
|
@ -3253,7 +3255,7 @@ restart:
|
|||
|
||||
if (write_mode == PAGECACHE_WRITE_DONE)
|
||||
{
|
||||
if ((block->status & PCBLOCK_ERROR) && page_st != PAGE_READ)
|
||||
if (!(block->status & PCBLOCK_ERROR))
|
||||
{
|
||||
/* Copy data from buff */
|
||||
if (!(size & 511))
|
||||
|
@ -3261,8 +3263,15 @@ restart:
|
|||
else
|
||||
memcpy(block->buffer + offset, buff, size);
|
||||
block->status= (PCBLOCK_READ | (block->status & PCBLOCK_WRLOCK));
|
||||
/*
|
||||
The validator can change the page content (removing page
|
||||
protection) so it have to be called
|
||||
*/
|
||||
if (validator != NULL &&
|
||||
(*validator)(block->buffer, validator_data))
|
||||
block->status|= PCBLOCK_ERROR;
|
||||
KEYCACHE_DBUG_PRINT("key_cache_insert",
|
||||
("primary request: new page in cache"));
|
||||
("Page injection"));
|
||||
#ifdef THREAD
|
||||
/* Signal that all pending requests for this now can be processed. */
|
||||
if (block->wqueue[COND_FOR_REQUESTED].last_thread)
|
||||
|
@ -3272,6 +3281,7 @@ restart:
|
|||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(validator == 0 && validator_data == 0);
|
||||
if (! (block->status & PCBLOCK_CHANGED))
|
||||
link_to_changed_list(pagecache, block);
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ typedef struct st_pagecache_hash_link PAGECACHE_HASH_LINK;
|
|||
|
||||
#include <wqueue.h>
|
||||
|
||||
typedef my_bool (*pagecache_disk_read_validator)(uchar *page, uchar** data);
|
||||
typedef my_bool (*pagecache_disk_read_validator)(uchar *page, uchar* data);
|
||||
|
||||
#define PAGECACHE_CHANGED_BLOCKS_HASH 128 /* must be power of 2 */
|
||||
|
||||
|
@ -190,7 +190,11 @@ extern uchar *pagecache_valid_read(PAGECACHE *pagecache,
|
|||
uchar* validator_data);
|
||||
|
||||
#define pagecache_write(P,F,N,L,B,T,O,I,M,K) \
|
||||
pagecache_write_part(P,F,N,L,B,T,O,I,M,K,0,(P)->block_size)
|
||||
pagecache_write_part(P,F,N,L,B,T,O,I,M,K,0,(P)->block_size,0,0)
|
||||
|
||||
#define pagecache_inject(P,F,N,L,B,T,O,I,K,V,D) \
|
||||
pagecache_write_part(P,F,N,L,B,T,O,I,PAGECACHE_WRITE_DONE, \
|
||||
K,0,(P)->block_size,V,D)
|
||||
|
||||
extern my_bool pagecache_write_part(PAGECACHE *pagecache,
|
||||
PAGECACHE_FILE *file,
|
||||
|
@ -203,7 +207,9 @@ extern my_bool pagecache_write_part(PAGECACHE *pagecache,
|
|||
enum pagecache_write_mode write_mode,
|
||||
PAGECACHE_PAGE_LINK *link,
|
||||
uint offset,
|
||||
uint size);
|
||||
uint size,
|
||||
pagecache_disk_read_validator validator,
|
||||
uchar* validator_data);
|
||||
extern void pagecache_unlock(PAGECACHE *pagecache,
|
||||
PAGECACHE_FILE *file,
|
||||
pgcache_page_no_t pageno,
|
||||
|
|
|
@ -42,7 +42,8 @@ noinst_PROGRAMS = ma_control_file-t trnman-t lockman2-t \
|
|||
ma_test_loghandler_multigroup-t \
|
||||
ma_test_loghandler_multithread-t \
|
||||
ma_test_loghandler_pagecache-t \
|
||||
ma_test_loghandler_long-t-big
|
||||
ma_test_loghandler_long-t-big \
|
||||
ma_test_loghandler_noflush-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
|
||||
|
@ -50,6 +51,7 @@ ma_test_loghandler_multithread_t_SOURCES = ma_test_loghandler_multithread-t.c ma
|
|||
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_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_pagecache_single_src = ma_pagecache_single.c test_file.c
|
||||
ma_pagecache_consist_src = ma_pagecache_consist.c test_file.c
|
||||
|
|
|
@ -19,8 +19,9 @@ static TRN *trn= &dummy_transaction_object;
|
|||
#define LOG_FLAGS 0
|
||||
#define LOG_FILE_SIZE (1024L*1024L)
|
||||
#define ITERATIONS (1600*4)
|
||||
|
||||
#else
|
||||
#define LOG_FLAGS TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC
|
||||
#define LOG_FLAGS (TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC)
|
||||
#define LOG_FILE_SIZE (1024L*1024L*3L)
|
||||
#define ITERATIONS 1600
|
||||
#endif
|
||||
|
@ -331,32 +332,8 @@ int main(int argc __attribute__((unused)), char *argv[])
|
|||
ok(1, "flush");
|
||||
}
|
||||
|
||||
translog_destroy();
|
||||
end_pagecache(&pagecache, 1);
|
||||
ma_control_file_end();
|
||||
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "pass2: Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
|
||||
TRANSLOG_PAGE_SIZE)) == 0)
|
||||
{
|
||||
fprintf(stderr, "pass2: Got error: init_pagecache() (errno: %d)\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, LOG_FLAGS))
|
||||
{
|
||||
fprintf(stderr, "pass2: Can't init loghandler (%d)\n", errno);
|
||||
translog_destroy();
|
||||
exit(1);
|
||||
}
|
||||
example_loghandler_init();
|
||||
srandom(122334817L);
|
||||
|
||||
|
||||
rc= 1;
|
||||
|
||||
{
|
||||
|
@ -639,5 +616,6 @@ err:
|
|||
|
||||
if (maria_log_remove())
|
||||
exit(1);
|
||||
|
||||
return(test(exit_status()));
|
||||
}
|
||||
|
|
132
storage/maria/unittest/ma_test_loghandler_noflush-t.c
Normal file
132
storage/maria/unittest/ma_test_loghandler_noflush-t.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include "../maria_def.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <tap.h>
|
||||
#include "../trnman.h"
|
||||
|
||||
extern my_bool maria_log_remove();
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
static const char *default_dbug_option;
|
||||
#endif
|
||||
|
||||
#define PCACHE_SIZE (1024*1024*10)
|
||||
#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
|
||||
#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
|
||||
#define LOG_FLAGS 0
|
||||
|
||||
static char *first_translog_file= (char*)"maria_log.00000001";
|
||||
|
||||
int main(int argc __attribute__((unused)), char *argv[])
|
||||
{
|
||||
uint pagen;
|
||||
int rc= 1;
|
||||
uchar long_tr_id[6];
|
||||
PAGECACHE pagecache;
|
||||
LSN first_lsn;
|
||||
MY_STAT st;
|
||||
TRANSLOG_HEADER_BUFFER rec;
|
||||
LEX_STRING parts[TRANSLOG_INTERNAL_PARTS + 1];
|
||||
|
||||
MY_INIT(argv[0]);
|
||||
|
||||
plan(1);
|
||||
|
||||
bzero(&pagecache, sizeof(pagecache));
|
||||
maria_data_root= ".";
|
||||
if (maria_log_remove())
|
||||
exit(1);
|
||||
/* be sure that we have no logs in the directory*/
|
||||
if (my_stat(CONTROL_FILE_BASE_NAME, &st, MYF(0)))
|
||||
my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
|
||||
if (my_stat(first_translog_file, &st, MYF(0)))
|
||||
my_delete(first_translog_file, MYF(0));
|
||||
|
||||
bzero(long_tr_id, 6);
|
||||
#ifndef DBUG_OFF
|
||||
#if defined(__WIN__)
|
||||
default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
|
||||
#else
|
||||
default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
|
||||
#endif
|
||||
if (argc > 1)
|
||||
{
|
||||
DBUG_SET(default_dbug_option);
|
||||
DBUG_SET_INITIAL(default_dbug_option);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ma_control_file_create_or_open(TRUE))
|
||||
{
|
||||
fprintf(stderr, "Can't init control file (%d)\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
|
||||
PCACHE_PAGE)) == 0)
|
||||
{
|
||||
fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if (translog_init(".", LOG_FILE_SIZE, 50112, 0, &pagecache, LOG_FLAGS))
|
||||
{
|
||||
fprintf(stderr, "Can't init loghandler (%d)\n", errno);
|
||||
translog_destroy();
|
||||
exit(1);
|
||||
}
|
||||
example_loghandler_init();
|
||||
|
||||
|
||||
int4store(long_tr_id, 0);
|
||||
long_tr_id[5]= 0xff;
|
||||
parts[TRANSLOG_INTERNAL_PARTS + 0].str= (char*)long_tr_id;
|
||||
parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
|
||||
if (translog_write_record(&first_lsn,
|
||||
LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
|
||||
&dummy_transaction_object, NULL, 6,
|
||||
TRANSLOG_INTERNAL_PARTS + 1,
|
||||
parts, NULL))
|
||||
{
|
||||
fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
|
||||
translog_destroy();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
translog_size_t len= translog_read_record_header(first_lsn, &rec);
|
||||
if (len == 0)
|
||||
{
|
||||
fprintf(stderr, "translog_read_record_header failed (%d)\n", errno);
|
||||
goto err;
|
||||
}
|
||||
if (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE || rec.short_trid != 0 ||
|
||||
rec.record_length != 6 || uint4korr(rec.header) != 0 ||
|
||||
((uchar)rec.header[4]) != 0 || ((uchar)rec.header[5]) != 0xFF ||
|
||||
first_lsn != rec.lsn)
|
||||
{
|
||||
fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
|
||||
"data read(0)\n"
|
||||
"type: %u (%d) strid: %u (%d) len: %u (%d) i: %u (%d), "
|
||||
"4: %u (%d) 5: %u (%d) "
|
||||
"lsn(%lu,0x%lx) (%d)\n",
|
||||
(uint) rec.type, (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE),
|
||||
(uint) rec.short_trid, (rec.short_trid != 0),
|
||||
(uint) rec.record_length, (rec.record_length != 6),
|
||||
(uint) uint4korr(rec.header), (uint4korr(rec.header) != 0),
|
||||
(uint) rec.header[4], (((uchar)rec.header[4]) != 0),
|
||||
(uint) rec.header[5], (((uchar)rec.header[5]) != 0xFF),
|
||||
(ulong) LSN_FILE_NO(rec.lsn), (ulong) LSN_OFFSET(rec.lsn),
|
||||
(first_lsn != rec.lsn));
|
||||
goto err;
|
||||
}
|
||||
|
||||
ok(1, "read OK");
|
||||
rc= 0;
|
||||
|
||||
err:
|
||||
translog_destroy();
|
||||
end_pagecache(&pagecache, 1);
|
||||
ma_control_file_end();
|
||||
my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
|
||||
my_delete(first_translog_file, MYF(0));
|
||||
|
||||
exit(rc);
|
||||
}
|
Loading…
Reference in a new issue