diff options
author | unknown <monty@hundin.mysql.fi> | 2002-08-08 15:24:47 +0300 |
---|---|---|
committer | unknown <monty@hundin.mysql.fi> | 2002-08-08 15:24:47 +0300 |
commit | 267b80834ad524c0d72976bc71e5b5bc9815ea1a (patch) | |
tree | e7f4a2013ed3d66e640f6574e62cb7e534a5d77f /innobase | |
parent | ca1875f54033c5ea067ec3ec07b00375de6975d7 (diff) | |
parent | 40d3c3901b0427eba76119730f46784f946990b3 (diff) | |
download | mariadb-git-267b80834ad524c0d72976bc71e5b5bc9815ea1a.tar.gz |
merge with 3.23.52
BitKeeper/etc/logging_ok:
auto-union
configure.in:
Auto merged
Docs/manual.texi:
Auto merged
include/my_pthread.h:
Auto merged
include/mysql_com.h:
Auto merged
include/mysql_version.h.in:
Auto merged
innobase/btr/btr0cur.c:
Auto merged
innobase/btr/btr0sea.c:
Auto merged
innobase/buf/buf0buf.c:
Auto merged
innobase/buf/buf0lru.c:
Auto merged
innobase/configure.in:
Auto merged
innobase/dict/dict0dict.c:
Auto merged
innobase/fil/fil0fil.c:
Auto merged
innobase/fsp/fsp0fsp.c:
Auto merged
innobase/include/buf0buf.ic:
Auto merged
innobase/include/dyn0dyn.ic:
Auto merged
innobase/include/ha0ha.ic:
Auto merged
innobase/include/sync0rw.ic:
Auto merged
innobase/include/univ.i:
Auto merged
innobase/lock/lock0lock.c:
Auto merged
innobase/log/log0log.c:
Auto merged
innobase/mem/mem0dbg.c:
Auto merged
innobase/os/os0file.c:
Auto merged
innobase/os/os0thread.c:
Auto merged
innobase/page/page0cur.c:
Auto merged
innobase/srv/srv0srv.c:
Auto merged
innobase/sync/sync0arr.c:
Auto merged
innobase/sync/sync0rw.c:
Auto merged
innobase/sync/sync0sync.c:
Auto merged
innobase/trx/trx0trx.c:
Auto merged
myisam/mi_create.c:
Auto merged
sql/ha_innodb.h:
Auto merged
sql/lex.h:
Auto merged
sql/log.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
strings/Makefile.am:
Auto merged
support-files/mysql.server.sh:
Auto merged
include/my_base.h:
merge with 3.23.52 (use local file)
include/sslopt-usage.h:
merge with 3.23.52 (use local file)
myisam/mi_search.c:
merge with 3.23.52 (use local file)
myisam/mi_write.c:
merge with 3.23.52 (use local file)
mysql-test/r/group_by.result:
merge with 3.23.52
(Need to be fixed before push)
mysys/my_pthread.c:
merge with 3.23.52 (use local file)
sql/gen_lex_hash.cc:
merge with 3.23.52 (use local file)
sql/ha_innodb.cc:
Total hand-merge with 3.23.52
sql/sql_yacc.yy:
merge with 3.23.52 (use local file)
support-files/mysql.spec.sh:
merge with 3.23.52 (use local file)
Diffstat (limited to 'innobase')
50 files changed, 1105 insertions, 343 deletions
diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c index 1fe322be81e..bab5c78b712 100644 --- a/innobase/btr/btr0cur.c +++ b/innobase/btr/btr0cur.c @@ -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 %lu index %lu\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; diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c index cfdfefebd1a..cef3a4e4b38 100644 --- a/innobase/btr/btr0sea.c +++ b/innobase/btr/btr0sea.c @@ -17,6 +17,7 @@ Created 2/17/1996 Heikki Tuuri #include "btr0cur.h" #include "btr0pcur.h" #include "btr0btr.h" +#include "ha0ha.h" ulint btr_search_n_succ = 0; ulint btr_search_n_hash_fail = 0; diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 663c6cefce6..8b946f4b2a1 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -286,7 +286,7 @@ buf_page_print( ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Page dump in ascii and hex (%u bytes):\n%s", - UNIV_PAGE_SIZE, buf); + (ulint)UNIV_PAGE_SIZE, buf); fprintf(stderr, "InnoDB: End of page dump\n"); mem_free(buf); @@ -1707,10 +1707,11 @@ buf_print(void) mutex_enter(&(buf_pool->mutex)); - printf("LRU len %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); - printf("free len %lu \n", UT_LIST_GET_LEN(buf_pool->free)); - printf("flush len %lu \n", UT_LIST_GET_LEN(buf_pool->flush_list)); printf("buf_pool size %lu \n", size); + printf("database pages %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); + printf("free pages %lu \n", UT_LIST_GET_LEN(buf_pool->free)); + printf("modified database pages %lu \n", + UT_LIST_GET_LEN(buf_pool->flush_list)); printf("n pending reads %lu \n", buf_pool->n_pend_reads); @@ -1819,13 +1820,20 @@ buf_print_io( mutex_enter(&(buf_pool->mutex)); buf += sprintf(buf, - "Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free)); + "Buffer pool size %lu\n", size); + buf += sprintf(buf, + "Free buffers %lu\n", UT_LIST_GET_LEN(buf_pool->free)); + buf += sprintf(buf, + "Database pages %lu\n", UT_LIST_GET_LEN(buf_pool->LRU)); +/* + buf += sprintf(buf, + "Lock heap buffers %lu\n", buf_pool->n_lock_heap_pages); buf += sprintf(buf, - "LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); + "Hash index buffers %lu\n", buf_pool->n_adaptive_hash_pages); +*/ buf += sprintf(buf, - "Flush list length %lu \n", + "Modified db pages %lu\n", UT_LIST_GET_LEN(buf_pool->flush_list)); - buf += sprintf(buf, "Buffer pool size %lu\n", size); buf += sprintf(buf, "Pending reads %lu \n", buf_pool->n_pend_reads); @@ -1836,8 +1844,8 @@ buf_print_io( buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); current_time = time(NULL); - time_elapsed = difftime(current_time, buf_pool->last_printout_time); - + time_elapsed = 0.001 + difftime(current_time, + buf_pool->last_printout_time); buf_pool->last_printout_time = current_time; buf += sprintf(buf, "Pages read %lu, created %lu, written %lu\n", @@ -1870,6 +1878,20 @@ buf_print_io( mutex_exit(&(buf_pool->mutex)); } +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +buf_refresh_io_stats(void) +/*======================*/ +{ + buf_pool->last_printout_time = time(NULL); + buf_pool->n_page_gets_old = buf_pool->n_page_gets; + buf_pool->n_pages_read_old = buf_pool->n_pages_read; + buf_pool->n_pages_created_old = buf_pool->n_pages_created; + buf_pool->n_pages_written_old = buf_pool->n_pages_written; +} + /************************************************************************* Checks that all file pages in the buffer are in a replaceable state. */ diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index 5ab045212c2..2ec1506c522 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -27,6 +27,7 @@ Created 11/5/1995 Heikki Tuuri #include "buf0rea.h" #include "btr0sea.h" #include "os0file.h" +#include "log0recv.h" /* The number of blocks from the LRU_old pointer onward, including the block pointed to, must be 3/8 of the whole LRU list length, except that the @@ -205,6 +206,44 @@ buf_LRU_get_free_block(void) loop: mutex_enter(&(buf_pool->mutex)); + if (!recv_recovery_on && 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 (!recv_recovery_on && 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 (!recv_recovery_on && 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)); diff --git a/innobase/configure.in b/innobase/configure.in index c234e1e192d..100692e06ab 100644 --- a/innobase/configure.in +++ b/innobase/configure.in @@ -86,8 +86,10 @@ else fi case "$target_os" in + hpux10*) + CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX -DUNIV_HPUX10";; hp*) - CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; + CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";; irix*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; osf*) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 5abec8dbb1e..85199b90a5a 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -261,7 +261,7 @@ dict_table_get_index_noninline( { return(dict_table_get_index(table, name)); } - + /************************************************************************ Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ @@ -270,7 +270,7 @@ void dict_table_autoinc_initialize( /*==========================*/ dict_table_t* table, /* in: table */ - ib_longlong value) /* in: value which was assigned to a row */ + ib_longlong value) /* in: next value to assign to a row */ { mutex_enter(&(table->autoinc_mutex)); @@ -281,8 +281,8 @@ dict_table_autoinc_initialize( } /************************************************************************ -Gets the next autoinc value, 0 if not yet initialized. If initialized, -increments the counter by 1. */ +Gets the next autoinc value (== autoinc counter value), 0 if not yet +initialized. If initialized, increments the counter by 1. */ ib_longlong dict_table_autoinc_get( @@ -298,8 +298,8 @@ dict_table_autoinc_get( value = 0; } else { - table->autoinc = table->autoinc + 1; value = table->autoinc; + table->autoinc = table->autoinc + 1; } mutex_exit(&(table->autoinc_mutex)); @@ -334,20 +334,43 @@ dict_table_autoinc_read( } /************************************************************************ -Updates the autoinc counter if the value supplied is bigger than the +Peeks the autoinc counter value, 0 if not yet initialized. Does not +increment the counter. The read not protected by any mutex! */ + +ib_longlong +dict_table_autoinc_peek( +/*====================*/ + /* out: value of the counter */ + dict_table_t* table) /* in: table */ +{ + ib_longlong value; + + if (!table->autoinc_inited) { + + value = 0; + } else { + value = table->autoinc; + } + + return(value); +} + +/************************************************************************ +Updates the autoinc counter if the value supplied is equal or bigger than the current value. If not inited, does nothing. */ void dict_table_autoinc_update( /*======================*/ + dict_table_t* table, /* in: table */ ib_longlong value) /* in: value which was assigned to a row */ { mutex_enter(&(table->autoinc_mutex)); if (table->autoinc_inited) { - if (value > table->autoinc) { - table->autoinc = value; + if (value >= table->autoinc) { + table->autoinc = value + 1; } } diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index da4aee5db76..3e0f21395ef 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -578,7 +578,7 @@ fil_read_flushed_lsn_and_arch_log_no( ulint arch_log_no; buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); - /* Align the memory for a possibel read from a raw device */ + /* Align the memory for a possible read from a raw device */ buf = ut_align(buf2, UNIV_PAGE_SIZE); os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index 32e7f5bcad7..1abb043fdc2 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -933,6 +933,36 @@ fsp_header_get_free_limit( return(limit); } +/************************************************************************** +Gets the size of the tablespace from the tablespace header. If we do not +have an auto-extending data file, this should be equal to the size of the +data files. If there is an auto-extending data file, this can be smaller. */ + +ulint +fsp_header_get_tablespace_size( +/*===========================*/ + /* out: size in pages */ + ulint space) /* in: space id */ +{ + fsp_header_t* header; + ulint size; + mtr_t mtr; + + ut_a(space == 0); /* We have only one log_fsp_current_... variable */ + + mtr_start(&mtr); + + mtr_x_lock(fil_space_get_latch(space), &mtr); + + header = fsp_get_space_header(space, &mtr); + + size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr); + + mtr_commit(&mtr); + + return(size); +} + /*************************************************************************** Tries to extend the last data file file if it is defined as auto-extending. */ static @@ -2629,7 +2659,7 @@ fseg_free_page_low( "InnoDB: Dump of the tablespace extent descriptor: %s\n", errbuf); fprintf(stderr, -"InnoDB: Serious error! InnoDB is trying to free page %lu\n", +"InnoDB: Serious error! InnoDB is trying to free page %lu\n" "InnoDB: though it is already marked as free in the tablespace!\n" "InnoDB: The tablespace free space info is corrupt.\n" "InnoDB: You may need to dump your InnoDB tables and recreate the whole\n" diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c index c3ad6cdca76..4489b25ec2b 100644 --- a/innobase/ha/ha0ha.c +++ b/innobase/ha/ha0ha.c @@ -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) { @@ -335,6 +336,20 @@ ha_print_info( } } - buf += sprintf(buf, "Hash table size %lu, used cells %lu\n", - hash_get_n_cells(table), cells); + buf += sprintf(buf, +"Hash table size %lu, used cells %lu", hash_get_n_cells(table), cells); + + if (table->heaps == NULL && table->heap != NULL) { + + /* 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); + } } diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h index bf433c0c264..f66ad3639d4 100644 --- a/innobase/include/btr0btr.h +++ b/innobase/include/btr0btr.h @@ -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. */ -UNIV_INLINE -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. */ diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index b80ed96f54c..591c0ec54ab 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -463,6 +463,12 @@ buf_print_io( /*=========*/ char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +buf_refresh_io_stats(void); +/*======================*/ /************************************************************************* Checks that all file pages in the buffer are in a replaceable state. */ diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic index e5a2c480922..7227c79dc6a 100644 --- a/innobase/include/buf0buf.ic +++ b/innobase/include/buf0buf.ic @@ -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); } diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index fd79e17090a..832654d2666 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -96,17 +96,17 @@ dict_col_get_clust_pos( /*===================*/ dict_col_t* col); /************************************************************************ -Initializes the autoinc counter. It is not an error to initialize already +Initializes the autoinc counter. It is not an error to initialize an already initialized counter. */ void dict_table_autoinc_initialize( /*==========================*/ dict_table_t* table, /* in: table */ - ib_longlong value); /* in: value which was assigned to a row */ + ib_longlong value); /* in: next value to assign to a row */ /************************************************************************ -Gets the next autoinc value, 0 if not yet initialized. If initialized, -increments the counter by 1. */ +Gets the next autoinc value (== autoinc counter value), 0 if not yet +initialized. If initialized, increments the counter by 1. */ ib_longlong dict_table_autoinc_get( @@ -123,12 +123,22 @@ dict_table_autoinc_read( /* out: value of the counter */ dict_table_t* table); /* in: table */ /************************************************************************ -Updates the autoinc counter if the value supplied is bigger than the +Peeks the autoinc counter value, 0 if not yet initialized. Does not +increment the counter. The read not protected by any mutex! */ + +ib_longlong +dict_table_autoinc_peek( +/*====================*/ + /* out: value of the counter */ + dict_table_t* table); /* in: table */ +/************************************************************************ +Updates the autoinc counter if the value supplied is equal or bigger than the current value. If not inited, does nothing. */ void dict_table_autoinc_update( /*======================*/ + dict_table_t* table, /* in: table */ ib_longlong value); /* in: value which was assigned to a row */ /************************************************************************** diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h index ef15c99fdba..cc27f2bad12 100644 --- a/innobase/include/dict0mem.h +++ b/innobase/include/dict0mem.h @@ -388,8 +388,8 @@ struct dict_table_struct{ /* TRUE if the autoinc counter has been inited; MySQL gets the init value by executing SELECT MAX(auto inc column) */ - ib_longlong autoinc;/* autoinc counter value already given to - a row */ + ib_longlong autoinc;/* autoinc counter value to give to the + next inserted row */ ulint magic_n;/* magic number */ }; #define DICT_TABLE_MAGIC_N 76333786 diff --git a/innobase/include/dyn0dyn.h b/innobase/include/dyn0dyn.h index 6f08da1533b..501fde05e90 100644 --- a/innobase/include/dyn0dyn.h +++ b/innobase/include/dyn0dyn.h @@ -17,7 +17,8 @@ typedef struct dyn_block_struct dyn_block_t; typedef dyn_block_t dyn_array_t; -/* This must be > MLOG_BUF_MARGIN + 30 */ +/* This is the initial 'payload' size of a dynamic array; +this must be > MLOG_BUF_MARGIN + 30! */ #define DYN_ARRAY_DATA_SIZE 512 /************************************************************************* @@ -123,14 +124,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. */ -UNIV_INLINE -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 diff --git a/innobase/include/fsp0fsp.h b/innobase/include/fsp0fsp.h index a0197ec2d97..3494f336b1e 100644 --- a/innobase/include/fsp0fsp.h +++ b/innobase/include/fsp0fsp.h @@ -57,6 +57,16 @@ fsp_header_get_free_limit( /* out: free limit in megabytes */ ulint space); /* in: space id */ /************************************************************************** +Gets the size of the tablespace from the tablespace header. If we do not +have an auto-extending data file, this should be equal to the size of the +data files. If there is an auto-extending data file, this can be smaller. */ + +ulint +fsp_header_get_tablespace_size( +/*===========================*/ + /* out: size in pages */ + ulint space); /* in: space id */ +/************************************************************************** Initializes the space header of a new created space. */ void diff --git a/innobase/include/ha0ha.h b/innobase/include/ha0ha.h index 945b1198a41..0beac928b7e 100644 --- a/innobase/include/ha0ha.h +++ b/innobase/include/ha0ha.h @@ -131,6 +131,14 @@ ha_print_info( char* buf_end,/* in: buffer end */ hash_table_t* table); /* in: hash table */ +/* The hash table external chain node */ + +typedef struct ha_node_struct ha_node_t; +struct ha_node_struct { + ha_node_t* next; /* next chain node or NULL if none */ + void* data; /* pointer to the data */ + ulint fold; /* fold value for the data */ +}; #ifndef UNIV_NONINL #include "ha0ha.ic" diff --git a/innobase/include/ha0ha.ic b/innobase/include/ha0ha.ic index 9d344bca04c..761bc3b20de 100644 --- a/innobase/include/ha0ha.ic +++ b/innobase/include/ha0ha.ic @@ -9,16 +9,6 @@ Created 8/18/1994 Heikki Tuuri #include "ut0rnd.h" #include "mem0mem.h" -/* The hash table external chain node */ - -typedef struct ha_node_struct ha_node_t; - -struct ha_node_struct { - ha_node_t* next; /* next chain node or NULL if none */ - void* data; /* pointer to the data */ - ulint fold; /* fold value for the data */ -}; - /*************************************************************** Deletes a hash node. */ diff --git a/innobase/include/log0log.h b/innobase/include/log0log.h index 5d848b85658..f200371de9d 100644 --- a/innobase/include/log0log.h +++ b/innobase/include/log0log.h @@ -431,15 +431,30 @@ log_block_set_data_len( byte* log_block, /* in: log block */ ulint len); /* in: data length */ /**************************************************************** -Gets a log block number stored in the trailer. */ +Calculates the checksum for a log block. */ UNIV_INLINE ulint -log_block_get_trl_no( -/*=================*/ - /* out: log block number stored in the block - trailer */ +log_block_calc_checksum( +/*====================*/ + /* out: checksum */ + byte* block); /* in: log block */ +/**************************************************************** +Gets a log block checksum field value. */ +UNIV_INLINE +ulint +log_block_get_checksum( +/*===================*/ + /* out: checksum */ byte* log_block); /* in: log block */ /**************************************************************** +Sets a log block checksum field value. */ +UNIV_INLINE +void +log_block_set_checksum( +/*===================*/ + byte* log_block, /* in: log block */ + ulint checksum); /* in: checksum */ +/**************************************************************** Gets a log block first mtr log record group offset. */ UNIV_INLINE ulint @@ -497,6 +512,12 @@ log_print( /*======*/ char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +log_refresh_stats(void); +/*===================*/ extern log_t* log_sys; @@ -544,10 +565,11 @@ extern log_t* log_sys; bytes */ /* Offsets of a log block trailer from the end of the block */ -#define LOG_BLOCK_TRL_CHECKSUM 4 /* 1 byte checksum of the log block - contents */ -#define LOG_BLOCK_TRL_NO 3 /* 3 lowest bytes of the log block - number */ +#define LOG_BLOCK_CHECKSUM 4 /* 4 byte checksum of the log block + contents; in InnoDB versions + < 3.23.52 this did not contain the + checksum but the same value as + .._HDR_NO */ #define LOG_BLOCK_TRL_SIZE 4 /* trailer size in bytes */ /* Offsets for a checkpoint field */ diff --git a/innobase/include/log0log.ic b/innobase/include/log0log.ic index 36e65239374..8de239df0bd 100644 --- a/innobase/include/log0log.ic +++ b/innobase/include/log0log.ic @@ -170,33 +170,6 @@ log_block_set_checkpoint_no( } /**************************************************************** -Gets a log block number stored in the trailer. */ -UNIV_INLINE -ulint -log_block_get_trl_no( -/*=================*/ - /* out: log block number stored in the block - trailer */ - byte* log_block) /* in: log block */ -{ - return(mach_read_from_3(log_block + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_NO)); -} - -/**************************************************************** -Sets the log block number stored in the trailer. */ -UNIV_INLINE -void -log_block_set_trl_no( -/*=================*/ - byte* log_block, /* in: log block */ - ulint n) /* in: log block number */ -{ - mach_write_to_3(log_block + OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_NO, - n & 0xFFFFFF); -} - -/**************************************************************** Converts a lsn to a log block number. */ UNIV_INLINE ulint @@ -217,6 +190,61 @@ log_block_convert_lsn_to_no( } /**************************************************************** +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 @@ -232,7 +260,6 @@ log_block_init( no = log_block_convert_lsn_to_no(lsn); log_block_set_hdr_no(log_block, no); - log_block_set_trl_no(log_block, no); log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE); log_block_set_first_rec_group(log_block, 0); @@ -256,7 +283,7 @@ log_block_init_in_old_format( log_block_set_hdr_no(log_block, no); mach_write_to_4(log_block + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_NO - 1, no); + - LOG_BLOCK_CHECKSUM, no); log_block_set_data_len(log_block, LOG_BLOCK_HDR_SIZE); log_block_set_first_rec_group(log_block, 0); } diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h index 0825325965d..baa2ba50c7d 100644 --- a/innobase/include/log0recv.h +++ b/innobase/include/log0recv.h @@ -313,6 +313,11 @@ struct recv_sys_struct{ this lsn */ dulint limit_lsn;/* recovery should be made at most up to this lsn */ + ibool found_corrupt_log; + /* this is set to TRUE if we during log + scan find a corrupt log block, or a corrupt + 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 */ @@ -328,6 +333,8 @@ extern ibool recv_recovery_on; extern ibool recv_no_ibuf_operations; extern ibool recv_needed_recovery; +extern ibool recv_is_making_a_backup; + /* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many times! */ #define RECV_PARSING_BUF_SIZE (2 * 1024 * 1024) diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index b7911c5014a..d65c7fd47e3 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -408,6 +408,12 @@ os_aio_print( char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ /************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +os_aio_refresh_stats(void); +/*======================*/ +/************************************************************************** Checks that all slots in the system have been freed, that is, there are no pending io operations. */ diff --git a/innobase/include/os0sync.ic b/innobase/include/os0sync.ic index 6bff75d8ec6..10b85c435e3 100644 --- a/innobase/include/os0sync.ic +++ b/innobase/include/os0sync.ic @@ -27,7 +27,21 @@ os_fast_mutex_trylock( return(0); #else +#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) + /* Since the hot backup version is standalone, MySQL does not redefine + pthread_mutex_trylock for HP-UX-10.20, and consequently we must invert + the return value here */ + + return((ulint) (1 - pthread_mutex_trylock(fast_mutex))); +#else + /* NOTE that the MySQL my_pthread.h redefines pthread_mutex_trylock + so that it returns 0 on success. In the operating system + libraries, HP-UX-10.20 follows the old Posix 1003.4a Draft 4 and + returns 1 on success (but MySQL remaps that to 0), while Linux, + FreeBSD, Solaris, AIX, Tru64 Unix, HP-UX-11.0 return 0 on success. */ + return((ulint) pthread_mutex_trylock(fast_mutex)); #endif +#endif } diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 0d6fa5a8f37..636cfd79e50 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -28,12 +28,30 @@ typedef void* os_thread_t; #else typedef pthread_t os_thread_t; #endif -typedef unsigned long int os_thread_id_t; + +#define os_thread_id_t os_thread_t /* Define a function pointer type to use in a typecast */ typedef void* (*os_posix_f_t) (void*); +/******************************************************************* +Compares two threads or thread ids for equality */ + +ibool +os_thread_eq( +/*=========*/ + /* out: TRUE if equal */ + os_thread_t a, /* in: OS thread or thread id */ + os_thread_t b); /* in: OS thread or thread id */ +/******************************************************************** +Converts an OS thread or thread id to a ulint. It is NOT guaranteed that +the ulint is unique for the thread though! */ +ulint +os_thread_pf( +/*=========*/ + /* out: unsigned long int */ + os_thread_t a); /* in: thread or thread id */ /******************************************************************** Creates a new thread of execution. The execution starts from the function given. The start function takes a void* parameter @@ -73,14 +91,6 @@ os_thread_t os_thread_get_curr(void); /*====================*/ /********************************************************************* -Converts a thread id to a ulint. */ - -ulint -os_thread_conv_id_to_ulint( -/*=======================*/ - /* out: converted to ulint */ - os_thread_id_t id); /* in: thread id */ -/********************************************************************* Waits for a thread to terminate. */ void diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h index 01ac063e1c9..646d2c1bb06 100644 --- a/innobase/include/srv0start.h +++ b/innobase/include/srv0start.h @@ -85,7 +85,7 @@ extern ibool srv_is_being_shut_down; /* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP and then to SRV_SHUTDOWN_LAST_PHASE */ -extern ulint srv_shutdown_state; +extern ulint srv_shutdown_state; #define SRV_SHUTDOWN_CLEANUP 1 #define SRV_SHUTDOWN_LAST_PHASE 2 diff --git a/innobase/include/sync0rw.ic b/innobase/include/sync0rw.ic index 43e9202360b..36ef0a985ed 100644 --- a/innobase/include/sync0rw.ic +++ b/innobase/include/sync0rw.ic @@ -312,7 +312,8 @@ rw_lock_x_lock_func_nowait( && ((rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) || ((rw_lock_get_writer(lock) == RW_LOCK_EX) && (lock->pass == 0) - && (lock->writer_thread == os_thread_get_curr_id())))) { + && os_thread_eq(lock->writer_thread, + os_thread_get_curr_id())))) { rw_lock_set_writer(lock, RW_LOCK_EX); lock->writer_thread = os_thread_get_curr_id(); diff --git a/innobase/include/sync0sync.ic b/innobase/include/sync0sync.ic index 9014eb5fb54..c11cc0d196e 100644 --- a/innobase/include/sync0sync.ic +++ b/innobase/include/sync0sync.ic @@ -104,6 +104,10 @@ mutex_test_and_set( ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex)); if (ret == 0) { + /* We check that os_fast_mutex_trylock does not leak + and allow race conditions */ + ut_a(mutex->lock_word == 0); + mutex->lock_word = 1; } diff --git a/innobase/include/trx0sys.h b/innobase/include/trx0sys.h index b08df7f6901..a54a6424a4f 100644 --- a/innobase/include/trx0sys.h +++ b/innobase/include/trx0sys.h @@ -257,6 +257,15 @@ void trx_sys_print_mysql_binlog_offset(void); /*===================================*/ /********************************************************************* +Prints to stdout the MySQL binlog info in the system header if the +magic number shows it valid. */ + +void +trx_sys_print_mysql_binlog_offset_from_page( +/*========================================*/ + byte* page); /* in: buffer containing the trx system header page, + i.e., page number TRX_SYS_PAGE_NO in the tablespace */ +/********************************************************************* Prints to stderr the MySQL master log offset info in the trx system header if the magic number shows it valid. */ @@ -300,11 +309,11 @@ therefore 256; each slot is currently 8 bytes in size */ #define TRX_SYS_MYSQL_LOG_NAME_LEN 512 #define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344 -/* The offset of the MySQL replication info on the trx system header page; +/* The offset of the MySQL replication info in the trx system header; this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ #define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000) -/* The offset of the MySQL binlog offset info on the trx system header page */ +/* The offset of the MySQL binlog offset info in the trx system header */ #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000) #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows if we have valid data in the diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 83789966514..6e98f22c34b 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -309,6 +309,9 @@ struct trx_struct{ of view of concurrency control: TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY, ... */ + time_t start_time; /* time the trx object was created + or the state last time became + TRX_ACTIVE */ ibool check_foreigns; /* normally TRUE, but if the user wants to suppress foreign key checks, (in table imports, for example) we @@ -468,6 +471,7 @@ struct trx_struct{ TRX_QUE_LOCK_WAIT, this points to the lock request, otherwise this is NULL */ + time_t wait_started; /* lock wait started at this time */ UT_LIST_BASE_NODE_T(que_thr_t) wait_thrs; /* query threads belonging to this trx that are in the QUE_THR_LOCK_WAIT diff --git a/innobase/include/univ.i b/innobase/include/univ.i index c852741d5ac..a4f29dc4cf3 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -80,8 +80,8 @@ memory is read outside the allocated blocks. */ /* #define UNIV_DEBUG -#define UNIV_MEM_DEBUG #define UNIV_SYNC_DEBUG +#define UNIV_MEM_DEBUG #define UNIV_IBUF_DEBUG #define UNIV_SEARCH_DEBUG @@ -116,7 +116,7 @@ memory is read outside the allocated blocks. */ #define UNIV_INLINE extern inline #else /* extern inline doesn't work with gcc 3.0.2 */ -#define UNIV_INLINE static inline +#define UNIV_INLINE static inline #endif #endif @@ -204,8 +204,12 @@ headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */ #endif /* The following number as the length of a logical field means that the field -has the SQL NULL as its value. */ -#define UNIV_SQL_NULL ULINT_UNDEFINED +has the SQL NULL as its value. NOTE that because we assume that the length +of a field is a 32-bit integer when we store it, for example, to an undo log +on disk, we must have also this number fit in 32 bits, also in 64-bit +computers! */ + +#define UNIV_SQL_NULL ULINT32_UNDEFINED /* Lengths which are not UNIV_SQL_NULL, but bigger than the following number indicate that a field contains a reference to an externally diff --git a/innobase/include/ut0dbg.h b/innobase/include/ut0dbg.h index fc5d493ca5e..3407483696c 100644 --- a/innobase/include/ut0dbg.h +++ b/innobase/include/ut0dbg.h @@ -26,9 +26,11 @@ extern ulint* ut_dbg_null_ptr; ulint dbg_i;\ \ if (!((ulint)(EXPR) + ut_dbg_zero)) {\ + ut_print_timestamp(stderr);\ fprintf(stderr,\ - "InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ - os_thread_get_curr_id(), IB__FILE__, (ulint)__LINE__);\ + " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\ + (ulint)__LINE__);\ fprintf(stderr,\ "InnoDB: We intentionally generate a memory trap.\n");\ fprintf(stderr,\ @@ -42,16 +44,17 @@ extern ulint* ut_dbg_null_ptr; if (ut_dbg_stop_threads) {\ fprintf(stderr,\ "InnoDB: Thread %lu stopped in file %s line %lu\n",\ - os_thread_get_curr_id(), IB__FILE__, (ulint)__LINE__);\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ os_thread_sleep(1000000000);\ }\ } #define ut_error {\ ulint dbg_i;\ + ut_print_timestamp(stderr);\ fprintf(stderr,\ - "InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ - os_thread_get_curr_id(), IB__FILE__, (ulint)__LINE__);\ + " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ fprintf(stderr,\ "InnoDB: We intentionally generate a memory trap.\n");\ fprintf(stderr,\ diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 7588a576a86..0bc7e9b4166 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -301,6 +301,11 @@ struct lock_struct{ } un_member; }; +/* We store info on the latest deadlock error to this buffer. InnoDB +Monitor will then fetch it and print */ +ibool lock_deadlock_found = FALSE; +char* lock_latest_err_buf; /* We allocate 5000 bytes for this */ + /************************************************************************ Checks if a lock request results in a deadlock. */ static @@ -576,6 +581,8 @@ lock_sys_create( lock_sys->rec_hash = hash_create(n_cells); /* hash_create_mutexes(lock_sys->rec_hash, 2, SYNC_REC_LOCK); */ + + lock_latest_err_buf = mem_alloc(5000); } /************************************************************************* @@ -1566,6 +1573,7 @@ index->table_name); } trx->que_state = TRX_QUE_LOCK_WAIT; + trx->wait_started = time(NULL); ut_a(que_thr_stop(thr)); @@ -2698,6 +2706,7 @@ lock_deadlock_occurs( trx_t* mark_trx; ibool ret; ulint cost = 0; + char* err_buf; ut_ad(trx && lock); ut_ad(mutex_own(&kernel_mutex)); @@ -2723,6 +2732,29 @@ lock_deadlock_occurs( index = lock->index; table = index->table; } + + lock_deadlock_found = TRUE; + + err_buf = lock_latest_err_buf + strlen(lock_latest_err_buf); + + err_buf += sprintf(err_buf, + "*** (2) WAITING FOR THIS LOCK TO BE GRANTED:\n"); + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(err_buf, lock); + err_buf += strlen(err_buf); + } else { + lock_table_print(err_buf, lock); + err_buf += strlen(err_buf); + } + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + err_buf += sprintf(err_buf, + "*** WE ROLL BACK TRANSACTION (2)\n"); + /* sess_raise_error_low(trx, DB_DEADLOCK, lock->type_mode, table, index, NULL, NULL, NULL); @@ -2750,6 +2782,7 @@ lock_deadlock_recursive( lock_t* lock; ulint bit_no = 0; /* remove warning */ trx_t* lock_trx; + char* err_buf; ut_a(trx && start && wait_lock); ut_ad(mutex_own(&kernel_mutex)); @@ -2801,6 +2834,53 @@ lock_deadlock_recursive( lock_trx = lock->trx; if (lock_trx == start) { + err_buf = lock_latest_err_buf; + + ut_sprintf_timestamp(err_buf); + err_buf += strlen(err_buf); + + err_buf += sprintf(err_buf, + " LATEST DETECTED DEADLOCK:\n" + "*** (1) TRANSACTION:\n"); + + trx_print(err_buf, wait_lock->trx); + err_buf += strlen(err_buf); + + err_buf += sprintf(err_buf, + "*** (1) WAITING FOR THIS LOCK TO BE GRANTED:\n"); + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + if (lock_get_type(wait_lock) == LOCK_REC) { + lock_rec_print(err_buf, wait_lock); + err_buf += strlen(err_buf); + } else { + lock_table_print(err_buf, wait_lock); + err_buf += strlen(err_buf); + } + + ut_a(err_buf <= lock_latest_err_buf + 4000); + err_buf += sprintf(err_buf, + "*** (2) TRANSACTION:\n"); + + trx_print(err_buf, lock->trx); + err_buf += strlen(err_buf); + + err_buf += sprintf(err_buf, + "*** (2) HOLDS THE LOCK(S):\n"); + + ut_a(err_buf <= lock_latest_err_buf + 4000); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(err_buf, lock); + err_buf += strlen(err_buf); + } else { + lock_table_print(err_buf, lock); + err_buf += strlen(err_buf); + } + + ut_a(err_buf <= lock_latest_err_buf + 4000); + if (lock_print_waits) { printf("Deadlock detected\n"); } @@ -2962,6 +3042,7 @@ table->name); } trx->que_state = TRX_QUE_LOCK_WAIT; + trx->wait_started = time(NULL); ut_a(que_thr_stop(thr)); @@ -3432,6 +3513,9 @@ lock_rec_print( buf += sprintf(buf, "Suppressing further record lock prints for this page\n"); + + mtr_commit(&mtr); + return; } @@ -3520,6 +3604,22 @@ lock_print_info( buf += sprintf(buf, "Total number of lock structs in row lock hash table %lu\n", lock_get_n_rec_locks()); + if (lock_deadlock_found) { + + if ((ulint)(buf_end - buf) + < 100 + strlen(lock_latest_err_buf)) { + + return; + } + + buf += sprintf(buf, "%s", lock_latest_err_buf); + } + + if (buf_end - buf < 600) { + return; + } + + buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); /* First print info on non-active transactions */ @@ -3588,7 +3688,8 @@ loop: if (trx->que_state == TRX_QUE_LOCK_WAIT) { buf += sprintf(buf, - "------------------TRX IS WAITING FOR THE LOCK:\n"); + "------- TRX HAS BEEN WAITING %lu SEC FOR THIS LOCK TO BE GRANTED:\n", + (ulint)difftime(time(NULL), trx->wait_started)); if (lock_get_type(trx->wait_lock) == LOCK_REC) { lock_rec_print(buf, trx->wait_lock); diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 9748384183c..c798a08e2de 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -270,7 +270,7 @@ part_loop: log->lsn = ut_dulint_add(log->lsn, len); - /* Initialize the next block header and trailer */ + /* Initialize the next block header */ log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, log->lsn); } else { log->lsn = ut_dulint_add(log->lsn, len); @@ -1070,28 +1070,16 @@ log_group_file_header_flush( } /********************************************************** -Stores a 1-byte checksum to the trailer checksum field of a log block +Stores a 4-byte checksum to the trailer checksum field of a log block before writing it to a log file. This checksum is used in recovery to -check the consistency of a log block. The checksum is simply the 8 low -bits of 1 + the sum of the bytes in the log block except the trailer bytes. */ +check the consistency of a log block. */ static void log_block_store_checksum( /*=====================*/ byte* block) /* in/out: pointer to a log block */ { - ulint i; - ulint sum; - - sum = 1; - - for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) { - sum += (ulint)(*(block + i)); - } - - mach_write_to_1(block + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_CHECKSUM, - 0xFF & sum); + log_block_set_checksum(block, log_block_calc_checksum(block)); } /********************************************************** @@ -3113,8 +3101,8 @@ log_print( current_time = time(NULL); - time_elapsed = difftime(current_time, log_sys->last_printout_time); - + time_elapsed = 0.001 + difftime(current_time, + log_sys->last_printout_time); buf += sprintf(buf, "%lu pending log writes, %lu pending chkp writes\n" "%lu log i/o's done, %.2f log i/o's/second\n", @@ -3128,3 +3116,14 @@ log_print( mutex_exit(&(log_sys->mutex)); } + +/************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +log_refresh_stats(void) +/*===================*/ +{ + log_sys->n_log_ios_old = log_sys->n_log_ios; + log_sys->last_printout_time = time(NULL); +} diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 53f75c176ea..1223f9b6041 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -58,12 +58,16 @@ 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. */ @@ -124,6 +128,8 @@ recv_sys_init( recv_sys->last_block = ut_align(recv_sys->last_block_buf_start, OS_FILE_LOG_BLOCK_SIZE); + recv_sys->found_corrupt_log = FALSE; + mutex_exit(&(recv_sys->mutex)); } @@ -569,9 +575,9 @@ recv_read_cp_info_for_backup( } /********************************************************** -Checks the 1-byte checksum to the trailer checksum field of a log block. -We also accept a log block in the old format where the checksum field -contained the highest byte of the log block number. */ +Checks the 4-byte checksum to the trailer checksum field of a log block. +We also accept a log block in the old format < InnoDB-3.23.52 where the +checksum field contains the log block number. */ static ibool log_block_checksum_is_ok_or_old_format( @@ -580,29 +586,12 @@ log_block_checksum_is_ok_or_old_format( format of InnoDB version < 3.23.52 */ byte* block) /* in: pointer to a log block */ { - ulint i; - ulint sum; - - sum = 1; - - for (i = 0; i < OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE; i++) { - sum += (ulint)(*(block + i)); - } - -/* printf("Checksum %lu, byte %lu\n", 0xFF & sum, - mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_CHECKSUM)); -*/ - if (mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_CHECKSUM) - == (0xFF & sum)) { + if (log_block_calc_checksum(block) == log_block_get_checksum(block)) { return(TRUE); } - if (((0xFF000000 & log_block_get_hdr_no(block)) >> 24) - == mach_read_from_1(block + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_CHECKSUM)) { + if (log_block_get_hdr_no(block) == log_block_get_checksum(block)) { /* We assume the log block is in the format of InnoDB version < 3.23.52 and the block is ok */ @@ -649,23 +638,20 @@ recv_scan_log_seg_for_backup( /* fprintf(stderr, "Log block header no %lu\n", no); */ - if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) - || no != log_block_convert_lsn_to_no(*scanned_lsn) + if (no != log_block_convert_lsn_to_no(*scanned_lsn) || !log_block_checksum_is_ok_or_old_format(log_block)) { /* printf( -"Log block n:o %lu, trailer n:o %lu, scanned lsn n:o %lu\n", - no, log_block_get_trl_no(log_block), - log_block_convert_lsn_to_no(*scanned_lsn)); +"Log block n:o %lu, scanned lsn n:o %lu\n", + no, log_block_convert_lsn_to_no(*scanned_lsn)); */ /* Garbage or an incompletely written log block */ log_block += OS_FILE_LOG_BLOCK_SIZE; /* printf( -"Next log block n:o %lu, trailer n:o %lu\n", - log_block_get_hdr_no(log_block), - log_block_get_trl_no(log_block)); +"Next log block n:o %lu\n", + log_block_get_hdr_no(log_block)); */ break; } @@ -788,14 +774,8 @@ 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", - (ulint)type); + + recv_sys->found_corrupt_log = TRUE; } ut_ad(!page || new_ptr); @@ -1399,18 +1379,30 @@ recv_apply_log_recs_for_backup( OS_FILE_OPEN, OS_FILE_READ_WRITE, &success); - ut_a(success); + if (!success) { + printf( +"InnoDB: Error: cannot open %lu'th data file %s\n", nth_file); + + exit(1); + } } recv_addr = recv_get_fil_addr_struct(0, i); if (recv_addr != NULL) { - os_file_read(data_file, page, + success = os_file_read(data_file, page, (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFF, nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), UNIV_PAGE_SIZE); + if (!success) { + printf( +"InnoDB: Error: cannot read page no %lu from %lu'th data file %s\n", + nth_page_in_file, nth_file); + exit(1); + } + /* We simulate a page read made by the buffer pool, to make sure recovery works ok. We must init the block corresponding to buf_pool->frame_zero @@ -1425,12 +1417,19 @@ recv_apply_log_recs_for_backup( mach_read_from_8(page + FIL_PAGE_LSN), 0, i); - os_file_write(data_files[nth_file], + success = os_file_write(data_files[nth_file], data_file, page, (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFF, nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), UNIV_PAGE_SIZE); + if (!success) { + printf( +"InnoDB: Error: cannot write page no %lu to %lu'th data file %s\n", + nth_page_in_file, nth_file); + + exit(1); + } } if ((100 * i) / n_pages_total @@ -1679,29 +1678,16 @@ recv_parse_log_rec( new_ptr = mlog_parse_initial_log_record(ptr, end_ptr, type, space, page_no); - - /* If the operating system writes to the log complete 512-byte - blocks, we should not get the warnings below in recovery. - A warning means that the header and the trailer appeared ok - in a 512-byte block, but in the middle there was something wrong. - TODO: (1) add similar warnings in the case there is an incompletely - written log record which does not extend to the boundary of a - 512-byte block. (2) Add a checksum to a log block. */ - if (!new_ptr) { + return(0); } /* 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", - (ulint)(*type), *space, *page_no); + + recv_sys->found_corrupt_log = TRUE; return(0); } @@ -1766,14 +1752,70 @@ 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. */ 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 */ @@ -1812,8 +1854,13 @@ 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) { + recv_report_corrupt_log(ptr, + type, space, page_no); + } + return(FALSE); } @@ -1828,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; @@ -1851,9 +1902,10 @@ loop: #ifdef UNIV_LOG_DEBUG recv_check_incomplete_log_recs(ptr, len); #endif - recv_update_replicate(type, space, page_no, body, +/* recv_update_replicate(type, space, page_no, body, ptr + len); recv_compare_replicate(space, page_no); +*/ } } else { /* Check that all the records associated with the single mtr @@ -1865,19 +1917,32 @@ loop: for (;;) { len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); - if (len == 0) { + if (len == 0 || recv_sys->found_corrupt_log) { - return(FALSE); + if (recv_sys->found_corrupt_log) { + + 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 */ #ifdef UNIV_LOG_DEBUG recv_check_incomplete_log_recs(ptr, len); #endif +/* recv_update_replicate(type, space, page_no, body, ptr + len); +*/ } if (log_debug_writes) { @@ -1919,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)); @@ -1941,7 +2012,7 @@ loop: page has become identical with the original page */ - recv_compare_replicate(space, page_no); +/* recv_compare_replicate(space, page_no); */ } ptr += len; @@ -2095,32 +2166,19 @@ recv_scan_log_recs( /* fprintf(stderr, "Log block header no %lu\n", no); */ - if ((no & 0xFFFFFF) != log_block_get_trl_no(log_block) - || no != log_block_convert_lsn_to_no(scanned_lsn) + if (no != log_block_convert_lsn_to_no(scanned_lsn) || !log_block_checksum_is_ok_or_old_format(log_block)) { - if ((no & 0xFFFFFF) == log_block_get_trl_no(log_block) - && no == log_block_convert_lsn_to_no(scanned_lsn) + if (no == log_block_convert_lsn_to_no(scanned_lsn) && !log_block_checksum_is_ok_or_old_format( log_block)) { fprintf(stderr, "InnoDB: Log block no %lu at lsn %lu %lu has\n" -"InnoDB: ok header and trailer, but checksum field contains %lu\n", - no, ut_dulint_get_high(scanned_lsn), - ut_dulint_get_low(scanned_lsn), - mach_read_from_1(log_block - + OS_FILE_LOG_BLOCK_SIZE - - LOG_BLOCK_TRL_CHECKSUM)); - } - - if ((no & 0xFFFFFF) - != log_block_get_trl_no(log_block)) { - fprintf(stderr, -"InnoDB: Log block with header no %lu at lsn %lu %lu has\n" -"InnoDB: trailer no %lu\n", +"InnoDB: ok header, but checksum field contains %lu, should be %lu\n", no, ut_dulint_get_high(scanned_lsn), ut_dulint_get_low(scanned_lsn), - log_block_get_trl_no(log_block)); + log_block_get_checksum(log_block), + log_block_calc_checksum(log_block)); } /* Garbage or an incompletely written log block */ @@ -2192,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); @@ -2213,7 +2274,8 @@ recv_scan_log_recs( *group_scanned_lsn = scanned_lsn; - if (recv_needed_recovery || recv_is_from_backup) { + if (recv_needed_recovery + || (recv_is_from_backup && !recv_is_making_a_backup)) { recv_scan_print_counter++; if (finished || (recv_scan_print_counter % 80 == 0)) { @@ -2225,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); @@ -2602,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; diff --git a/innobase/mem/mem0dbg.c b/innobase/mem/mem0dbg.c index f94119b7f38..23585e494b8 100644 --- a/innobase/mem/mem0dbg.c +++ b/innobase/mem/mem0dbg.c @@ -668,7 +668,7 @@ mem_print_info_low( mem_pool_print_info(outfile, mem_comm_pool); - mem_validate(); +/* mem_validate(); */ /* fclose(outfile); */ #endif diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 3681c8ef779..61cf1e50ce9 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -251,6 +251,7 @@ mem_pool_fill_free_list( mem_area_t* area; mem_area_t* area2; ibool ret; + char err_buf[500]; ut_ad(mutex_own(&(pool->mutex))); @@ -279,15 +280,34 @@ mem_pool_fill_free_list( area = UT_LIST_GET_FIRST(pool->free_list[i + 1]); if (area == NULL) { + if (UT_LIST_GET_LEN(pool->free_list[i + 1]) > 0) { + ut_print_timestamp(stderr); + + fprintf(stderr, +" InnoDB: Error: mem pool free list %lu length is %lu\n" +"InnoDB: though the list is empty!\n", + i + 1, UT_LIST_GET_LEN(pool->free_list[i + 1])); + } + ret = mem_pool_fill_free_list(i + 1, pool); if (ret == FALSE) { + return(FALSE); } area = UT_LIST_GET_FIRST(pool->free_list[i + 1]); } - + + if (UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Removing element from mem pool free list %lu\n" +"InnoDB: though the list length is 0! Dump of 100 bytes around element:\n%s\n", + i + 1, err_buf); + ut_a(0); + } + UT_LIST_REMOVE(free_list, pool->free_list[i + 1], area); area2 = (mem_area_t*)(((byte*)area) + ut_2_exp(i)); @@ -320,6 +340,7 @@ mem_area_alloc( mem_area_t* area; ulint n; ibool ret; + char err_buf[500]; n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE)); @@ -342,7 +363,24 @@ mem_area_alloc( area = UT_LIST_GET_FIRST(pool->free_list[n]); } - ut_a(mem_area_get_free(area)); + if (!mem_area_get_free(area)) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Removing element from mem pool free list %lu though the\n" +"InnoDB: element is not marked free! Dump of 100 bytes around element:\n%s\n", + n, err_buf); + ut_a(0); + } + + if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Removing element from mem pool free list %lu\n" +"InnoDB: though the list length is 0! Dump of 100 bytes around element:\n%s\n", + n, err_buf); + ut_a(0); + } + ut_ad(mem_area_get_size(area) == ut_2_exp(n)); mem_area_set_free(area, FALSE); @@ -413,6 +451,7 @@ mem_area_free( void* new_ptr; ulint size; ulint n; + char err_buf[500]; if (mem_out_of_mem_err_msg_count > 0) { /* It may be that the area was really allocated from the @@ -429,10 +468,18 @@ mem_area_free( area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE); + if (mem_area_get_free(area)) { + ut_sprintf_buf(err_buf, ((byte*)area) - 50, 100); + fprintf(stderr, +"InnoDB: Error: Freeing element to mem pool free list though the\n" +"InnoDB: element is marked free! Dump of 100 bytes around element:\n%s\n", + err_buf); + ut_a(0); + } + size = mem_area_get_size(area); ut_ad(size != 0); - ut_a(!mem_area_get_free(area)); #ifdef UNIV_LIGHT_MEM_DEBUG if (((byte*)area) + size < pool->buf + pool->size) { diff --git a/innobase/mtr/mtr0log.c b/innobase/mtr/mtr0log.c index b582afc5710..2cfe81d3261 100644 --- a/innobase/mtr/mtr0log.c +++ b/innobase/mtr/mtr0log.c @@ -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; diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index ae3c8a45f62..3ca0fbd68a4 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -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 */ @@ -2483,7 +2483,7 @@ loop: buf += sprintf(buf, "\n"); current_time = time(NULL); - time_elapsed = difftime(current_time, os_last_printout); + time_elapsed = 0.001 + difftime(current_time, os_last_printout); buf += sprintf(buf, "Pending flushes (fsync) log: %lu; buffer pool: %lu\n", @@ -2518,6 +2518,21 @@ loop: } /************************************************************************** +Refreshes the statistics used to print per-second averages. */ + +void +os_aio_refresh_stats(void) +/*======================*/ +{ + os_n_file_reads_old = os_n_file_reads; + os_n_file_writes_old = os_n_file_writes; + os_n_fsyncs_old = os_n_fsyncs; + os_bytes_read_since_printout = 0; + + os_last_printout = time(NULL); +} + +/************************************************************************** Checks that all slots in the system have been freed, that is, there are no pending io operations. */ diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 49d4c8518fb..a8b417f4f3a 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -18,26 +18,63 @@ Created 9/8/1995 Heikki Tuuri #include "srv0srv.h" +/******************************************************************* +Compares two threads or thread ids for equality */ + +ibool +os_thread_eq( +/*=========*/ + /* out: TRUE if equal */ + os_thread_t a, /* in: OS thread or thread id */ + os_thread_t b) /* in: OS thread or thread id */ +{ +#ifdef __WIN__ + if (a == b) { + return(TRUE); + } + + return(FALSE); +#else + if (pthread_equal(a, b)) { + return(TRUE); + } + + return(FALSE); +#endif +} + +/******************************************************************** +Converts an OS thread or thread id to a ulint. It is NOT guaranteed that +the ulint is unique for the thread though! */ + +ulint +os_thread_pf( +/*=========*/ + os_thread_t a) +{ +#ifdef UNIV_HPUX + /* In HP-UX a pthread_t is a struct of 3 fields: field1, field2, + field3. We do not know if field1 determines the thread uniquely. */ + + return((ulint)(a.field1)); +#else + return((ulint)a); +#endif +} + /********************************************************************* -Returns the thread identifier of current thread. */ +Returns the thread identifier of current thread. Currently the thread +identifier is the thread handle itself. Note that in HP-UX pthread_t is +a struct of 3 fields. */ os_thread_id_t os_thread_get_curr_id(void) /*=======================*/ { #ifdef __WIN__ - return(GetCurrentThreadId()); + return(GetCurrentThread()); #else - pthread_t pthr; - - pthr = pthread_self(); - - /* TODO: in the future we have to change os_thread_id - to pthread_t; the following cast may work in a wrong way on some - systems if pthread_t is a struct; this is just a quick fix - for HP-UX to eliminate a compiler warning */ - - return(*(os_thread_id_t*)((void*) (&pthr))); + return(pthread_self()); #endif } @@ -71,7 +108,6 @@ os_thread_create( arg, 0, /* thread runs immediately */ thread_id); - ut_a(thread); if (srv_set_thread_priorities) { @@ -108,7 +144,7 @@ Returns handle to the current thread. */ os_thread_t os_thread_get_curr(void) -/*=======================*/ +/*====================*/ { #ifdef __WIN__ return(GetCurrentThread()); @@ -116,18 +152,6 @@ os_thread_get_curr(void) return(pthread_self()); #endif } - -/********************************************************************* -Converts a thread id to a ulint. */ - -ulint -os_thread_conv_id_to_ulint( -/*=======================*/ - /* out: converted to ulint */ - os_thread_id_t id) /* in: thread id */ -{ - return((ulint)id); -} /********************************************************************* Advises the os to give up remainder of the thread's time slice. */ diff --git a/innobase/page/page0cur.c b/innobase/page/page0cur.c index 0eaf96f7e51..2909573b14b 100644 --- a/innobase/page/page0cur.c +++ b/innobase/page/page0cur.c @@ -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); @@ -1010,6 +1030,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); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index e0737f53213..3ee458f43bf 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -595,6 +595,11 @@ row_lock_table_autoinc_for_mysql( ut_ad(trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); + if (trx->auto_inc_lock) { + + return(DB_SUCCESS); + } + trx->op_info = (char *) "setting auto-inc lock"; if (node == NULL) { diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c index 9508e73f45d..cd8b18e5e12 100644 --- a/innobase/row/row0vers.c +++ b/innobase/row/row0vers.c @@ -58,6 +58,7 @@ row_vers_impl_x_locked_off_kernel( ibool rec_del; ulint err; mtr_t mtr; + char err_buf[1000]; ut_ad(mutex_own(&kernel_mutex)); ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); @@ -74,7 +75,26 @@ row_vers_impl_x_locked_off_kernel( clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); - ut_a(clust_rec); + if (!clust_rec) { + rec_sprintf(err_buf, 900, rec); + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: cannot find the clustered index record\n" +"InnoDB: for a secondary index record in table %s index %s.\n" +"InnoDB: Secondary index record %s.\n" +"InnoDB: The table is probably corrupt. Please run CHECK TABLE on it.\n" +"InnoDB: You can try to repair the table by dump + drop + reimport.\n" +"InnoDB: Send a detailed bug report to mysql@lists.mysql.com.\n", + index->table_name, index->name, err_buf); + mutex_enter(&kernel_mutex); + mtr_commit(&mtr); + + /* We assume there is no lock on the record, though this + is not certain because the table is apparently corrupt */ + + return(NULL); + } trx_id = row_get_rec_trx_id(clust_rec, clust_index); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 3efb82eb8eb..3b16e9557fa 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -2024,7 +2024,7 @@ srv_table_reserve_slot_for_mysql(void) fprintf(stderr, "Slot %lu: thread id %lu, type %lu, in use %lu, susp %lu, time %lu\n", - i, (ulint)(slot->id), + i, os_thread_pf(slot->id), slot->type, slot->in_use, slot->suspended, (ulint)difftime(ut_time(), slot->suspend_time)); @@ -2169,6 +2169,34 @@ srv_release_mysql_thread_if_suspended( } /********************************************************************** +Refreshes the values used to calculate per-second averages. */ +static +void +srv_refresh_innodb_monitor_stats(void) +/*==================================*/ +{ + mutex_enter(&srv_innodb_monitor_mutex); + + srv_last_monitor_time = time(NULL); + + os_aio_refresh_stats(); + + btr_cur_n_sea_old = btr_cur_n_sea; + btr_cur_n_non_sea_old = btr_cur_n_non_sea; + + log_refresh_stats(); + + buf_refresh_io_stats(); + + srv_n_rows_inserted_old = srv_n_rows_inserted; + srv_n_rows_updated_old = srv_n_rows_updated; + srv_n_rows_deleted_old = srv_n_rows_deleted; + srv_n_rows_read_old = srv_n_rows_read; + + mutex_exit(&srv_innodb_monitor_mutex); +} + +/********************************************************************** Sprintfs to a buffer the output of the InnoDB Monitor. */ void @@ -2205,7 +2233,7 @@ srv_sprintf_innodb_monitor( "=====================================\n"); buf += sprintf(buf, -"Per second values calculated from the last %lu seconds\n", +"Per second averages calculated from the last %lu seconds\n", (ulint)time_elapsed); buf += sprintf(buf, "----------\n" @@ -2242,8 +2270,8 @@ srv_sprintf_innodb_monitor( / time_elapsed, (btr_cur_n_non_sea - btr_cur_n_non_sea_old) / time_elapsed); - btr_cur_n_sea_old = btr_cur_n_sea; - btr_cur_n_non_sea_old = btr_cur_n_non_sea; + btr_cur_n_sea_old = btr_cur_n_sea; + btr_cur_n_non_sea_old = btr_cur_n_non_sea; buf += sprintf(buf,"---\n" "LOG\n" @@ -2285,10 +2313,10 @@ srv_sprintf_innodb_monitor( (srv_n_rows_read - srv_n_rows_read_old) / time_elapsed); - srv_n_rows_inserted_old = srv_n_rows_inserted; - srv_n_rows_updated_old = srv_n_rows_updated; - srv_n_rows_deleted_old = srv_n_rows_deleted; - srv_n_rows_read_old = srv_n_rows_read; + srv_n_rows_inserted_old = srv_n_rows_inserted; + srv_n_rows_updated_old = srv_n_rows_updated; + srv_n_rows_deleted_old = srv_n_rows_deleted; + srv_n_rows_read_old = srv_n_rows_read; buf += sprintf(buf, "----------------------------\n" "END OF INNODB MONITOR OUTPUT\n" @@ -2331,7 +2359,7 @@ loop: /* When someone is waiting for a lock, we wake up every second and check if a timeout has passed for a lock wait */ - os_thread_sleep(1000000); + os_thread_sleep(1000000); /* In case mutex_exit is not a memory barrier, it is theoretically possible some threads are left waiting though @@ -2348,9 +2376,9 @@ loop: if (srv_print_innodb_monitor) { - buf = mem_alloc(100000); + buf = mem_alloc(100000); - srv_sprintf_innodb_monitor(buf, 100000); + srv_sprintf_innodb_monitor(buf, 100000); printf("%s", buf); @@ -2481,12 +2509,30 @@ srv_error_monitor_thread( void* arg) /* in: a dummy parameter required by os_thread_create */ { + ulint cnt = 0; + UT_NOT_USED(arg); loop: srv_error_monitor_active = TRUE; - os_thread_sleep(10000000); + cnt++; + os_thread_sleep(2000000); + + if (difftime(time(NULL), srv_last_monitor_time) > 60) { + /* We referesh InnoDB Monitor values so that averages are + printed from at most 60 last seconds */ + + srv_refresh_innodb_monitor_stats(); + } + +/* mem_print_new_info(); + + if (cnt % 10 == 0) { + + mem_print_info(); + } +*/ sync_array_print_long_waits(); /* Flush stdout and stderr so that a database user gets their output diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 55e734be3bd..dfa122b2ece 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -74,6 +74,12 @@ ulint ios; ulint n[SRV_MAX_N_IO_THREADS + 5]; os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5]; +/* We use this mutex to test the return value of pthread_mutex_trylock + on successful locking. HP-UX does NOT return 0, though Linux et al do. */ +os_fast_mutex_t srv_os_test_mutex; + +ibool srv_os_test_mutex_is_locked = FALSE; + #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 @@ -927,6 +933,8 @@ innobase_start_or_create_for_mysql(void) ulint max_arch_log_no; ibool start_archive; ulint sum_of_new_sizes; + ulint sum_of_data_file_sizes; + ulint tablespace_size_in_header; ulint err; ulint i; ulint k; @@ -1324,7 +1332,49 @@ innobase_start_or_create_for_mysql(void) os_thread_create(&srv_master_thread, NULL, thread_ids + 1 + SRV_MAX_N_IO_THREADS); /* buf_debug_prints = TRUE; */ + + sum_of_data_file_sizes = 0; + for (i = 0; i < srv_n_data_files; i++) { + sum_of_data_file_sizes += srv_data_file_sizes[i]; + } + + tablespace_size_in_header = fsp_header_get_tablespace_size(0); + + if (!srv_auto_extend_last_data_file + && sum_of_data_file_sizes != tablespace_size_in_header) { + + fprintf(stderr, +"InnoDB: Error: tablespace size stored in header is %lu pages, but\n" +"InnoDB: the sum of data file sizes is %lu pages\n", + tablespace_size_in_header, sum_of_data_file_sizes); + } + + if (srv_auto_extend_last_data_file + && sum_of_data_file_sizes < tablespace_size_in_header) { + + fprintf(stderr, +"InnoDB: Error: tablespace size stored in header is %lu pages, but\n" +"InnoDB: the sum of data file sizes is only %lu pages\n", + tablespace_size_in_header, sum_of_data_file_sizes); + } + + /* Check that os_fast_mutexes work as exptected */ + os_fast_mutex_init(&srv_os_test_mutex); + + if (0 != os_fast_mutex_trylock(&srv_os_test_mutex)) { + fprintf(stderr, +"InnoDB: Error: pthread_mutex_trylock returns an unexpected value on\n" + "InnoDB: success! Cannot continue.\n"); + exit(1); + } + + os_fast_mutex_unlock(&srv_os_test_mutex); + + os_fast_mutex_lock(&srv_os_test_mutex); + + os_fast_mutex_unlock(&srv_os_test_mutex); + if (srv_print_verbose_log) { ut_print_timestamp(stderr); diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 36dd8a7d80c..4d14c32b1ae 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -454,7 +454,7 @@ sync_array_cell_print( buf += sprintf(buf, "--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n", - (ulint)cell->thread, cell->file, cell->line, + os_thread_pf(cell->thread), cell->file, cell->line, difftime(time(NULL), cell->reservation_time)); if (type == SYNC_MUTEX) { @@ -486,7 +486,7 @@ sync_array_cell_print( if (rwlock->writer != RW_LOCK_NOT_LOCKED) { buf += sprintf(buf, "a writer (thread id %lu) has reserved it in mode", - (ulint)rwlock->writer_thread); + os_thread_pf(rwlock->writer_thread)); if (rwlock->writer == RW_LOCK_EX) { buf += sprintf(buf, " exclusive\n"); } else { @@ -535,8 +535,8 @@ sync_array_find_thread( cell = sync_array_get_nth_cell(arr, i); - if ((cell->wait_object != NULL) - && (cell->thread == thread)) { + if (cell->wait_object != NULL + && os_thread_eq(cell->thread, thread)) { return(cell); /* Found */ } @@ -651,9 +651,9 @@ sync_array_detect_deadlock( sync_array_cell_print(buf, cell); printf( "Mutex %lx owned by thread %lu file %s line %lu\n%s", - (ulint)mutex, mutex->thread_id, - mutex->file_name, mutex->line, - buf); + (ulint)mutex, os_thread_pf(mutex->thread_id), + mutex->file_name, mutex->line, buf); + return(TRUE); } } @@ -671,9 +671,9 @@ sync_array_detect_deadlock( thread = debug->thread_id; if (((debug->lock_type == RW_LOCK_EX) - && (thread != cell->thread)) + && !os_thread_eq(thread, cell->thread)) || ((debug->lock_type == RW_LOCK_WAIT_EX) - && (thread != cell->thread)) + && !os_thread_eq(thread, cell->thread)) || (debug->lock_type == RW_LOCK_SHARED)) { /* The (wait) x-lock request can block infinitely @@ -771,7 +771,7 @@ sync_arr_cell_can_wake_up( if (rw_lock_get_reader_count(lock) == 0 && rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX - && lock->writer_thread == cell->thread) { + && os_thread_eq(lock->writer_thread, cell->thread)) { return(TRUE); } @@ -927,7 +927,7 @@ sync_array_print_long_waits(void) && difftime(time(NULL), cell->reservation_time) > 420) { fprintf(stderr, -"InnoDB: Error: semaphore wait has lasted > 420 seconds\n" +"InnoDB: Error: semaphore wait has lasted > 600 seconds\n" "InnoDB: We intentionally crash the server, because it appears to be hung.\n" ); @@ -1011,3 +1011,4 @@ sync_array_print_info( sync_array_exit(arr); } + diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c index 86ffed7ca95..fe837b119f3 100644 --- a/innobase/sync/sync0rw.c +++ b/innobase/sync/sync0rw.c @@ -223,7 +223,7 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait rw-s-lock at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)lock, + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, lock->cfile_name, lock->cline, i); } @@ -253,7 +253,7 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu OS wait rw-s-lock at %lx cfile %s cline %lu\n", - os_thread_get_curr_id(), (ulint)lock, + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, lock->cfile_name, lock->cline); } @@ -343,7 +343,8 @@ rw_lock_x_lock_low( } } else if ((rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX) - && (lock->writer_thread == os_thread_get_curr_id())) { + && os_thread_eq(lock->writer_thread, + os_thread_get_curr_id())) { if (rw_lock_get_reader_count(lock) == 0) { @@ -368,7 +369,8 @@ rw_lock_x_lock_low( return(RW_LOCK_WAIT_EX); } else if ((rw_lock_get_writer(lock) == RW_LOCK_EX) - && (lock->writer_thread == os_thread_get_curr_id()) + && os_thread_eq(lock->writer_thread, + os_thread_get_curr_id()) && (lock->pass == 0) && (pass == 0)) { @@ -469,7 +471,7 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait rw-x-lock at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)lock, + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, lock->cfile_name, lock->cline, i); } @@ -502,8 +504,8 @@ lock_loop: if (srv_print_latch_waits) { printf( "Thread %lu OS wait for rw-x-lock at %lx cfile %s cline %lu\n", - os_thread_get_curr_id(), (ulint)lock, lock->cfile_name, - lock->cline); + os_thread_pf(os_thread_get_curr_id()), (ulint)lock, + lock->cfile_name, lock->cline); } rw_x_system_call_count++; @@ -621,7 +623,8 @@ rw_lock_remove_debug_info( while (info != NULL) { if ((pass == info->pass) && ((pass != 0) - || (info->thread_id == os_thread_get_curr_id())) + || os_thread_eq(info->thread_id, + os_thread_get_curr_id())) && (info->lock_type == lock_type)) { /* Found! */ @@ -676,7 +679,7 @@ rw_lock_own( while (info != NULL) { - if ((info->thread_id == os_thread_get_curr_id()) + if (os_thread_eq(info->thread_id, os_thread_get_curr_id()) && (info->pass == 0) && (info->lock_type == lock_type)) { @@ -834,7 +837,7 @@ rw_lock_debug_print( rwt = info->lock_type; printf("Locked: thread %ld file %s line %ld ", - info->thread_id, info->file_name, info->line); + os_thread_pf(info->thread_id), info->file_name, info->line); if (rwt == RW_LOCK_SHARED) { printf("S-LOCK"); } else if (rwt == RW_LOCK_EX) { diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 14a2a6f8cc1..3ea996afd6b 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -230,7 +230,6 @@ mutex_create_func( mutex->magic_n = MUTEX_MAGIC_N; mutex->line = 0; mutex->file_name = (char *) "not yet reserved"; - mutex->thread_id = ULINT_UNDEFINED; mutex->level = SYNC_LEVEL_NONE; mutex->cfile_name = cfile_name; mutex->cline = cline; @@ -392,8 +391,8 @@ spin_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait mutex at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)mutex, mutex->cfile_name, - mutex->cline, i); + os_thread_pf(os_thread_get_curr_id()), (ulint)mutex, + mutex->cfile_name, mutex->cline, i); } mutex_spin_round_count += i; @@ -458,7 +457,7 @@ spin_loop: if (srv_print_latch_waits) { printf( "Thread %lu spin wait succeeds at 2: mutex at %lx\n", - os_thread_get_curr_id(), (ulint)mutex); + os_thread_pf(os_thread_get_curr_id()), (ulint)mutex); } return; @@ -476,8 +475,8 @@ spin_loop: if (srv_print_latch_waits) { printf( "Thread %lu OS wait mutex at %lx cfile %s cline %lu rnds %lu\n", - os_thread_get_curr_id(), (ulint)mutex, mutex->cfile_name, - mutex->cline, i); + os_thread_pf(os_thread_get_curr_id()), (ulint)mutex, + mutex->cfile_name, mutex->cline, i); } mutex_system_call_count++; @@ -572,7 +571,7 @@ mutex_own( return(FALSE); } - if (mutex->thread_id != os_thread_get_curr_id()) { + if (!os_thread_eq(mutex->thread_id, os_thread_get_curr_id())) { return(FALSE); } @@ -611,7 +610,8 @@ mutex_list_print_info(void) &thread_id); printf( "Locked mutex: addr %lx thread %ld file %s line %ld\n", - (ulint)mutex, thread_id, file_name, line); + (ulint)mutex, os_thread_pf(thread_id), + file_name, line); } mutex = UT_LIST_GET_NEXT(list, mutex); @@ -716,7 +716,7 @@ sync_thread_level_arrays_find_slot(void) slot = sync_thread_level_arrays_get_nth(i); - if (slot->levels && (slot->id == id)) { + if (slot->levels && os_thread_eq(slot->id, id)) { return(slot); } @@ -780,7 +780,7 @@ sync_thread_levels_g( { char* file_name; ulint line; - ulint thread_id; + os_thread_id_t thread_id; sync_level_t* slot; rw_lock_t* lock; mutex_t* mutex; @@ -810,7 +810,7 @@ sync_thread_levels_g( &file_name, &line, &thread_id); printf("InnoDB: Locked mutex: addr %lx thread %ld file %s line %ld\n", - (ulint)mutex, thread_id, + (ulint)mutex, os_thread_pf(thread_id), file_name, line); } else { printf("Not locked\n"); diff --git a/innobase/thr/thr0loc.c b/innobase/thr/thr0loc.c index d3d7a58d313..fbf3e3a1dad 100644 --- a/innobase/thr/thr0loc.c +++ b/innobase/thr/thr0loc.c @@ -69,8 +69,8 @@ try_again: local = NULL; - HASH_SEARCH(hash, thr_local_hash, os_thread_conv_id_to_ulint(id), - local, local->id == id); + HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), + local, os_thread_eq(local->id, id)); if (local == NULL) { mutex_exit(&thr_local_mutex); @@ -173,7 +173,7 @@ thr_local_create(void) mutex_enter(&thr_local_mutex); HASH_INSERT(thr_local_t, hash, thr_local_hash, - os_thread_conv_id_to_ulint(os_thread_get_curr_id()), + os_thread_pf(os_thread_get_curr_id()), local); mutex_exit(&thr_local_mutex); @@ -193,8 +193,8 @@ thr_local_free( /* Look for the local struct in the hash table */ - HASH_SEARCH(hash, thr_local_hash, os_thread_conv_id_to_ulint(id), - local, local->id == id); + HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), + local, os_thread_eq(local->id, id)); if (local == NULL) { mutex_exit(&thr_local_mutex); @@ -202,7 +202,7 @@ thr_local_free( } HASH_DELETE(thr_local_t, hash, thr_local_hash, - os_thread_conv_id_to_ulint(id), local); + os_thread_pf(id), local); mutex_exit(&thr_local_mutex); diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 675cdf1b7e4..33c962772e8 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -494,6 +494,34 @@ trx_sys_update_mysql_binlog_offset( } /********************************************************************* +Prints to stdout the MySQL binlog info in the system header if the +magic number shows it valid. */ + +void +trx_sys_print_mysql_binlog_offset_from_page( +/*========================================*/ + byte* page) /* in: buffer containing the trx system header page, + i.e., page number TRX_SYS_PAGE_NO in the tablespace */ +{ + trx_sysf_t* sys_header; + + sys_header = page + TRX_SYS; + + if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) + == TRX_SYS_MYSQL_LOG_MAGIC_N) { + + printf( + "ibbackup: Last MySQL binlog file position %lu %lu, file name %s\n", + mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), + mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_LOW), + sys_header + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME); + } +} + +/********************************************************************* Prints to stderr the MySQL binlog offset info in the trx system header if the magic number shows it valid. */ diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 8d84967a49d..ef17588a2bb 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -72,6 +72,7 @@ trx_create( trx->type = TRX_USER; trx->conc_state = TRX_NOT_STARTED; + trx->start_time = time(NULL); trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; @@ -516,6 +517,7 @@ trx_start_low( if (trx->type == TRX_PURGE) { trx->id = ut_dulint_zero; trx->conc_state = TRX_ACTIVE; + trx->start_time = time(NULL); return(TRUE); } @@ -539,6 +541,7 @@ trx_start_low( trx->rseg = rseg; trx->conc_state = TRX_ACTIVE; + trx->start_time = time(NULL); UT_LIST_ADD_FIRST(trx_list, trx_sys->trx_list, trx); @@ -1465,45 +1468,57 @@ trx_print( 500 bytes */ trx_t* trx) /* in: transaction */ { - buf += sprintf(buf, "TRANSACTION %lu %lu, OS thread id %lu", + char* start_of_line; + + buf += sprintf(buf, "TRANSACTION %lu %lu", ut_dulint_get_high(trx->id), - ut_dulint_get_low(trx->id), - (ulint)trx->mysql_thread_id); + ut_dulint_get_low(trx->id)); - if (ut_strlen(trx->op_info) > 0) { - buf += sprintf(buf, " %s", trx->op_info); - } - - if (trx->type != TRX_USER) { - buf += sprintf(buf, " purge trx"); - } - switch (trx->conc_state) { case TRX_NOT_STARTED: buf += sprintf(buf, ", not started"); break; case TRX_ACTIVE: buf += sprintf(buf, - ", active"); break; + ", ACTIVE %lu sec", + (ulint)difftime(time(NULL), trx->start_time)); break; case TRX_COMMITTED_IN_MEMORY: buf += sprintf(buf, - ", committed in memory"); + ", COMMITTED IN MEMORY"); break; default: buf += sprintf(buf, " state %lu", trx->conc_state); } + buf += sprintf(buf, ", OS thread id %lu", + os_thread_pf(trx->mysql_thread_id)); + + if (ut_strlen(trx->op_info) > 0) { + buf += sprintf(buf, " %s", trx->op_info); + } + + if (trx->type != TRX_USER) { + buf += sprintf(buf, " purge trx"); + } + + buf += sprintf(buf, "\n"); + + start_of_line = buf; + switch (trx->que_state) { - case TRX_QUE_RUNNING: buf += sprintf(buf, - ", runs or sleeps"); break; + case TRX_QUE_RUNNING: break; case TRX_QUE_LOCK_WAIT: buf += sprintf(buf, - ", lock wait"); break; + "LOCK WAIT "); break; case TRX_QUE_ROLLING_BACK: buf += sprintf(buf, - ", rolling back"); break; + "ROLLING BACK "); break; case TRX_QUE_COMMITTING: buf += sprintf(buf, - ", committing"); break; - default: buf += sprintf(buf, " que state %lu", trx->que_state); + "COMMITTING "); break; + default: buf += sprintf(buf, "que state %lu", trx->que_state); } - if (0 < UT_LIST_GET_LEN(trx->trx_locks)) { - buf += sprintf(buf, ", has %lu lock struct(s)", - UT_LIST_GET_LEN(trx->trx_locks)); + if (0 < UT_LIST_GET_LEN(trx->trx_locks) || + mem_heap_get_size(trx->lock_heap) > 400) { + + buf += sprintf(buf, +"%lu lock struct(s), heap size %lu", + UT_LIST_GET_LEN(trx->trx_locks), + mem_heap_get_size(trx->lock_heap)); } if (trx->has_search_latch) { @@ -1515,7 +1530,10 @@ trx_print( ut_dulint_get_low(trx->undo_no)); } - buf += sprintf(buf, "\n"); + if (buf != start_of_line) { + + buf += sprintf(buf, "\n"); + } if (trx->mysql_thd != NULL) { innobase_mysql_print_thd(buf, trx->mysql_thd); |