Commit f7b766c0 authored by unknown's avatar unknown

Added maria_commit() and maria_begin() to be used with external tests

Now ma_test1 -M -T and ma_test2 -M -T produces readable, applyable logs

Note: The .MAD file is not binary identical after applying redo compare to a an original file.
(This is becasue we don't have full information which function called PURGE_REDO_BLOCKS).
To verify if a file was correctly applied, we now instead compare row checksums


BitKeeper/etc/ignore:
  added storage/maria/tmp/*
include/maria.h:
  Added maria_commit() and maria_begin() to be used with external tests
storage/maria/ha_maria.cc:
  Ensure maria_def. is read in C mode
storage/maria/ma_blockrec.c:
  Fixed redo handling.
  _ma_apply_redo_purge_blocks() updated to handle any number of purged blocks
  Removed code to make data file idenitcal after redo (can't easily be done). See changeset comments
  
  Now ma_test1 -M -T and ma_test2 -M -T produces readable, applyable logs
storage/maria/ma_commit.c:
  More DBUG statements
  Moved variable declaration to start of function (portability fix)
  Added helper functions 'maria_commit()' and 'maria_begin()'
storage/maria/ma_loghandler.c:
  Fixed wrong REDO_PURGE_BLOCKS initialization
storage/maria/ma_recovery.c:
  Added UNDO_ROW_UPDATE
  Removed wrong setting of lsn (there was no lsn at the used position)
  Fixed REDO_PURGE_BLOCKS to handle any number of blocks
storage/maria/ma_test1.c:
  Added transaction support (via maria_begin() & maria_commit()) to get a log that can be applied with maria_read_log
storage/maria/ma_test2.c:
  Added transaction support (via maria_begin() & maria_commit()) to get a log that can be applied with maria_read_log
storage/maria/ma_test_recovery:
  Create temporary files in maria/tmp
  Verify files with checksums instead of byte comparisons
storage/maria/maria_chk.c:
  When using with -dss we only get  filename, records and checksum.
  This is useful to do a quick comparision if a files is identical to another one.
storage/maria/maria_def.h:
  Added ma_commit()
storage/maria/maria_read_log.c:
  Added --help
parent d430e5bf
...@@ -3045,3 +3045,6 @@ win/vs71cache.txt ...@@ -3045,3 +3045,6 @@ win/vs71cache.txt
win/vs8cache.txt win/vs8cache.txt
zlib/*.ds? zlib/*.ds?
zlib/*.vcproj zlib/*.vcproj
maria_log_control
storage/maria/tmp/*
storage/maria/tmp/*
...@@ -300,7 +300,8 @@ extern ha_rows maria_records_in_range(struct st_maria_info *info, int inx, ...@@ -300,7 +300,8 @@ extern ha_rows maria_records_in_range(struct st_maria_info *info, int inx,
extern int maria_is_changed(struct st_maria_info *info); extern int maria_is_changed(struct st_maria_info *info);
extern int maria_delete_all_rows(struct st_maria_info *info); extern int maria_delete_all_rows(struct st_maria_info *info);
extern uint maria_get_pointer_length(ulonglong file_length, uint def); extern uint maria_get_pointer_length(ulonglong file_length, uint def);
extern int maria_commit(struct st_maria_info *info);
extern int maria_begin(struct st_maria_info *info);
/* this is used to pass to mysql_mariachk_table */ /* this is used to pass to mysql_mariachk_table */
......
...@@ -27,10 +27,11 @@ ...@@ -27,10 +27,11 @@
#include "ha_maria.h" #include "ha_maria.h"
#include "trnman_public.h" #include "trnman_public.h"
C_MODE_START
#include "maria_def.h" #include "maria_def.h"
#include "ma_rt_index.h" #include "ma_rt_index.h"
#include "ma_blockrec.h" #include "ma_blockrec.h"
#include "ma_commit.h" C_MODE_END
#define MARIA_CANNOT_ROLLBACK HA_NO_TRANSACTIONS #define MARIA_CANNOT_ROLLBACK HA_NO_TRANSACTIONS
#ifdef MARIA_CANNOT_ROLLBACK #ifdef MARIA_CANNOT_ROLLBACK
......
...@@ -530,6 +530,21 @@ static inline uint start_of_next_entry(uchar *dir) ...@@ -530,6 +530,21 @@ static inline uint start_of_next_entry(uchar *dir)
} }
static inline uint end_of_previous_entry(uchar *dir, uchar *end)
{
uchar *pos;
for (pos= dir + DIR_ENTRY_SIZE ; pos < end ; pos+= DIR_ENTRY_SIZE)
{
uint offset;
if ((offset= uint2korr(pos)))
{
return offset + uint2korr(pos+2);
}
}
return PAGE_HEADER_SIZE;
}
/* /*
Check that a region is all zero Check that a region is all zero
...@@ -1438,7 +1453,7 @@ static my_bool free_full_pages(MARIA_HA *info, MARIA_ROW *row) ...@@ -1438,7 +1453,7 @@ static my_bool free_full_pages(MARIA_HA *info, MARIA_ROW *row)
log_data)) log_data))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_RETURN (_ma_bitmap_free_full_pages(info, row->extents, DBUG_RETURN(_ma_bitmap_free_full_pages(info, row->extents,
row->extents_count)); row->extents_count));
} }
...@@ -1457,6 +1472,7 @@ static my_bool free_full_pages(MARIA_HA *info, MARIA_ROW *row) ...@@ -1457,6 +1472,7 @@ static my_bool free_full_pages(MARIA_HA *info, MARIA_ROW *row)
static my_bool free_full_page_range(MARIA_HA *info, ulonglong page, uint count) static my_bool free_full_page_range(MARIA_HA *info, ulonglong page, uint count)
{ {
my_bool res= 0; my_bool res= 0;
DBUG_ENTER("free_full_page_range");
if (pagecache_delete_pages(info->s->pagecache, &info->dfile, if (pagecache_delete_pages(info->s->pagecache, &info->dfile,
page, count, PAGECACHE_LOCK_WRITE, 0)) page, count, PAGECACHE_LOCK_WRITE, 0))
...@@ -1490,7 +1506,7 @@ static my_bool free_full_page_range(MARIA_HA *info, ulonglong page, uint count) ...@@ -1490,7 +1506,7 @@ static my_bool free_full_page_range(MARIA_HA *info, ulonglong page, uint count)
count)) count))
res= 1; res= 1;
pthread_mutex_unlock(&info->s->bitmap.bitmap_lock); pthread_mutex_unlock(&info->s->bitmap.bitmap_lock);
return res; DBUG_RETURN(res);
} }
...@@ -2470,7 +2486,7 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos, ...@@ -2470,7 +2486,7 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos,
/* Update cur_row, if someone calls update at once again */ /* Update cur_row, if someone calls update at once again */
cur_row->head_length= new_row->total_length; cur_row->head_length= new_row->total_length;
if (free_full_pages(info, cur_row)) if (cur_row->extents_count && free_full_pages(info, cur_row))
goto err; goto err;
DBUG_RETURN(write_block_record(info, oldrec, record, new_row, blocks, DBUG_RETURN(write_block_record(info, oldrec, record, new_row, blocks,
1, &row_pos)); 1, &row_pos));
...@@ -2492,9 +2508,9 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos, ...@@ -2492,9 +2508,9 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos,
} }
/* Delete old row */ /* Delete old row */
if (delete_tails(info, cur_row->tail_positions)) if (*cur_row->tail_positions && delete_tails(info, cur_row->tail_positions))
goto err; goto err;
if (free_full_pages(info, cur_row)) if (cur_row->extents_count && free_full_pages(info, cur_row))
goto err; goto err;
if (_ma_bitmap_find_new_place(info, new_row, page, head_length, blocks)) if (_ma_bitmap_find_new_place(info, new_row, page, head_length, blocks))
goto err; goto err;
...@@ -4207,7 +4223,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -4207,7 +4223,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
PAGE_SUFFIX_SIZE); PAGE_SUFFIX_SIZE);
empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET); empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
if (max_entry >= rownr) if (max_entry <= rownr)
{ {
/* Add directory entry first in directory and data last on page */ /* Add directory entry first in directory and data last on page */
DBUG_ASSERT(max_entry == rownr); DBUG_ASSERT(max_entry == rownr);
...@@ -4232,40 +4248,27 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -4232,40 +4248,27 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
} }
else else
{ {
/* reuse old empty entry */ /*
uchar *pos, *end, *end_data; reuse old entry. This is empty if the command was an insert and
DBUG_ASSERT(uint2korr(dir) == 0); possible used if the command was an update.
if (uint2korr(dir)) */
goto err; /* Should have been empty */ uchar *end_data;
uint rec_end;
/* Find start of where we can put data */
end= (buff + block_size - DIR_ENTRY_SIZE * max_entry - /* Add back space if we are reusing entry */
PAGE_SUFFIX_SIZE); empty_space+= uint2korr(dir+2);
for (pos= dir ; pos >= end ; pos-= DIR_ENTRY_SIZE)
{ /* Find first possible position where to put new data */
if ((rec_offset= uint2korr(pos))) end_data= (buff + block_size - PAGE_SUFFIX_SIZE -
{ DIR_ENTRY_SIZE * max_entry);
rec_offset+= uint2korr(pos+2); rec_offset= end_of_previous_entry(dir, end_data);
break; if (rownr != max_entry -1)
} rec_end= start_of_next_entry(dir);
} else
DBUG_ASSERT(pos >= end); rec_end= (uint) (buff - end_data);
if (pos < end) /* Wrong directory */ DBUG_ASSERT(rec_end > rec_offset);
goto err;
/* find end data */ if ((uint) (rec_end - rec_offset) < data_length)
end_data= end; /* Start of directory */
end= (buff + block_size - PAGE_SUFFIX_SIZE);
for (pos= dir ; pos < end ; pos+= DIR_ENTRY_SIZE)
{
uint offset;
if ((offset= uint2korr(pos)))
{
end_data= buff + offset;
break;
}
}
if ((uint) (end_data - (buff + rec_offset)) < data_length)
{ {
uint length; uint length;
/* Not enough continues space, compact page to get more */ /* Not enough continues space, compact page to get more */
...@@ -4397,70 +4400,53 @@ uint _ma_apply_redo_purge_blocks(MARIA_HA *info, ...@@ -4397,70 +4400,53 @@ uint _ma_apply_redo_purge_blocks(MARIA_HA *info,
{ {
MARIA_SHARE *share= info->s; MARIA_SHARE *share= info->s;
ulonglong page; ulonglong page;
uint page_range; uint page_range, ranges;
uint res; uint res= 0;
uchar *buff= info->keyread_buff; uchar *buff= info->keyread_buff;
uint block_size= share->block_size;
DBUG_ENTER("_ma_apply_redo_purge_blocks"); DBUG_ENTER("_ma_apply_redo_purge_blocks");
info->keyread_buff_used= 1; info->keyread_buff_used= 1;
page_range= pagerange_korr(header); ranges= pagerange_korr(header);
/* works only for a one-page range for now */
DBUG_ASSERT(page_range == 1); // for now
header+= PAGERANGE_STORE_SIZE; header+= PAGERANGE_STORE_SIZE;
page= page_korr(header);
header+= PAGE_STORE_SIZE;
page_range= pagerange_korr(header);
DBUG_ASSERT(page_range == 1); // for now
if (!(buff= pagecache_read(share->pagecache, while (ranges--)
&info->dfile,
page, 0,
buff, PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
DBUG_RETURN(my_errno);
if (lsn_korr(buff) >= lsn)
{ {
/* Already applied */ uint i;
goto mark_free_in_bitmap; page= page_korr(header);
} header+= PAGE_STORE_SIZE;
page_range= pagerange_korr(header);
header+= PAGERANGE_STORE_SIZE;
buff[PAGE_TYPE_OFFSET]= UNALLOCATED_PAGE; for (i= 0; i < page_range ; i++)
{
if (!(buff= pagecache_read(share->pagecache,
&info->dfile,
page+i, 0,
buff, PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
DBUG_RETURN(my_errno);
/* if (lsn_korr(buff) >= lsn)
Strictly speaking, we don't need to zero the last directory entry of this {
page; setting the directory's count to zero is enough (it makes the last /* Already applied */
directory entry invisible, irrelevant). continue;
But as the "runtime" code (delete_head_or_tail()) called }
delete_dir_entry() which zeroed the entry, if we don't do it here, we get buff[PAGE_TYPE_OFFSET]= UNALLOCATED_PAGE;
a difference between runtime and log-applying. Irrelevant, but it's lsn_store(buff, lsn);
time-consuming to differentiate irrelevant differences from relevant if (pagecache_write(share->pagecache,
ones. So we remove the difference by zeroing the entry. &info->dfile, page+i, 0,
*/ buff, PAGECACHE_PLAIN_PAGE,
{ PAGECACHE_LOCK_LEFT_UNLOCKED,
uint rownr= ((uint) ((uchar *) buff)[DIR_COUNT_OFFSET]) - 1; PAGECACHE_PIN_LEFT_UNPINNED,
uchar *dir= (buff + block_size - DIR_ENTRY_SIZE * rownr - PAGECACHE_WRITE_DELAY, 0))
DIR_ENTRY_SIZE - PAGE_SUFFIX_SIZE); DBUG_RETURN(my_errno);
dir[0]= dir[1]= 0; /* Delete entry */ }
/** @todo leave bitmap lock to the bitmap code... */
pthread_mutex_lock(&share->bitmap.bitmap_lock);
res= _ma_reset_full_page_bits(info, &share->bitmap, page, page_range);
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
if (res)
DBUG_RETURN(res);
} }
DBUG_RETURN(0);
buff[DIR_COUNT_OFFSET]= 0;
lsn_store(buff, lsn);
if (pagecache_write(share->pagecache,
&info->dfile, page, 0,
buff, PAGECACHE_PLAIN_PAGE,
PAGECACHE_LOCK_LEFT_UNLOCKED,
PAGECACHE_PIN_LEFT_UNPINNED,
PAGECACHE_WRITE_DELAY, 0))
DBUG_RETURN(my_errno);
mark_free_in_bitmap:
/** @todo leave bitmap lock to the bitmap code... */
pthread_mutex_lock(&share->bitmap.bitmap_lock);
res= _ma_reset_full_page_bits(info, &share->bitmap, page, 1);
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
DBUG_RETURN(res);
} }
...@@ -28,8 +28,13 @@ ...@@ -28,8 +28,13 @@
int ma_commit(TRN *trn) int ma_commit(TRN *trn)
{ {
int res;
LSN commit_lsn;
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS];
DBUG_ENTER("ma_commit");
if (trn->undo_lsn == 0) /* no work done, rollback (cheaper than commit) */ if (trn->undo_lsn == 0) /* no work done, rollback (cheaper than commit) */
return trnman_rollback_trn(trn); DBUG_RETURN(trnman_rollback_trn(trn));
/* /*
- if COMMIT record is written before trnman_commit_trn(): - if COMMIT record is written before trnman_commit_trn():
if Checkpoint comes in the middle it will see trn is not committed, if Checkpoint comes in the middle it will see trn is not committed,
...@@ -45,27 +50,76 @@ int ma_commit(TRN *trn) ...@@ -45,27 +50,76 @@ int ma_commit(TRN *trn)
issue (transaction's updates were made visible to other transactions). issue (transaction's updates were made visible to other transactions).
So we need to go the first way. So we need to go the first way.
*/ */
/** /**
@todo RECOVERY share's state is written to disk only in @todo RECOVERY share's state is written to disk only in
maria_lock_database(), so COMMIT record is not the last record of the maria_lock_database(), so COMMIT record is not the last record of the
transaction! It is probably an issue. Recovery of the state is a problem transaction! It is probably an issue. Recovery of the state is a problem
not yet solved. not yet solved.
*/ */
LSN commit_lsn;
LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS];
/* /*
We do not store "thd->transaction.xid_state.xid" for now, it will be We do not store "thd->transaction.xid_state.xid" for now, it will be
needed only when we support XA. needed only when we support XA.
*/ */
return res= (translog_write_record(&commit_lsn, LOGREC_COMMIT,
translog_write_record(&commit_lsn, LOGREC_COMMIT, trn, NULL, 0,
trn, NULL, 0, sizeof(log_array)/sizeof(log_array[0]),
sizeof(log_array)/sizeof(log_array[0]), log_array, NULL) ||
log_array, NULL) || translog_flush(commit_lsn) ||
translog_flush(commit_lsn) || trnman_commit_trn(trn); trnman_commit_trn(trn));
trn->undo_lsn= 0;
/* /*
Note: if trnman_commit_trn() fails above, we have already Note: if trnman_commit_trn() fails above, we have already
written the COMMIT record, so Checkpoint and Recovery will see the written the COMMIT record, so Checkpoint and Recovery will see the
transaction as committed. transaction as committed.
*/ */
DBUG_RETURN(res);
}
/**
@brief Writes a COMMIT record for a transaciton associated with a file
@param info Maria handler
@return Operation status
@retval 0 ok
@retval # error (disk error or out of memory)
*/
int maria_commit(MARIA_HA *info)
{
return info->s->now_transactional ? ma_commit(info->trn) : 0;
}
/**
@brief Starts a transaction on a file handle
@param info Maria handler
@return Operation status
@retval 0 ok
@retval # Error code.
*/
int maria_begin(MARIA_HA *info)
{
DBUG_ENTER("maria_begin");
if (info->s->now_transactional)
{
TRN *trn;
struct st_my_thread_var *mysys_var= my_thread_var;
trn= trnman_new_trn(&mysys_var->mutex,
&mysys_var->suspend,
(char*) &mysys_var + STACK_DIRECTION *1024*128);
if (unlikely(!trn))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
DBUG_PRINT("info", ("TRN set to 0x%lx", (ulong) trn));
info->trn= trn;
}
DBUG_RETURN(0);
} }
...@@ -299,13 +299,9 @@ static LOG_DESC INIT_LOGREC_REDO_PURGE_ROW_TAIL= ...@@ -299,13 +299,9 @@ static LOG_DESC INIT_LOGREC_REDO_PURGE_ROW_TAIL=
NULL, write_hook_for_redo, NULL, 0, NULL, write_hook_for_redo, NULL, 0,
"redo_purge_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL}; "redo_purge_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
/* QQQ: TODO: variable and fixed size??? */
static LOG_DESC INIT_LOGREC_REDO_PURGE_BLOCKS= static LOG_DESC INIT_LOGREC_REDO_PURGE_BLOCKS=
{LOGRECTYPE_VARIABLE_LENGTH, {LOGRECTYPE_VARIABLE_LENGTH, 0,
FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE + FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE,
PAGE_STORE_SIZE + PAGERANGE_STORE_SIZE,
FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE +
PAGE_STORE_SIZE + PAGERANGE_STORE_SIZE,
NULL, write_hook_for_redo, NULL, 0, NULL, write_hook_for_redo, NULL, 0,
"redo_purge_blocks", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL}; "redo_purge_blocks", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
...@@ -5288,8 +5284,9 @@ translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner) ...@@ -5288,8 +5284,9 @@ translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner)
@param page_offset Offset of the first chunk in the page @param page_offset Offset of the first chunk in the page
@param buff Buffer to be filled with header data @param buff Buffer to be filled with header data
@param scanner If present should be moved to the header page if @param scanner If present should be moved to the header page if
it differ from LSN page it differ from LSN page
@return Length of header or operation status
@return Length of header or operation status
@retval RECHEADER_READ_ERROR error @retval RECHEADER_READ_ERROR error
@retval # number of bytes in @retval # number of bytes in
TRANSLOG_HEADER_BUFFER::header where TRANSLOG_HEADER_BUFFER::header where
...@@ -5311,7 +5308,6 @@ int translog_variable_length_header(uchar *page, translog_size_t page_offset, ...@@ -5311,7 +5308,6 @@ int translog_variable_length_header(uchar *page, translog_size_t page_offset,
uint16 buffer_length= length; uint16 buffer_length= length;
uint16 body_len; uint16 body_len;
TRANSLOG_SCANNER_DATA internal_scanner; TRANSLOG_SCANNER_DATA internal_scanner;
DBUG_ENTER("translog_variable_length_header"); DBUG_ENTER("translog_variable_length_header");
buff->record_length= translog_variable_record_1group_decode_len(&src); buff->record_length= translog_variable_record_1group_decode_len(&src);
......
...@@ -53,6 +53,7 @@ prototype_exec_hook(REDO_PURGE_BLOCKS); ...@@ -53,6 +53,7 @@ prototype_exec_hook(REDO_PURGE_BLOCKS);
prototype_exec_hook(REDO_DELETE_ALL); prototype_exec_hook(REDO_DELETE_ALL);
prototype_exec_hook(UNDO_ROW_INSERT); prototype_exec_hook(UNDO_ROW_INSERT);
prototype_exec_hook(UNDO_ROW_DELETE); prototype_exec_hook(UNDO_ROW_DELETE);
prototype_exec_hook(UNDO_ROW_UPDATE);
prototype_exec_hook(UNDO_ROW_PURGE); prototype_exec_hook(UNDO_ROW_PURGE);
prototype_exec_hook(COMMIT); prototype_exec_hook(COMMIT);
static int end_of_redo_phase(); static int end_of_redo_phase();
...@@ -197,6 +198,7 @@ int maria_apply_log(LSN lsn, my_bool apply, FILE *trace_file) ...@@ -197,6 +198,7 @@ int maria_apply_log(LSN lsn, my_bool apply, FILE *trace_file)
install_exec_hook(REDO_DELETE_ALL); install_exec_hook(REDO_DELETE_ALL);
install_exec_hook(UNDO_ROW_INSERT); install_exec_hook(UNDO_ROW_INSERT);
install_exec_hook(UNDO_ROW_DELETE); install_exec_hook(UNDO_ROW_DELETE);
install_exec_hook(UNDO_ROW_UPDATE);
install_exec_hook(UNDO_ROW_PURGE); install_exec_hook(UNDO_ROW_PURGE);
install_exec_hook(COMMIT); install_exec_hook(COMMIT);
...@@ -512,9 +514,6 @@ prototype_exec_hook(REDO_CREATE_TABLE) ...@@ -512,9 +514,6 @@ prototype_exec_hook(REDO_CREATE_TABLE)
ptr+= 2; ptr+= 2;
/* set create_rename_lsn (for maria_read_log to be idempotent) */ /* set create_rename_lsn (for maria_read_log to be idempotent) */
lsn_store(ptr + sizeof(info->s->state.header) + 2, rec->lsn); lsn_store(ptr + sizeof(info->s->state.header) + 2, rec->lsn);
/* we also set is_of_lsn, like maria_create() does */
lsn_store(ptr + sizeof(info->s->state.header) + 2 + LSN_STORE_SIZE,
rec->lsn);
if (my_pwrite(kfile, ptr, if (my_pwrite(kfile, ptr,
kfile_size_before_extension, 0, MYF(MY_NABP|MY_WME)) || kfile_size_before_extension, 0, MYF(MY_NABP|MY_WME)) ||
my_chsize(kfile, keystart, 0, MYF(MY_WME))) my_chsize(kfile, keystart, 0, MYF(MY_WME)))
...@@ -766,7 +765,7 @@ prototype_exec_hook(REDO_INSERT_ROW_HEAD) ...@@ -766,7 +765,7 @@ prototype_exec_hook(REDO_INSERT_ROW_HEAD)
prototype_exec_hook(REDO_INSERT_ROW_TAIL) prototype_exec_hook(REDO_INSERT_ROW_TAIL)
{ {
int error= 1; int error= 1;
uchar *buff= NULL; uchar *buff;
MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec); MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
if (info == NULL) if (info == NULL)
goto end; goto end;
...@@ -834,11 +833,24 @@ prototype_exec_hook(REDO_PURGE_ROW_TAIL) ...@@ -834,11 +833,24 @@ prototype_exec_hook(REDO_PURGE_ROW_TAIL)
prototype_exec_hook(REDO_PURGE_BLOCKS) prototype_exec_hook(REDO_PURGE_BLOCKS)
{ {
int error= 1; int error= 1;
uchar *buff;
MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec); MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
if (info == NULL) if (info == NULL)
goto end; goto end;
enlarge_buffer(rec);
if (log_record_buffer.str == NULL ||
translog_read_record(rec->lsn, 0, rec->record_length,
log_record_buffer.str, NULL) !=
rec->record_length)
{
fprintf(tracef, "Failed to read record\n");
goto end;
}
buff= log_record_buffer.str;
if (_ma_apply_redo_purge_blocks(info, current_group_end_lsn, if (_ma_apply_redo_purge_blocks(info, current_group_end_lsn,
rec->header + FILEID_STORE_SIZE)) buff + FILEID_STORE_SIZE))
goto end; goto end;
error= 0; error= 0;
end: end:
...@@ -911,6 +923,23 @@ prototype_exec_hook(UNDO_ROW_DELETE) ...@@ -911,6 +923,23 @@ prototype_exec_hook(UNDO_ROW_DELETE)
} }
prototype_exec_hook(UNDO_ROW_UPDATE)
{
int error= 1;
MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
if (info == NULL)
goto end;
all_active_trans[rec->short_trid].undo_lsn= rec->lsn;
/*
todo: instead of above, call write_hook_for_undo, it will also set
first_undo_lsn
*/
error= 0;
end:
return error;
}
prototype_exec_hook(UNDO_ROW_PURGE) prototype_exec_hook(UNDO_ROW_PURGE)
{ {
int error= 1; int error= 1;
......
...@@ -66,7 +66,8 @@ int main(int argc,char *argv[]) ...@@ -66,7 +66,8 @@ int main(int argc,char *argv[])
TRANSLOG_PAGE_SIZE) == 0) || TRANSLOG_PAGE_SIZE) == 0) ||
translog_init(maria_data_root, TRANSLOG_FILE_SIZE, translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
0, 0, maria_log_pagecache, 0, 0, maria_log_pagecache,
TRANSLOG_DEFAULT_FLAGS)) TRANSLOG_DEFAULT_FLAGS) ||
(transactional && trnman_init()))
{ {
fprintf(stderr, "Error in initialization"); fprintf(stderr, "Error in initialization");
exit(1); exit(1);
...@@ -180,6 +181,8 @@ static int run_test(const char *filename) ...@@ -180,6 +181,8 @@ static int run_test(const char *filename)
if (!silent) if (!silent)
printf("- Writing key:s\n"); printf("- Writing key:s\n");
if (maria_begin(file))
goto err;
my_errno=0; my_errno=0;
row_count=deleted=0; row_count=deleted=0;
for (i=49 ; i>=1 ; i-=2 ) for (i=49 ; i>=1 ; i-=2 )
...@@ -266,8 +269,14 @@ static int run_test(const char *filename) ...@@ -266,8 +269,14 @@ static int run_test(const char *filename)
if (!silent) if (!silent)
printf("- Reopening file\n"); printf("- Reopening file\n");
if (maria_close(file)) goto err; if (maria_commit(file))
if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED))) goto err; goto err;
if (maria_close(file))
goto err;
if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
goto err;
if (maria_begin(file))
goto err;
if (!skip_delete) if (!skip_delete)
{ {
if (!silent) if (!silent)
...@@ -354,6 +363,8 @@ static int run_test(const char *filename) ...@@ -354,6 +363,8 @@ static int run_test(const char *filename)
i-1,error,my_errno,read_record+1); i-1,error,my_errno,read_record+1);
} }
} }
if (maria_commit(file))
goto err;
if (maria_close(file)) if (maria_close(file))
goto err; goto err;
maria_end(); maria_end();
......
...@@ -244,13 +244,15 @@ int main(int argc, char *argv[]) ...@@ -244,13 +244,15 @@ int main(int argc, char *argv[])
if (opt_quick_mode) if (opt_quick_mode)
maria_extra(file,HA_EXTRA_QUICK,0); maria_extra(file,HA_EXTRA_QUICK,0);
maria_begin(file);
for (i=0 ; i < recant ; i++) for (i=0 ; i < recant ; i++)
{ {
ulong blob_length; ulong blob_length;
#if 0 #if 0
/* /*
Starting from i==72, there was a difference between runtime and Starting from i==72, there was a difference between runtime and
log-appplying. This is now fixed, by not using non_header_data_len in log-applying. This is now fixed, by not using non_header_data_len in
log-applying. log-applying.
*/ */
if (i == 72) goto end; if (i == 72) goto end;
...@@ -890,6 +892,8 @@ int main(int argc, char *argv[]) ...@@ -890,6 +892,8 @@ int main(int argc, char *argv[])
goto err; goto err;
} }
end: end:
if (maria_commit(file))
goto err;
if (maria_close(file)) if (maria_close(file))
goto err; goto err;
maria_panic(HA_PANIC_CLOSE); /* Should close log */ maria_panic(HA_PANIC_CLOSE); /* Should close log */
......
#!/bin/sh
set -e set -e
silent="-s" silent="-s"
if [ -z "$maria_path" ] if [ -z "$maria_path" ]
...@@ -5,6 +7,13 @@ then ...@@ -5,6 +7,13 @@ then
maria_path="." maria_path="."
fi fi
tmp=$maria_path/tmp
if test '!' -d $tmp
then
mkdir $tmp
fi
echo "MARIA RECOVERY TESTS - success is if exit code is 0" echo "MARIA RECOVERY TESTS - success is if exit code is 0"
# runs a program inserting/deleting rows, then moves the resulting table # runs a program inserting/deleting rows, then moves the resulting table
...@@ -14,28 +23,40 @@ echo "MARIA RECOVERY TESTS - success is if exit code is 0" ...@@ -14,28 +23,40 @@ echo "MARIA RECOVERY TESTS - success is if exit code is 0"
for prog in "$maria_path/ma_test1 $silent -M -T --skip-update -c" "$maria_path/ma_test2 $silent -L -K -W -P -M -T -g -c" for prog in "$maria_path/ma_test1 $silent -M -T --skip-update -c" "$maria_path/ma_test2 $silent -L -K -W -P -M -T -g -c"
do do
rm -f maria_log* rm -f maria_log.* maria_log_control
echo "TEST WITH $prog" echo "TEST WITH $prog"
$prog $prog
# derive table's name from program's name # derive table's name from program's name
table=`echo $prog | sed -e 's;.*ma_\(test[0-9]\).*;\1;' ` table=`echo $prog | sed -e 's;.*ma_\(test[0-9]\).*;\1;' `
$maria_path/maria_chk -dvv $table > maria_chk_message.good.txt 2>&1 $maria_path/maria_chk -dvv $table > $tmp/maria_chk_message.good.txt 2>&1
mv -f $table.MAD $table.MAD.good checksum=`$maria_path/maria_chk -dss $table`
mv -f $table.MAD $tmp/$table.MAD.good
rm $table.MAI rm $table.MAI
echo "applying log" echo "applying log"
$maria_path/maria_read_log -a > maria_read_log_$table.txt $maria_path/maria_read_log -a > $tmp/maria_read_log_$table.txt
cmp $table.MAD $table.MAD.good $maria_path/maria_chk -dvv $table > $tmp/maria_chk_message.txt 2>&1
$maria_path/maria_chk -dvv $table > maria_chk_message.txt 2>&1
# QQ: Remove the following line when we also can recovert the index file
$maria_path/maria_chk -s -r $table
$maria_path/maria_chk -s -e $table
checksum2=`$maria_path/maria_chk -dss $table`
if test "$checksum" != "$checksum2"
then
echo "checksum differs for $table before and after recovery"
exit 1;
fi
# cmp $table.MAD $tmp/$table.MAD.good
# When "recovery of the table's state" is ready, we can test it like this: # When "recovery of the table's state" is ready, we can test it like this:
# diff maria_chk_message.good.txt maria_chk_message.txt >maria_chk_diff.txt || true # diff $tmp/maria_chk_message.good.txt $tmp/maria_chk_message.txt > $tmp/maria_chk_diff.txt || true
# if [ -s maria_chk_diff.txt ] # if [ -s $tmp/maria_chk_diff.txt ]
# then # then
# echo "Differences in maria_chk -dvv, recovery not yet perfect !" # echo "Differences in maria_chk -dvv, recovery not yet perfect !"
# echo "========DIFF START=======" # echo "========DIFF START======="
# cat maria_chk_diff.txt # cat $tmp/maria_chk_diff.txt
# echo "========DIFF END=======" # echo "========DIFF END======="
# fi # fi
rm -f $table.* maria_chk_*.txt maria_read_log_$table.txt rm -f $table.* $tmp/maria_chk_*.txt $tmp/maria_read_log_$table.txt
done done
echo "ALL RECOVERY TESTS OK" echo "ALL RECOVERY TESTS OK"
...@@ -115,7 +115,7 @@ int main(int argc, char **argv) ...@@ -115,7 +115,7 @@ int main(int argc, char **argv)
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS | (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
T_SORT_INDEX)))) T_SORT_INDEX))))
{ {
uint old_testflag=check_param.testflag; ulonglong old_testflag=check_param.testflag;
if (!(check_param.testflag & T_REP)) if (!(check_param.testflag & T_REP))
check_param.testflag|= T_REP_BY_SORT; check_param.testflag|= T_REP_BY_SORT;
check_param.testflag&= ~T_EXTEND; /* Don't needed */ check_param.testflag&= ~T_EXTEND; /* Don't needed */
...@@ -126,7 +126,8 @@ int main(int argc, char **argv) ...@@ -126,7 +126,8 @@ int main(int argc, char **argv)
} }
else else
error|=new_error; error|=new_error;
if (argc && (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)) if (argc && (!(check_param.testflag & T_SILENT) ||
check_param.testflag & T_INFO))
{ {
puts("\n---------\n"); puts("\n---------\n");
VOID(fflush(stdout)); VOID(fflush(stdout));
...@@ -1236,6 +1237,16 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name) ...@@ -1236,6 +1237,16 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
char llbuff[22],llbuff2[22]; char llbuff[22],llbuff2[22];
DBUG_ENTER("describe"); DBUG_ENTER("describe");
if (param->testflag & T_VERY_SILENT)
{
longlong checksum= info->state->checksum;
if (!(share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
checksum= 0;
printf("%s %s %s\n", name, llstr(info->state->records,llbuff),
llstr(checksum, llbuff2));
DBUG_VOID_RETURN;
}
printf("\nMARIA file: %s\n",name); printf("\nMARIA file: %s\n",name);
printf("Record format: %s\n", record_formats[share->data_file_type]); printf("Record format: %s\n", record_formats[share->data_file_type]);
printf("Character set: %s (%d)\n", printf("Character set: %s (%d)\n",
......
...@@ -894,6 +894,7 @@ void _ma_restore_status(void *param); ...@@ -894,6 +894,7 @@ void _ma_restore_status(void *param);
void _ma_copy_status(void *to, void *from); void _ma_copy_status(void *to, void *from);
my_bool _ma_check_status(void *param); my_bool _ma_check_status(void *param);
void _ma_reset_status(MARIA_HA *maria); void _ma_reset_status(MARIA_HA *maria);
int ma_commit(struct st_transaction *trn);
extern MARIA_HA *_ma_test_if_reopen(char *filename); extern MARIA_HA *_ma_test_if_reopen(char *filename);
my_bool _ma_check_table_is_closed(const char *name, const char *where); my_bool _ma_check_table_is_closed(const char *name, const char *where);
......
...@@ -113,6 +113,8 @@ int main(int argc, char **argv) ...@@ -113,6 +113,8 @@ int main(int argc, char **argv)
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
{"help", '?', "Display this help and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"only-display", 'o', "display brief info about records's header", {"only-display", 'o', "display brief info about records's header",
(uchar **) &opt_only_display, (uchar **) &opt_only_display, 0, GET_BOOL, (uchar **) &opt_only_display, (uchar **) &opt_only_display, 0, GET_BOOL,
NO_ARG,0, 0, 0, 0, 0, 0}, NO_ARG,0, 0, 0, 0, 0, 0},
...@@ -161,6 +163,9 @@ get_one_option(int optid __attribute__((unused)), ...@@ -161,6 +163,9 @@ get_one_option(int optid __attribute__((unused)),
char *argument __attribute__((unused))) char *argument __attribute__((unused)))
{ {
switch (optid) { switch (optid) {
case '?':
usage();
exit(0);
#ifndef DBUG_OFF #ifndef DBUG_OFF
case '#': case '#':
DBUG_SET_INITIAL(argument ? argument : default_dbug_option); DBUG_SET_INITIAL(argument ? argument : 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