diff options
Diffstat (limited to 'storage/xtradb/log/log0log.c')
-rw-r--r-- | storage/xtradb/log/log0log.c | 126 |
1 files changed, 124 insertions, 2 deletions
diff --git a/storage/xtradb/log/log0log.c b/storage/xtradb/log/log0log.c index dcaf951a0ed..e3e023c0c5a 100644 --- a/storage/xtradb/log/log0log.c +++ b/storage/xtradb/log/log0log.c @@ -216,6 +216,54 @@ log_buf_pool_get_oldest_modification(void) return(lsn); } +/****************************************************************//** +Safely reads the log_sys->tracked_lsn value. Uses atomic operations +if available, otherwise this field is protected with the log system +mutex. The writer counterpart function is log_set_tracked_lsn() in +log0online.c. + +@return log_sys->tracked_lsn value. */ +UNIV_INLINE +ib_uint64_t +log_get_tracked_lsn() +{ +#ifdef HAVE_ATOMIC_BUILTINS_64 + return os_atomic_increment_uint64(&log_sys->tracked_lsn, 0); +#else + ut_ad(mutex_own(&(log_sys->mutex))); + return log_sys->tracked_lsn; +#endif +} + +/****************************************************************//** +Checks if the log groups have a big enough margin of free space in +so that a new log entry can be written without overwriting log data +that is not read by the changed page bitmap thread. +@return TRUE if there is not enough free space. */ +static +ibool +log_check_tracking_margin( + ulint lsn_advance) /*!< in: an upper limit on how much log data we + plan to write. If zero, the margin will be + checked for the already-written log. */ +{ + ib_uint64_t tracked_lsn; + ulint tracked_lsn_age; + + if (!srv_track_changed_pages) { + return FALSE; + } + + ut_ad(mutex_own(&(log_sys->mutex))); + + tracked_lsn = log_get_tracked_lsn(); + tracked_lsn_age = log_sys->lsn - tracked_lsn; + + /* The overwrite would happen when log_sys->log_group_capacity is + exceeded, but we use max_checkpoint_age for an extra safety margin. */ + return tracked_lsn_age + lsn_advance > log_sys->max_checkpoint_age; +} + /************************************************************//** Opens the log for log_write_low. The log must be closed with log_close and released with log_release. @@ -232,9 +280,7 @@ log_reserve_and_open( ulint archived_lsn_age; ulint dummy; #endif /* UNIV_LOG_ARCHIVE */ -#ifdef UNIV_DEBUG ulint count = 0; -#endif /* UNIV_DEBUG */ ut_a(len < log->buf_size / 2); loop: @@ -262,6 +308,19 @@ loop: goto loop; } + if (log_check_tracking_margin(len_upper_limit) && (++count < 50)) { + + /* This log write would violate the untracked LSN free space + margin. Limit this to 50 retries as there might be situations + where we have no choice but to proceed anyway, i.e. if the log + is about to be overflown, log tracking or not. */ + mutex_exit(&(log->mutex)); + + os_thread_sleep(10000); + + goto loop; + } + #ifdef UNIV_LOG_ARCHIVE if (log->archiving_state != LOG_ARCH_OFF) { @@ -400,6 +459,8 @@ log_close(void) ulint first_rec_group; ib_uint64_t oldest_lsn; ib_uint64_t lsn; + ib_uint64_t tracked_lsn; + ulint tracked_lsn_age; log_t* log = log_sys; ib_uint64_t checkpoint_age; @@ -426,6 +487,19 @@ log_close(void) log->check_flush_or_checkpoint = TRUE; } + if (srv_track_changed_pages) { + + tracked_lsn = log_get_tracked_lsn(); + tracked_lsn_age = lsn - tracked_lsn; + + if (tracked_lsn_age >= log->log_group_capacity) { + + fprintf(stderr, " InnoDB: Error: the age of the " + "oldest untracked record exceeds the log " + "group capacity!\n"); + } + } + checkpoint_age = lsn - log->last_checkpoint_lsn; if (checkpoint_age >= log->log_group_capacity) { @@ -893,6 +967,8 @@ log_init(void) log_sys->archiving_on = os_event_create(NULL); #endif /* UNIV_LOG_ARCHIVE */ + log_sys->tracked_lsn = 0; + /*----------------------------*/ log_block_init(log_sys->buf, log_sys->lsn); @@ -1742,6 +1818,12 @@ log_io_complete_checkpoint(void) } mutex_exit(&(log_sys->mutex)); + + /* Wake the redo log watching thread to parse the log up to this + checkpoint. */ + if (srv_track_changed_pages) { + os_event_set(srv_checkpoint_completed_event); + } } /*******************************************************************//** @@ -3169,6 +3251,15 @@ loop: log_checkpoint_margin(); + mutex_enter(&(log_sys->mutex)); + if (log_check_tracking_margin(0)) { + + mutex_exit(&(log_sys->mutex)); + os_thread_sleep(10000); + goto loop; + } + mutex_exit(&(log_sys->mutex)); + #ifdef UNIV_LOG_ARCHIVE log_archive_margin(); #endif /* UNIV_LOG_ARCHIVE */ @@ -3197,6 +3288,7 @@ logs_empty_and_mark_files_at_shutdown(void) /*=======================================*/ { ib_uint64_t lsn; + ib_uint64_t tracked_lsn; ulint arch_log_no; ibool server_busy; ulint count = 0; @@ -3388,6 +3480,12 @@ loop: } srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE; + /* Wake the log tracking thread which will then immediatelly + quit because of srv_shutdown_state value */ + if (srv_track_changed_pages) { + os_event_set(srv_checkpoint_completed_event); + os_event_wait(srv_redo_log_thread_finished_event); + } fil_close_all_files(); ut_a(srv_get_active_thread_type() == ULINT_UNDEFINED); return; @@ -3397,9 +3495,12 @@ loop: mutex_enter(&log_sys->mutex); + tracked_lsn = log_get_tracked_lsn(); + lsn = log_sys->lsn; if (lsn != log_sys->last_checkpoint_lsn + || (srv_track_changed_pages && (tracked_lsn != log_sys->last_checkpoint_lsn)) #ifdef UNIV_LOG_ARCHIVE || (srv_log_archive_on && lsn != log_sys->archived_lsn + LOG_BLOCK_HDR_SIZE) @@ -3457,6 +3558,11 @@ loop: srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE; + /* Signal the log following thread to quit */ + if (srv_track_changed_pages) { + os_event_set(srv_checkpoint_completed_event); + } + /* Make some checks that the server really is quiet */ ut_a(srv_get_active_thread_type() == ULINT_UNDEFINED); @@ -3477,6 +3583,10 @@ loop: fil_flush_file_spaces(FIL_TABLESPACE); + if (srv_track_changed_pages) { + os_event_wait(srv_redo_log_thread_finished_event); + } + fil_close_all_files(); /* Make some checks that the server really is quiet */ @@ -3603,6 +3713,18 @@ log_print( ((log_sys->n_log_ios - log_sys->n_log_ios_old) / time_elapsed)); + if (srv_track_changed_pages) { + + /* The maximum tracked LSN age is equal to the maximum + checkpoint age */ + fprintf(file, + "Log tracking enabled\n" + "Log tracked up to %llu\n" + "Max tracked LSN age %lu\n", + log_get_tracked_lsn(), + log_sys->max_checkpoint_age); + } + log_sys->n_log_ios_old = log_sys->n_log_ios; log_sys->last_printout_time = current_time; |