From dc593c3ec4f4d4e44ed6874c414952ee51bb6074 Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Thu, 31 Jul 2008 15:47:57 -0600 Subject: [PATCH 1/4] Cherry-pick InnoDB fixes for Bug#34286, Bug#35352, and Bug#36600 from snapshot innodb-5.0-ss2475. Bug #34286 Assertion failure in thread 2816 in file .\row\row0sel.c line 3500 Since autoinc init performs a MySQL SELECT query to determine the auto-inc value, set prebuilt->sql_stat_start = TRUE so that it is performed like any normal SELECT, regardless of the context in which it was invoked. Bug #35352 If InnoDB crashes with UNDO slots full error the error persists on restart We've added a heuristic that checks the size of the UNDO slots cache lists (insert and upate). If either of cached lists has more than 500 entries then we add any UNDO slots that are freed, to the common free list instead of the cache list, this is to avoid the case where all the free slots end up in only one of the lists on startup after a crash. Tested with test case for 26590 and passes all mysql-test(s). Bug #36600 SHOW STATUS takes a lot of CPU in buf_get_latched_pages_number Fixed by removing the Innodb_buffer_pool_pages_latched variable from SHOW STATUS output in non-UNIV_DEBUG compilation. --- innobase/buf/buf0buf.c | 2 ++ innobase/include/buf0buf.h | 13 +++++---- innobase/include/srv0srv.h | 2 ++ innobase/include/trx0undo.h | 1 + innobase/srv/srv0srv.c | 2 ++ innobase/trx/trx0trx.c | 8 +++--- innobase/trx/trx0undo.c | 29 ++++++++++++++++----- mysql-test/r/innodb-autoinc-optimize.result | 6 +++++ mysql-test/t/innodb-autoinc-optimize.test | 16 ++++++++++++ sql/ha_innodb.cc | 10 ++++++- 10 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 mysql-test/r/innodb-autoinc-optimize.result create mode 100644 mysql-test/t/innodb-autoinc-optimize.test diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 9df48495355..6cfcb0fc724 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -2260,6 +2260,7 @@ buf_print(void) ut_a(buf_validate()); } +#ifdef UNIV_DEBUG /************************************************************************* Returns the number of latched pages in the buffer pool. */ @@ -2290,6 +2291,7 @@ buf_get_latched_pages_number(void) mutex_exit(&(buf_pool->mutex)); return fixed_pages_number; } +#endif /* UNIV_DEBUG */ /************************************************************************* Returns the number of pending buf pool ios. */ diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index 11e5bb39e63..f802ffa6510 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -495,7 +495,15 @@ Prints info of the buffer pool data structure. */ void buf_print(void); /*============*/ + +/************************************************************************* +Returns the number of latched pages in the buffer pool. */ + +ulint +buf_get_latched_pages_number(void); +/*==============================*/ #endif /* UNIV_DEBUG */ + /************************************************************************ Prints a page to stderr. */ @@ -503,12 +511,7 @@ void buf_page_print( /*===========*/ byte* read_buf); /* in: a database page */ -/************************************************************************* -Returns the number of latched pages in the buffer pool. */ -ulint -buf_get_latched_pages_number(void); -/*==============================*/ /************************************************************************* Returns the number of pending buf pool ios. */ diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index f379efa98eb..97e9136040d 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -531,7 +531,9 @@ struct export_var_struct{ ulint innodb_buffer_pool_pages_dirty; ulint innodb_buffer_pool_pages_misc; ulint innodb_buffer_pool_pages_free; +#ifdef UNIV_DEBUG ulint innodb_buffer_pool_pages_latched; +#endif /* UNIV_DEBUG */ ulint innodb_buffer_pool_read_requests; ulint innodb_buffer_pool_reads; ulint innodb_buffer_pool_wait_free; diff --git a/innobase/include/trx0undo.h b/innobase/include/trx0undo.h index bd7337e4f90..4f1847aa88c 100644 --- a/innobase/include/trx0undo.h +++ b/innobase/include/trx0undo.h @@ -237,6 +237,7 @@ trx_undo_set_state_at_finish( /*=========================*/ /* out: undo log segment header page, x-latched */ + trx_rseg_t* rseg, /* in: rollback segment memory object */ trx_t* trx, /* in: transaction */ trx_undo_t* undo, /* in: undo log memory copy */ mtr_t* mtr); /* in: mtr */ diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 1227824ef80..431138400b6 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1803,7 +1803,9 @@ srv_export_innodb_status(void) export_vars.innodb_buffer_pool_pages_data= UT_LIST_GET_LEN(buf_pool->LRU); export_vars.innodb_buffer_pool_pages_dirty= UT_LIST_GET_LEN(buf_pool->flush_list); export_vars.innodb_buffer_pool_pages_free= UT_LIST_GET_LEN(buf_pool->free); +#ifdef UNIV_DEBUG export_vars.innodb_buffer_pool_pages_latched= buf_get_latched_pages_number(); +#endif /* UNIV_DEBUG */ export_vars.innodb_buffer_pool_pages_total= buf_pool->curr_size; export_vars.innodb_buffer_pool_pages_misc= buf_pool->max_size - UT_LIST_GET_LEN(buf_pool->LRU) - UT_LIST_GET_LEN(buf_pool->free); diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index d865c709bf6..70fd73f2488 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -761,8 +761,8 @@ trx_commit_off_kernel( mutex_enter(&(rseg->mutex)); if (trx->insert_undo != NULL) { - trx_undo_set_state_at_finish(trx, trx->insert_undo, - &mtr); + trx_undo_set_state_at_finish( + rseg, trx, trx->insert_undo, &mtr); } undo = trx->update_undo; @@ -777,8 +777,8 @@ trx_commit_off_kernel( because only a single OS thread is allowed to do the transaction commit for this transaction. */ - update_hdr_page = trx_undo_set_state_at_finish(trx, - undo, &mtr); + update_hdr_page = trx_undo_set_state_at_finish( + rseg, trx, undo, &mtr); /* We have to do the cleanup for the update log while holding the rseg mutex because update log headers diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c index 7441dd3f152..251cd355897 100644 --- a/innobase/trx/trx0undo.c +++ b/innobase/trx/trx0undo.c @@ -1724,6 +1724,7 @@ trx_undo_set_state_at_finish( /*=========================*/ /* out: undo log segment header page, x-latched */ + trx_rseg_t* rseg, /* in: rollback segment memory object */ trx_t* trx __attribute__((unused)), /* in: transaction */ trx_undo_t* undo, /* in: undo log memory copy */ mtr_t* mtr) /* in: mtr */ @@ -1732,8 +1733,10 @@ trx_undo_set_state_at_finish( trx_upagef_t* page_hdr; page_t* undo_page; ulint state; - - ut_ad(trx && undo && mtr); + + ut_ad(trx); + ut_ad(undo); + ut_ad(mtr); if (undo->id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", @@ -1747,9 +1750,23 @@ trx_undo_set_state_at_finish( seg_hdr = undo_page + TRX_UNDO_SEG_HDR; page_hdr = undo_page + TRX_UNDO_PAGE_HDR; - if (undo->size == 1 && mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE) - < TRX_UNDO_PAGE_REUSE_LIMIT) { - state = TRX_UNDO_CACHED; + if (undo->size == 1 + && mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE) + < TRX_UNDO_PAGE_REUSE_LIMIT) { + + /* This is a heuristic to avoid the problem of all UNDO + slots ending up in one of the UNDO lists. Previously if + the server crashed with all the slots in one of the lists, + transactions that required the slots of a different type + would fail for lack of slots. */ + + if (UT_LIST_GET_LEN(rseg->update_undo_list) < 500 + && UT_LIST_GET_LEN(rseg->insert_undo_list) < 500) { + + state = TRX_UNDO_CACHED; + } else { + state = TRX_UNDO_TO_FREE; + } } else if (undo->type == TRX_UNDO_INSERT) { @@ -1759,7 +1776,7 @@ trx_undo_set_state_at_finish( } undo->state = state; - + mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, state, MLOG_2BYTES, mtr); return(undo_page); diff --git a/mysql-test/r/innodb-autoinc-optimize.result b/mysql-test/r/innodb-autoinc-optimize.result new file mode 100644 index 00000000000..61739f0713a --- /dev/null +++ b/mysql-test/r/innodb-autoinc-optimize.result @@ -0,0 +1,6 @@ +drop table if exists t1; +create table t1(a int not null auto_increment primary key) engine=innodb; +insert into t1 set a = -1; +optimize table t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK diff --git a/mysql-test/t/innodb-autoinc-optimize.test b/mysql-test/t/innodb-autoinc-optimize.test new file mode 100644 index 00000000000..c7e22a8ff40 --- /dev/null +++ b/mysql-test/t/innodb-autoinc-optimize.test @@ -0,0 +1,16 @@ +-- source include/have_innodb.inc +# embedded server ignores 'delayed', so skip this +-- source include/not_embedded.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Bug 34286 +# +create table t1(a int not null auto_increment primary key) engine=innodb; +insert into t1 set a = -1; +# NOTE: The database needs to be shutdown and restarted (here) for +# the test to work. It's included for reference only. +optimize table t1; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1be6137460b..1c0f8a6e9b3 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -244,8 +244,10 @@ struct show_var_st innodb_status_variables[]= { (char*) &export_vars.innodb_buffer_pool_pages_flushed, SHOW_LONG}, {"buffer_pool_pages_free", (char*) &export_vars.innodb_buffer_pool_pages_free, SHOW_LONG}, +#ifdef UNIV_DEBUG {"buffer_pool_pages_latched", (char*) &export_vars.innodb_buffer_pool_pages_latched, SHOW_LONG}, +#endif /* UNIV_DEBUG */ {"buffer_pool_pages_misc", (char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG}, {"buffer_pool_pages_total", @@ -4250,7 +4252,7 @@ ha_innobase::rnd_pos( int error; uint keynr = active_index; DBUG_ENTER("rnd_pos"); - DBUG_DUMP("key", (uchar *)pos, ref_length); + DBUG_DUMP("key", (uchar*) pos, ref_length); statistic_increment(current_thd->status_var.ha_read_rnd_count, &LOCK_status); @@ -6882,6 +6884,12 @@ ha_innobase::innobase_read_and_init_auto_inc( from a table when no table has been locked in ::external_lock(). */ prebuilt->trx->n_mysql_tables_in_use++; + /* Since we will perform a MySQL SELECT query to determine the + auto-inc value, set prebuilt->sql_stat_start = TRUE so that it + is performed like any normal SELECT, regardless of the context + we come here. */ + prebuilt->sql_stat_start = TRUE; + error = index_last(table->record[1]); prebuilt->trx->n_mysql_tables_in_use--; From 9d9fa39b976e0dd6569f97b1ee6b115f3bc2b178 Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Thu, 7 Aug 2008 18:25:24 -0600 Subject: [PATCH 2/4] Cherry-pick fix for Bug#35220 from innodb-5.0-ss2475 snapshot. Bug#35220: ALTER TABLE too picky on reserved word "foreign" In ALTER TABLE, change the internal parser to search for ``FOREIGN[[:space:]]'' instead of only ``FOREIGN'' when parsing ALTER TABLE ... DROP FOREIGN KEY ...; otherwise it could be mistaken with ALTER TABLE ... DROP foreign_col; (This fix is already present in MySQL 5.1 and higher.) --- innobase/dict/dict0dict.c | 2 +- mysql-test/r/innodb_bug35220.result | 1 + mysql-test/t/innodb_bug35220.test | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 mysql-test/r/innodb_bug35220.result create mode 100644 mysql-test/t/innodb_bug35220.test diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 96c822857df..b8d9f362b06 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -3554,7 +3554,7 @@ loop: ptr = dict_accept(ptr, "FOREIGN", &success); - if (!success) { + if (!success || !ib_isspace(*ptr)) { goto loop; } diff --git a/mysql-test/r/innodb_bug35220.result b/mysql-test/r/innodb_bug35220.result new file mode 100644 index 00000000000..195775f74c8 --- /dev/null +++ b/mysql-test/r/innodb_bug35220.result @@ -0,0 +1 @@ +SET storage_engine=InnoDB; diff --git a/mysql-test/t/innodb_bug35220.test b/mysql-test/t/innodb_bug35220.test new file mode 100644 index 00000000000..26f7d6b1ddd --- /dev/null +++ b/mysql-test/t/innodb_bug35220.test @@ -0,0 +1,16 @@ +# +# Bug#35220 ALTER TABLE too picky on reserved word "foreign" +# http://bugs.mysql.com/35220 +# + +-- source include/have_innodb.inc + +SET storage_engine=InnoDB; + +# we care only that the following SQL commands do not produce errors +-- disable_query_log +-- disable_result_log + +CREATE TABLE bug35220 (foreign_col INT, dummy_cant_delete_all_columns INT); +ALTER TABLE bug35220 DROP foreign_col; +DROP TABLE bug35220; From 6cab759d7a2d1534cf167971a4da0b7d0e5f0f5c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Aug 2008 11:05:24 +0200 Subject: [PATCH 3/4] Raise version number after cloning 5.0.68 --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index ab56fc24c71..e302aaa5c4a 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.68) +AM_INIT_AUTOMAKE(mysql, 5.0.69) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=68 +NDB_VERSION_BUILD=69 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ? From 182b2383347cca5c6870b3f574191d5984799f67 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Wed, 13 Aug 2008 12:34:35 +0200 Subject: [PATCH 4/4] Correct the version number to 5.0.70. configure.in: Version number raise was incomplete, the 5.0 tree steps by 2. --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index e302aaa5c4a..bd993bb5fcf 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! # remember to also change ndb version below and update version.c in ndb -AM_INIT_AUTOMAKE(mysql, 5.0.69) +AM_INIT_AUTOMAKE(mysql, 5.0.70) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -23,7 +23,7 @@ NDB_SHARED_LIB_VERSION=$NDB_SHARED_LIB_MAJOR_VERSION:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=69 +NDB_VERSION_BUILD=70 NDB_VERSION_STATUS="" # Set all version vars based on $VERSION. How do we do this more elegant ?