diff options
Diffstat (limited to 'storage/innobase/include/log0log.ic')
-rw-r--r-- | storage/innobase/include/log0log.ic | 201 |
1 files changed, 116 insertions, 85 deletions
diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index 38ed2b51a4e..a53f8770cea 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -25,27 +25,17 @@ Created 12/9/1995 Heikki Tuuri #include "os0file.h" #include "mach0data.h" -#include "mtr0mtr.h" #include "srv0mon.h" +#include "srv0srv.h" +#include "ut0crc32.h" -#ifdef UNIV_LOG_DEBUG -/******************************************************//** -Checks by parsing that the catenated log segment for a single mtr is -consistent. */ -UNIV_INTERN -ibool -log_check_log_recs( -/*===============*/ - const byte* buf, /*!< in: pointer to the start of - the log segment in the - log_sys->buf log buffer */ - ulint len, /*!< in: segment length in bytes */ - ib_uint64_t buf_start_lsn); /*!< in: buffer start lsn */ -#endif /* UNIV_LOG_DEBUG */ +#ifdef UNIV_LOG_LSN_DEBUG +#include "mtr0types.h" +#endif /* UNIV_LOG_LSN_DEBUG */ /************************************************************//** Gets a log block flush bit. -@return TRUE if this block was the first to be written in a log flush */ +@return TRUE if this block was the first to be written in a log flush */ UNIV_INLINE ibool log_block_get_flush_bit( @@ -85,7 +75,7 @@ log_block_set_flush_bit( /************************************************************//** Gets a log block number stored in the header. -@return log block number stored in the block header */ +@return log block number stored in the block header */ UNIV_INLINE ulint log_block_get_hdr_no( @@ -115,7 +105,7 @@ log_block_set_hdr_no( /************************************************************//** Gets a log block data length. -@return log block data length measured as a byte offset from the block start */ +@return log block data length measured as a byte offset from the block start */ UNIV_INLINE ulint log_block_get_data_len( @@ -164,7 +154,7 @@ log_block_set_first_rec_group( /************************************************************//** Gets a log block checkpoint number field (4 lowest bytes). -@return checkpoint no (4 lowest bytes) */ +@return checkpoint no (4 lowest bytes) */ UNIV_INLINE ulint log_block_get_checkpoint_no( @@ -188,7 +178,7 @@ log_block_set_checkpoint_no( /************************************************************//** Converts a lsn to a log block number. -@return log block number, it is > 0 and <= 1G */ +@return log block number, it is > 0 and <= 1G */ UNIV_INLINE ulint log_block_convert_lsn_to_no( @@ -200,13 +190,24 @@ log_block_convert_lsn_to_no( /************************************************************//** Calculates the checksum for a log block. -@return checksum */ +@return checksum */ UNIV_INLINE ulint log_block_calc_checksum( /*====================*/ const byte* block) /*!< in: log block */ { + return(log_checksum_algorithm_ptr(block)); +} + +/** Calculate the checksum for a log block using the pre-5.7.9 algorithm. +@param[in] block log block +@return checksum */ +UNIV_INLINE +ulint +log_block_calc_checksum_format_0( + const byte* block) +{ ulint sum; ulint sh; ulint i; @@ -228,9 +229,31 @@ log_block_calc_checksum( return(sum); } +/** Calculate the checksum for a log block using the MySQL 5.7 algorithm. +@param[in] block log block +@return checksum */ +UNIV_INLINE +ulint +log_block_calc_checksum_crc32( + const byte* block) +{ + return(ut_crc32(block, OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE)); +} + +/** Calculates the checksum for a log block using the "no-op" algorithm. +@param[in] block log block +@return checksum */ +UNIV_INLINE +ulint +log_block_calc_checksum_none( + const byte* block) +{ + return(LOG_NO_CHECKSUM_MAGIC); +} + /************************************************************//** Gets a log block checksum field value. -@return checksum */ +@return checksum */ UNIV_INLINE ulint log_block_get_checksum( @@ -266,8 +289,6 @@ log_block_init( { ulint no; - ut_ad(mutex_own(&(log_sys->mutex))); - no = log_block_convert_lsn_to_no(lsn); log_block_set_hdr_no(log_block, no); @@ -276,6 +297,7 @@ log_block_init( log_block_set_first_rec_group(log_block, 0); } +#ifdef UNIV_HOTBACKUP /************************************************************//** Initializes a log block in the log buffer in the old format, where there was no checksum yet. */ @@ -288,7 +310,7 @@ log_block_init_in_old_format( { ulint no; - ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(log_mutex_own()); no = log_block_convert_lsn_to_no(lsn); @@ -298,34 +320,47 @@ log_block_init_in_old_format( log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE); log_block_set_first_rec_group(log_block, 0); } +#endif /* UNIV_HOTBACKUP */ #ifndef UNIV_HOTBACKUP -/************************************************************//** -Writes to the log the string given. The log must be released with -log_release. -@return end lsn of the log record, zero if did not succeed */ +/** Append a string to the log. +@param[in] str string +@param[in] len string length +@param[out] start_lsn start LSN of the log record +@return end lsn of the log record, zero if did not succeed */ UNIV_INLINE lsn_t log_reserve_and_write_fast( -/*=======================*/ - const void* str, /*!< in: string */ - ulint len, /*!< in: string length */ - lsn_t* start_lsn)/*!< out: start lsn of the log record */ + const void* str, + ulint len, + lsn_t* start_lsn) { - ulint data_len; -#ifdef UNIV_LOG_LSN_DEBUG - /* length of the LSN pseudo-record */ - ulint lsn_len; -#endif /* UNIV_LOG_LSN_DEBUG */ + ut_ad(log_mutex_own()); + ut_ad(len > 0); - mutex_enter(&log_sys->mutex); #ifdef UNIV_LOG_LSN_DEBUG - lsn_len = 1 + /* Append a MLOG_LSN record after mtr_commit(), except when + the last bytes could be a MLOG_CHECKPOINT marker. We have special + handling when the log consists of only a single MLOG_CHECKPOINT + record since the latest checkpoint, and appending the + MLOG_LSN would ruin that. + + Note that a longer redo log record could happen to end in what + looks like MLOG_CHECKPOINT, and we could be omitting MLOG_LSN + without reason. This is OK, because writing the MLOG_LSN is + just a 'best effort', aimed at finding log corruption due to + bugs in the redo log writing logic. */ + const ulint lsn_len + = len >= SIZE_OF_MLOG_CHECKPOINT + && MLOG_CHECKPOINT == static_cast<const char*>(str)[ + len - SIZE_OF_MLOG_CHECKPOINT] + ? 0 + : 1 + mach_get_compressed_size(log_sys->lsn >> 32) + mach_get_compressed_size(log_sys->lsn & 0xFFFFFFFFUL); #endif /* UNIV_LOG_LSN_DEBUG */ - data_len = len + const ulint data_len = len #ifdef UNIV_LOG_LSN_DEBUG + lsn_len #endif /* UNIV_LOG_LSN_DEBUG */ @@ -336,39 +371,37 @@ log_reserve_and_write_fast( /* The string does not fit within the current log block or the log block would become full */ - mutex_exit(&log_sys->mutex); - return(0); } *start_lsn = log_sys->lsn; #ifdef UNIV_LOG_LSN_DEBUG - { + if (lsn_len) { /* Write the LSN pseudo-record. */ byte* b = &log_sys->buf[log_sys->buf_free]; + *b++ = MLOG_LSN | (MLOG_SINGLE_REC_FLAG & *(const byte*) str); + /* Write the LSN in two parts, as a pseudo page number and space id. */ b += mach_write_compressed(b, log_sys->lsn >> 32); b += mach_write_compressed(b, log_sys->lsn & 0xFFFFFFFFUL); ut_a(b - lsn_len == &log_sys->buf[log_sys->buf_free]); - memcpy(b, str, len); + ::memcpy(b, str, len); + len += lsn_len; - } -#else /* UNIV_LOG_LSN_DEBUG */ - memcpy(log_sys->buf + log_sys->buf_free, str, len); + } else #endif /* UNIV_LOG_LSN_DEBUG */ + memcpy(log_sys->buf + log_sys->buf_free, str, len); + + log_block_set_data_len( + reinterpret_cast<byte*>(ut_align_down( + log_sys->buf + log_sys->buf_free, + OS_FILE_LOG_BLOCK_SIZE)), + data_len); - log_block_set_data_len((byte*) ut_align_down(log_sys->buf - + log_sys->buf_free, - OS_FILE_LOG_BLOCK_SIZE), - data_len); -#ifdef UNIV_LOG_DEBUG - log_sys->old_buf_free = log_sys->buf_free; - log_sys->old_lsn = log_sys->lsn; -#endif log_sys->buf_free += len; ut_ad(log_sys->buf_free <= log_sys->buf_size); @@ -378,27 +411,12 @@ log_reserve_and_write_fast( MONITOR_SET(MONITOR_LSN_CHECKPOINT_AGE, log_sys->lsn - log_sys->last_checkpoint_lsn); -#ifdef UNIV_LOG_DEBUG - log_check_log_recs(log_sys->buf + log_sys->old_buf_free, - log_sys->buf_free - log_sys->old_buf_free, - log_sys->old_lsn); -#endif return(log_sys->lsn); } -/***********************************************************************//** -Releases the log mutex. */ -UNIV_INLINE -void -log_release(void) -/*=============*/ -{ - mutex_exit(&(log_sys->mutex)); -} - /************************************************************//** Gets the current lsn. -@return current lsn */ +@return current lsn */ UNIV_INLINE lsn_t log_get_lsn(void) @@ -406,11 +424,11 @@ log_get_lsn(void) { lsn_t lsn; - mutex_enter(&(log_sys->mutex)); + log_mutex_enter(); lsn = log_sys->lsn; - mutex_exit(&(log_sys->mutex)); + log_mutex_exit(); return(lsn); } @@ -421,15 +439,14 @@ Gets the last lsn that is fully flushed to disk. UNIV_INLINE ib_uint64_t log_get_flush_lsn(void) -/*=============*/ { ib_uint64_t lsn; - mutex_enter(&(log_sys->mutex)); + log_mutex_enter(); lsn = log_sys->flushed_to_disk_lsn; - mutex_exit(&(log_sys->mutex)); + log_mutex_exit(); return(lsn); } @@ -440,7 +457,7 @@ Gets the current lsn with a trylock UNIV_INLINE lsn_t log_get_lsn_nowait(void) -/*=============*/ +/*====================*/ { lsn_t lsn=0; @@ -457,7 +474,7 @@ log_get_lsn_nowait(void) /**************************************************************** Gets the log group capacity. It is OK to read the value without holding log_sys->mutex because it is constant. -@return log group capacity */ +@return log group capacity */ UNIV_INLINE lsn_t log_get_capacity(void) @@ -469,7 +486,7 @@ log_get_capacity(void) /**************************************************************** Get log_sys::max_modified_age_async. It is OK to read the value without holding log_sys::mutex because it is constant. -@return max_modified_age_async */ +@return max_modified_age_async */ UNIV_INLINE lsn_t log_get_max_modified_age_async(void) @@ -488,10 +505,24 @@ void log_free_check(void) /*================*/ { - -#ifdef UNIV_SYNC_DEBUG - ut_ad(sync_thread_levels_empty_except_dict()); -#endif /* UNIV_SYNC_DEBUG */ +#ifdef UNIV_DEBUG + /* During row_log_table_apply(), this function will be called while we + are holding some latches. This is OK, as long as we are not holding + any latches on buffer blocks. */ + + static const latch_level_t latches[] = { + SYNC_DICT, /* dict_sys->mutex during + commit_try_rebuild() */ + SYNC_DICT_OPERATION, /* dict_operation_lock X-latch during + commit_try_rebuild() */ + SYNC_INDEX_TREE /* index->lock */ + }; + + sync_allowed_latches check( + latches, latches + sizeof(latches)/sizeof(*latches)); + + ut_ad(!sync_check_iterate(check)); +#endif /* UNIV_DEBUG */ if (log_sys->check_flush_or_checkpoint) { |