Commit 1e0b42d9 authored by Michael Widenius's avatar Michael Widenius

Fixed recovery problem in Aria where bitmap had wrong information after recovery.

LP#619731: Aria recovery corruption "Page 1: Row: 1 has an extent with wrong information in bitmap

storage/maria/ma_bitmap.c:
  Don't send broadcast if no one is waiting for it
storage/maria/ma_blockrec.c:
  Don't update bitmap if the page is not in the dirty_page list (or LSN is after checkpoint start)
  Fixes the case where we have in the log redo_free_block followed by another redo entry for the same page which is ignored.
  Also fixed that _ma_apply_redo_insert_row_blobs() doesn't update the bitmap in similar circumstances.
storage/maria/ma_blockrec.h:
  Updated prototype
storage/maria/ma_check.c:
  Added printing of bitmap information if used with maria_chk -vvv (for debugging)
storage/maria/ma_recovery.c:
  Updated call parameters to _ma_apply_redo_free_blocks().
parent 427c6c78
......@@ -399,7 +399,8 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share)
become false, wake them up.
*/
DBUG_PRINT("info", ("bitmap flusher waking up others"));
pthread_cond_broadcast(&bitmap->bitmap_cond);
if (bitmap->flush_all_requested)
pthread_cond_broadcast(&bitmap->bitmap_cond);
}
pthread_mutex_unlock(&bitmap->bitmap_lock);
DBUG_RETURN(res);
......@@ -465,7 +466,8 @@ void _ma_bitmap_unlock(MARIA_SHARE *share)
bitmap->flush_all_requested--;
bitmap->non_flushable= 0;
pthread_mutex_unlock(&bitmap->bitmap_lock);
pthread_cond_broadcast(&bitmap->bitmap_cond);
if (bitmap->flush_all_requested > 0)
pthread_cond_broadcast(&bitmap->bitmap_cond);
DBUG_VOID_RETURN;
}
......
......@@ -6485,7 +6485,13 @@ err:
@param info Maria handler
@param header Header (without FILEID)
@note It marks the pages free in the bitmap
Mark the pages free in the bitmap.
We have to check against _ma_redo_not_needed_for_page()
to guard against the case where we first clear a block and after
that insert new data into the blocks. If we would unconditionally
clear the bitmap here, future changes would be ignored for the page
if it's not in the dirty list (ie, it would be flushed).
@return Operation status
@retval 0 OK
......@@ -6494,19 +6500,25 @@ err:
uint _ma_apply_redo_free_blocks(MARIA_HA *info,
LSN lsn __attribute__((unused)),
LSN redo_lsn,
const uchar *header)
{
MARIA_SHARE *share= info->s;
uint ranges;
uint16 sid;
DBUG_ENTER("_ma_apply_redo_free_blocks");
share->state.changed|= (STATE_CHANGED | STATE_NOT_ZEROFILLED |
STATE_NOT_MOVABLE);
sid= fileid_korr(header);
header+= FILEID_STORE_SIZE;
ranges= pagerange_korr(header);
header+= PAGERANGE_STORE_SIZE;
DBUG_ASSERT(ranges > 0);
/** @todo leave bitmap lock to the bitmap code... */
pthread_mutex_lock(&share->bitmap.bitmap_lock);
while (ranges--)
{
my_bool res;
......@@ -6523,18 +6535,22 @@ uint _ma_apply_redo_free_blocks(MARIA_HA *info,
DBUG_PRINT("info", ("page: %lu pages: %u", (long) page, page_range));
/** @todo leave bitmap lock to the bitmap code... */
pthread_mutex_lock(&share->bitmap.bitmap_lock);
res= _ma_bitmap_reset_full_page_bits(info, &share->bitmap, start_page,
page_range);
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
if (res)
for ( ; page_range-- ; start_page++)
{
_ma_mark_file_crashed(share);
DBUG_ASSERT(0);
DBUG_RETURN(res);
if (_ma_redo_not_needed_for_page(sid, redo_lsn, start_page, FALSE))
continue;
res= _ma_bitmap_reset_full_page_bits(info, &share->bitmap, start_page,
1);
if (res)
{
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
_ma_mark_file_crashed(share);
DBUG_ASSERT(0);
DBUG_RETURN(res);
}
}
}
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
DBUG_RETURN(0);
}
......@@ -6764,7 +6780,7 @@ uint _ma_apply_redo_insert_row_blobs(MARIA_HA *info,
PAGECACHE_LOCK_WRITE_UNLOCK,
PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
LSN_IMPOSSIBLE, 0, FALSE);
continue;
goto fix_bitmap;
}
DBUG_ASSERT((found_page_type == (uchar) BLOB_PAGE) ||
(found_page_type == (uchar) UNALLOCATED_PAGE));
......@@ -6799,14 +6815,16 @@ uint _ma_apply_redo_insert_row_blobs(MARIA_HA *info,
unlock_method, unpin_method,
PAGECACHE_WRITE_DELAY, 0, LSN_IMPOSSIBLE))
goto err;
}
fix_bitmap:
/** @todo leave bitmap lock to the bitmap code... */
pthread_mutex_lock(&share->bitmap.bitmap_lock);
res= _ma_bitmap_set_full_page_bits(info, &share->bitmap, start_page,
page_range);
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
if (res)
goto err;
pthread_mutex_lock(&share->bitmap.bitmap_lock);
res= _ma_bitmap_set_full_page_bits(info, &share->bitmap, page,
1);
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
if (res)
goto err;
}
}
}
*first_page= first_page2;
......
......@@ -235,7 +235,7 @@ uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
uint page_type,
const uchar *header);
uint _ma_apply_redo_free_blocks(MARIA_HA *info, LSN lsn,
uint _ma_apply_redo_free_blocks(MARIA_HA *info, LSN lsn, LSN rec_lsn,
const uchar *header);
uint _ma_apply_redo_free_head_or_tail(MARIA_HA *info, LSN lsn,
const uchar *header);
......
......@@ -100,6 +100,9 @@ static my_bool _ma_flush_table_files_before_swap(HA_CHECK *param,
static TrID max_trid_in_system(void);
static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid);
void retry_if_quick(MARIA_SORT_PARAM *param, int error);
static void print_bitmap_description(MARIA_SHARE *share,
pgcache_page_no_t page,
uchar *buff);
/* Initialize check param with default values */
......@@ -1842,6 +1845,8 @@ static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
}
param->used+= block_size;
param->link_used+= block_size;
if (param->verbose > 2)
print_bitmap_description(share, page, bitmap_buff);
continue;
}
/* Skip pages marked as empty in bitmap */
......@@ -2177,12 +2182,17 @@ int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
llstr(param->del_length, llbuff2));
printf("Empty space: %12s Linkdata: %10s\n",
llstr(param->empty, llbuff),llstr(param->link_used, llbuff2));
if (param->lost)
printf("Lost space: %12s", llstr(param->lost, llbuff));
if (param->max_found_trid)
if (share->data_file_type == BLOCK_RECORD)
{
printf("Max trans. id: %11s\n",
llstr(param->max_found_trid, llbuff));
printf("Full pages: %12s Tail count: %12s\n",
llstr(param->full_page_count, llbuff),
llstr(param->tail_count, llbuff2));
printf("Lost space: %12s\n", llstr(param->lost, llbuff));
if (param->max_found_trid)
{
printf("Max trans. id: %11s\n",
llstr(param->max_found_trid, llbuff));
}
}
}
my_free(record,MYF(0));
......@@ -6799,3 +6809,46 @@ void retry_if_quick(MARIA_SORT_PARAM *sort_param, int error)
param->testflag|=T_RETRY_WITHOUT_QUICK;
}
}
/* Print information about bitmap page */
static void print_bitmap_description(MARIA_SHARE *share,
pgcache_page_no_t page,
uchar *bitmap_data)
{
uchar *pos, *end;
MARIA_FILE_BITMAP *bitmap= &share->bitmap;
uint count=0, dot_printed= 0;
char buff[80], last[80];
printf("Bitmap page %lu\n", (ulong) page);
page++;
last[0]=0;
for (pos= bitmap_data, end= pos+ bitmap->used_size ; pos < end ; pos+= 6)
{
ulonglong bits= uint6korr(pos); /* 6 bytes = 6*8/3= 16 patterns */
uint i;
for (i= 0; i < 16 ; i++, bits>>= 3)
{
if (count > 60)
{
buff[count]= 0;
if (strcmp(buff, last))
{
memcpy(last, buff, count+1);
printf("%8lu: %s\n", (ulong) page - count, buff);
dot_printed= 0;
}
else if (!(dot_printed++))
printf("...\n");
count= 0;
}
buff[count++]= '0' + (uint) (bits & 7);
page++;
}
}
buff[count]= 0;
printf("%8lu: %s\n", (ulong) page - count, buff);
fputs("\n", stdout);
}
......@@ -1643,8 +1643,8 @@ prototype_redo_exec_hook(REDO_FREE_BLOCKS)
}
buff= log_record_buffer.str;
if (_ma_apply_redo_free_blocks(info, current_group_end_lsn,
buff + FILEID_STORE_SIZE))
if (_ma_apply_redo_free_blocks(info, current_group_end_lsn, rec->lsn,
buff))
goto end;
error= 0;
end:
......@@ -3015,10 +3015,11 @@ static MARIA_HA *get_MARIA_HA_from_REDO_record(const
page= page_korr(rec->header + FILEID_STORE_SIZE);
llstr(page, llbuf);
break;
case LOGREC_REDO_FREE_BLOCKS:
/*
For REDO_FREE_BLOCKS, no need to look at dirty pages list: it does not
read data pages, only reads/modifies bitmap page(s) which is cheap.
We are checking against the dirty pages in _ma_apply_redo_free_blocks()
*/
break;
default:
break;
}
......
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