Commit 964570b4 authored by Michael Widenius's avatar Michael Widenius

Fixed LP#605798 RQG: Table corruption after Maria engine recovery - "Wrong data in bitmap"

maria_chk & maria_read_log now reads block size from control file.



mysql-test/suite/maria/r/maria.result:
  Updated results after trivial change of maria_chk's output
storage/maria/ma_bitmap.c:
  More DBUG_PRINT
storage/maria/ma_blockrec.c:
  Fixed bug that we didn't mark page full in bitmap if directory is full
storage/maria/ma_check.c:
  Write out if directory is full for errors in bitmap
storage/maria/ma_control_file.c:
  Don't give error for wrong block size if block size is 0
storage/maria/maria_chk.c:
  Read block size from control file
  In case of -dvv, write also out bitmap information (good for debugging)
storage/maria/maria_read_log.c:
  Read block size from control file
  Fixed that maria_read_log works with different page size than TRANSLOG_PAGE_SIZE
parent 36d95177
...@@ -2139,7 +2139,7 @@ Data records: 0 Deleted blocks: 0 ...@@ -2139,7 +2139,7 @@ Data records: 0 Deleted blocks: 0
Block_size: 8192 Block_size: 8192
Recordlength: 99 Recordlength: 99
table description: Table description:
Key Start Len Index Type Key Start Len Index Type
1 2 30 multip. varchar 1 2 30 multip. varchar
2 33 30 multip. char NULL 2 33 30 multip. char NULL
......
...@@ -2393,6 +2393,8 @@ my_bool _ma_bitmap_set(MARIA_HA *info, pgcache_page_no_t page, my_bool head, ...@@ -2393,6 +2393,8 @@ my_bool _ma_bitmap_set(MARIA_HA *info, pgcache_page_no_t page, my_bool head,
uint bits; uint bits;
my_bool res; my_bool res;
DBUG_ENTER("_ma_bitmap_set"); DBUG_ENTER("_ma_bitmap_set");
DBUG_PRINT("enter", ("page: %lu head: %d empty_space: %u",
(ulong) page, head, empty_space));
pthread_mutex_lock(&info->s->bitmap.bitmap_lock); pthread_mutex_lock(&info->s->bitmap.bitmap_lock);
bits= (head ? bits= (head ?
......
...@@ -698,7 +698,8 @@ static void check_directory(uchar *buff, uint block_size, uint min_row_length) ...@@ -698,7 +698,8 @@ static void check_directory(uchar *buff, uint block_size, uint min_row_length)
@brief Calculate if there is enough entries on the page @brief Calculate if there is enough entries on the page
*/ */
my_bool enough_free_entries(uchar *buff, uint block_size, uint wanted_entries) static my_bool enough_free_entries(uchar *buff, uint block_size,
uint wanted_entries)
{ {
uint entries= (uint) buff[DIR_COUNT_OFFSET]; uint entries= (uint) buff[DIR_COUNT_OFFSET];
uint needed_free_entries, free_entry; uint needed_free_entries, free_entry;
...@@ -722,6 +723,33 @@ my_bool enough_free_entries(uchar *buff, uint block_size, uint wanted_entries) ...@@ -722,6 +723,33 @@ my_bool enough_free_entries(uchar *buff, uint block_size, uint wanted_entries)
} }
/**
@brief Check if there is room for more rows on page
@fn enough_free_entries_on_page
@return 0 Directory is full
@return 1 There is room for more entries on the page
*/
static my_bool enough_free_entries_on_page(MARIA_SHARE *share,
uchar *page_buff)
{
enum en_page_type page_type;
page_type= (enum en_page_type) (page_buff[PAGE_TYPE_OFFSET] &
~(uchar) PAGE_CAN_BE_COMPACTED);
if (page_type == HEAD_PAGE)
{
uint row_count= (uint) page_buff[DIR_COUNT_OFFSET];
return !(row_count == MAX_ROWS_PER_PAGE &&
page_buff[DIR_FREE_OFFSET] == END_OF_DIR_FREE_LIST);
}
return enough_free_entries(page_buff, share->block_size,
1 + share->base.blobs);
}
/** /**
@brief Extend a record area to fit a given size block @brief Extend a record area to fit a given size block
...@@ -6106,6 +6134,9 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6106,6 +6134,9 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
{ {
/* Fix bitmap, just in case */ /* Fix bitmap, just in case */
empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET); empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
if (!enough_free_entries_on_page(share, buff))
empty_space= 0; /* Page is full */
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space)) if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
goto err; goto err;
pagecache_unlock_by_link(share->pagecache, page_link.link, pagecache_unlock_by_link(share->pagecache, page_link.link,
...@@ -6178,6 +6209,8 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6178,6 +6209,8 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
result= my_errno; result= my_errno;
/* Fix bitmap */ /* Fix bitmap */
if (!enough_free_entries_on_page(share, buff))
empty_space= 0; /* Page is full */
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space)) if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
goto err; goto err;
...@@ -6265,6 +6298,8 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6265,6 +6298,8 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
if ((uint) (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type) if ((uint) (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type)
{ {
empty_space= uint2korr(buff+EMPTY_SPACE_OFFSET); empty_space= uint2korr(buff+EMPTY_SPACE_OFFSET);
if (!enough_free_entries_on_page(share, buff))
empty_space= 0; /* Page is full */
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE,
empty_space)) empty_space))
goto err; goto err;
...@@ -6289,6 +6324,8 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn, ...@@ -6289,6 +6324,8 @@ uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
push_dynamic(&info->pinned_pages, (void*) &page_link); push_dynamic(&info->pinned_pages, (void*) &page_link);
result= 0; result= 0;
if (!enough_free_entries_on_page(share, buff))
empty_space= 0; /* Page is full */
/* This will work even if the page was marked as UNALLOCATED_PAGE */ /* This will work even if the page was marked as UNALLOCATED_PAGE */
if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space)) if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
result= my_errno; result= my_errno;
......
...@@ -1929,8 +1929,8 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend, ...@@ -1929,8 +1929,8 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
else else
_ma_check_print_error(param, _ma_check_print_error(param,
"Page %9s: Wrong data in bitmap. Page_type: " "Page %9s: Wrong data in bitmap. Page_type: "
"%d empty_space: %u Bitmap-bits: %d", "%d full: %d empty_space: %u Bitmap-bits: %d",
llstr(page, llbuff), page_type, llstr(page, llbuff), full_dir, page_type,
empty_space, bitmap_pattern); empty_space, bitmap_pattern);
if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE)) if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
goto err; goto err;
...@@ -6762,7 +6762,7 @@ static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid) ...@@ -6762,7 +6762,7 @@ static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid)
{ {
_ma_check_print_warning(param, _ma_check_print_warning(param,
"Found row with transaction id %s but no " "Found row with transaction id %s but no "
"maria_control_file was specified. " "maria_control_file was used or specified. "
"The table may be corrupted", "The table may be corrupted",
llstr(used_trid, buff)); llstr(used_trid, buff));
} }
......
...@@ -398,7 +398,7 @@ CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing, ...@@ -398,7 +398,7 @@ CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
} }
new_block_size= uint2korr(buffer + CF_BLOCKSIZE_OFFSET); new_block_size= uint2korr(buffer + CF_BLOCKSIZE_OFFSET);
if (new_block_size != maria_block_size) if (new_block_size != maria_block_size && maria_block_size)
{ {
error= CONTROL_FILE_WRONG_BLOCKSIZE; error= CONTROL_FILE_WRONG_BLOCKSIZE;
sprintf(errmsg_buff, sprintf(errmsg_buff,
...@@ -407,6 +407,7 @@ CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing, ...@@ -407,6 +407,7 @@ CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
errmsg= errmsg_buff; errmsg= errmsg_buff;
goto err; goto err;
} }
maria_block_size= new_block_size;
if (my_checksum(0, buffer, new_cf_create_time_size - CF_CHECKSUM_SIZE) != if (my_checksum(0, buffer, new_cf_create_time_size - CF_CHECKSUM_SIZE) !=
uint4korr(buffer + new_cf_create_time_size - CF_CHECKSUM_SIZE)) uint4korr(buffer + new_cf_create_time_size - CF_CHECKSUM_SIZE))
......
...@@ -71,6 +71,14 @@ static const char *record_formats[]= ...@@ -71,6 +71,14 @@ static const char *record_formats[]=
"Fixed length", "Packed", "Compressed", "Block", "?" "Fixed length", "Packed", "Compressed", "Block", "?"
}; };
static const char *bitmap_description[]=
{
"Empty page", "Part filled head page","Part filled head page",
"Part filled head page", "Full head page",
"Part filled tail page","Part filled tail page",
"Full tail or blob page"
};
static const char *maria_stats_method_str="nulls_unequal"; static const char *maria_stats_method_str="nulls_unequal";
static char default_open_errmsg[]= "%d when opening MARIA-table '%s'"; static char default_open_errmsg[]= "%d when opening MARIA-table '%s'";
static char default_close_errmsg[]= "%d when closing MARIA-table '%s'"; static char default_close_errmsg[]= "%d when closing MARIA-table '%s'";
...@@ -106,7 +114,9 @@ int main(int argc, char **argv) ...@@ -106,7 +114,9 @@ int main(int argc, char **argv)
error=0; error=0;
maria_init(); maria_init();
if (ma_control_file_open(FALSE, opt_require_control_file) && maria_block_size= 0; /* Use block size from control file */
if (ma_control_file_open(FALSE, opt_require_control_file ||
!(check_param.testflag & T_SILENT)) &&
(opt_require_control_file || (opt_require_control_file ||
(opt_transaction_logging && (check_param.testflag & T_REP_ANY)))) (opt_transaction_logging && (check_param.testflag & T_REP_ANY))))
{ {
...@@ -1516,7 +1526,7 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name) ...@@ -1516,7 +1526,7 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
printf("Using only keys '%s' of %d possibly keys\n", printf("Using only keys '%s' of %d possibly keys\n",
buff, share->base.keys); buff, share->base.keys);
} }
puts("\ntable description:"); puts("\nTable description:");
printf("Key Start Len Index Type"); printf("Key Start Len Index Type");
if (param->testflag & T_VERBOSE) if (param->testflag & T_VERBOSE)
printf(" Rec/key Root Blocksize"); printf(" Rec/key Root Blocksize");
...@@ -1658,6 +1668,14 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name) ...@@ -1658,6 +1668,14 @@ static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
} }
VOID(putchar('\n')); VOID(putchar('\n'));
} }
if (share->data_file_type == BLOCK_RECORD)
{
uint i;
puts("\nBitmap Data size Description");
for (i=0 ; i <= 7 ; i++)
printf("%u %5u %s\n", i, share->bitmap.sizes[i],
bitmap_description[i]);
}
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} /* describe */ } /* describe */
......
...@@ -56,6 +56,7 @@ int main(int argc, char **argv) ...@@ -56,6 +56,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Can't init Maria engine (%d)\n", errno); fprintf(stderr, "Can't init Maria engine (%d)\n", errno);
goto err; goto err;
} }
maria_block_size= 0; /* Use block size from file */
/* we don't want to create a control file, it MUST exist */ /* we don't want to create a control file, it MUST exist */
if (ma_control_file_open(FALSE, TRUE)) if (ma_control_file_open(FALSE, TRUE))
{ {
...@@ -68,7 +69,7 @@ int main(int argc, char **argv) ...@@ -68,7 +69,7 @@ int main(int argc, char **argv)
goto err; goto err;
} }
if (init_pagecache(maria_pagecache, opt_page_buffer_size, 0, 0, if (init_pagecache(maria_pagecache, opt_page_buffer_size, 0, 0,
TRANSLOG_PAGE_SIZE, MY_WME) == 0) maria_block_size, MY_WME) == 0)
{ {
fprintf(stderr, "Got error in init_pagecache() (errno: %d)\n", errno); fprintf(stderr, "Got error in init_pagecache() (errno: %d)\n", errno);
goto err; goto err;
......
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