mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
0ebb78e8ef
Merge InnoDB-3.23.52c ha_innobase.cc: Test the ref length sanity also in the production version sql/ha_innobase.cc: Test the ref length sanity also in the production version innobase/btr/btr0cur.c: Merge InnoDB-3.23.52c innobase/buf/buf0buf.c: Merge InnoDB-3.23.52c innobase/buf/buf0lru.c: Merge InnoDB-3.23.52c innobase/ha/ha0ha.c: Merge InnoDB-3.23.52c innobase/log/log0recv.c: Merge InnoDB-3.23.52c innobase/mtr/mtr0log.c: Merge InnoDB-3.23.52c innobase/os/os0file.c: Merge InnoDB-3.23.52c innobase/page/page0cur.c: Merge InnoDB-3.23.52c innobase/include/btr0btr.h: Merge InnoDB-3.23.52c innobase/include/dyn0dyn.h: Merge InnoDB-3.23.52c innobase/include/log0recv.h: Merge InnoDB-3.23.52c innobase/include/buf0buf.ic: Merge InnoDB-3.23.52c innobase/include/log0log.ic: Merge InnoDB-3.23.52c
428 lines
10 KiB
Text
428 lines
10 KiB
Text
/******************************************************
|
|
Database log
|
|
|
|
(c) 1995 Innobase Oy
|
|
|
|
Created 12/9/1995 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#include "os0file.h"
|
|
#include "mach0data.h"
|
|
#include "mtr0mtr.h"
|
|
|
|
/**********************************************************
|
|
Checks by parsing that the catenated log segment for a single mtr is
|
|
consistent. */
|
|
|
|
ibool
|
|
log_check_log_recs(
|
|
/*===============*/
|
|
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 */
|
|
dulint buf_start_lsn); /* in: buffer start lsn */
|
|
|
|
/****************************************************************
|
|
Gets a log block flush bit. */
|
|
UNIV_INLINE
|
|
ibool
|
|
log_block_get_flush_bit(
|
|
/*====================*/
|
|
/* out: TRUE if this block was the first
|
|
to be written in a log flush */
|
|
byte* log_block) /* in: log block */
|
|
{
|
|
if (LOG_BLOCK_FLUSH_BIT_MASK
|
|
& mach_read_from_4(log_block + LOG_BLOCK_HDR_NO)) {
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/****************************************************************
|
|
Sets the log block flush bit. */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_set_flush_bit(
|
|
/*====================*/
|
|
byte* log_block, /* in: log block */
|
|
ibool val) /* in: value to set */
|
|
{
|
|
ulint field;
|
|
|
|
field = mach_read_from_4(log_block + LOG_BLOCK_HDR_NO);
|
|
|
|
if (val) {
|
|
field = field | LOG_BLOCK_FLUSH_BIT_MASK;
|
|
} else {
|
|
field = field & ~LOG_BLOCK_FLUSH_BIT_MASK;
|
|
}
|
|
|
|
mach_write_to_4(log_block + LOG_BLOCK_HDR_NO, field);
|
|
}
|
|
|
|
/****************************************************************
|
|
Gets a log block number stored in the header. */
|
|
UNIV_INLINE
|
|
ulint
|
|
log_block_get_hdr_no(
|
|
/*=================*/
|
|
/* out: log block number stored in the block
|
|
header */
|
|
byte* log_block) /* in: log block */
|
|
{
|
|
return(~LOG_BLOCK_FLUSH_BIT_MASK
|
|
& mach_read_from_4(log_block + LOG_BLOCK_HDR_NO));
|
|
}
|
|
|
|
/****************************************************************
|
|
Sets the log block number stored in the header; NOTE that this must be set
|
|
before the flush bit! */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_set_hdr_no(
|
|
/*=================*/
|
|
byte* log_block, /* in: log block */
|
|
ulint n) /* in: log block number: must be > 0 and
|
|
< LOG_BLOCK_FLUSH_BIT_MASK */
|
|
{
|
|
ut_ad(n > 0);
|
|
ut_ad(n < LOG_BLOCK_FLUSH_BIT_MASK);
|
|
|
|
mach_write_to_4(log_block + LOG_BLOCK_HDR_NO, n);
|
|
}
|
|
|
|
/****************************************************************
|
|
Gets a log block data length. */
|
|
UNIV_INLINE
|
|
ulint
|
|
log_block_get_data_len(
|
|
/*===================*/
|
|
/* out: log block data length measured as a
|
|
byte offset from the block start */
|
|
byte* log_block) /* in: log block */
|
|
{
|
|
return(mach_read_from_2(log_block + LOG_BLOCK_HDR_DATA_LEN));
|
|
}
|
|
|
|
/****************************************************************
|
|
Sets the log block data length. */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_set_data_len(
|
|
/*===================*/
|
|
byte* log_block, /* in: log block */
|
|
ulint len) /* in: data length */
|
|
{
|
|
mach_write_to_2(log_block + LOG_BLOCK_HDR_DATA_LEN, len);
|
|
}
|
|
|
|
/****************************************************************
|
|
Gets a log block first mtr log record group offset. */
|
|
UNIV_INLINE
|
|
ulint
|
|
log_block_get_first_rec_group(
|
|
/*==========================*/
|
|
/* out: first mtr log record group byte offset
|
|
from the block start, 0 if none */
|
|
byte* log_block) /* in: log block */
|
|
{
|
|
return(mach_read_from_2(log_block + LOG_BLOCK_FIRST_REC_GROUP));
|
|
}
|
|
|
|
/****************************************************************
|
|
Sets the log block first mtr log record group offset. */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_set_first_rec_group(
|
|
/*==========================*/
|
|
byte* log_block, /* in: log block */
|
|
ulint offset) /* in: offset, 0 if none */
|
|
{
|
|
mach_write_to_2(log_block + LOG_BLOCK_FIRST_REC_GROUP, offset);
|
|
}
|
|
|
|
/****************************************************************
|
|
Gets a log block checkpoint number field (4 lowest bytes). */
|
|
UNIV_INLINE
|
|
ulint
|
|
log_block_get_checkpoint_no(
|
|
/*========================*/
|
|
/* out: checkpoint no (4 lowest bytes) */
|
|
byte* log_block) /* in: log block */
|
|
{
|
|
return(mach_read_from_4(log_block + LOG_BLOCK_CHECKPOINT_NO));
|
|
}
|
|
|
|
/****************************************************************
|
|
Sets a log block checkpoint number field (4 lowest bytes). */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_set_checkpoint_no(
|
|
/*========================*/
|
|
byte* log_block, /* in: log block */
|
|
dulint no) /* in: checkpoint no */
|
|
{
|
|
mach_write_to_4(log_block + LOG_BLOCK_CHECKPOINT_NO,
|
|
ut_dulint_get_low(no));
|
|
}
|
|
|
|
/****************************************************************
|
|
Converts a lsn to a log block number. */
|
|
UNIV_INLINE
|
|
ulint
|
|
log_block_convert_lsn_to_no(
|
|
/*========================*/
|
|
/* out: log block number, it is > 0 and <= 1G */
|
|
dulint lsn) /* in: lsn of a byte within the block */
|
|
{
|
|
ulint no;
|
|
|
|
no = ut_dulint_get_low(lsn) / OS_FILE_LOG_BLOCK_SIZE;
|
|
no += (ut_dulint_get_high(lsn) % OS_FILE_LOG_BLOCK_SIZE)
|
|
* 2 * (0x80000000 / OS_FILE_LOG_BLOCK_SIZE);
|
|
|
|
no = no & 0x3FFFFFFF;
|
|
|
|
return(no + 1);
|
|
}
|
|
|
|
/****************************************************************
|
|
Calculates the checksum for a log block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
log_block_calc_checksum(
|
|
/*====================*/
|
|
/* out: checksum */
|
|
byte* block) /* in: log block */
|
|
{
|
|
ulint sum;
|
|
ulint sh;
|
|
ulint i;
|
|
|
|
sum = 1;
|
|
sh = 0;
|
|
|
|
for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
|
|
sum = sum & 0x7FFFFFFF;
|
|
sum += (((ulint)(*(block + i))) << sh) + (ulint)(*(block + i));
|
|
sh++;
|
|
if (sh > 24) {
|
|
sh = 0;
|
|
}
|
|
}
|
|
|
|
return(sum);
|
|
}
|
|
|
|
/****************************************************************
|
|
Gets a log block checksum field value. */
|
|
UNIV_INLINE
|
|
ulint
|
|
log_block_get_checksum(
|
|
/*===================*/
|
|
/* out: checksum */
|
|
byte* log_block) /* in: log block */
|
|
{
|
|
return(mach_read_from_4(log_block + OS_FILE_LOG_BLOCK_SIZE
|
|
- LOG_BLOCK_CHECKSUM));
|
|
}
|
|
|
|
/****************************************************************
|
|
Sets a log block checksum field value. */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_set_checksum(
|
|
/*===================*/
|
|
byte* log_block, /* in: log block */
|
|
ulint checksum) /* in: checksum */
|
|
{
|
|
mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE
|
|
- LOG_BLOCK_CHECKSUM,
|
|
checksum);
|
|
}
|
|
|
|
/****************************************************************
|
|
Initializes a log block in the log buffer. */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_init(
|
|
/*===========*/
|
|
byte* log_block, /* in: pointer to the log buffer */
|
|
dulint lsn) /* in: lsn within the log block */
|
|
{
|
|
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);
|
|
|
|
log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE);
|
|
log_block_set_first_rec_group(log_block, 0);
|
|
}
|
|
|
|
/****************************************************************
|
|
Initializes a log block in the log buffer in the old format, where there
|
|
was no checksum yet. */
|
|
UNIV_INLINE
|
|
void
|
|
log_block_init_in_old_format(
|
|
/*=========================*/
|
|
byte* log_block, /* in: pointer to the log buffer */
|
|
dulint lsn) /* in: lsn within the log block */
|
|
{
|
|
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);
|
|
mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE
|
|
- LOG_BLOCK_CHECKSUM, no);
|
|
log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE);
|
|
log_block_set_first_rec_group(log_block, 0);
|
|
}
|
|
|
|
/****************************************************************
|
|
Writes to the log the string given. The log must be released with
|
|
log_release. */
|
|
UNIV_INLINE
|
|
dulint
|
|
log_reserve_and_write_fast(
|
|
/*=======================*/
|
|
/* out: end lsn of the log record, ut_dulint_zero if
|
|
did not succeed */
|
|
byte* str, /* in: string */
|
|
ulint len, /* in: string length */
|
|
dulint* start_lsn,/* out: start lsn of the log record */
|
|
ibool* success)/* out: TRUE if success */
|
|
{
|
|
log_t* log = log_sys;
|
|
ulint data_len;
|
|
dulint lsn;
|
|
|
|
*success = TRUE;
|
|
|
|
mutex_enter(&(log->mutex));
|
|
|
|
data_len = len + log->buf_free % OS_FILE_LOG_BLOCK_SIZE;
|
|
|
|
if (log->online_backup_state
|
|
|| (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE)) {
|
|
|
|
/* The string does not fit within the current log block
|
|
or the log block would become full */
|
|
|
|
*success = FALSE;
|
|
|
|
mutex_exit(&(log->mutex));
|
|
|
|
return(ut_dulint_zero);
|
|
}
|
|
|
|
*start_lsn = log->lsn;
|
|
|
|
ut_memcpy(log->buf + log->buf_free, str, len);
|
|
|
|
log_block_set_data_len(ut_align_down(log->buf + log->buf_free,
|
|
OS_FILE_LOG_BLOCK_SIZE),
|
|
data_len);
|
|
#ifdef UNIV_LOG_DEBUG
|
|
log->old_buf_free = log->buf_free;
|
|
log->old_lsn = log->lsn;
|
|
#endif
|
|
log->buf_free += len;
|
|
|
|
ut_ad(log->buf_free <= log->buf_size);
|
|
|
|
lsn = ut_dulint_add(log->lsn, len);
|
|
|
|
log->lsn = lsn;
|
|
|
|
#ifdef UNIV_LOG_DEBUG
|
|
log_check_log_recs(log->buf + log->old_buf_free,
|
|
log->buf_free - log->old_buf_free, log->old_lsn);
|
|
#endif
|
|
return(lsn);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Releases the log mutex. */
|
|
UNIV_INLINE
|
|
void
|
|
log_release(void)
|
|
/*=============*/
|
|
{
|
|
mutex_exit(&(log_sys->mutex));
|
|
}
|
|
|
|
/****************************************************************
|
|
Gets the current lsn. */
|
|
UNIV_INLINE
|
|
dulint
|
|
log_get_lsn(void)
|
|
/*=============*/
|
|
/* out: current lsn */
|
|
{
|
|
dulint lsn;
|
|
|
|
mutex_enter(&(log_sys->mutex));
|
|
|
|
lsn = log_sys->lsn;
|
|
|
|
mutex_exit(&(log_sys->mutex));
|
|
|
|
return(lsn);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Checks if there is need for a log buffer flush or a new checkpoint, and does
|
|
this if yes. Any database operation should call this when it has modified
|
|
more than about 4 pages. NOTE that this function may only be called when the
|
|
OS thread owns no synchronization objects except the dictionary mutex. */
|
|
UNIV_INLINE
|
|
void
|
|
log_free_check(void)
|
|
/*================*/
|
|
{
|
|
/* ut_ad(sync_thread_levels_empty()); */
|
|
|
|
if (log_sys->check_flush_or_checkpoint) {
|
|
|
|
log_check_margins();
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Gets the online backup lsn. */
|
|
UNIV_INLINE
|
|
dulint
|
|
log_get_online_backup_lsn_low(void)
|
|
/*===============================*/
|
|
/* out: online_backup_lsn, the caller must
|
|
own the log_sys mutex */
|
|
{
|
|
ut_ad(mutex_own(&(log_sys->mutex)));
|
|
ut_ad(log_sys->online_backup_state);
|
|
|
|
return(log_sys->online_backup_lsn);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Gets the online backup state. */
|
|
UNIV_INLINE
|
|
ibool
|
|
log_get_online_backup_state_low(void)
|
|
/*=================================*/
|
|
/* out: online backup state, the caller must
|
|
own the log_sys mutex */
|
|
{
|
|
ut_ad(mutex_own(&(log_sys->mutex)));
|
|
|
|
return(log_sys->online_backup_state);
|
|
}
|