Many files:

  Merge InnoDB-3.23.52c
ha_innobase.cc:
  Test the ref length sanity also in the production version
parent 4f56ed82
......@@ -808,7 +808,7 @@ btr_cur_optimistic_insert(
if (!dtuple_check_typed_no_assert(entry)) {
fprintf(stderr,
"InnoDB: Error in a tuple to insert into table %s index %s\n",
"InnoDB: Error in a tuple to insert into table %lu index %s\n",
index->table_name, index->name);
}
......@@ -1213,6 +1213,8 @@ btr_cur_parse_update_in_place(
rec_offset = mach_read_from_2(ptr);
ptr += 2;
ut_a(rec_offset <= UNIV_PAGE_SIZE);
heap = mem_heap_create(256);
ptr = row_upd_index_parse(ptr, end_ptr, heap, &update);
......@@ -1977,6 +1979,8 @@ btr_cur_parse_del_mark_set_clust_rec(
offset = mach_read_from_2(ptr);
ptr += 2;
ut_a(offset <= UNIV_PAGE_SIZE);
if (page) {
rec = page + offset;
......@@ -2127,6 +2131,8 @@ btr_cur_parse_del_mark_set_sec_rec(
offset = mach_read_from_2(ptr);
ptr += 2;
ut_a(offset <= UNIV_PAGE_SIZE);
if (page) {
rec = page + offset;
......
......@@ -286,7 +286,7 @@ buf_page_print(
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Page dump in ascii and hex (%lu bytes):\n%s",
(unsigned long) UNIV_PAGE_SIZE, buf);
(ulint)UNIV_PAGE_SIZE, buf);
fprintf(stderr, "InnoDB: End of page dump\n");
mem_free(buf);
......
......@@ -204,6 +204,44 @@ buf_LRU_get_free_block(void)
loop:
mutex_enter(&(buf_pool->mutex));
if (UT_LIST_GET_LEN(buf_pool->free)
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 10) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: ERROR: over 9 / 10 of the buffer pool is occupied by\n"
"InnoDB: lock heaps or the adaptive hash index!\n"
"InnoDB: We intentionally generate a seg fault to print a stack trace\n"
"InnoDB: on Linux!\n");
ut_a(0);
} else if (UT_LIST_GET_LEN(buf_pool->free)
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) {
/* Over 80 % of the buffer pool is occupied by lock heaps
or the adaptive hash index. This may be a memory leak! */
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n"
"InnoDB: lock heaps or the adaptive hash index! Check that your\n"
"InnoDB: transactions do not set too many row locks. Starting InnoDB\n"
"InnoDB: Monitor to print diagnostics, including lock heap and hash index\n"
"InnoDB: sizes.\n");
srv_print_innodb_monitor = TRUE;
} else if (UT_LIST_GET_LEN(buf_pool->free)
+ UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) {
/* Switch off the InnoDB Monitor; this is a simple way
to stop the monitor if the situation becomes less urgent,
but may also surprise users! */
srv_print_innodb_monitor = FALSE;
}
if (buf_pool->LRU_flush_ended > 0) {
mutex_exit(&(buf_pool->mutex));
......
......@@ -298,6 +298,7 @@ ha_print_info(
ulint cells = 0;
ulint len = 0;
ulint max_len = 0;
ulint n_bufs;
ulint i;
if (buf_end - buf < 200) {
......@@ -339,7 +340,16 @@ ha_print_info(
"Hash table size %lu, used cells %lu", hash_get_n_cells(table), cells);
if (table->heaps == NULL && table->heap != NULL) {
buf += sprintf(buf,
", node heap has %lu buffer(s)\n", UT_LIST_GET_LEN(table->heap->base));
/* This calculation is intended for the adaptive hash
index: how many buffer frames we have reserved? */
n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
if (table->heap->free_block) {
n_bufs++;
}
buf += sprintf(buf, ", node heap has %lu buffer(s)\n", n_bufs);
}
}
......@@ -313,14 +313,6 @@ btr_discard_page(
btr_cur_t* cursor, /* in: cursor on the page to discard: not on
the root page */
mtr_t* mtr); /* in: mtr */
/************************************************************************
Declares the latching order level for the page latch in the debug version. */
void
btr_declare_page_latch(
/*===================*/
page_t* page, /* in: page */
ibool leaf); /* in: TRUE if a leaf */
/********************************************************************
Parses the redo log record for setting an index record as the predefined
minimum record. */
......
......@@ -211,8 +211,15 @@ buf_block_align(
block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero))
>> UNIV_PAGE_SIZE_SHIFT);
ut_a(block >= buf_pool->blocks);
ut_a(block < buf_pool->blocks + buf_pool->max_size);
if (block < buf_pool->blocks
|| block >= buf_pool->blocks + buf_pool->max_size) {
fprintf(stderr,
"InnoDB: Error: trying to access a stray pointer %lx\n"
"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr,
(ulint)frame_zero, buf_pool->max_size);
ut_a(0);
}
return(block);
}
......@@ -238,8 +245,15 @@ buf_block_align_low(
block = buf_pool_get_nth_block(buf_pool, ((ulint)(ptr - frame_zero))
>> UNIV_PAGE_SIZE_SHIFT);
ut_a(block >= buf_pool->blocks);
ut_a(block < buf_pool->blocks + buf_pool->max_size);
if (block < buf_pool->blocks
|| block >= buf_pool->blocks + buf_pool->max_size) {
fprintf(stderr,
"InnoDB: Error: trying to access a stray pointer %lx\n"
"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr,
(ulint)frame_zero, buf_pool->max_size);
ut_a(0);
}
return(block);
}
......@@ -259,10 +273,17 @@ buf_frame_align(
frame = ut_align_down(ptr, UNIV_PAGE_SIZE);
ut_a((ulint)frame
>= (ulint)(buf_pool_get_nth_block(buf_pool, 0)->frame));
ut_a((ulint)frame <= (ulint)(buf_pool_get_nth_block(buf_pool,
buf_pool->max_size - 1)->frame));
if (((ulint)frame
< (ulint)(buf_pool->frame_zero))
|| ((ulint)frame > (ulint)(buf_pool_get_nth_block(buf_pool,
buf_pool->max_size - 1)->frame))) {
fprintf(stderr,
"InnoDB: Error: trying to access a stray pointer %lx\n"
"InnoDB: buf pool start is at %lx, number of pages %lu\n", (ulint)ptr,
(ulint)(buf_pool->frame_zero), buf_pool->max_size);
ut_a(0);
}
return(frame);
}
......
......@@ -125,14 +125,6 @@ dyn_block_get_data(
/*===============*/
/* out: pointer to data */
dyn_block_t* block); /* in: dyn array block */
/************************************************************************
Gets the next block in a dyn array. */
dyn_block_t*
dyn_block_get_next(
/*===============*/
/* out: pointer to next, NULL if end of list */
dyn_block_t* block); /* in: dyn array block */
/************************************************************
Pushes n bytes to a dyn array. */
UNIV_INLINE
......
......@@ -207,7 +207,7 @@ log_block_calc_checksum(
for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) {
sum = sum & 0x7FFFFFFF;
sum += ((ulint)(*(block + i))) << sh;
sum += (((ulint)(*(block + i))) << sh) + (ulint)(*(block + i));
sh++;
if (sh > 24) {
sh = 0;
......
......@@ -316,7 +316,8 @@ struct recv_sys_struct{
ibool found_corrupt_log;
/* this is set to TRUE if we during log
scan find a corrupt log block, or a corrupt
log record */
log record, or there is a log parsing
buffer overflow */
log_group_t* archive_group;
/* in archive recovery: the log group whose
archive is read */
......
......@@ -58,13 +58,17 @@ yet: the variable name is misleading */
ibool recv_no_ibuf_operations = FALSE;
/* the following counter is used to decide when to print info on
/* The following counter is used to decide when to print info on
log scan */
ulint recv_scan_print_counter = 0;
ibool recv_is_from_backup = FALSE;
ibool recv_is_making_a_backup = FALSE;
ulint recv_previous_parsed_rec_type = 999999;
ulint recv_previous_parsed_rec_offset = 0;
ulint recv_previous_parsed_rec_is_multi = 0;
/************************************************************
Creates the recovery system. */
......@@ -695,7 +699,7 @@ byte*
recv_parse_or_apply_log_rec_body(
/*=============================*/
/* out: log record end, NULL if not a complete
record, or a corrupt record */
record */
byte type, /* in: type */
byte* ptr, /* in: pointer to a buffer */
byte* end_ptr,/* in: pointer to the buffer end */
......@@ -770,15 +774,6 @@ recv_parse_or_apply_log_rec_body(
new_ptr = mlog_parse_string(ptr, end_ptr, page);
} else {
new_ptr = NULL;
fprintf(stderr,
"InnoDB: WARNING: the log file may have been corrupt and it\n"
"InnoDB: is possible that the log scan did not proceed\n"
"InnoDB: far enough in recovery. Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\n"
"InnoDB: Corrupt log record type %lu\n, lsn %lu %lu\n",
(ulint)type, ut_dulint_get_high(recv_sys->recovered_lsn),
ut_dulint_get_low(recv_sys->recovered_lsn));
recv_sys->found_corrupt_log = TRUE;
}
......@@ -1651,7 +1646,7 @@ ulint
recv_parse_log_rec(
/*===============*/
/* out: length of the record, or 0 if the record was
not complete or it was corrupt */
not complete */
byte* ptr, /* in: pointer to a buffer */
byte* end_ptr,/* in: pointer to the buffer end */
byte* type, /* out: type */
......@@ -1691,16 +1686,6 @@ recv_parse_log_rec(
/* Check that space id and page_no are sensible */
if (*space != 0 || *page_no > 0x8FFFFFFF) {
fprintf(stderr,
"InnoDB: WARNING: the log file may have been corrupt and it\n"
"InnoDB: is possible that the log scan did not proceed\n"
"InnoDB: far enough in recovery. Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\n"
"InnoDB: Corrupt log record type %lu, space id %lu, page no %lu\n",
"InnoDB: lsn %lu %lu\n",
(ulint)(*type), *space, *page_no,
ut_dulint_get_high(recv_sys->recovered_lsn),
ut_dulint_get_low(recv_sys->recovered_lsn));
recv_sys->found_corrupt_log = TRUE;
......@@ -1766,6 +1751,63 @@ recv_check_incomplete_log_recs(
}
}
/***********************************************************
Prints diagnostic info of corrupt log. */
static
void
recv_report_corrupt_log(
/*====================*/
byte* ptr, /* in: pointer to corrupt log record */
byte type, /* in: type of the record */
ulint space, /* in: space id, this may also be garbage */
ulint page_no)/* in: page number, this may also be garbage */
{
char* err_buf;
fprintf(stderr,
"InnoDB: ############### CORRUPT LOG RECORD FOUND\n"
"InnoDB: Log record type %lu, space id %lu, page number %lu\n"
"InnoDB: Log parsing proceeded successfully up to %lu %lu\n",
(ulint)type, space, page_no,
ut_dulint_get_high(recv_sys->recovered_lsn),
ut_dulint_get_low(recv_sys->recovered_lsn));
err_buf = ut_malloc(1000000);
fprintf(stderr,
"InnoDB: Previous log record type %lu, is multi %lu\n"
"InnoDB: Recv offset %lu, prev %lu\n",
recv_previous_parsed_rec_type,
recv_previous_parsed_rec_is_multi,
ptr - recv_sys->buf,
recv_previous_parsed_rec_offset);
if ((ulint)(ptr - recv_sys->buf + 100)
> recv_previous_parsed_rec_offset
&& (ulint)(ptr - recv_sys->buf + 100
- recv_previous_parsed_rec_offset)
< 200000) {
ut_sprintf_buf(err_buf,
recv_sys->buf + recv_previous_parsed_rec_offset - 100,
ptr - recv_sys->buf + 200 -
recv_previous_parsed_rec_offset);
fprintf(stderr,
"InnoDB: Hex dump of corrupt log starting 100 bytes before the start\n"
"InnoDB: of the previous log rec,\n"
"InnoDB: and ending 100 bytes after the start of the corrupt rec:\n%s\n",
err_buf);
}
ut_free(err_buf);
fprintf(stderr,
"InnoDB: WARNING: the log file may have been corrupt and it\n"
"InnoDB: is possible that the log scan did not proceed\n"
"InnoDB: far enough in recovery! Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\n");
}
/***********************************************************
Parses log records from a buffer and stores them to a hash table to wait
merging to file pages. */
......@@ -1773,8 +1815,7 @@ static
ibool
recv_parse_log_recs(
/*================*/
/* out: TRUE if the hash table of parsed log
records became full */
/* out: currently always returns FALSE */
ibool store_to_hash) /* in: TRUE if the records should be stored
to the hash table; this is set to FALSE if just
debug checking is needed */
......@@ -1791,7 +1832,6 @@ recv_parse_log_recs(
ulint page_no;
byte* body;
ulint n_recs;
char err_buf[2500];
ut_ad(mutex_own(&(log_sys->mutex)));
ut_ad(!ut_dulint_is_zero(recv_sys->parse_start_lsn));
......@@ -1814,17 +1854,11 @@ loop:
len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body);
if (len == 0) {
if (len == 0 || recv_sys->found_corrupt_log) {
if (recv_sys->found_corrupt_log) {
ut_sprintf_buf(err_buf,
recv_sys->buf + ut_calc_align_down(
recv_sys->recovered_offset,
OS_FILE_LOG_BLOCK_SIZE) - 8,
OS_FILE_LOG_BLOCK_SIZE + 16);
fprintf(stderr,
"InnoDB: hex dump of a corrupt log segment: %s\n", err_buf);
recv_report_corrupt_log(ptr,
type, space, page_no);
}
return(FALSE);
......@@ -1841,6 +1875,10 @@ loop:
return(FALSE);
}
recv_previous_parsed_rec_type = (ulint)type;
recv_previous_parsed_rec_offset = recv_sys->recovered_offset;
recv_previous_parsed_rec_is_multi = 0;
recv_sys->recovered_offset += len;
recv_sys->recovered_lsn = new_recovered_lsn;
......@@ -1879,22 +1917,22 @@ loop:
for (;;) {
len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body);
if (len == 0) {
if (recv_sys->found_corrupt_log) {
ut_sprintf_buf(err_buf,
recv_sys->buf + ut_calc_align_down(
recv_sys->recovered_offset,
OS_FILE_LOG_BLOCK_SIZE) - 8,
OS_FILE_LOG_BLOCK_SIZE + 16);
fprintf(stderr,
"InnoDB: hex dump of a corrupt log segment: %s\n", err_buf);
}
if (len == 0 || recv_sys->found_corrupt_log) {
if (recv_sys->found_corrupt_log) {
return(FALSE);
recv_report_corrupt_log(ptr,
type, space, page_no);
}
return(FALSE);
}
recv_previous_parsed_rec_type = (ulint)type;
recv_previous_parsed_rec_offset
= recv_sys->recovered_offset + total_len;
recv_previous_parsed_rec_is_multi = 1;
if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) {
/* In debug checking, update a replicate page
according to the log record */
......@@ -1946,6 +1984,12 @@ loop:
old_lsn = recv_sys->recovered_lsn;
len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body);
if (recv_sys->found_corrupt_log) {
recv_report_corrupt_log(ptr,
type, space, page_no);
}
ut_a(len != 0);
ut_a(0 == ((ulint)*ptr & MLOG_SINGLE_REC_FLAG));
......@@ -2206,11 +2250,14 @@ recv_scan_log_recs(
>= RECV_PARSING_BUF_SIZE) {
fprintf(stderr,
"InnoDB: Error: log parsing buffer overflow. Recovery may have failed!\n");
finished = TRUE;
recv_sys->found_corrupt_log = TRUE;
} else if (!recv_sys->found_corrupt_log) {
more_data = recv_sys_add_to_parsing_buf(
log_block, scanned_lsn);
}
more_data = recv_sys_add_to_parsing_buf(log_block,
scanned_lsn);
recv_sys->scanned_lsn = scanned_lsn;
recv_sys->scanned_checkpoint_no =
log_block_get_checkpoint_no(log_block);
......@@ -2240,7 +2287,7 @@ recv_scan_log_recs(
}
}
if (more_data) {
if (more_data && !recv_sys->found_corrupt_log) {
/* Try to parse more log records */
recv_parse_log_recs(store_to_hash);
......@@ -2617,6 +2664,17 @@ recv_recovery_from_checkpoint_finish(void)
trx_sys_print_mysql_binlog_offset();
}
if (recv_sys->found_corrupt_log) {
fprintf(stderr,
"InnoDB: WARNING: the log file may have been corrupt and it\n"
"InnoDB: is possible that the log scan or parsing did not proceed\n"
"InnoDB: far enough in recovery. Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\n"
"InnoDB: It may be safest to recover your InnoDB database from\n"
"InnoDB: a backup!\n");
}
/* Free the resources of the recovery system */
recv_recovery_on = FALSE;
......
......@@ -14,6 +14,7 @@ Created 12/7/1995 Heikki Tuuri
#include "buf0buf.h"
#include "dict0boot.h"
#include "log0recv.h"
/************************************************************
Catenates n bytes to the mtr log. */
......@@ -121,7 +122,7 @@ byte*
mlog_parse_nbytes(
/*==============*/
/* out: parsed record end, NULL if not a complete
record */
record or a corrupt record */
ulint type, /* in: log record type: MLOG_1BYTE, ... */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
......@@ -141,6 +142,12 @@ mlog_parse_nbytes(
offset = mach_read_from_2(ptr);
ptr += 2;
if (offset >= UNIV_PAGE_SIZE) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
if (type == MLOG_8BYTES) {
ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval);
......@@ -163,13 +170,33 @@ mlog_parse_nbytes(
return(NULL);
}
if (type == MLOG_1BYTE) {
if (val > 0xFF) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
} else if (type == MLOG_2BYTES) {
if (val > 0xFFFF) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
} else {
if (type != MLOG_4BYTES) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
}
if (page) {
if (type == MLOG_1BYTE) {
mach_write_to_1(page + offset, val);
} else if (type == MLOG_2BYTES) {
mach_write_to_2(page + offset, val);
} else {
ut_ad(type == MLOG_4BYTES);
ut_a(type == MLOG_4BYTES);
mach_write_to_4(page + offset, val);
}
}
......@@ -338,7 +365,11 @@ mlog_parse_string(
offset = mach_read_from_2(ptr);
ptr += 2;
ut_a(offset < UNIV_PAGE_SIZE);
if (offset >= UNIV_PAGE_SIZE) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
len = mach_read_from_2(ptr);
ptr += 2;
......
......@@ -22,7 +22,7 @@ Created 10/21/1995 Heikki Tuuri
#endif
/* This specifies the file permissions InnoDB uses when it craetes files in
/* This specifies the file permissions InnoDB uses when it creates files in
Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to
my_umask */
......
......@@ -13,6 +13,7 @@ Created 10/4/1994 Heikki Tuuri
#include "rem0cmp.h"
#include "mtr0log.h"
#include "log0recv.h"
ulint page_cur_short_succ = 0;
......@@ -481,6 +482,9 @@ page_cur_insert_rec_write_log(
/* Write the mismatch index */
log_ptr += mach_write_compressed(log_ptr, i);
ut_a(i < UNIV_PAGE_SIZE);
ut_a(extra_size < UNIV_PAGE_SIZE);
}
/* Write to the log the inserted index record end segment which
......@@ -533,6 +537,13 @@ page_cur_parse_insert_rec(
}
offset = mach_read_from_2(ptr);
if (offset >= UNIV_PAGE_SIZE) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
ptr += 2;
}
......@@ -546,6 +557,12 @@ page_cur_parse_insert_rec(
extra_info_yes = end_seg_len & 0x1;
end_seg_len = end_seg_len / 2;
if (end_seg_len >= UNIV_PAGE_SIZE) {
recv_sys->found_corrupt_log = TRUE;
return(NULL);
}
if (extra_info_yes) {
/* Read the info bits */
......@@ -565,12 +582,16 @@ page_cur_parse_insert_rec(
return(NULL);
}
ut_a(origin_offset < UNIV_PAGE_SIZE);
ptr = mach_parse_compressed(ptr, end_ptr, &mismatch_index);
if (ptr == NULL) {
return(NULL);
}
ut_a(mismatch_index < UNIV_PAGE_SIZE);
}
if (end_ptr < ptr + end_seg_len) {
......@@ -607,7 +628,6 @@ page_cur_parse_insert_rec(
/* Build the inserted record to buf */
ut_a(mismatch_index < UNIV_PAGE_SIZE);
ut_a(end_seg_len < UNIV_PAGE_SIZE);
ut_memcpy(buf, rec_get_start(cursor_rec), mismatch_index);
ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
......@@ -1009,6 +1029,8 @@ page_cur_parse_delete_rec(
offset = mach_read_from_2(ptr);
ptr += 2;
ut_a(offset <= UNIV_PAGE_SIZE);
if (page) {
page_cur_position(page + offset, &cursor);
......
......@@ -2474,7 +2474,7 @@ ha_innobase::position(
that len is always fixed for this table. The following assertion
checks this. */
DBUG_ASSERT(len == ref_length);
ut_a(len == ref_length);
}
/*********************************************************************
......
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