Commit 0ad6d3b6 authored by unknown's avatar unknown

Merge gbichot@bk-internal.mysql.com:/home/bk/mysql-maria

into  gbichot4.local:/home/mysql_src/mysql-maria-for-undo-phase


storage/maria/ma_recovery.c:
  Auto merged
parents cf811f9e cfe03d87
...@@ -1976,7 +1976,7 @@ drop table t1; ...@@ -1976,7 +1976,7 @@ drop table t1;
show variables like 'maria%'; show variables like 'maria%';
Variable_name Value Variable_name Value
maria_block_size 8192 maria_block_size 8192
maria_checkpoint_frequency 30 maria_checkpoint_frequency 0
maria_max_sort_file_size 9223372036853727232 maria_max_sort_file_size 9223372036853727232
maria_pagecache_age_threshold 300 maria_pagecache_age_threshold 300
maria_pagecache_buffer_size 8384512 maria_pagecache_buffer_size 8384512
......
...@@ -95,7 +95,8 @@ static MYSQL_SYSVAR_ULONG(checkpoint_frequency, maria_checkpoint_frequency, ...@@ -95,7 +95,8 @@ static MYSQL_SYSVAR_ULONG(checkpoint_frequency, maria_checkpoint_frequency,
PLUGIN_VAR_RQCMDARG, PLUGIN_VAR_RQCMDARG,
"Frequency of automatic checkpoints, in seconds;" "Frequency of automatic checkpoints, in seconds;"
" 0 means 'no checkpoints'.", " 0 means 'no checkpoints'.",
NULL, update_checkpoint_frequency, 30, 0, UINT_MAX, 1); /* disabled for now */
NULL, update_checkpoint_frequency, 0, 0, UINT_MAX, 1);
static MYSQL_SYSVAR_ULONGLONG(max_sort_file_size, static MYSQL_SYSVAR_ULONGLONG(max_sort_file_size,
maria_max_temp_length, PLUGIN_VAR_RQCMDARG, maria_max_temp_length, PLUGIN_VAR_RQCMDARG,
...@@ -2541,6 +2542,7 @@ static struct st_mysql_sys_var* system_variables[]= { ...@@ -2541,6 +2542,7 @@ static struct st_mysql_sys_var* system_variables[]= {
checkpoint frequency. So when the user wants to modify it, we stop and checkpoint frequency. So when the user wants to modify it, we stop and
restart the thread. restart the thread.
*/ */
static void update_checkpoint_frequency(MYSQL_THD thd, static void update_checkpoint_frequency(MYSQL_THD thd,
struct st_mysql_sys_var *var, struct st_mysql_sys_var *var,
void *var_ptr, void *save) void *var_ptr, void *save)
......
...@@ -20,11 +20,7 @@ ...@@ -20,11 +20,7 @@
/* Here is the implementation of this module */ /* Here is the implementation of this module */
/** /** @todo RECOVERY BUG this is unreviewed code */
@todo RECOVERY BUG this is unreviewed code, but used in safe conditions:
ha_maria takes a checkpoint at end of recovery and one at clean shutdown,
that's all. So there never are open tables, dirty pages, transactions.
*/
/* /*
Summary: Summary:
checkpoints are done either by a background thread (checkpoint every Nth checkpoints are done either by a background thread (checkpoint every Nth
...@@ -44,23 +40,6 @@ ...@@ -44,23 +40,6 @@
/** @brief Frequency of background checkpoints, in seconds */ /** @brief Frequency of background checkpoints, in seconds */
ulong maria_checkpoint_frequency; ulong maria_checkpoint_frequency;
/*
Checkpoints currently happen only at ha_maria's startup (after recovery) and
at shutdown, always when there is no open tables.
Background page flushing is not used.
So, needed pagecache functions for doing this flushing are not yet pushed.
*/
#define flush_pagecache_blocks_with_filter(A,B,C,D,E) (int)(((ulong)D) * 0)
/**
filter has to return 0, 1 or 2: 0 means "don't flush this page", 1 means
"flush it", 2 means "don't flush this page and following pages".
Will move to ma_pagecache.h
*/
typedef int (*PAGECACHE_FILTER)(enum pagecache_page_type type,
pgcache_page_no_t page,
LSN rec_lsn, void *arg);
/** @brief type of checkpoint currently running */ /** @brief type of checkpoint currently running */
static CHECKPOINT_LEVEL checkpoint_in_progress= CHECKPOINT_NONE; static CHECKPOINT_LEVEL checkpoint_in_progress= CHECKPOINT_NONE;
/** @brief protects checkpoint_in_progress */ /** @brief protects checkpoint_in_progress */
...@@ -89,16 +68,20 @@ struct st_filter_param ...@@ -89,16 +68,20 @@ struct st_filter_param
uint max_pages; /**< stop after flushing this number pages */ uint max_pages; /**< stop after flushing this number pages */
}; /**< information to determine which dirty pages should be flushed */ }; /**< information to determine which dirty pages should be flushed */
static int filter_flush_data_file_medium(enum pagecache_page_type type, static enum pagecache_flush_filter_result
filter_flush_data_file_medium(enum pagecache_page_type type,
pgcache_page_no_t page, pgcache_page_no_t page,
LSN rec_lsn, void *arg); LSN rec_lsn, void *arg);
static int filter_flush_data_file_full(enum pagecache_page_type type, static enum pagecache_flush_filter_result
filter_flush_data_file_full(enum pagecache_page_type type,
pgcache_page_no_t page, pgcache_page_no_t page,
LSN rec_lsn, void *arg); LSN rec_lsn, void *arg);
static int filter_flush_data_file_indirect(enum pagecache_page_type type, static enum pagecache_flush_filter_result
filter_flush_data_file_indirect(enum pagecache_page_type type,
pgcache_page_no_t page, pgcache_page_no_t page,
LSN rec_lsn, void *arg); LSN rec_lsn, void *arg);
static int filter_flush_data_file_evenly(enum pagecache_page_type type, static enum pagecache_flush_filter_result
filter_flush_data_file_evenly(enum pagecache_page_type type,
pgcache_page_no_t pageno, pgcache_page_no_t pageno,
LSN rec_lsn, void *arg); LSN rec_lsn, void *arg);
static int really_execute_checkpoint(void); static int really_execute_checkpoint(void);
...@@ -191,13 +174,6 @@ static int really_execute_checkpoint(void) ...@@ -191,13 +174,6 @@ static int really_execute_checkpoint(void)
rules, the log's lock is a mutex). rules, the log's lock is a mutex).
"Horizon" is a lower bound of the LSN of the next log record. "Horizon" is a lower bound of the LSN of the next log record.
*/ */
/**
@todo RECOVERY BUG
this is an horizon, but it is used as a LSN (REDO phase may start from
there! probably log handler would refuse to read then;
Sanja proposed to make a loghandler's function which finds the LSN after
this horizon.
*/
checkpoint_start_log_horizon= translog_get_horizon(); checkpoint_start_log_horizon= translog_get_horizon();
DBUG_PRINT("info",("checkpoint_start_log_horizon (%lu,0x%lx)", DBUG_PRINT("info",("checkpoint_start_log_horizon (%lu,0x%lx)",
LSN_IN_PARTS(checkpoint_start_log_horizon))); LSN_IN_PARTS(checkpoint_start_log_horizon)));
...@@ -263,7 +239,6 @@ static int really_execute_checkpoint(void) ...@@ -263,7 +239,6 @@ static int really_execute_checkpoint(void)
log_array[TRANSLOG_INTERNAL_PARTS + 1 + i]= record_pieces[i]; log_array[TRANSLOG_INTERNAL_PARTS + 1 + i]= record_pieces[i];
total_rec_length+= record_pieces[i].length; total_rec_length+= record_pieces[i].length;
} }
if (unlikely(translog_write_record(&lsn, LOGREC_CHECKPOINT, if (unlikely(translog_write_record(&lsn, LOGREC_CHECKPOINT,
&dummy_transaction_object, NULL, &dummy_transaction_object, NULL,
total_rec_length, total_rec_length,
...@@ -271,7 +246,6 @@ static int really_execute_checkpoint(void) ...@@ -271,7 +246,6 @@ static int really_execute_checkpoint(void)
log_array, NULL, NULL) || log_array, NULL, NULL) ||
translog_flush(lsn))) translog_flush(lsn)))
goto err; goto err;
translog_lock(); translog_lock();
/* /*
This cannot be done as a inwrite_rec_hook of LOGREC_CHECKPOINT, because This cannot be done as a inwrite_rec_hook of LOGREC_CHECKPOINT, because
...@@ -353,8 +327,6 @@ int ma_checkpoint_init(my_bool create_background_thread) ...@@ -353,8 +327,6 @@ int ma_checkpoint_init(my_bool create_background_thread)
DBUG_ENTER("ma_checkpoint_init"); DBUG_ENTER("ma_checkpoint_init");
checkpoint_inited= TRUE; checkpoint_inited= TRUE;
checkpoint_thread_die= 2; /* not yet born == dead */ checkpoint_thread_die= 2; /* not yet born == dead */
/* Background thread will be enabled in a later changeset */
create_background_thread= FALSE;
if (maria_checkpoint_frequency == 0) if (maria_checkpoint_frequency == 0)
create_background_thread= FALSE; create_background_thread= FALSE;
if (pthread_mutex_init(&LOCK_checkpoint, MY_MUTEX_INIT_SLOW) || if (pthread_mutex_init(&LOCK_checkpoint, MY_MUTEX_INIT_SLOW) ||
...@@ -417,13 +389,10 @@ void ma_checkpoint_end(void) ...@@ -417,13 +389,10 @@ void ma_checkpoint_end(void)
@param pageno Page's number @param pageno Page's number
@param rec_lsn Page's rec_lsn @param rec_lsn Page's rec_lsn
@param arg filter_param @param arg filter_param
@return Operation status
@retval 0 don't flush the page
@retval 1 flush the page
*/ */
static int filter_flush_data_file_medium(enum pagecache_page_type type, static enum pagecache_flush_filter_result
filter_flush_data_file_medium(enum pagecache_page_type type,
pgcache_page_no_t pageno, pgcache_page_no_t pageno,
LSN rec_lsn, void *arg) LSN rec_lsn, void *arg)
{ {
...@@ -444,16 +413,12 @@ static int filter_flush_data_file_medium(enum pagecache_page_type type, ...@@ -444,16 +413,12 @@ static int filter_flush_data_file_medium(enum pagecache_page_type type,
@param pageno Page's number @param pageno Page's number
@param rec_lsn Page's rec_lsn @param rec_lsn Page's rec_lsn
@param arg filter_param @param arg filter_param
@return Operation status
@retval 0 don't flush the page
@retval 1 flush the page
*/ */
static int filter_flush_data_file_full(enum pagecache_page_type type, static enum pagecache_flush_filter_result
filter_flush_data_file_full(enum pagecache_page_type type,
pgcache_page_no_t pageno, pgcache_page_no_t pageno,
LSN rec_lsn LSN rec_lsn __attribute__ ((unused)),
__attribute__ ((unused)),
void *arg) void *arg)
{ {
struct st_filter_param *param= (struct st_filter_param *)arg; struct st_filter_param *param= (struct st_filter_param *)arg;
...@@ -472,17 +437,13 @@ static int filter_flush_data_file_full(enum pagecache_page_type type, ...@@ -472,17 +437,13 @@ static int filter_flush_data_file_full(enum pagecache_page_type type,
@param pageno Page's number @param pageno Page's number
@param rec_lsn Page's rec_lsn @param rec_lsn Page's rec_lsn
@param arg filter_param @param arg filter_param
@return Operation status
@retval 0 don't flush the page
@retval 1 flush the page
*/ */
static int filter_flush_data_file_indirect(enum pagecache_page_type type static enum pagecache_flush_filter_result
filter_flush_data_file_indirect(enum pagecache_page_type type
__attribute__ ((unused)), __attribute__ ((unused)),
pgcache_page_no_t pageno, pgcache_page_no_t pageno,
LSN rec_lsn LSN rec_lsn __attribute__ ((unused)),
__attribute__ ((unused)),
void *arg) void *arg)
{ {
struct st_filter_param *param= (struct st_filter_param *)arg; struct st_filter_param *param= (struct st_filter_param *)arg;
...@@ -505,28 +466,23 @@ static int filter_flush_data_file_indirect(enum pagecache_page_type type ...@@ -505,28 +466,23 @@ static int filter_flush_data_file_indirect(enum pagecache_page_type type
@param pageno Page's number @param pageno Page's number
@param rec_lsn Page's rec_lsn @param rec_lsn Page's rec_lsn
@param arg filter_param @param arg filter_param
@return Operation status
@retval 0 don't flush the page
@retval 1 flush the page
@retval 2 don't flush the page and following pages
*/ */
static int filter_flush_data_file_evenly(enum pagecache_page_type type, static enum pagecache_flush_filter_result
pgcache_page_no_t pageno filter_flush_data_file_evenly(enum pagecache_page_type type,
__attribute__ ((unused)), pgcache_page_no_t pageno __attribute__ ((unused)),
LSN rec_lsn, void *arg) LSN rec_lsn, void *arg)
{ {
struct st_filter_param *param= (struct st_filter_param *)arg; struct st_filter_param *param= (struct st_filter_param *)arg;
if (unlikely(param->max_pages == 0)) /* all flushed already */ if (unlikely(param->max_pages == 0)) /* all flushed already */
return 2; return FLUSH_FILTER_SKIP_ALL;
if ((type == PAGECACHE_LSN_PAGE) && if ((type == PAGECACHE_LSN_PAGE) &&
(cmp_translog_addr(rec_lsn, param->up_to_lsn) <= 0)) (cmp_translog_addr(rec_lsn, param->up_to_lsn) <= 0))
{ {
param->max_pages--; param->max_pages--;
return 1; return FLUSH_FILTER_OK;
} }
return 0; return FLUSH_FILTER_SKIP_TRY_NEXT;
} }
...@@ -554,6 +510,8 @@ pthread_handler_t ma_checkpoint_background(void *arg __attribute__((unused))) ...@@ -554,6 +510,8 @@ pthread_handler_t ma_checkpoint_background(void *arg __attribute__((unused)))
/** @brief At least this of log/page bytes written between checkpoints */ /** @brief At least this of log/page bytes written between checkpoints */
const uint checkpoint_min_activity= 2*1024*1024; const uint checkpoint_min_activity= 2*1024*1024;
uint sleeps= 0; uint sleeps= 0;
TRANSLOG_ADDRESS log_horizon_at_last_checkpoint= LSN_IMPOSSIBLE;
ulonglong pagecache_flushes_at_last_checkpoint= 0;
my_thread_init(); my_thread_init();
DBUG_PRINT("info",("Maria background checkpoint thread starts")); DBUG_PRINT("info",("Maria background checkpoint thread starts"));
...@@ -566,15 +524,15 @@ pthread_handler_t ma_checkpoint_background(void *arg __attribute__((unused))) ...@@ -566,15 +524,15 @@ pthread_handler_t ma_checkpoint_background(void *arg __attribute__((unused)))
struct st_filter_param filter_param; struct st_filter_param filter_param;
PAGECACHE_FILE *dfile; /**< data file currently being flushed */ PAGECACHE_FILE *dfile; /**< data file currently being flushed */
PAGECACHE_FILE *kfile; /**< index file currently being flushed */ PAGECACHE_FILE *kfile; /**< index file currently being flushed */
TRANSLOG_ADDRESS log_horizon_at_last_checkpoint= LSN_IMPOSSIBLE;
ulonglong pagecache_flushes_at_last_checkpoint= 0;
struct timespec abstime; struct timespec abstime;
LINT_INIT(kfile); LINT_INIT(kfile);
LINT_INIT(dfile); LINT_INIT(dfile);
LINT_INIT(pages_bunch_size);
/* /*
If the frequency could be changed by the user while we are in this loop, If the frequency could be changed by the user while we are in this loop,
it could be annoying: for example it could cause "case 2" to be executed it could be annoying: for example it could cause "case 2" to be executed
right after "case 0", thus having 'dfile' unset. right after "case 0", thus having 'dfile'
unset. update_checkpoint_frequency() takes care of stopping this thread.
*/ */
switch((sleeps++) % maria_checkpoint_frequency) switch((sleeps++) % maria_checkpoint_frequency)
{ {
...@@ -823,7 +781,7 @@ static int collect_tables(LEX_STRING *str, LSN checkpoint_start_log_horizon) ...@@ -823,7 +781,7 @@ static int collect_tables(LEX_STRING *str, LSN checkpoint_start_log_horizon)
struct st_filter_param filter_param; struct st_filter_param filter_param;
/* only possible checkpointer, so can do the read below without mutex */ /* only possible checkpointer, so can do the read below without mutex */
filter_param.up_to_lsn= last_checkpoint_lsn; filter_param.up_to_lsn= last_checkpoint_lsn;
PAGECACHE_FILTER filter; PAGECACHE_FLUSH_FILTER filter;
switch(checkpoint_in_progress) switch(checkpoint_in_progress)
{ {
case CHECKPOINT_MEDIUM: case CHECKPOINT_MEDIUM:
......
...@@ -841,7 +841,7 @@ static int flush_all_key_blocks(PAGECACHE *pagecache) ...@@ -841,7 +841,7 @@ static int flush_all_key_blocks(PAGECACHE *pagecache)
KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used); KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used);
#endif #endif
if (flush_pagecache_blocks_int(pagecache, &block->hash_link->file, if (flush_pagecache_blocks_int(pagecache, &block->hash_link->file,
FLUSH_RELEASE)) FLUSH_RELEASE, NULL, NULL))
return 1; return 1;
break; break;
} }
...@@ -3489,7 +3489,7 @@ static int flush_cached_blocks(PAGECACHE *pagecache, ...@@ -3489,7 +3489,7 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
pagecache_pthread_mutex_unlock(&pagecache->cache_lock); pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
/* /*
As all blocks referred in 'cache' are marked by PCBLOCK_IN_FLUSH As all blocks referred in 'cache' are marked by PCBLOCK_IN_FLUSH
we are guarantied no thread will change them we are guaranteed that no thread will change them
*/ */
qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link); qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
...@@ -3506,6 +3506,8 @@ static int flush_cached_blocks(PAGECACHE *pagecache, ...@@ -3506,6 +3506,8 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
DBUG_PRINT("info", ("block: %u (0x%lx) pinned", DBUG_PRINT("info", ("block: %u (0x%lx) pinned",
PCBLOCK_NUMBER(pagecache, block), (ulong)block)); PCBLOCK_NUMBER(pagecache, block), (ulong)block));
PCBLOCK_INFO(block); PCBLOCK_INFO(block);
/* undo the mark put by flush_pagecache_blocks_int(): */
block->status&= ~PCBLOCK_IN_FLUSH;
last_errno= -1; last_errno= -1;
unreg_request(pagecache, block, 1); unreg_request(pagecache, block, 1);
continue; continue;
...@@ -3573,11 +3575,15 @@ static int flush_cached_blocks(PAGECACHE *pagecache, ...@@ -3573,11 +3575,15 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
/** /**
@brief flush all key blocks for a file to disk but don't do any mutex locks @brief flush all blocks for a file to disk but don't do any mutex locks
@param pagecache pointer to a pagecache data structure @param pagecache pointer to a pagecache data structure
@param file handler for the file to flush to @param file handler for the file to flush to
@param flush_type type of the flush @param flush_type type of the flush
@param filter optional function which tells what blocks to flush;
can be non-NULL only if FLUSH_KEEP or FLUSH_FORCE_WRITE.
@param filter_arg an argument to pass to 'filter'. Information about
the block will be passed too.
@note @note
This function doesn't do any mutex locks because it needs to be called This function doesn't do any mutex locks because it needs to be called
...@@ -3591,7 +3597,9 @@ static int flush_cached_blocks(PAGECACHE *pagecache, ...@@ -3591,7 +3597,9 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
static int flush_pagecache_blocks_int(PAGECACHE *pagecache, static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
PAGECACHE_FILE *file, PAGECACHE_FILE *file,
enum flush_type type) enum flush_type type,
PAGECACHE_FLUSH_FILTER filter,
void *filter_arg)
{ {
PAGECACHE_BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache; PAGECACHE_BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
int last_errno= 0; int last_errno= 0;
...@@ -3622,9 +3630,29 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache, ...@@ -3622,9 +3630,29 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
if (type != FLUSH_IGNORE_CHANGED) if (type != FLUSH_IGNORE_CHANGED)
{ {
/* /**
Count how many key blocks we have to cache to be able Count how many key blocks we have to cache to be able
to flush all dirty pages with minimum seek moves to flush all dirty pages with minimum seek moves.
@todo RECOVERY BUG
We will soon here put code to wait if another thread is flushing the
same file, to avoid concurrency bugs. Examples of concurrency bugs
which happened without serialization:
- assume maria_chk_size() (via CHECK TABLE) happens
concurrently with Checkpoint: Checkpoint may be flushing a page, and
maria_chk_size() wants to flush this page too so gets an error
because Checkpoint pinned this page. Such error leads to marking the
table corrupted.
- assume maria_close() happens concurrently with Checkpoint:
Checkpoint may be flushing a page, and maria_close() flushes this
page too with FLUSH_RELEASE: the FLUSH_RELEASE will cause a
free_block() which assumes the page is in the LRU, but it is not (as
Checkpoint is flushing it). Crash.
- assume two flushes of the same file happen concurrently (like
above), and a third thread is pushing a page of this file out of the
LRU and runs first. Then one flusher will remove the page from
changed_blocks[] and put it in its first_in_switch, so the other
flusher will not see the page at all and return too early.
*/ */
for (block= pagecache->changed_blocks[FILE_HASH(*file)] ; for (block= pagecache->changed_blocks[FILE_HASH(*file)] ;
block; block;
...@@ -3659,7 +3687,19 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache, ...@@ -3659,7 +3687,19 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used); KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used);
#endif #endif
next= block->next_changed; next= block->next_changed;
if (block->hash_link->file.file == file->file) if (block->hash_link->file.file != file->file)
continue;
if (filter != NULL)
{
int filter_res= (*filter)(block->type, block->hash_link->pageno,
block->rec_lsn, filter_arg);
DBUG_PRINT("info",("filter returned %d", filter_res));
if (filter_res == FLUSH_FILTER_SKIP_TRY_NEXT)
continue;
if (filter_res == FLUSH_FILTER_SKIP_ALL)
break;
DBUG_ASSERT(filter_res == FLUSH_FILTER_OK);
}
{ {
/* /*
Mark the block with BLOCK_IN_FLUSH in order not to let Mark the block with BLOCK_IN_FLUSH in order not to let
...@@ -3775,6 +3815,11 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache, ...@@ -3775,6 +3815,11 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
/* The following happens very seldom */ /* The following happens very seldom */
if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE)) if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
{ {
/*
this code would free all blocks while filter maybe handled only a
few, that is not possible.
*/
DBUG_ASSERT(filter == NULL);
#if defined(PAGECACHE_DEBUG) #if defined(PAGECACHE_DEBUG)
cnt=0; cnt=0;
#endif #endif
...@@ -3810,23 +3855,27 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache, ...@@ -3810,23 +3855,27 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
} }
/* /**
Flush all blocks for a file to disk @brief flush all blocks for a file to disk
SYNOPSIS
flush_pagecache_blocks() @param pagecache pointer to a pagecache data structure
pagecache pointer to a page cache data structure @param file handler for the file to flush to
file handler for the file to flush to @param flush_type type of the flush
flush_type type of the flush @param filter optional function which tells what blocks to flush;
can be non-NULL only if FLUSH_KEEP or FLUSH_FORCE_WRITE.
@param filter_arg an argument to pass to 'filter'. Information about
the block will be passed too.
RETURN @return Operation status
0 OK @retval 0 OK
1 error @retval 1 Error
*/ */
int flush_pagecache_blocks(PAGECACHE *pagecache, int flush_pagecache_blocks_with_filter(PAGECACHE *pagecache,
PAGECACHE_FILE *file, enum flush_type type) PAGECACHE_FILE *file,
enum flush_type type,
PAGECACHE_FLUSH_FILTER filter,
void *filter_arg)
{ {
int res; int res;
DBUG_ENTER("flush_pagecache_blocks"); DBUG_ENTER("flush_pagecache_blocks");
...@@ -3836,7 +3885,7 @@ int flush_pagecache_blocks(PAGECACHE *pagecache, ...@@ -3836,7 +3885,7 @@ int flush_pagecache_blocks(PAGECACHE *pagecache,
DBUG_RETURN(0); DBUG_RETURN(0);
pagecache_pthread_mutex_lock(&pagecache->cache_lock); pagecache_pthread_mutex_lock(&pagecache->cache_lock);
inc_counter_for_resize_op(pagecache); inc_counter_for_resize_op(pagecache);
res= flush_pagecache_blocks_int(pagecache, file, type); res= flush_pagecache_blocks_int(pagecache, file, type, filter, filter_arg);
dec_counter_for_resize_op(pagecache); dec_counter_for_resize_op(pagecache);
pagecache_pthread_mutex_unlock(&pagecache->cache_lock); pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
DBUG_RETURN(res); DBUG_RETURN(res);
......
...@@ -161,6 +161,18 @@ typedef struct st_pagecache ...@@ -161,6 +161,18 @@ typedef struct st_pagecache
my_bool in_init; /* Set to 1 in MySQL during init/resize */ my_bool in_init; /* Set to 1 in MySQL during init/resize */
} PAGECACHE; } PAGECACHE;
/** @brief Return values for PAGECACHE_FLUSH_FILTER */
enum pagecache_flush_filter_result
{
FLUSH_FILTER_SKIP_TRY_NEXT= 0,/**< skip page and move on to next one */
FLUSH_FILTER_OK, /**< flush page and move on to next one */
FLUSH_FILTER_SKIP_ALL /**< skip page and all next ones */
};
/** @brief a filter function type for flush_pagecache_blocks_with_filter() */
typedef enum pagecache_flush_filter_result
(*PAGECACHE_FLUSH_FILTER)(enum pagecache_page_type type, pgcache_page_no_t page,
LSN rec_lsn, void *arg);
/* The default key cache */ /* The default key cache */
extern PAGECACHE dflt_pagecache_var, *dflt_pagecache; extern PAGECACHE dflt_pagecache_var, *dflt_pagecache;
...@@ -228,9 +240,13 @@ extern void pagecache_unpin(PAGECACHE *pagecache, ...@@ -228,9 +240,13 @@ extern void pagecache_unpin(PAGECACHE *pagecache,
extern void pagecache_unpin_by_link(PAGECACHE *pagecache, extern void pagecache_unpin_by_link(PAGECACHE *pagecache,
PAGECACHE_BLOCK_LINK *link, PAGECACHE_BLOCK_LINK *link,
LSN lsn); LSN lsn);
extern int flush_pagecache_blocks(PAGECACHE *keycache, #define flush_pagecache_blocks(A,B,C) \
flush_pagecache_blocks_with_filter(A,B,C,NULL,NULL)
extern int flush_pagecache_blocks_with_filter(PAGECACHE *keycache,
PAGECACHE_FILE *file, PAGECACHE_FILE *file,
enum flush_type type); enum flush_type type,
PAGECACHE_FLUSH_FILTER filter,
void *filter_arg);
extern my_bool pagecache_delete(PAGECACHE *pagecache, extern my_bool pagecache_delete(PAGECACHE *pagecache,
PAGECACHE_FILE *file, PAGECACHE_FILE *file,
pgcache_page_no_t pageno, pgcache_page_no_t pageno,
......
...@@ -2256,6 +2256,13 @@ static int close_all_tables(void) ...@@ -2256,6 +2256,13 @@ static int close_all_tables(void)
next_open= list_element->next; next_open= list_element->next;
info= (MARIA_HA*)list_element->data; info= (MARIA_HA*)list_element->data;
pthread_mutex_unlock(&THR_LOCK_maria); /* ok, UNDO phase not online yet */ pthread_mutex_unlock(&THR_LOCK_maria); /* ok, UNDO phase not online yet */
/*
Tables which we see here are exactly those which were open at time of
crash. They might have open_count>0 as Checkpoint maybe flushed their
state while they were used. As Recovery corrected them, don't alarm the
user, don't ask for a table check:
*/
info->s->state.open_count= 0;
prepare_table_for_close(info, addr); prepare_table_for_close(info, addr);
error|= maria_close(info); error|= maria_close(info);
pthread_mutex_lock(&THR_LOCK_maria); pthread_mutex_lock(&THR_LOCK_maria);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <m_string.h> #include <m_string.h>
#include "ma_control_file.h" #include "ma_control_file.h"
#include "ma_loghandler.h" #include "ma_loghandler.h"
#include "ma_checkpoint.h"
#include "trnman.h" #include "trnman.h"
extern PAGECACHE *maria_log_pagecache; extern PAGECACHE *maria_log_pagecache;
...@@ -29,7 +30,7 @@ extern const char *maria_data_root; ...@@ -29,7 +30,7 @@ extern const char *maria_data_root;
static void usage(); static void usage();
static int rec_pointer_size=0, flags[50], testflag; static int rec_pointer_size=0, flags[50], testflag, checkpoint;
static int key_field=FIELD_SKIP_PRESPACE,extra_field=FIELD_SKIP_ENDSPACE; static int key_field=FIELD_SKIP_PRESPACE,extra_field=FIELD_SKIP_ENDSPACE;
static int key_type=HA_KEYTYPE_NUM; static int key_type=HA_KEYTYPE_NUM;
static int create_flag=0; static int create_flag=0;
...@@ -82,7 +83,7 @@ int main(int argc,char *argv[]) ...@@ -82,7 +83,7 @@ int main(int argc,char *argv[])
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(0))) (transactional && (trnman_init(0) || ma_checkpoint_init(FALSE))))
{ {
fprintf(stderr, "Error in initialization"); fprintf(stderr, "Error in initialization");
exit(1); exit(1);
...@@ -226,6 +227,9 @@ static int run_test(const char *filename) ...@@ -226,6 +227,9 @@ static int run_test(const char *filename)
if (maria_commit(file) || maria_begin(file)) if (maria_commit(file) || maria_begin(file))
goto err; goto err;
if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (testflag == 1) if (testflag == 1)
goto end; goto end;
...@@ -246,6 +250,9 @@ static int run_test(const char *filename) ...@@ -246,6 +250,9 @@ static int run_test(const char *filename)
flags[0]=2; flags[0]=2;
} }
if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (testflag == 2) if (testflag == 2)
{ {
printf("Terminating after inserts\n"); printf("Terminating after inserts\n");
...@@ -307,6 +314,9 @@ static int run_test(const char *filename) ...@@ -307,6 +314,9 @@ static int run_test(const char *filename)
maria_scan_end(file); maria_scan_end(file);
} }
if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (testflag == 3) if (testflag == 3)
{ {
printf("Terminating after updates\n"); printf("Terminating after updates\n");
...@@ -370,6 +380,9 @@ static int run_test(const char *filename) ...@@ -370,6 +380,9 @@ static int run_test(const char *filename)
} }
} }
if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (testflag == 4) if (testflag == 4)
{ {
printf("Terminating after deletes\n"); printf("Terminating after deletes\n");
...@@ -672,6 +685,8 @@ static void update_record(uchar *record) ...@@ -672,6 +685,8 @@ static void update_record(uchar *record)
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
{"checkpoint", 'H', "Checkpoint at specified stage", (uchar**) &checkpoint,
(uchar**) &checkpoint, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"checksum", 'c', "Undocumented", {"checksum", 'c', "Undocumented",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DBUG_OFF #ifndef DBUG_OFF
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "trnman.h" #include "trnman.h"
#include <m_ctype.h> #include <m_ctype.h>
#include <my_bit.h> #include <my_bit.h>
#include "ma_checkpoint.h"
#define STANDARD_LENGTH 37 #define STANDARD_LENGTH 37
#define MARIA_KEYS 6 #define MARIA_KEYS 6
...@@ -51,7 +51,7 @@ static int verbose=0,testflag=0, ...@@ -51,7 +51,7 @@ static int verbose=0,testflag=0,
opt_quick_mode=0, transactional= 0, skip_update= 0, opt_quick_mode=0, transactional= 0, skip_update= 0,
die_in_middle_of_transaction= 0; die_in_middle_of_transaction= 0;
static int pack_seg=HA_SPACE_PACK,pack_type=HA_PACK_KEY,remove_count=-1; static int pack_seg=HA_SPACE_PACK,pack_type=HA_PACK_KEY,remove_count=-1;
static int create_flag= 0, srand_arg= 0; static int create_flag= 0, srand_arg= 0, checkpoint= 0;
static ulong pagecache_size=IO_SIZE*16; static ulong pagecache_size=IO_SIZE*16;
static enum data_file_type record_type= DYNAMIC_RECORD; static enum data_file_type record_type= DYNAMIC_RECORD;
...@@ -98,7 +98,7 @@ int main(int argc, char *argv[]) ...@@ -98,7 +98,7 @@ int main(int argc, char *argv[])
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(0))) (transactional && (trnman_init(0) || ma_checkpoint_init(FALSE))))
{ {
fprintf(stderr, "Error in initialization"); fprintf(stderr, "Error in initialization");
exit(1); exit(1);
...@@ -240,6 +240,8 @@ int main(int argc, char *argv[]) ...@@ -240,6 +240,8 @@ int main(int argc, char *argv[])
maria_begin(file); maria_begin(file);
if (testflag == 1) if (testflag == 1)
goto end; goto end;
if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (!silent) if (!silent)
printf("- Writing key:s\n"); printf("- Writing key:s\n");
if (locking) if (locking)
...@@ -302,6 +304,8 @@ int main(int argc, char *argv[]) ...@@ -302,6 +304,8 @@ int main(int argc, char *argv[])
} }
if (testflag == 2) if (testflag == 2)
goto end; goto end;
if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (write_cacheing) if (write_cacheing)
{ {
...@@ -353,6 +357,8 @@ int main(int argc, char *argv[]) ...@@ -353,6 +357,8 @@ int main(int argc, char *argv[])
} }
if (testflag == 3) if (testflag == 3)
goto end; goto end;
if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (!silent) if (!silent)
printf("- Update\n"); printf("- Update\n");
...@@ -414,6 +420,8 @@ int main(int argc, char *argv[]) ...@@ -414,6 +420,8 @@ int main(int argc, char *argv[])
} }
if (testflag == 4) if (testflag == 4)
goto end; goto end;
if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
for (i=999, dupp_keys=j=0 ; i>0 ; i--) for (i=999, dupp_keys=j=0 ; i>0 ; i--)
{ {
...@@ -824,6 +832,8 @@ int main(int argc, char *argv[]) ...@@ -824,6 +832,8 @@ int main(int argc, char *argv[])
if (testflag == 5) if (testflag == 5)
goto end; goto end;
if (checkpoint == 5 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
goto err;
if (!silent) if (!silent)
printf("- Removing keys\n"); printf("- Removing keys\n");
...@@ -1057,6 +1067,9 @@ static void get_options(int argc, char **argv) ...@@ -1057,6 +1067,9 @@ static void get_options(int argc, char **argv)
if ((first_key=atoi(++pos)) < 0 || first_key >= MARIA_KEYS) if ((first_key=atoi(++pos)) < 0 || first_key >= MARIA_KEYS)
first_key=0; first_key=0;
break; break;
case 'H':
checkpoint= atoi(++pos);
break;
case 'k': case 'k':
if ((keys=(uint) atoi(++pos)) < 1 || if ((keys=(uint) atoi(++pos)) < 1 ||
keys > (uint) (MARIA_KEYS-first_key)) keys > (uint) (MARIA_KEYS-first_key))
......
...@@ -126,16 +126,22 @@ echo "Testing the REDO AND UNDO PHASE" ...@@ -126,16 +126,22 @@ echo "Testing the REDO AND UNDO PHASE"
# Then we run it again and let it exit at T2. Then we compare # Then we run it again and let it exit at T2. Then we compare
# and expect identity. # and expect identity.
for take_checkpoint in "no" "yes"
do
for blobs in "" "-b" # we test table without blobs and then table with blobs for blobs in "" "-b" # we test table without blobs and then table with blobs
do do
for test_undo in 1 2 3 for test_undo in 1 2 3
do do
# first iteration tests rollback of insert, second tests rollback of delete # first iteration tests rollback of insert, second tests rollback of delete
set -- "ma_test1 $silent -M -T -c -N $blobs" "--testflag=1" "--testflag=2 --test-undo=" "ma_test1 $silent -M -T -c -N $blobs" "--testflag=3" "--testflag=4 --test-undo=" "ma_test1 $silent -M -T -c -N $blobs" "--testflag=2" "--testflag=3 --test-undo=" "ma_test2 $silent -L -K -W -P -M -T -c $blobs" "-t1" "-t2 -u" set -- "ma_test1 $silent -M -T -c -N $blobs -H1" "--testflag=1" "--testflag=2 --test-undo=" "ma_test1 $silent -M -T -c -N $blobs -H2" "--testflag=3" "--testflag=4 --test-undo=" "ma_test1 $silent -M -T -c -N $blobs -H2 " "--testflag=2" "--testflag=3 --test-undo=" "ma_test2 $silent -L -K -W -P -M -T -c $blobs -H1" "-t1" "-t2 -u"
# -N (create NULL fields) is needed because --test-undo adds it anyway # -N (create NULL fields) is needed because --test-undo adds it anyway
while [ $# != 0 ] while [ $# != 0 ]
do do
prog=$1 prog=$1
if [ "$take_checkpoint" == "no" ]
then
prog=`echo $prog | sed 's/ -H[0-9]//'`
fi
commit_run_args=$2 commit_run_args=$2
abort_run_args=$3; abort_run_args=$3;
rm -f maria_log.* maria_log_control rm -f maria_log.* maria_log_control
...@@ -192,6 +198,7 @@ do ...@@ -192,6 +198,7 @@ do
rm -f $table.* $tmp/$table* $tmp/maria_chk_*.txt $tmp/maria_read_log_$table.txt rm -f $table.* $tmp/$table* $tmp/maria_chk_*.txt $tmp/maria_read_log_$table.txt
done done
done done
done
) 2>&1 > $tmp/ma_test_recovery.output ) 2>&1 > $tmp/ma_test_recovery.output
......
This diff is collapsed.
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