From 70fbfa0ce2f3310f2a80e424e0d96ff8234ed91b Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 8 Jul 2011 16:25:32 +0200 Subject: [PATCH 01/49] Fix Bug #47337: innochecksum not built for --with-plugin-innodb_plugin --without-plugin-innobase In 5.1, we can have the traditional "innobase" code (built-in) or the new version "innodb" (plugin). The help tool "innochecksum" is useful for both, but its generation was coupled to "innobase" only. Fix this by treating both "innobase" and "innodb" equivalent in the configure phase, this affects both "innochecksum" and the InnoDB documentation. This patch was proposed by Mark Callaghan. --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 0948fe1349d..fffbde0fd00 100644 --- a/configure.in +++ b/configure.in @@ -2711,7 +2711,7 @@ then MAN_DROP="$MAN_DROP embedded" grep -v 'embedded' $MANLISTFIL > $TMPLISTFIL ; mv -f $TMPLISTFIL $MANLISTFIL fi - if test X"$with_plugin_innobase" != Xyes + if test X"$with_plugin_innobase" != Xyes -a X"$with_plugin_innodb_plugin" != Xyes then MAN_DROP="$MAN_DROP innodb" grep -v 'inno' $MANLISTFIL > $TMPLISTFIL ; mv -f $TMPLISTFIL $MANLISTFIL @@ -2790,7 +2790,7 @@ then fi # "innochecksum" is not in the "innobase/" subdirectory, but should be switched -AM_CONDITIONAL([BUILD_INNODB_TOOLS], [test X"$with_plugin_innobase" = Xyes]) +AM_CONDITIONAL([BUILD_INNODB_TOOLS], [test X"$with_plugin_innobase" = Xyes -o X"$with_plugin_innodb_plugin" = Xyes ]) # IMPORTANT - do not modify LIBS past this line - this hack is the only way # I know to add the static NSS magic if we have static NSS libraries with From 083a316d1f9020d48a5b9769fafbb3accad3c03a Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Tue, 12 Jul 2011 06:08:52 +0100 Subject: [PATCH 02/49] Bug#11758414/Bug#50614: Default storage_engine not honored when set from within a stored procedure When CREATE TABLE wasn't given ENGINE=... it would determine the default ENGINE at parse-time rather than at execution time, leading to incorrect behaviour (namely, later changes to the default engine being ignore) when calling CREATE TABLE from a stored procedure. We now defer working out the default engine till execution of CREATE TABLE. mysql-test/r/sp_trans.result: results! mysql-test/t/sp_trans.test: Show that CREATE TABLE (called from store routine) heeds any changes after CREATE SP / parse-time. Show that explicitly requesting an ENGINE still works. sql/sql_parse.cc: If no ENGINE=... was given at parse-time, determine default engine at execution time of CREATE TABLE. sql/sql_yacc.yy: If CREATE TABLE is not given ENGINE=..., don't bother figuring out the default engine during parsing; we'll do it at execution time instead to be aware of the latest updates. --- mysql-test/r/sp_trans.result | 46 ++++++++++++++++++++++++++++++++++++ mysql-test/t/sp_trans.test | 33 ++++++++++++++++++++++++++ sql/sql_parse.cc | 6 +++++ sql/sql_yacc.yy | 4 ++-- 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp_trans.result b/mysql-test/r/sp_trans.result index a64f53efde7..dec37db652a 100644 --- a/mysql-test/r/sp_trans.result +++ b/mysql-test/r/sp_trans.result @@ -556,3 +556,49 @@ f1 bug13575(f1) 3 ccc drop function bug13575| drop table t3| +SELECT @@GLOBAL.storage_engine INTO @old_engine| +SET @@GLOBAL.storage_engine=InnoDB| +SET @@SESSION.storage_engine=InnoDB| +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine InnoDB +SHOW SESSION VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine InnoDB +CREATE PROCEDURE bug11758414() +BEGIN +SET @@GLOBAL.storage_engine="MyISAM"; +SET @@SESSION.storage_engine="MyISAM"; +# show defaults at execution time / that setting them worked +SHOW GLOBAL VARIABLES LIKE 'storage_engine'; +SHOW SESSION VARIABLES LIKE 'storage_engine'; +CREATE TABLE t1 (id int); +CREATE TABLE t2 (id int) ENGINE=InnoDB; +# show we're heeding the default (at run-time, not parse-time!) + SHOW CREATE TABLE t1; + # show that we didn't break explicit override with ENGINE=... +SHOW CREATE TABLE t2; +END; +| +CALL bug11758414| +Variable_name Value +storage_engine MyISAM +Variable_name Value +storage_engine MyISAM +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine MyISAM +SHOW SESSION VARIABLES LIKE 'storage_engine'| +Variable_name Value +storage_engine MyISAM +DROP PROCEDURE bug11758414| +DROP TABLE t1, t2| +SET @@GLOBAL.storage_engine=@old_engine| diff --git a/mysql-test/t/sp_trans.test b/mysql-test/t/sp_trans.test index 0b04b9d7668..2d59fb20bbd 100644 --- a/mysql-test/t/sp_trans.test +++ b/mysql-test/t/sp_trans.test @@ -593,6 +593,39 @@ drop function bug13575| drop table t3| +# +# BUG#11758414: Default storage_engine not honored when set +# from within a stored procedure +# +SELECT @@GLOBAL.storage_engine INTO @old_engine| +SET @@GLOBAL.storage_engine=InnoDB| +SET @@SESSION.storage_engine=InnoDB| +# show defaults at define-time +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +SHOW SESSION VARIABLES LIKE 'storage_engine'| +CREATE PROCEDURE bug11758414() +BEGIN + SET @@GLOBAL.storage_engine="MyISAM"; + SET @@SESSION.storage_engine="MyISAM"; + # show defaults at execution time / that setting them worked + SHOW GLOBAL VARIABLES LIKE 'storage_engine'; + SHOW SESSION VARIABLES LIKE 'storage_engine'; + CREATE TABLE t1 (id int); + CREATE TABLE t2 (id int) ENGINE=InnoDB; + # show we're heeding the default (at run-time, not parse-time!) + SHOW CREATE TABLE t1; + # show that we didn't break explicit override with ENGINE=... + SHOW CREATE TABLE t2; +END; +| +CALL bug11758414| +# show that changing defaults within SP stuck +SHOW GLOBAL VARIABLES LIKE 'storage_engine'| +SHOW SESSION VARIABLES LIKE 'storage_engine'| +DROP PROCEDURE bug11758414| +DROP TABLE t1, t2| +SET @@GLOBAL.storage_engine=@old_engine| + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2eeabc2f0c1..14ad77d29fd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2616,6 +2616,12 @@ mysql_execute_command(THD *thd) create_table->table_name)) goto end_with_restore_list; #endif + /* + If no engine type was given, work out the default now + rather than at parse-time. + */ + if (!(create_info.used_fields & HA_CREATE_USED_ENGINE)) + create_info.db_type= ha_default_handlerton(thd); /* If we are using SET CHARSET without DEFAULT, add an implicit DEFAULT to not confuse old users. (This may change). diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6245f07b9cf..f4fb822b294 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1838,7 +1838,6 @@ create: lex->change=NullS; bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.options=$2 | $4; - lex->create_info.db_type= ha_default_handlerton(thd); lex->create_info.default_table_charset= NULL; lex->name.str= 0; lex->name.length= 0; @@ -1847,7 +1846,8 @@ create: { LEX *lex= YYTHD->lex; lex->current_select= &lex->select_lex; - if (!lex->create_info.db_type) + if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && + !lex->create_info.db_type) { lex->create_info.db_type= ha_default_handlerton(YYTHD); push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN, From 341989469f31225646b4fedf9d42a8f73a4d4801 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 28 Jul 2011 12:54:02 +0200 Subject: [PATCH 03/49] Bug #12726039 MTR SHOULD PROVIDE ABILITY TO DISABLE TEST ON SELECTED PLATFORMS Add extra patterns to look for @ --- mysql-test/lib/mtr_cases.pm | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 708b8e90fc4..3dcd99f235f 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -317,10 +317,30 @@ sub collect_one_suite($) my %disabled; if ( open(DISABLED, "$testdir/disabled.def" ) ) { + # $^O on Windows considered not generic enough + my $plat= (IS_WINDOWS) ? 'windows' : $^O; + while ( ) { chomp; - if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) + #diasble the test case if platform matches + if ( /\@/ ) + { + if ( /\@$plat/ ) + { + /^\s*(\S+)\s*\@$plat.*:\s*(.*?)\s*$/ ; + $disabled{$1}= $2; + } + elsif ( /\@!(\S*)/ ) + { + if ( $1 ne $plat) + { + /^\s*(\S+)\s*\@!.*:\s*(.*?)\s*$/ ; + $disabled{$1}= $2; + } + } + } + elsif ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) { $disabled{$1}= $2; } From 730bb779076980ae67460521d94b2cbe96a70a54 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 28 Jul 2011 13:01:51 +0200 Subject: [PATCH 04/49] Fixed test ndb.ndb_partition_error2, didn't include have_ndb.inc --- mysql-test/suite/ndb/t/ndb_partition_error2.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/ndb/t/ndb_partition_error2.test b/mysql-test/suite/ndb/t/ndb_partition_error2.test index afedd0e3c5c..58c38f2dd37 100644 --- a/mysql-test/suite/ndb/t/ndb_partition_error2.test +++ b/mysql-test/suite/ndb/t/ndb_partition_error2.test @@ -1,3 +1,4 @@ +-- source include/have_ndb.inc disable_query_log; --require r/true.require select support = 'Enabled' as `TRUE` from information_schema.engines where engine = 'ndbcluster'; From a79cabcfefbf79648597c65de559880f78ae0563 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Aug 2011 14:20:17 +0300 Subject: [PATCH 05/49] bumped the version to 5.1.60 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 0e336c5522b..e56a18540b5 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.59], [], [mysql]) +AC_INIT([MySQL Server], [5.1.60], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 669ff0370347ccf18622ba7f8dbe04e04c63795d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 15 Aug 2011 12:11:43 +0300 Subject: [PATCH 06/49] Bug #11766591 59733: Possible deadlock when buffered changes are to be discarded in buf_page_create() This bug turned out to be a false alarm, a bug in the UNIV_SYNC_DEBUG diagnostic code. Because of this, the patch was not backported to the built-in InnoDB in MySQL 5.1. Furthermore, there is no test case for InnoDB Plugin in MySQL 5.1, because the delete buffering in MySQL 5.5 makes triggering the failure much easier. When a freed page for which there exist orphaned buffered changes is allocated and reused for something else, buf_page_create() will discard the buffered changes by invoking ibuf_merge_or_delete_for_page(). This would violate the InnoDB latching order. Tweak the latching order as follows. Move SYNC_IBUF_MUTEX below SYNC_FSP_PAGE, where it logically belongs, and assign new latching levels for the ibuf->index->lock and the insert buffer B-tree pages: #define SYNC_IBUF_MUTEX 370 /* ibuf_mutex */ #define SYNC_IBUF_INDEX_TREE 360 #define SYNC_IBUF_TREE_NODE_NEW 359 #define SYNC_IBUF_TREE_NODE 358 btr_block_get(), btr_page_get(): In UNIV_SYNC_DEBUG, add the parameter "index" for determining the appropriate latching order (SYNC_IBUF_TREE_NODE or SYNC_TREE_NODE). btr_page_alloc_for_ibuf(), btr_create(): Use SYNC_IBUF_TREE_NODE_NEW instead of SYNC_TREE_NODE_NEW for insert buffer pages. btr_cur_search_to_nth_level(), btr_pcur_restore_position_func(): Use SYNC_IBUF_TREE_NODE instead of SYNC_TREE_NODE for insert buffer pages. btr_search_guess_on_hash(): Assert that the index is not an insert buffer tree. dict_index_add_to_cache(): Use SYNC_IBUF_INDEX_TREE for the insert buffer tree (ibuf->index->lock). ibuf0ibuf.c: Use SYNC_IBUF_TREE_NODE or SYNC_IBUF_TREE_NODE_NEW for all B-tree pages. ibuf_merge_or_delete_for_page(): Assert that the user page is BUF_IO_READ fixed. Only in this way it is OK to latch it as SYNC_IBUF_TREE_NODE instead of the proper SYNC_TREE_NODE (which would violate the changed latching order). sync_thread_add_level(): Remove the special tweak for SYNC_IBUF_MUTEX. Add rules for the added latching levels. rb:591 approved by Jimmy Yang --- storage/innodb_plugin/ChangeLog | 9 ++ storage/innodb_plugin/btr/btr0btr.c | 100 ++++++++++++++-------- storage/innodb_plugin/btr/btr0cur.c | 36 ++++---- storage/innodb_plugin/btr/btr0pcur.c | 11 ++- storage/innodb_plugin/btr/btr0sea.c | 3 +- storage/innodb_plugin/dict/dict0crea.c | 4 +- storage/innodb_plugin/dict/dict0dict.c | 6 +- storage/innodb_plugin/ibuf/ibuf0ibuf.c | 24 ++++-- storage/innodb_plugin/include/btr0btr.h | 34 ++++++-- storage/innodb_plugin/include/btr0btr.ic | 10 ++- storage/innodb_plugin/include/sync0sync.h | 9 +- storage/innodb_plugin/sync/sync0sync.c | 31 ++++--- 12 files changed, 181 insertions(+), 96 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index f873f3a24bd..0b90b5729d5 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,12 @@ +2011-08-15 The InnoDB Team + + * btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c, + dict/dict0crea.c, dict/dict0dict.c, ibuf/ibuf0ibuf.c, + include/btr0btr.h, include/btr0btr.ic, include/sync0sync.h, + sync/sync0sync.c: + Fix Bug#11766591 59733: Possible deadlock when buffered changes + are to be discarded in buf_page_create() + 2011-08-08 The InnoDB Team * row/row0sel.c: diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index ac188c8c2fd..5e6724bbd54 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -690,7 +690,8 @@ btr_root_block_get( zip_size = dict_table_zip_size(index->table); root_page_no = dict_index_get_page(index); - block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, + index, mtr); ut_a((ibool)!!page_is_comp(buf_block_get_frame(block)) == dict_table_is_comp(index->table)); #ifdef UNIV_BTR_DEBUG @@ -891,7 +892,7 @@ btr_page_alloc_for_ibuf( dict_table_zip_size(index->table), node_addr.page, RW_X_LATCH, mtr); new_page = buf_block_get_frame(new_block); - buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level(new_block, SYNC_IBUF_TREE_NODE_NEW); flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, @@ -1139,7 +1140,7 @@ btr_node_ptr_get_child( page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); return(btr_block_get(space, dict_table_zip_size(index->table), - page_no, RW_X_LATCH, mtr)); + page_no, RW_X_LATCH, index, mtr)); } /************************************************************//** @@ -1311,7 +1312,8 @@ btr_create( space, 0, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); - buf_block_dbg_add_level(ibuf_hdr_block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level( + ibuf_hdr_block, SYNC_IBUF_TREE_NODE_NEW); ut_ad(buf_block_get_page_no(ibuf_hdr_block) == IBUF_HEADER_PAGE_NO); @@ -1348,10 +1350,9 @@ btr_create( page_no = buf_block_get_page_no(block); frame = buf_block_get_frame(block); - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); - if (type & DICT_IBUF) { /* It is an insert buffer tree: initialize the free list */ + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); @@ -1359,6 +1360,8 @@ btr_create( } else { /* It is a non-ibuf tree: create a file segment for leaf pages */ + buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); + if (!fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { /* Not enough space for new segment, free root @@ -1430,7 +1433,8 @@ btr_free_but_not_root( leaf_loop: mtr_start(&mtr); - root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr); + root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, &mtr); #ifdef UNIV_BTR_DEBUG ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + root, space)); @@ -1452,7 +1456,8 @@ leaf_loop: top_loop: mtr_start(&mtr); - root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr); + root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, &mtr); #ifdef UNIV_BTR_DEBUG ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP + root, space)); @@ -1478,13 +1483,13 @@ btr_free_root( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint root_page_no, /*!< in: root page number */ - mtr_t* mtr) /*!< in: a mini-transaction which has already - been started */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { buf_block_t* block; fseg_header_t* header; - block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, + NULL, mtr); btr_search_drop_page_hash_index(block); @@ -2362,9 +2367,8 @@ btr_attach_half_pages( /* Update page links of the level */ if (prev_page_no != FIL_NULL) { - buf_block_t* prev_block = btr_block_get(space, zip_size, - prev_page_no, - RW_X_LATCH, mtr); + buf_block_t* prev_block = btr_block_get( + space, zip_size, prev_page_no, RW_X_LATCH, index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(prev_block->frame) == page_is_comp(page)); ut_a(btr_page_get_next(prev_block->frame, mtr) @@ -2377,9 +2381,8 @@ btr_attach_half_pages( } if (next_page_no != FIL_NULL) { - buf_block_t* next_block = btr_block_get(space, zip_size, - next_page_no, - RW_X_LATCH, mtr); + buf_block_t* next_block = btr_block_get( + space, zip_size, next_page_no, RW_X_LATCH, index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(next_block->frame) == page_is_comp(page)); ut_a(btr_page_get_prev(next_block->frame, mtr) @@ -2801,17 +2804,42 @@ func_exit: return(rec); } +#ifdef UNIV_SYNC_DEBUG +/*************************************************************//** +Removes a page from the level list of pages. +@param space in: space where removed +@param zip_size in: compressed page size in bytes, or 0 for uncompressed +@param page in/out: page to remove +@param index in: index tree +@param mtr in/out: mini-transaction */ +# define btr_level_list_remove(space,zip_size,page,index,mtr) \ + btr_level_list_remove_func(space,zip_size,page,index,mtr) +#else /* UNIV_SYNC_DEBUG */ +/*************************************************************//** +Removes a page from the level list of pages. +@param space in: space where removed +@param zip_size in: compressed page size in bytes, or 0 for uncompressed +@param page in/out: page to remove +@param index in: index tree +@param mtr in/out: mini-transaction */ +# define btr_level_list_remove(space,zip_size,page,index,mtr) \ + btr_level_list_remove_func(space,zip_size,page,mtr) +#endif /* UNIV_SYNC_DEBUG */ + /*************************************************************//** Removes a page from the level list of pages. */ -static +static __attribute__((nonnull)) void -btr_level_list_remove( -/*==================*/ - ulint space, /*!< in: space where removed */ - ulint zip_size,/*!< in: compressed page size in bytes - or 0 for uncompressed pages */ - page_t* page, /*!< in: page to remove */ - mtr_t* mtr) /*!< in: mtr */ +btr_level_list_remove_func( +/*=======================*/ + ulint space, /*!< in: space where removed */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + page_t* page, /*!< in/out: page to remove */ +#ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree */ +#endif /* UNIV_SYNC_DEBUG */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint prev_page_no; ulint next_page_no; @@ -2829,7 +2857,7 @@ btr_level_list_remove( if (prev_page_no != FIL_NULL) { buf_block_t* prev_block = btr_block_get(space, zip_size, prev_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); page_t* prev_page = buf_block_get_frame(prev_block); #ifdef UNIV_BTR_DEBUG @@ -2846,7 +2874,7 @@ btr_level_list_remove( if (next_page_no != FIL_NULL) { buf_block_t* next_block = btr_block_get(space, zip_size, next_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); page_t* next_page = buf_block_get_frame(next_block); #ifdef UNIV_BTR_DEBUG @@ -3172,7 +3200,7 @@ btr_compress( if (is_left) { merge_block = btr_block_get(space, zip_size, left_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_next(merge_page, mtr) @@ -3181,7 +3209,7 @@ btr_compress( } else if (right_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_prev(merge_page, mtr) @@ -3270,7 +3298,7 @@ err_exit: btr_search_drop_page_hash_index(block); /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); btr_node_ptr_delete(index, block, mtr); lock_update_merge_left(merge_block, orig_pred, block); @@ -3327,7 +3355,7 @@ err_exit: #endif /* UNIV_BTR_DEBUG */ /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); /* Replace the address of the old child node (= page) with the address of the merge page to the right */ @@ -3519,7 +3547,7 @@ btr_discard_page( if (left_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, left_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_next(merge_page, mtr) @@ -3527,7 +3555,7 @@ btr_discard_page( #endif /* UNIV_BTR_DEBUG */ } else if (right_page_no != FIL_NULL) { merge_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, index, mtr); merge_page = buf_block_get_frame(merge_block); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_prev(merge_page, mtr) @@ -3562,7 +3590,7 @@ btr_discard_page( btr_node_ptr_delete(index, block, mtr); /* Remove the page from the level list */ - btr_level_list_remove(space, zip_size, page, mtr); + btr_level_list_remove(space, zip_size, page, index, mtr); #ifdef UNIV_ZIP_DEBUG { page_zip_des_t* merge_page_zip @@ -4080,7 +4108,7 @@ loop: if (right_page_no != FIL_NULL) { const rec_t* right_rec; right_block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, &mtr); + RW_X_LATCH, index, &mtr); right_page = buf_block_get_frame(right_block); if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr) != page_get_page_no(page))) { @@ -4306,7 +4334,7 @@ node_ptr_fails: mtr_start(&mtr); block = btr_block_get(space, zip_size, right_page_no, - RW_X_LATCH, &mtr); + RW_X_LATCH, index, &mtr); page = buf_block_get_frame(block); goto loop; diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index f378c477537..5cefa51bcd5 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -238,7 +238,8 @@ btr_cur_latch_leaves( case BTR_SEARCH_LEAF: case BTR_MODIFY_LEAF: mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH; - get_block = btr_block_get(space, zip_size, page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, page_no, mode, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -249,9 +250,9 @@ btr_cur_latch_leaves( left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - left_page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, left_page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); @@ -261,8 +262,9 @@ btr_cur_latch_leaves( get_block->check_index_page_at_flush = TRUE; } - get_block = btr_block_get(space, zip_size, page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -271,9 +273,9 @@ btr_cur_latch_leaves( right_page_no = btr_page_get_next(page, mtr); if (right_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - right_page_no, - RW_X_LATCH, mtr); + get_block = btr_block_get( + space, zip_size, right_page_no, + RW_X_LATCH, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); @@ -292,8 +294,9 @@ btr_cur_latch_leaves( left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { - get_block = btr_block_get(space, zip_size, - left_page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, + left_page_no, mode, cursor->index, mtr); cursor->left_block = get_block; #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) @@ -304,7 +307,8 @@ btr_cur_latch_leaves( get_block->check_index_page_at_flush = TRUE; } - get_block = btr_block_get(space, zip_size, page_no, mode, mtr); + get_block = btr_block_get( + space, zip_size, page_no, mode, cursor->index, mtr); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(get_block->frame) == page_is_comp(page)); #endif /* UNIV_BTR_DEBUG */ @@ -572,7 +576,9 @@ retry_page_get: ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level( + block, dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); } ut_ad(0 == ut_dulint_cmp(index->id, @@ -630,8 +636,8 @@ retry_page_get: if (level > 0) { /* x-latch the page */ - page = btr_page_get(space, zip_size, - page_no, RW_X_LATCH, mtr); + page = btr_page_get(space, zip_size, page_no, + RW_X_LATCH, index, mtr); ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table)); } diff --git a/storage/innodb_plugin/btr/btr0pcur.c b/storage/innodb_plugin/btr/btr0pcur.c index 056896c7927..3bd2e9fd7d6 100644 --- a/storage/innodb_plugin/btr/btr0pcur.c +++ b/storage/innodb_plugin/btr/btr0pcur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -266,8 +266,10 @@ btr_pcur_restore_position_func( file, line, mtr))) { cursor->pos_state = BTR_PCUR_IS_POSITIONED; - buf_block_dbg_add_level(btr_pcur_get_block(cursor), - SYNC_TREE_NODE); + buf_block_dbg_add_level( + btr_pcur_get_block(cursor), + dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); if (cursor->rel_pos == BTR_PCUR_ON) { #ifdef UNIV_DEBUG @@ -417,7 +419,8 @@ btr_pcur_move_to_next_page( ut_ad(next_page_no != FIL_NULL); next_block = btr_block_get(space, zip_size, next_page_no, - cursor->latch_mode, mtr); + cursor->latch_mode, + btr_pcur_get_btr_cur(cursor)->index, mtr); next_page = buf_block_get_frame(next_block); #ifdef UNIV_BTR_DEBUG ut_a(page_is_comp(next_page) == page_is_comp(page)); diff --git a/storage/innodb_plugin/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c index cd0eadbb1b8..88442b7d4f0 100644 --- a/storage/innodb_plugin/btr/btr0sea.c +++ b/storage/innodb_plugin/btr/btr0sea.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -832,6 +832,7 @@ btr_search_guess_on_hash( btr_pcur_t pcur; #endif ut_ad(index && info && tuple && cursor && mtr); + ut_ad(!dict_index_is_ibuf(index)); ut_ad((latch_mode == BTR_SEARCH_LEAF) || (latch_mode == BTR_MODIFY_LEAF)); diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c index 7d6cbc8c1c8..a57b2eca9e2 100644 --- a/storage/innodb_plugin/dict/dict0crea.c +++ b/storage/innodb_plugin/dict/dict0crea.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -828,7 +828,7 @@ dict_truncate_index_tree( appropriate field in the SYS_INDEXES record: this mini-transaction marks the B-tree totally truncated */ - btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, NULL, mtr); btr_free_root(space, zip_size, root_page_no, mtr); create: diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index a8787bbda61..2d2262acf87 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1661,7 +1661,9 @@ undo_size_ok: new_index->stat_n_leaf_pages = 1; new_index->page = page_no; - rw_lock_create(&new_index->lock, SYNC_INDEX_TREE); + rw_lock_create(&new_index->lock, + dict_index_is_ibuf(index) + ? SYNC_IBUF_INDEX_TREE : SYNC_INDEX_TREE); if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) { diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index 23981ac388e..effd7b9572b 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -356,7 +356,7 @@ ibuf_tree_root_get( block = buf_page_get( IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); return(buf_block_get_frame(block)); } @@ -496,7 +496,7 @@ ibuf_init_at_db_start(void) block = buf_page_get( IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); root = buf_block_get_frame(block); } @@ -1766,7 +1766,7 @@ ibuf_add_free_page(void) block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); page = buf_block_get_frame(block); @@ -1897,8 +1897,7 @@ ibuf_remove_free_page(void) block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); - + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); page = buf_block_get_frame(block); } @@ -2408,7 +2407,7 @@ ibuf_get_volume_buffered( block = buf_page_get( IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); prev_page = buf_block_get_frame(block); @@ -2482,7 +2481,7 @@ count_later: block = buf_page_get( IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); next_page = buf_block_get_frame(block); @@ -3248,6 +3247,7 @@ ibuf_merge_or_delete_for_page( ut_ad(!block || buf_block_get_space(block) == space); ut_ad(!block || buf_block_get_page_no(block) == page_no); ut_ad(!block || buf_block_get_zip_size(block) == zip_size); + ut_ad(!block || buf_block_get_io_fix(block) == BUF_IO_READ); if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE || trx_sys_hdr_page(space, page_no)) { @@ -3403,7 +3403,13 @@ loop: ut_a(success); - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + /* This is a user page (secondary index leaf page), + but we pretend that it is a change buffer page in + order to obey the latching order. This should be OK, + because buffered changes are applied immediately while + the block is io-fixed. Other threads must not try to + latch an io-fixed block. */ + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE); } /* Position pcur in the insert buffer at the first entry for this diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h index 987de03b349..c0a038dd21d 100644 --- a/storage/innodb_plugin/include/btr0btr.h +++ b/storage/innodb_plugin/include/btr0btr.h @@ -188,26 +188,45 @@ btr_block_get_func( ulint mode, /*!< in: latch mode */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ - mtr_t* mtr) /*!< in/out: mtr */ - __attribute__((nonnull)); +# ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree, may be NULL + if it is not an insert buffer tree */ +# endif /* UNIV_SYNC_DEBUG */ + mtr_t* mtr); /*!< in/out: mini-transaction */ +# ifdef UNIV_SYNC_DEBUG /** Gets a buffer page and declares its latching order level. @param space tablespace identifier @param zip_size compressed page size in bytes or 0 for uncompressed pages @param page_no page number @param mode latch mode +@param index index tree, may be NULL if not the insert buffer tree @param mtr mini-transaction handle @return the block descriptor */ -# define btr_block_get(space,zip_size,page_no,mode,mtr) \ - btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr) +# define btr_block_get(space,zip_size,page_no,mode,index,mtr) \ + btr_block_get_func(space,zip_size,page_no,mode, \ + __FILE__,__LINE__,index,mtr) +# else /* UNIV_SYNC_DEBUG */ /** Gets a buffer page and declares its latching order level. @param space tablespace identifier @param zip_size compressed page size in bytes or 0 for uncompressed pages @param page_no page number @param mode latch mode +@param idx index tree, may be NULL if not the insert buffer tree +@param mtr mini-transaction handle +@return the block descriptor */ +# define btr_block_get(space,zip_size,page_no,mode,idx,mtr) \ + btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr) +# endif /* UNIV_SYNC_DEBUG */ +/** Gets a buffer page and declares its latching order level. +@param space tablespace identifier +@param zip_size compressed page size in bytes or 0 for uncompressed pages +@param page_no page number +@param mode latch mode +@param idx index tree, may be NULL if not the insert buffer tree @param mtr mini-transaction handle @return the uncompressed page frame */ -# define btr_page_get(space,zip_size,page_no,mode,mtr) \ - buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,mtr)) +# define btr_page_get(space,zip_size,page_no,mode,idx,mtr) \ + buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,idx,mtr)) #endif /* !UNIV_HOTBACKUP */ /**************************************************************//** Gets the index id field of a page. @@ -333,8 +352,7 @@ btr_free_root( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint root_page_no, /*!< in: root page number */ - mtr_t* mtr); /*!< in: a mini-transaction which has already - been started */ + mtr_t* mtr); /*!< in/out: mini-transaction */ /*************************************************************//** Makes tree one level higher by splitting the root, and inserts the tuple. It is assumed that mtr contains an x-latch on the tree. diff --git a/storage/innodb_plugin/include/btr0btr.ic b/storage/innodb_plugin/include/btr0btr.ic index 83eb3627abb..1837d091ccf 100644 --- a/storage/innodb_plugin/include/btr0btr.ic +++ b/storage/innodb_plugin/include/btr0btr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -48,6 +48,10 @@ btr_block_get_func( ulint mode, /*!< in: latch mode */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ +#ifdef UNIV_SYNC_DEBUG + const dict_index_t* index, /*!< in: index tree, may be NULL + if it is not an insert buffer tree */ +#endif /* UNIV_SYNC_DEBUG */ mtr_t* mtr) /*!< in/out: mtr */ { buf_block_t* block; @@ -57,7 +61,9 @@ btr_block_get_func( if (mode != RW_NO_LATCH) { - buf_block_dbg_add_level(block, SYNC_TREE_NODE); + buf_block_dbg_add_level( + block, index != NULL && dict_index_is_ibuf(index) + ? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE); } return(block); diff --git a/storage/innodb_plugin/include/sync0sync.h b/storage/innodb_plugin/include/sync0sync.h index d9dcf91accb..f2013c202c1 100644 --- a/storage/innodb_plugin/include/sync0sync.h +++ b/storage/innodb_plugin/include/sync0sync.h @@ -448,10 +448,6 @@ or row lock! */ #define SYNC_DICT_HEADER 995 #define SYNC_IBUF_HEADER 914 #define SYNC_IBUF_PESS_INSERT_MUTEX 912 -#define SYNC_IBUF_MUTEX 910 /* ibuf mutex is really below - SYNC_FSP_PAGE: we assign a value this - high only to make the program to pass - the debug checks */ /*-------------------------------*/ #define SYNC_INDEX_TREE 900 #define SYNC_TREE_NODE_NEW 892 @@ -468,8 +464,11 @@ or row lock! */ #define SYNC_FSP 400 #define SYNC_FSP_PAGE 395 /*------------------------------------- Insert buffer headers */ -/*------------------------------------- ibuf_mutex */ +#define SYNC_IBUF_MUTEX 370 /* ibuf_mutex */ /*------------------------------------- Insert buffer tree */ +#define SYNC_IBUF_INDEX_TREE 360 +#define SYNC_IBUF_TREE_NODE_NEW 359 +#define SYNC_IBUF_TREE_NODE 358 #define SYNC_IBUF_BITMAP_MUTEX 351 #define SYNC_IBUF_BITMAP 350 /*------------------------------------- MySQL query cache mutex */ diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 59498386fda..1b97e1f11f3 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1173,6 +1173,7 @@ sync_thread_add_level( case SYNC_DICT_HEADER: case SYNC_TRX_I_S_RWLOCK: case SYNC_TRX_I_S_LAST_READ: + case SYNC_IBUF_MUTEX: if (!sync_thread_levels_g(array, level, TRUE)) { fprintf(stderr, "InnoDB: sync_thread_levels_g(array, %lu)" @@ -1236,21 +1237,27 @@ sync_thread_add_level( || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; case SYNC_TREE_NODE_NEW: - ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE) - || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE)); break; case SYNC_INDEX_TREE: - if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && sync_thread_levels_contain(array, SYNC_FSP)) { - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, - TRUE)); - } else { - ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, - TRUE)); - } + ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; - case SYNC_IBUF_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE)); + case SYNC_IBUF_TREE_NODE: + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_INDEX_TREE) + || sync_thread_levels_g(array, SYNC_IBUF_TREE_NODE - 1, + TRUE)); + break; + case SYNC_IBUF_TREE_NODE_NEW: + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + break; + case SYNC_IBUF_INDEX_TREE: + if (sync_thread_levels_contain(array, SYNC_FSP)) { + ut_a(sync_thread_levels_g( + array, SYNC_FSP_PAGE - 1, TRUE)); + } else { + ut_a(sync_thread_levels_g( + array, SYNC_IBUF_TREE_NODE - 1, TRUE)); + } break; case SYNC_IBUF_PESS_INSERT_MUTEX: ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); From c79b036ed1804bb06073965badf2b2fa18b597c6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Aug 2011 19:29:06 +0200 Subject: [PATCH 07/49] fix for bug 55713 innochecksum is NOT built with large file support enabled --- extra/innochecksum.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/extra/innochecksum.c b/extra/innochecksum.c index 7ad900d16d3..f066cab2b3a 100644 --- a/extra/innochecksum.c +++ b/extra/innochecksum.c @@ -25,12 +25,7 @@ Published with a permission. */ -/* needed to have access to 64 bit file functions */ -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE - -#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */ - +#include #include #include #include From b213e7f814c7145a98b689710f14a479cf700912 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Aug 2011 00:34:11 +0200 Subject: [PATCH 08/49] 2nd fix for Bug #55713 innochecksum is NOT built with large file support enabled --- extra/innochecksum.c | 1 - 1 file changed, 1 deletion(-) diff --git a/extra/innochecksum.c b/extra/innochecksum.c index f066cab2b3a..b55b510b888 100644 --- a/extra/innochecksum.c +++ b/extra/innochecksum.c @@ -48,7 +48,6 @@ /* another argument to specify page ranges... seek to right spot and go from there */ typedef unsigned long int ulint; -typedef unsigned char uchar; /* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */ ulint mach_read_from_4(uchar *b) From 704e51644a428611c9a0993eac81c0bbf4d394f9 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 17 Aug 2011 14:42:18 +0200 Subject: [PATCH 09/49] Bug #11766654 59811: RE-INSTATE PROCEDURE MTR.FORCE_RESTART IN MTR, REMOVED BY 49978 Just put it back in where it was. --- mysql-test/include/mtr_check.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index 55e346c2007..699a35a1831 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -72,3 +72,13 @@ BEGIN mysql.user; END|| + +-- +-- Procedure used by test case used to force all +-- servers to restart after testcase and thus skipping +-- check test case after test +-- +CREATE DEFINER=root@localhost PROCEDURE force_restart() +BEGIN + SELECT 1 INTO OUTFILE 'force_restart'; +END|| From a8ee6e48f7129d35a2d83beab26f920e01092032 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 18 Aug 2011 10:38:51 +0400 Subject: [PATCH 10/49] BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD CRASHES SERVER Flushing of MERGE table or one of its child tables, which was locked by flushing thread using LOCK TABLES, might have caused crashes or assertion failures if the thread failed to reopen child or parent table. Particularly, this might have happened when another connection killed this FLUSH TABLE statement/connection. Also this problem might have occurred when we failed to reopen MERGE table or one of its children when executing DDL statement under LOCK TABLES. The problem was caused by the fact that reopen_tables() might have failed to reopen child table but still tried to reopen, reattach children for and re-lock its parent. Vice versa it might have failed to reopen parent but kept references from children to parent around. Since reopen_tables() closes table it has failed to reopen and therefore frees all associated memory such dangling references led to crashes when followed. This patch solves this problem by ensuring that we always close parent table and all its children if we fail to reopen this table or one of its children. Same happens if we fail to reattach children to parent. Affects 5.1 only. mysql-test/r/merge.result: A test case for BUG#11763712. mysql-test/t/merge.test: A test case for BUG#11763712. sql/sql_base.cc: When flushing tables under LOCK TABLES, all locked and flushed tables are released and then reopened. It may happen that we failed to reopen some tables, in this case we reopen as much tables as possible. If it was not possible to reopen MERGE child, MERGE parent is unusable and must be removed from thread open tables list. If it was not possible to reopen MERGE parent, all MERGE child table objects are unusable as well, at least because their locks are handled by MERGE parent. They must also be removed from thread open tables list. In other words if it was impossible to reopen any object of a MERGE table or reattach child tables, all objects of this MERGE table must be considered unusable and closed. --- mysql-test/r/merge.result | 29 ++++++ mysql-test/t/merge.test | 45 ++++++++++ sql/sql_base.cc | 183 +++++++++++++++++++++++++++++--------- 3 files changed, 215 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 3af152672ab..a4f1c79dff4 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -2341,4 +2341,33 @@ REPAIR TABLE m1; Table Op Msg_type Msg_text test.m1 repair note The storage engine for the table doesn't support repair DROP TABLE m1, t1; +# +# BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD +# CRASHES SERVER +# +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT); +CREATE TABLE t3(a INT, b INT); +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); +# Test reopen merge parent failure +LOCK TABLES m1 READ; +# Remove 'm1' table using file operations. +FLUSH TABLES; +ERROR 42S02: Table 'test.m1' doesn't exist +UNLOCK TABLES; +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); +# Test reopen merge child failure +LOCK TABLES m1 READ; +# Remove 't1' table using file operations. +FLUSH TABLES; +ERROR 42S02: Table 'test.t1' doesn't exist +UNLOCK TABLES; +CREATE TABLE t1(a INT); +# Test reattach merge failure +LOCK TABLES m1 READ; +# Replace 't1' with 't3' table using file operations. +FLUSH TABLES; +ERROR HY000: Can't reopen table: 'm1' +UNLOCK TABLES; +DROP TABLE t1, t2, t3, m1; End of 5.1 tests diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index f290803bbd2..a6affbb0540 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -1783,4 +1783,49 @@ REPAIR TABLE m1; # DROP TABLE m1, t1; + +--echo # +--echo # BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD +--echo # CRASHES SERVER +--echo # +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT); +CREATE TABLE t3(a INT, b INT); +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); + +--echo # Test reopen merge parent failure +LOCK TABLES m1 READ; +--echo # Remove 'm1' table using file operations. +remove_file $MYSQLD_DATADIR/test/m1.MRG; +remove_file $MYSQLD_DATADIR/test/m1.frm; +--error ER_NO_SUCH_TABLE +FLUSH TABLES; +UNLOCK TABLES; +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); + +--echo # Test reopen merge child failure +LOCK TABLES m1 READ; +--echo # Remove 't1' table using file operations. +remove_file $MYSQLD_DATADIR/test/t1.frm; +remove_file $MYSQLD_DATADIR/test/t1.MYI; +remove_file $MYSQLD_DATADIR/test/t1.MYD; +--error ER_NO_SUCH_TABLE +FLUSH TABLES; +UNLOCK TABLES; +CREATE TABLE t1(a INT); + +--echo # Test reattach merge failure +LOCK TABLES m1 READ; +--echo # Replace 't1' with 't3' table using file operations. +remove_file $MYSQLD_DATADIR/test/t1.frm; +remove_file $MYSQLD_DATADIR/test/t1.MYI; +remove_file $MYSQLD_DATADIR/test/t1.MYD; +copy_file $MYSQLD_DATADIR/test/t3.frm $MYSQLD_DATADIR/test/t1.frm; +copy_file $MYSQLD_DATADIR/test/t3.MYI $MYSQLD_DATADIR/test/t1.MYI; +copy_file $MYSQLD_DATADIR/test/t3.MYD $MYSQLD_DATADIR/test/t1.MYD; +--error ER_CANT_REOPEN_TABLE +FLUSH TABLES; +UNLOCK TABLES; +DROP TABLE t1, t2, t3, m1; + --echo End of 5.1 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index dc78f3b84c6..971a54d88c2 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -96,6 +96,13 @@ static TABLE_SHARE *oldest_unused_share, end_of_unused_share; static pthread_mutex_t LOCK_table_share; static bool table_def_inited= 0; +/** + Dummy TABLE instance which is used in reopen_tables() and reattach_merge() + functions to mark MERGE tables and their children with which there is some + kind of problem and which therefore we need to close. +*/ +static TABLE bad_merge_marker; + static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list, const char *alias, char *cache_key, uint cache_key_length, @@ -3214,47 +3221,66 @@ void close_data_files_and_morph_locks(THD *thd, const char *db, } +/** + @brief Mark merge parent and children with bad_merge_marker + + @param[in,out] parent the TABLE object of the parent +*/ + +static void mark_merge_parent_and_children_as_bad(TABLE *parent) +{ + TABLE_LIST *child_l; + DBUG_ENTER("mark_merge_parent_and_children_as_bad"); + parent->parent= &bad_merge_marker; + for (child_l= parent->child_l; ; child_l= child_l->next_global) + { + child_l->table->parent= &bad_merge_marker; + child_l->table= NULL; + if (&child_l->next_global == parent->child_last_l) + break; + } + DBUG_VOID_RETURN; +} + + /** Reattach MERGE children after reopen. @param[in] thd thread context - @param[in,out] err_tables_p pointer to pointer of tables in error + + @note If reattach failed for certain MERGE table, the table (and all + it's children) are marked with bad_merge_marker. @return status - @retval FALSE OK, err_tables_p unchanged - @retval TRUE Error, err_tables_p contains table(s) + @retval FALSE OK + @retval TRUE Error */ -static bool reattach_merge(THD *thd, TABLE **err_tables_p) +static bool reattach_merge(THD *thd) { TABLE *table; - TABLE *next; - TABLE **prv_p= &thd->open_tables; bool error= FALSE; DBUG_ENTER("reattach_merge"); - for (table= thd->open_tables; table; table= next) + for (table= thd->open_tables; table; table= table->next) { - next= table->next; - DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx next: 0x%lx", + DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx", table->s->db.str, table->s->table_name.str, - (long) table, (long) next)); - /* Reattach children for MERGE tables with "closed data files" only. */ - if (table->child_l && !table->children_attached) + (long) table)); + /* + Reattach children only for MERGE tables that had children or parent + with "closed data files" and were reopen. For extra safety skip MERGE + tables which we failed to reopen (should not happen with current code). + */ + if (table->child_l && table->parent != &bad_merge_marker && + !table->children_attached) { DBUG_PRINT("tcache", ("MERGE parent, attach children")); - if(table->file->extra(HA_EXTRA_ATTACH_CHILDREN)) + if (table->file->extra(HA_EXTRA_ATTACH_CHILDREN)) { my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); error= TRUE; - /* Remove table from open_tables. */ - *prv_p= next; - if (next) - prv_p= &next->next; - /* Stack table on error list. */ - table->next= *err_tables_p; - *err_tables_p= table; - continue; + mark_merge_parent_and_children_as_bad(table); } else { @@ -3264,7 +3290,6 @@ static bool reattach_merge(THD *thd, TABLE **err_tables_p) table->s->table_name.str, (long) table)); } } - prv_p= &table->next; } DBUG_RETURN(error); } @@ -3294,7 +3319,6 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old) { TABLE *table,*next,**prev; TABLE **tables,**tables_ptr; // For locks - TABLE *err_tables= NULL; bool error=0, not_used; bool merge_table_found= FALSE; const uint flags= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN | @@ -3328,29 +3352,69 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old) for (table=thd->open_tables; table ; table=next) { uint db_stat=table->db_stat; + TABLE *parent= table->child_l ? table : table->parent; next=table->next; DBUG_PRINT("tcache", ("open table: '%s'.'%s' 0x%lx " "parent: 0x%lx db_stat: %u", table->s->db.str, table->s->table_name.str, (long) table, (long) table->parent, db_stat)); - if (table->child_l && !db_stat) + /* + If we need to reopen child or parent table in a MERGE table, then + children in this MERGE table has to be already detached at this + point. + */ + DBUG_ASSERT(db_stat || !parent || !parent->children_attached); + /* + Thanks to the above assumption the below condition will guarantee that + merge_table_found is TRUE when we need to reopen child or parent table. + Note that it works even in situation when it is only a child and not a + parent that needs reopen (this can happen when get_locks == FALSE). + */ + if (table->child_l && !table->children_attached) merge_table_found= TRUE; - if (!tables || (!db_stat && reopen_table(table))) + + if (!tables) { - my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); /* - If we could not allocate 'tables', we may close open tables - here. If a MERGE table is affected, detach the children first. - It is not necessary to clear the child or parent table reference - of this table because the TABLE is freed. But we need to clear - the child or parent references of the other belonging tables so - that they cannot be moved into the unused_tables chain with - these pointers set. + If we could not allocate 'tables' we close ALL open tables here. + Before closing MERGE child or parent we need to detach children + and/or clear references in/to them. */ - if (table->child_l || table->parent) + if (parent) detach_merge_children(table, TRUE); - VOID(hash_delete(&open_cache,(uchar*) table)); - error=1; + } + else if (table->parent == &bad_merge_marker) + { + /* + This is either a child or a parent of a MERGE table for which + we already decided that we are unable to reopen it. Close it. + + Reset parent reference, it may be used while freeing the table. + */ + table->parent= NULL; + } + else if (!db_stat && reopen_table(table)) + { + /* + If we fail to reopen a child or a parent in a MERGE table and the + MERGE table is affected for the first time, mark all relevant tables + invalid. Otherwise handle it as usual. + + All in all we must end up with: + - child tables are detached from parent. This was done earlier, + but child<->parent references were kept valid for reopen. + - parent is not in the to-be-locked tables + - all child tables and parent are not in the THD::open_tables. + - all child tables and parent are not in the open_cache. + + Please note that below we do additional pass through THD::open_tables + list to achieve the last three points. + */ + if (parent) + { + mark_merge_parent_and_children_as_bad(parent); + table->parent= NULL; + } } else { @@ -3366,21 +3430,56 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old) table->s->version=0; table->open_placeholder= 0; } + continue; } + my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); + VOID(hash_delete(&open_cache, (uchar *) table)); + error= 1; } *prev=0; /* When all tables are open again, we can re-attach MERGE children to - their parents. All TABLE objects are still present. + their parents. + + If there was an error while reopening a child or a parent of a MERGE + table, or while reattaching child tables to their parents, some tables + may have been kept open but marked for close with bad_merge_marker. + Close these tables now. */ - DBUG_PRINT("tcache", ("re-attaching MERGE tables: %d", merge_table_found)); - if (!error && merge_table_found && reattach_merge(thd, &err_tables)) + if (tables && merge_table_found && (error|= reattach_merge(thd))) { - while (err_tables) + prev= &thd->open_tables; + for (table= thd->open_tables; table; table= next) { - VOID(hash_delete(&open_cache, (uchar*) err_tables)); - err_tables= err_tables->next; + next= table->next; + if (table->parent == &bad_merge_marker) + { + /* Remove merge parent from to-be-locked tables array. */ + if (get_locks && table->child_l) + { + TABLE **t; + for (t= tables; t < tables_ptr; t++) + { + if (*t == table) + { + tables_ptr--; + memmove(t, t + 1, (tables_ptr - t) * sizeof(TABLE *)); + break; + } + } + } + /* Reset parent reference, it may be used while freeing the table. */ + table->parent= NULL; + /* Free table. */ + VOID(hash_delete(&open_cache, (uchar *) table)); + } + else + { + *prev= table; + prev= &table->next; + } } + *prev= 0; } DBUG_PRINT("tcache", ("open tables to lock: %u", (uint) (tables_ptr - tables))); From e8f2e3c2176a1625220b3189e73bba91dae7684c Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Fri, 19 Aug 2011 18:48:14 +0200 Subject: [PATCH 11/49] Fix bug#37165 "((Generic rpm)) fail to install on Fedora 9 x86_64" On Fedora, certain accesses to "/var/lib/mysql/HOSTNAME.err" were blocked by SELinux policy, this made the server start fail with the message Manager of pid-file quit without updating file Calling "/sbin/restorecon -R /var/lib/mysql" fixes this. --- support-files/mysql.spec.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 006dea45e64..28f2b0f773a 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -382,7 +382,7 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --enable-local-infile \ --with-fast-mutexes \ --with-mysqld-user=%{mysqld_user} \ - --with-unix-socket-path=/var/lib/mysql/mysql.sock \ + --with-unix-socket-path=%{mysqldatadir}/mysql.sock \ --with-pic \ --prefix=/ \ %if %{CLUSTER_BUILD} @@ -858,6 +858,13 @@ chown -R %{mysqld_user}:%{mysqld_group} $mysql_datadir # ---------------------------------------------------------------------- chmod -R og-rw $mysql_datadir/mysql +# ---------------------------------------------------------------------- +# Deal with SELinux, if it is installed / used +# ---------------------------------------------------------------------- +if [ -x /sbin/restorecon ] ; then + /sbin/restorecon -R %{mysqldatadir} +fi + # Was the server running before the upgrade? If so, restart the new one. if [ "$SERVER_TO_START" = "true" ] ; then # Restart in the same way that mysqld will be started normally. @@ -1165,6 +1172,15 @@ fi # merging BK trees) ############################################################################## %changelog +* Fri Aug 19 2011 Joerg Bruehe + +- Fix bug#37165 "((Generic rpm)) fail to install on Fedora 9 x86_64" + On Fedora, certain accesses to "/var/lib/mysql/HOSTNAME.err" were blocked + by SELinux policy, this made the server start fail with the message + Manager of pid-file quit without updating file + Calling "/sbin/restorecon -R /var/lib/mysql" fixes this. +- Replace occurrences of that path name by the spec file variable %{mysqldatadir}. + * Thu Jul 07 2011 Joerg Bruehe - Fix bug#45415: "rpm upgrade recreates test database" From 49ee12d03b763a460cfcc371566465019a4dc067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 22 Aug 2011 17:03:07 +0300 Subject: [PATCH 12/49] Bug #11766591 59733: POSSIBLE DEADLOCK WHEN BUFFERED CHANGES ARE TO BE DISCARDED The fix in revision id marko.makela@oracle.com-20110815091143-h3zbvm0pv8ni3qql introduced a false UNIV_SYNC_DEBUG alarm. Relax the assertion. --- storage/innodb_plugin/sync/sync0sync.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 1b97e1f11f3..64aadffdfad 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1248,7 +1248,13 @@ sync_thread_add_level( TRUE)); break; case SYNC_IBUF_TREE_NODE_NEW: - ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + /* ibuf_add_free_page() allocates new pages for the + change buffer while only holding the tablespace + x-latch. These pre-allocated new pages may only be + taken in use while holding ibuf_mutex, in + btr_page_alloc_for_ibuf(). */ + ut_a(sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) + || sync_thread_levels_contain(array, SYNC_FSP)); break; case SYNC_IBUF_INDEX_TREE: if (sync_thread_levels_contain(array, SYNC_FSP)) { From 0c7db7839b052269e034d91a7597a74b3d1f90ba Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Thu, 25 Aug 2011 10:38:07 +0200 Subject: [PATCH 13/49] Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX Suppress the known warnings generated by filesort(). The real fix belongs to worklog 1509: Pack values of non-sorted fields in the sort buffer (which is basically the same issue, but in an optimization context: We are writing the entire sort buffer to disk, including un-used space for varchar columns.) mysql-test/valgrind.supp: Add new Memcheck suppressions for filesort. sql/filesort.cc: Remove the ifdef HAVE_purify/bzero code, use valgrind suppressions instead. --- mysql-test/valgrind.supp | 34 ++++++++++++++++++++++++++++++++++ sql/filesort.cc | 11 ----------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 8720cd511b9..3751a339a1a 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -791,3 +791,37 @@ fun:fil_delete_tablespace fun:row_drop_table_for_mysql } + +{ + Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / one + Memcheck:Param + write(buf) + obj:*/libpthread*.so + fun:my_write + fun:my_b_flush_io_cache + fun:_my_b_write + fun:_ZL10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ + fun:_ZL13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_S6_ + fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy +} + +{ + Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / two + Memcheck:Param + write(buf) + obj:*/libpthread*.so + fun:my_write + fun:my_b_flush_io_cache + fun:_Z15merge_many_buffP13st_sort_paramPhP10st_buffpekPjP11st_io_cache + fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy +} + +{ + Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / three + Memcheck:Param + write(buf) + obj:*/libpthread*.so + fun:my_write + fun:my_b_flush_io_cache + fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy +} diff --git a/sql/filesort.cc b/sql/filesort.cc index 99e5156427a..0ff354b334c 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -959,21 +959,10 @@ static void make_sortkey(register SORTPARAM *param, if (addonf->null_bit && field->is_null()) { nulls[addonf->null_offset]|= addonf->null_bit; -#ifdef HAVE_purify - bzero(to, addonf->length); -#endif } else { -#ifdef HAVE_purify - uchar *end= field->pack(to, field->ptr); - uint length= (uint) ((to + addonf->length) - end); - DBUG_ASSERT((int) length >= 0); - if (length) - bzero(end, length); -#else (void) field->pack(to, field->ptr); -#endif } to+= addonf->length; } From e46b3453bfd379f7eef4fcc01853f085007c012b Mon Sep 17 00:00:00 2001 From: Rohit Kalhans Date: Fri, 26 Aug 2011 15:27:29 +0530 Subject: [PATCH 14/49] BUG#11878104: FIXES OF BUG 11752963 - 44312 TO BACKPORT TO MYSQL-5.1 Background: Backporting fix for BUG 11752963 to Mysql5.1 branch. Problem: Fix of bug 11752963 was only available for trunk and 5.5 branch. Partial fix has been pushed to 5.1 branch as well. Fix: backporting the fixes of bug 11752963 to 5.1 branch. 1. Made all major changes to make 5.1 branch in line with 5.5 and the trunk. 2. skipped the partial patch that was already applied to the 5.1 branch. sql/rpl_rli.h: Made inited Volatile (find inline comments) sql/slave.cc: backported all changes from the fix of BUG#11752963. --- sql/rpl_rli.h | 8 +++++++- sql/slave.cc | 11 ++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 811ad8eb864..ae8639c69ac 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -221,7 +221,13 @@ public: #endif /* if not set, the value of other members of the structure are undefined */ - bool inited; + /* + inited changes its value within LOCK_active_mi-guarded critical + sections at times of start_slave_threads() (0->1) and end_slave() (1->0). + Readers may not acquire the mutex while they realize potential concurrency + issue. + */ + volatile bool inited; volatile bool abort_slave; volatile uint slave_running; diff --git a/sql/slave.cc b/sql/slave.cc index 6c375238ce4..02d8cc2c199 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -598,11 +598,15 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock, DBUG_PRINT("sleep",("Waiting for slave thread to start")); const char* old_msg = thd->enter_cond(start_cond,cond_lock, "Waiting for slave thread to start"); - pthread_cond_wait(start_cond,cond_lock); + pthread_cond_wait(start_cond, cond_lock); thd->exit_cond(old_msg); pthread_mutex_lock(cond_lock); // re-acquire it as exit_cond() released if (thd->killed) + { + if (start_lock) + pthread_mutex_unlock(start_lock); DBUG_RETURN(thd->killed_errno()); + } } } if (start_lock) @@ -2531,6 +2535,7 @@ pthread_handler_t handle_slave_io(void *arg) thd= new THD; // note that contructor of THD uses DBUG_ ! THD_CHECK_SENTRY(thd); + DBUG_ASSERT(mi->io_thd == 0); mi->io_thd = thd; pthread_detach_this_thread(); @@ -4489,9 +4494,6 @@ int rotate_relay_log(Master_info* mi) Relay_log_info* rli= &mi->rli; int error= 0; - /* We don't lock rli->run_lock. This would lead to deadlocks. */ - pthread_mutex_lock(&mi->run_lock); - /* We need to test inited because otherwise, new_file() will attempt to lock LOCK_log, which may not be inited (if we're not a slave). @@ -4521,7 +4523,6 @@ int rotate_relay_log(Master_info* mi) */ rli->relay_log.harvest_bytes_written(&rli->log_space_total); end: - pthread_mutex_unlock(&mi->run_lock); DBUG_RETURN(error); } From 41f229cd9ed5a1549fb6438bdc1614e48d003625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Aug 2011 11:16:42 +0300 Subject: [PATCH 15/49] Bug#12704861 Corruption after a crash during BLOB update The fix of Bug#12612184 broke crash recovery. When a record that contains off-page columns (BLOBs) is updated, we must first write redo log about the BLOB page writes, and only after that write the redo log about the B-tree changes. The buggy fix would log the B-tree changes first, meaning that after recovery, we could end up having a record that contains a null BLOB pointer. Because we will be redo logging the writes off the off-page columns before the B-tree changes, we must make sure that the pages chosen for the off-page columns are free both before and after the B-tree changes. In this way, the worst thing that can happen in crash recovery is that the BLOBs are written to free pages, but the B-tree changes are not applied. The BLOB pages would correctly remain free in this case. To achieve this, we must allocate the BLOB pages in the mini-transaction of the B-tree operation. A further quirk is that BLOB pages are allocated from the same file segment as leaf pages. Because of this, we must temporarily "hide" any leaf pages that were freed during the B-tree operation by "fake allocating" them prior to writing the BLOBs, and freeing them again before the mtr_commit() of the B-tree operation, in btr_mark_freed_leaves(). btr_cur_mtr_commit_and_start(): Remove this faulty function that was introduced in the Bug#12612184 fix. The problem that this function was trying to address was that when we did mtr_commit() the BLOB writes before the mtr_commit() of the update, the new BLOB pages could have overwritten clustered index B-tree leaf pages that were freed during the update. If recovery applied the redo log of the BLOB writes but did not see the log of the record update, the index tree would be corrupted. The correct solution is to make the freed clustered index pages unavailable to the BLOB allocation. This function is also a likely culprit of InnoDB hangs that were observed when testing the Bug#12612184 fix. btr_mark_freed_leaves(): Mark all freed clustered index leaf pages of a mini-transaction allocated (nonfree=TRUE) before storing the BLOBs, or freed (nonfree=FALSE) before committing the mini-transaction. btr_freed_leaves_validate(): A debug function for checking that all clustered index leaf pages that have been marked free in the mini-transaction are consistent (have not been zeroed out). btr_page_alloc_low(): Refactored from btr_page_alloc(). Return the number of the allocated page, or FIL_NULL if out of space. Add the parameter "mtr_t* init_mtr" for specifying the mini-transaction where the page should be initialized, or if this is a "fake allocation" (init_mtr=NULL) by btr_mark_freed_leaves(nonfree=TRUE). btr_page_alloc(): Add the parameter init_mtr, allowing the page to be initialized and X-latched in a different mini-transaction than the one that is used for the allocation. Invoke btr_page_alloc_low(). If a clustered index leaf page was previously freed in mtr, remove it from the memo of previously freed pages. btr_page_free(): Assert that the page is a B-tree page and it has been X-latched by the mini-transaction. If the freed page was a leaf page of a clustered index, link it by a MTR_MEMO_FREE_CLUST_LEAF marker to the mini-transaction. btr_store_big_rec_extern_fields_func(): Add the parameter alloc_mtr, which is NULL (old behaviour in inserts) and the same as local_mtr in updates. If alloc_mtr!=NULL, the BLOB pages will be allocated from it instead of the mini-transaction that is used for writing the BLOBs. fsp_alloc_from_free_frag(): Refactored from fsp_alloc_free_page(). Allocate the specified page from a partially free extent. fseg_alloc_free_page_low(), fseg_alloc_free_page_general(): Add the parameter "mtr_t* init_mtr" for specifying the mini-transaction where the page should be initialized, or NULL if this is a "fake allocation" that prevents the reuse of a previously freed B-tree page for BLOB storage. If init_mtr==NULL, try harder to reallocate the specified page and assert that it succeeded. fsp_alloc_free_page(): Add the parameter "mtr_t* init_mtr" for specifying the mini-transaction where the page should be initialized. Do not allow init_mtr == NULL, because this function is never to be used for "fake allocations". mtr_t: Add the operation MTR_MEMO_FREE_CLUST_LEAF and the flag mtr->freed_clust_leaf for quickly determining if any MTR_MEMO_FREE_CLUST_LEAF operations have been posted. row_ins_index_entry_low(): When columns are being made off-page in insert-by-update, invoke btr_mark_freed_leaves(nonfree=TRUE) and pass the mini-transaction as the alloc_mtr to btr_store_big_rec_extern_fields(). Finally, invoke btr_mark_freed_leaves(nonfree=FALSE) to avoid leaking pages. row_build(): Correct a comment, and add a debug assertion that a record that contains NULL BLOB pointers must be a fresh insert. row_upd_clust_rec(): When columns are being moved off-page, invoke btr_mark_freed_leaves(nonfree=TRUE) and pass the mini-transaction as the alloc_mtr to btr_store_big_rec_extern_fields(). Finally, invoke btr_mark_freed_leaves(nonfree=FALSE) to avoid leaking pages. buf_reset_check_index_page_at_flush(): Remove. The function fsp_init_file_page_low() already sets bpage->check_index_page_at_flush=FALSE. There is a known issue in tablespace extension. If the request to allocate a BLOB page leads to the tablespace being extended, crash recovery could see BLOB writes to pages that are off the tablespace file bounds. This should trigger an assertion failure in fil_io() at crash recovery. The safe thing would be to write redo log about the tablespace extension to the mini-transaction of the BLOB write, not to the mini-transaction of the record update. However, there is no redo log record for file extension in the current redo log format. rb:693 approved by Sunny Bains --- .../suite/innodb_plugin/r/innodb-index.result | 9 + .../suite/innodb_plugin/t/innodb-index.test | 13 + storage/innobase/btr/btr0btr.c | 222 +++++++++++++++-- storage/innobase/btr/btr0cur.c | 92 ++++--- storage/innobase/buf/buf0buf.c | 23 -- storage/innobase/fsp/fsp0fsp.c | 168 +++++++++---- storage/innobase/include/btr0btr.h | 31 ++- storage/innobase/include/btr0cur.h | 14 +- storage/innobase/include/buf0buf.h | 9 - storage/innobase/include/fsp0fsp.h | 8 +- storage/innobase/include/mtr0mtr.h | 7 +- storage/innobase/include/mtr0mtr.ic | 4 +- storage/innobase/mtr/mtr0mtr.c | 10 +- storage/innobase/row/row0ins.c | 32 ++- storage/innobase/row/row0row.c | 32 +-- storage/innobase/row/row0upd.c | 21 +- storage/innobase/trx/trx0undo.c | 2 +- storage/innodb_plugin/ChangeLog | 14 ++ storage/innodb_plugin/btr/btr0btr.c | 220 ++++++++++++++-- storage/innodb_plugin/btr/btr0cur.c | 114 +++++---- storage/innodb_plugin/buf/buf0buf.c | 23 -- storage/innodb_plugin/fsp/fsp0fsp.c | 234 +++++++++++------- storage/innodb_plugin/include/btr0btr.h | 34 ++- storage/innodb_plugin/include/btr0cur.h | 38 ++- storage/innodb_plugin/include/buf0buf.h | 9 - storage/innodb_plugin/include/fsp0fsp.h | 30 ++- storage/innodb_plugin/include/mtr0mtr.h | 13 +- storage/innodb_plugin/include/mtr0mtr.ic | 6 +- storage/innodb_plugin/include/trx0undo.h | 46 +++- storage/innodb_plugin/mtr/mtr0mtr.c | 7 +- storage/innodb_plugin/row/row0ins.c | 31 ++- storage/innodb_plugin/row/row0row.c | 25 +- storage/innodb_plugin/row/row0upd.c | 21 +- storage/innodb_plugin/trx/trx0rec.c | 68 +++-- storage/innodb_plugin/trx/trx0undo.c | 70 +++--- 35 files changed, 1148 insertions(+), 552 deletions(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb-index.result b/mysql-test/suite/innodb_plugin/r/innodb-index.result index b24f282dfc4..5be1460d2b7 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-index.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-index.result @@ -1024,6 +1024,15 @@ INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); UPDATE t1 SET a=1000; DELETE FROM t1; DROP TABLE t1; +CREATE TABLE bug12547647( +a INT NOT NULL, b BLOB NOT NULL, c TEXT, +PRIMARY KEY (b(10), a), INDEX (c(10)) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7731)); +COMMIT; +UPDATE bug12547647 SET c = REPEAT('b',16928); +ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +DROP TABLE bug12547647; set global innodb_file_per_table=0; set global innodb_file_format=Antelope; set global innodb_file_format_check=Antelope; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index 52f94990b15..b4e2aae09e9 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -480,6 +480,19 @@ DELETE FROM t1; -- sleep 10 DROP TABLE t1; +# Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE +CREATE TABLE bug12547647( +a INT NOT NULL, b BLOB NOT NULL, c TEXT, +PRIMARY KEY (b(10), a), INDEX (c(10)) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7731)); +COMMIT; +# The following used to cause infinite undo log allocation. +--error ER_TOO_BIG_ROWSIZE +UPDATE bug12547647 SET c = REPEAT('b',16928); +DROP TABLE bug12547647; + eval set global innodb_file_per_table=$per_table; eval set global innodb_file_format=$format; eval set global innodb_file_format_check=$format; diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 790582815a3..ad99913cf3b 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -300,29 +300,30 @@ btr_page_alloc_for_ibuf( /****************************************************************** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! */ - -page_t* -btr_page_alloc( -/*===========*/ - /* out: new allocated page, x-latched; - NULL if out of space */ +static +ulint +btr_page_alloc_low( +/*===============*/ + /* out: allocated page number, + FIL_NULL if out of space */ dict_index_t* index, /* in: index */ ulint hint_page_no, /* in: hint of a good page */ byte file_direction, /* in: direction where a possible page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr) /* in: mtr */ + mtr_t* mtr, /* in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /* in/out: mini-transaction + in which the page should be + initialized (may be the same + as mtr), or NULL if it should + not be initialized (the page + at hint was previously freed + in mtr) */ { fseg_header_t* seg_header; page_t* root; - page_t* new_page; - ulint new_page_no; - - if (index->type & DICT_IBUF) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } root = btr_root_get(index, mtr); @@ -336,19 +337,61 @@ btr_page_alloc( reservation for free extents, and thus we know that a page can be allocated: */ - new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, - file_direction, TRUE, mtr); + return(fseg_alloc_free_page_general(seg_header, hint_page_no, + file_direction, TRUE, + mtr, init_mtr)); +} + +/**************************************************************//** +Allocates a new file page to be used in an index tree. NOTE: we assume +that the caller has made the reservation for free extents! */ + +page_t* +btr_page_alloc( +/*===========*/ + /* out: new allocated block, x-latched; + NULL if out of space */ + dict_index_t* index, /* in: index */ + ulint hint_page_no, /* in: hint of a good page */ + byte file_direction, /* in: direction where a possible + page split is made */ + ulint level, /* in: level where the page is placed + in the tree */ + mtr_t* mtr, /* in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /* in/out: mini-transaction + for x-latching and initializing + the page */ +{ + page_t* new_page; + ulint new_page_no; + + if (index->type & DICT_IBUF) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } + + new_page_no = btr_page_alloc_low( + index, hint_page_no, file_direction, level, mtr, init_mtr); + if (new_page_no == FIL_NULL) { return(NULL); } new_page = buf_page_get(dict_index_get_space(index), new_page_no, - RW_X_LATCH, mtr); + RW_X_LATCH, init_mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW); #endif /* UNIV_SYNC_DEBUG */ + if (mtr->freed_clust_leaf) { + mtr_memo_release(mtr, new_page, MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(!mtr_memo_contains(mtr, buf_block_align(new_page), + MTR_MEMO_FREE_CLUST_LEAF)); + } + + ut_ad(btr_freed_leaves_validate(mtr)); return(new_page); } @@ -464,6 +507,16 @@ btr_page_free_low( page_no = buf_frame_get_page_no(page); fseg_free_page(seg_header, space, page_no, mtr); + + /* The page was marked free in the allocation bitmap, but it + should remain buffer-fixed until mtr_commit(mtr) or until it + is explicitly freed from the mini-transaction. */ + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + /* TODO: Discard any operations on the page from the redo log + and remove the block from the flush list and the buffer pool. + This would free up buffer pool earlier and reduce writes to + both the tablespace and the redo log. */ } /****************************************************************** @@ -479,13 +532,144 @@ btr_page_free( { ulint level; + ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX); ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); level = btr_page_get_level(page, mtr); btr_page_free_low(index, page, level, mtr); + + /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ + ut_ad(mtr_memo_contains(mtr, buf_block_align(page), + MTR_MEMO_PAGE_X_FIX)); + + if (level == 0 && (index->type & DICT_CLUSTERED)) { + /* We may have to call btr_mark_freed_leaves() to + temporarily mark the block nonfree for invoking + btr_store_big_rec_extern_fields() after an + update. Remember that the block was freed. */ + mtr->freed_clust_leaf = TRUE; + mtr_memo_push(mtr, buf_block_align(page), + MTR_MEMO_FREE_CLUST_LEAF); + } + + ut_ad(btr_freed_leaves_validate(mtr)); } +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ + +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /* in/out: clustered index */ + mtr_t* mtr, /* in/out: mini-transaction */ + ibool nonfree)/* in: TRUE=mark nonfree, FALSE=mark freed */ +{ + /* This is loosely based on mtr_memo_release(). */ + + ulint offset; + + ut_ad(index->type & DICT_CLUSTERED); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + if (!mtr->freed_clust_leaf) { + return; + } + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + mtr_memo_slot_t* slot; + buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(buf_block_get_space(block) + == dict_index_get_space(index)); + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); + + if (nonfree) { + /* Allocate the same page again. */ + ulint page_no; + page_no = btr_page_alloc_low( + index, buf_block_get_page_no(block), + FSP_NO_DIR, 0, mtr, NULL); + ut_a(page_no == buf_block_get_page_no(block)); + } else { + /* Assert that the page is allocated and free it. */ + btr_page_free_low(index, buf_block_get_frame(block), + 0, mtr); + } + } + + ut_ad(btr_freed_leaves_validate(mtr)); +} + +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +See btr_mark_freed_leaves(). */ + +ibool +btr_freed_leaves_validate( +/*======================*/ + /* out: TRUE if valid */ + mtr_t* mtr) /* in: mini-transaction */ +{ + ulint offset; + + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + mtr_memo_slot_t* slot; + buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + ut_a(mtr->freed_clust_leaf); + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(btr_page_get_level(buf_block_get_frame(block), mtr) == 0); + } + + return(TRUE); +} +#endif /* UNIV_DEBUG */ + /****************************************************************** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1015,7 +1199,7 @@ btr_root_raise_and_insert( a node pointer to the new page, and then splitting the new page. */ new_page = btr_page_alloc(index, 0, FSP_NO_DIR, - btr_page_get_level(root, mtr), mtr); + btr_page_get_level(root, mtr), mtr, mtr); btr_page_create(new_page, index, mtr); @@ -1636,7 +1820,7 @@ func_start: /* 2. Allocate a new page to the index */ new_page = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr); + btr_page_get_level(page, mtr), mtr, mtr); btr_page_create(new_page, cursor->index, mtr); /* 3. Calculate the first record on the upper half-page, and the diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 9ce09929f9a..a1dda8edf69 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -2051,43 +2051,6 @@ return_after_reservations: return(err); } -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ - -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /* in: cursor */ - mtr_t* mtr) /* in/out: mini-transaction */ -{ - buf_block_t* block; - - block = buf_block_align(btr_cur_get_rec(cursor)); - - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* Keep the locks across the mtr_commit(mtr). */ - rw_lock_x_lock(dict_index_get_lock(cursor->index)); - rw_lock_x_lock(&block->lock); - mutex_enter(&block->mutex); -#ifdef UNIV_SYNC_DEBUG - buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__); -#else - buf_block_buf_fix_inc(block); -#endif - mutex_exit(&block->mutex); - /* Write out the redo log. */ - mtr_commit(mtr); - mtr_start(mtr); - /* Reassociate the locks with the mini-transaction. - They will be released on mtr_commit(mtr). */ - mtr_memo_push(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK); - mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); -} - /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /******************************************************************** @@ -3494,6 +3457,11 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ + mtr_t* alloc_mtr, /* in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ mtr_t* local_mtr __attribute__((unused))) /* in: mtr containing the latch to rec and to the tree */ @@ -3514,6 +3482,8 @@ btr_store_big_rec_extern_fields( ulint i; mtr_t mtr; + ut_ad(local_mtr); + ut_ad(!alloc_mtr || alloc_mtr == local_mtr); ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); @@ -3523,6 +3493,25 @@ btr_store_big_rec_extern_fields( space_id = buf_frame_get_space_id(rec); + if (alloc_mtr) { + /* Because alloc_mtr will be committed after + mtr, it is possible that the tablespace has been + extended when the B-tree record was updated or + inserted, or it will be extended while allocating + pages for big_rec. + + TODO: In mtr (not alloc_mtr), write a redo log record + about extending the tablespace to its current size, + and remember the current size. Whenever the tablespace + grows as pages are allocated, write further redo log + records to mtr. (Currently tablespace extension is not + covered by the redo log. If it were, the record would + only be written to alloc_mtr, which is committed after + mtr.) */ + } else { + alloc_mtr = &mtr; + } + /* We have to create a file segment to the tablespace for each field and put the pointer to the field in rec */ @@ -3549,7 +3538,7 @@ btr_store_big_rec_extern_fields( } page = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, &mtr); + FSP_NO_DIR, 0, alloc_mtr, &mtr); if (page == NULL) { mtr_commit(&mtr); @@ -3603,37 +3592,42 @@ btr_store_big_rec_extern_fields( extern_len -= store_len; + if (alloc_mtr == &mtr) { #ifdef UNIV_SYNC_DEBUG - rec_page = + rec_page = #endif /* UNIV_SYNC_DEBUG */ - buf_page_get(space_id, - buf_frame_get_page_no(data), - RW_X_LATCH, &mtr); + buf_page_get( + space_id, + buf_frame_get_page_no(data), + RW_X_LATCH, &mtr); #ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK); + buf_page_dbg_add_level( + rec_page, SYNC_NO_ORDER_CHECK); #endif /* UNIV_SYNC_DEBUG */ + } + mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); if (prev_page_no == FIL_NULL) { mlog_write_ulint(data + local_len + BTR_EXTERN_SPACE_ID, space_id, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_PAGE_NO, page_no, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(data + local_len + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); /* Set the bit denoting that this field in rec is stored externally */ @@ -3641,7 +3635,7 @@ btr_store_big_rec_extern_fields( rec_set_nth_field_extern_bit( rec, index, big_rec_vec->fields[i].field_no, - TRUE, &mtr); + TRUE, alloc_mtr); } prev_page_no = page_no; diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 08e033e7a63..78b39812cff 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -1008,29 +1008,6 @@ buf_page_peek_block( return(block); } -/************************************************************************ -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ - -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /* in: space id */ - ulint offset) /* in: page number */ -{ - buf_block_t* block; - - mutex_enter_fast(&(buf_pool->mutex)); - - block = buf_page_hash_get(space, offset); - - if (block) { - block->check_index_page_at_flush = FALSE; - } - - mutex_exit(&(buf_pool->mutex)); -} - /************************************************************************ Returns the current state of is_hashed of a page. FALSE if the page is not in the pool. NOTE that this operation does not fix the page in the diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index d228e683957..d5be8fca38f 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -293,15 +293,19 @@ fseg_alloc_free_page_low( /* out: the allocated page number, FIL_NULL if no page could be allocated */ ulint space, /* in: space */ - fseg_inode_t* seg_inode, /* in: segment inode */ + fseg_inode_t* seg_inode, /* in/out: segment inode */ ulint hint, /* in: hint of which page would be desirable */ byte direction, /* in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr); /* in: mtr handle */ - + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr);/* in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ /************************************************************************** Reads the file space size stored in the header page. */ @@ -1371,6 +1375,43 @@ fsp_alloc_free_extent( return(descr); } +/**********************************************************************//** +Allocates a single free page from a space. */ +static __attribute__((nonnull)) +void +fsp_alloc_from_free_frag( +/*=====================*/ + fsp_header_t* header, /* in/out: tablespace header */ + xdes_t* descr, /* in/out: extent descriptor */ + ulint bit, /* in: slot to allocate in the extent */ + mtr_t* mtr) /* in/out: mini-transaction */ +{ + ulint frag_n_used; + + ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); + xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } +} + /************************************************************************** Allocates a single free page from a space. The page is marked as used. */ static @@ -1381,19 +1422,22 @@ fsp_alloc_free_page( be allocated */ ulint space, /* in: space id */ ulint hint, /* in: hint of which page would be desirable */ - mtr_t* mtr) /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr)/* in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr) */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; page_t* page; ulint free; - ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); + ut_ad(init_mtr); header = fsp_get_space_header(space, mtr); @@ -1441,6 +1485,7 @@ fsp_alloc_free_page( if (free == ULINT_UNDEFINED) { ut_print_buf(stderr, ((byte*)descr) - 500, 1000); + putc('\n', stderr); ut_error; } @@ -1472,40 +1517,21 @@ fsp_alloc_free_page( } } - xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } + fsp_alloc_from_free_frag(header, descr, free, mtr); /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, mtr); + buf_page_create(space, page_no, init_mtr); - page = buf_page_get(space, page_no, RW_X_LATCH, mtr); + page = buf_page_get(space, page_no, RW_X_LATCH, init_mtr); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ /* Prior contents of the page should be ignored */ - fsp_init_file_page(page, mtr); + fsp_init_file_page(page, init_mtr); return(page_no); } @@ -1724,7 +1750,7 @@ fsp_alloc_seg_inode_page( space = buf_frame_get_space_id(space_header); - page_no = fsp_alloc_free_page(space, 0, mtr); + page_no = fsp_alloc_free_page(space, 0, mtr, mtr); if (page_no == FIL_NULL) { @@ -2094,7 +2120,8 @@ fseg_create_general( } if (page == 0) { - page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr); + page = fseg_alloc_free_page_low(space, + inode, 0, FSP_UP, mtr, mtr); if (page == FIL_NULL) { @@ -2331,14 +2358,19 @@ fseg_alloc_free_page_low( /* out: the allocated page number, FIL_NULL if no page could be allocated */ ulint space, /* in: space */ - fseg_inode_t* seg_inode, /* in: segment inode */ + fseg_inode_t* seg_inode, /* in/out: segment inode */ ulint hint, /* in: hint of which page would be desirable */ byte direction, /* in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr) /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr)/* in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ { fsp_header_t* space_header; ulint space_size; @@ -2350,7 +2382,6 @@ fseg_alloc_free_page_low( if could not be allocated */ xdes_t* ret_descr; /* the extent of the allocated page */ page_t* page; - ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2371,6 +2402,8 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ + ut_a(init_mtr); + /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, hint, mtr); } @@ -2382,15 +2415,20 @@ fseg_alloc_free_page_low( mtr), seg_id)) && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { - +take_hinted_page: /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; + /* Skip the check for extending the tablespace. If the + page hint were not within the size of the tablespace, + we would have got (descr == NULL) above and reset the hint. */ + goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if ((xdes_get_state(descr, mtr) == XDES_FREE) - && ((reserved - used) < reserved / FSEG_FILLFACTOR) - && (used >= FSEG_FRAG_LIMIT)) { + } else if (xdes_get_state(descr, mtr) == XDES_FREE + && (!init_mtr + || ((reserved - used < reserved / FSEG_FILLFACTOR) + && used >= FSEG_FRAG_LIMIT))) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2408,8 +2446,20 @@ fseg_alloc_free_page_low( /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, hint + FSP_EXTENT_SIZE, mtr); - ret_page = hint; + goto take_hinted_page; /*-----------------------------------------------------------*/ + } else if (!init_mtr) { + ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + fsp_alloc_from_free_frag(space_header, descr, + hint % FSP_EXTENT_SIZE, mtr); + ret_page = hint; + ret_descr = NULL; + + /* Put the page in the fragment page array of the segment */ + n = fseg_find_free_frag_page_slot(seg_inode, mtr); + ut_a(n != FIL_NULL); + fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); + goto got_hinted_page; } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2467,11 +2517,9 @@ fseg_alloc_free_page_low( } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, hint, mtr); + ret_page = fsp_alloc_free_page(space, hint, mtr, init_mtr); ret_descr = NULL; - frag_page_allocated = TRUE; - if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2481,6 +2529,10 @@ fseg_alloc_free_page_low( fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } + + /* fsp_alloc_free_page() invoked fsp_init_file_page() + already. */ + return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2527,22 +2579,31 @@ fseg_alloc_free_page_low( } } - if (!frag_page_allocated) { +got_hinted_page: + { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ + mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - page = buf_page_create(space, ret_page, mtr); + page = buf_page_create(space, ret_page, block_mtr); - ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, mtr)); + ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, + block_mtr)); #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_FSP_PAGE); #endif /* UNIV_SYNC_DEBUG */ - /* The prior contents of the page should be ignored */ - fsp_init_file_page(page, mtr); + if (init_mtr) { + /* The prior contents of the page should be ignored */ + fsp_init_file_page(page, init_mtr); + } + } + /* ret_descr == NULL if the block was allocated from free_frag + (XDES_FREE_FRAG) */ + if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2554,8 +2615,6 @@ fseg_alloc_free_page_low( fseg_mark_page_used(seg_inode, space, ret_page, mtr); } - buf_reset_check_index_page_at_flush(space, ret_page); - return(ret_page); } @@ -2569,7 +2628,7 @@ fseg_alloc_free_page_general( /*=========================*/ /* out: allocated page offset, FIL_NULL if no page could be allocated */ - fseg_header_t* seg_header,/* in: segment header */ + fseg_header_t* seg_header,/* in/out: segment header */ ulint hint, /* in: hint of which page would be desirable */ byte direction,/* in: if the new page is needed because of an index page split, and records are @@ -2581,7 +2640,11 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr) /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction handle */ + mtr_t* init_mtr)/* in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ { fseg_inode_t* inode; ulint space; @@ -2619,7 +2682,8 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode), - inode, hint, direction, mtr); + inode, hint, direction, + mtr, init_mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2647,7 +2711,7 @@ fseg_alloc_free_page( mtr_t* mtr) /* in: mtr handle */ { return(fseg_alloc_free_page_general(seg_header, hint, direction, - FALSE, mtr)); + FALSE, mtr, mtr)); } /************************************************************************** diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 269fa355558..3988019589d 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -379,7 +379,11 @@ btr_page_alloc( page split is made */ ulint level, /* in: level where the page is placed in the tree */ - mtr_t* mtr); /* in: mtr */ + mtr_t* mtr, /* in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr); /* in/out: mini-transaction + for x-latching and initializing + the page */ /****************************************************************** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -402,6 +406,31 @@ btr_page_free_low( page_t* page, /* in: page to be freed, x-latched */ ulint level, /* in: page level */ mtr_t* mtr); /* in: mtr */ +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ + +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /* in/out: clustered index */ + mtr_t* mtr, /* in/out: mini-transaction */ + ibool nonfree);/* in: TRUE=mark nonfree, FALSE=mark freed */ +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +See btr_mark_freed_leaves(). */ + +ibool +btr_freed_leaves_validate( +/*======================*/ + /* out: TRUE if valid */ + mtr_t* mtr); /* in: mini-transaction */ +#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /***************************************************************** Prints size info of a B-tree. */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index c068d8d3318..c2bf84ef9cb 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -252,15 +252,6 @@ btr_cur_pessimistic_update( updates */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr); /* in: mtr */ -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ - -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /* in: cursor */ - mtr_t* mtr); /* in/out: mini-transaction */ /*************************************************************** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -471,6 +462,11 @@ btr_store_big_rec_extern_fields( this function returns */ big_rec_t* big_rec_vec, /* in: vector containing fields to be stored externally */ + mtr_t* alloc_mtr, /* in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ mtr_t* local_mtr); /* in: mtr containing the latch to rec and to the tree */ /*********************************************************************** diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 7479ce9cbf0..87b2f6172de 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -294,15 +294,6 @@ buf_page_peek_block( ulint space, /* in: space id */ ulint offset);/* in: page number */ /************************************************************************ -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ - -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /* in: space id */ - ulint offset);/* in: page number */ -/************************************************************************ Sets file_page_was_freed TRUE if the page is found in the buffer pool. This function should be called when we free a file page and want the debug version to check that it is not accessed any more unless diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index 17bfbeec2c1..4c58d6075e6 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -167,7 +167,7 @@ fseg_alloc_free_page_general( /*=========================*/ /* out: allocated page offset, FIL_NULL if no page could be allocated */ - fseg_header_t* seg_header,/* in: segment header */ + fseg_header_t* seg_header,/* in/out: segment header */ ulint hint, /* in: hint of which page would be desirable */ byte direction,/* in: if the new page is needed because of an index page split, and records are @@ -179,7 +179,11 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr); /* in: mtr handle */ + mtr_t* mtr, /* in/out: mini-transaction */ + mtr_t* init_mtr);/* in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ /************************************************************************** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index a6e2976830b..a0a51dbbd17 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -36,6 +36,8 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 +/* The mini-transaction freed a clustered index leaf page. */ +#define MTR_MEMO_FREE_CLUST_LEAF 57 /* Log item types: we have made them to be of the type 'byte' for the compiler to warn if val and type parameters are switched @@ -325,9 +327,12 @@ struct mtr_struct{ ulint state; /* MTR_ACTIVE, MTR_COMMITTING, MTR_COMMITTED */ dyn_array_t memo; /* memo stack for locks etc. */ dyn_array_t log; /* mini-transaction log */ - ibool modifications; + unsigned modifications:1; /* TRUE if the mtr made modifications to buffer pool pages */ + unsigned freed_clust_leaf:1; + /* TRUE if MTR_MEMO_FREE_CLUST_LEAF + was logged in the mini-transaction */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 81eec3bfc92..6b4cacf0766 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -26,6 +26,7 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; + mtr->freed_clust_leaf = FALSE; mtr->n_log_recs = 0; #ifdef UNIV_DEBUG @@ -50,7 +51,8 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_X_LOCK); + ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index 365fa15878a..a11e20ca661 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -53,17 +53,13 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type, mtr); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); -#ifdef UNIV_DEBUG - } else if (type == MTR_MEMO_X_LOCK) { - rw_lock_x_unlock((rw_lock_t*)object); - } else { - ut_ad(type == MTR_MEMO_MODIFY); + } else if (type != MTR_MEMO_X_LOCK) { + ut_ad(type == MTR_MEMO_MODIFY + || type == MTR_MEMO_FREE_CLUST_LEAF); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); -#else } else { rw_lock_x_unlock((rw_lock_t*)object); -#endif } } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 7ff443a11ad..6366beb6b47 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -2089,15 +2089,20 @@ row_ins_index_entry_low( if (big_rec) { ut_a(err == DB_SUCCESS); /* Write out the externally stored - columns while still x-latching - index->lock and block->lock. We have - to mtr_commit(mtr) first, so that the - redo log will be written in the - correct order. Otherwise, we would run - into trouble on crash recovery if mtr - freed B-tree pages on which some of - the big_rec fields will be written. */ - btr_cur_mtr_commit_and_start(&cursor, &mtr); + columns, but allocate the pages and + write the pointers using the + mini-transaction of the record update. + If any pages were freed in the update, + temporarily mark them allocated so + that off-page columns will not + overwrite them. We must do this, + because we will write the redo log for + the BLOB writes before writing the + redo log for the record update. Thus, + redo log application at crash recovery + will see BLOBs being written to free pages. */ + + btr_mark_freed_leaves(index, &mtr, TRUE); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets(rec, index, offsets, @@ -2105,7 +2110,8 @@ row_ins_index_entry_low( &heap); err = btr_store_big_rec_extern_fields( - index, rec, offsets, big_rec, &mtr); + index, rec, offsets, big_rec, + &mtr, &mtr); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if @@ -2118,6 +2124,9 @@ row_ins_index_entry_low( undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again + in order to avoid a leak. */ + btr_mark_freed_leaves(index, &mtr, FALSE); goto stored_big_rec; } } else { @@ -2165,7 +2174,8 @@ function_exit: ULINT_UNDEFINED, &heap); err = btr_store_big_rec_extern_fields(index, rec, - offsets, big_rec, &mtr); + offsets, big_rec, + NULL, &mtr); stored_big_rec: if (modify) { dtuple_big_rec_free(big_rec); diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index 171039e34ac..ccb3c1f7781 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -212,23 +212,27 @@ row_build( } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - /* This condition can occur during crash recovery before - trx_rollback_or_clean_all_without_sess() has completed - execution. + if (rec_offs_any_null_extern(rec, offsets)) { + /* This condition can occur during crash recovery + before trx_rollback_or_clean_all_without_sess() has + completed execution. - This condition is possible if the server crashed - during an insert or update before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the clustered index record. + This condition is possible if the server crashed + during an insert or update before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the clustered index record. - If the record contains a null BLOB pointer, look up the - transaction that holds the implicit lock on this record, and - assert that it is active. (In this version of InnoDB, we - cannot assert that it was recovered, because there is no - trx->is_recovered field.) */ + If the record contains a null BLOB pointer, look up the + transaction that holds the implicit lock on this record, and + assert that it is active. (In this version of InnoDB, we + cannot assert that it was recovered, because there is no + trx->is_recovered field.) */ - ut_a(!rec_offs_any_null_extern(rec, offsets) - || trx_assert_active(row_get_rec_trx_id(rec, index, offsets))); + ut_a(trx_assert_active( + row_get_rec_trx_id(rec, index, offsets))); + ut_a(trx_undo_roll_ptr_is_insert( + row_get_rec_roll_ptr(rec, index, offsets))); + } #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 694b00ea265..58739edfd98 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1591,21 +1591,22 @@ row_upd_clust_rec( *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns while still - x-latching index->lock and block->lock. We have to - mtr_commit(mtr) first, so that the redo log will be - written in the correct order. Otherwise, we would run - into trouble on crash recovery if mtr freed B-tree - pages on which some of the big_rec fields will be - written. */ - btr_cur_mtr_commit_and_start(btr_cur, mtr); + /* Write out the externally stored columns, but + allocate the pages and write the pointers using the + mini-transaction of the record update. If any pages + were freed in the update, temporarily mark them + allocated so that off-page columns will not overwrite + them. We must do this, because we write the redo log + for the BLOB writes before writing the redo log for + the record update. */ + btr_mark_freed_leaves(index, mtr, TRUE); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - big_rec, mtr); + big_rec, mtr, mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -1618,6 +1619,8 @@ row_upd_clust_rec( to the undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again in order to avoid a leak. */ + btr_mark_freed_leaves(index, mtr, FALSE); } mtr_commit(mtr); diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index 329565943c8..ce09862f317 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -864,7 +864,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr); + TRUE, mtr, mtr); fil_space_release_free_extents(undo->space, n_reserved); diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 0b90b5729d5..96b6a47085a 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,17 @@ +2011-08-29 The InnoDB Team + + * btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, + include/btr0btr.h, include/btr0cur.h, include/fsp0fsp.h, + include/mtr0mtr.h, include/mtr0mtr.ic, mtr/mtr0mtr.c, + row/row0ins.c, row/row0row.c, row/row0upd.c, trx/trx0undo.c: + Fix Bug#12704861 Corruption after a crash during BLOB update + and other regressions from the fix of Bug#12612184 + +2011-08-23 The InnoDB Team + + * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: + Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE + 2011-08-15 The InnoDB Team * btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c, diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index 5e6724bbd54..71e1599d19e 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -906,28 +906,29 @@ btr_page_alloc_for_ibuf( /**************************************************************//** Allocates a new file page to be used in an index tree. NOTE: we assume that the caller has made the reservation for free extents! -@return new allocated block, x-latched; NULL if out of space */ -UNIV_INTERN -buf_block_t* -btr_page_alloc( -/*===========*/ +@return allocated page number, FIL_NULL if out of space */ +static __attribute__((nonnull(1,5), warn_unused_result)) +ulint +btr_page_alloc_low( +/*===============*/ dict_index_t* index, /*!< in: index */ ulint hint_page_no, /*!< in: hint of a good page */ byte file_direction, /*!< in: direction where a possible page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr) /*!< in: mtr */ + mtr_t* mtr, /*!< in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /*!< in/out: mini-transaction + in which the page should be + initialized (may be the same + as mtr), or NULL if it should + not be initialized (the page + at hint was previously freed + in mtr) */ { fseg_header_t* seg_header; page_t* root; - buf_block_t* new_block; - ulint new_page_no; - - if (dict_index_is_ibuf(index)) { - - return(btr_page_alloc_for_ibuf(index, mtr)); - } root = btr_root_get(index, mtr); @@ -941,8 +942,42 @@ btr_page_alloc( reservation for free extents, and thus we know that a page can be allocated: */ - new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no, - file_direction, TRUE, mtr); + return(fseg_alloc_free_page_general( + seg_header, hint_page_no, file_direction, + TRUE, mtr, init_mtr)); +} + +/**************************************************************//** +Allocates a new file page to be used in an index tree. NOTE: we assume +that the caller has made the reservation for free extents! +@return new allocated block, x-latched; NULL if out of space */ +UNIV_INTERN +buf_block_t* +btr_page_alloc( +/*===========*/ + dict_index_t* index, /*!< in: index */ + ulint hint_page_no, /*!< in: hint of a good page */ + byte file_direction, /*!< in: direction where a possible + page split is made */ + ulint level, /*!< in: level where the page is placed + in the tree */ + mtr_t* mtr, /*!< in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /*!< in/out: mini-transaction + for x-latching and initializing + the page */ +{ + buf_block_t* new_block; + ulint new_page_no; + + if (dict_index_is_ibuf(index)) { + + return(btr_page_alloc_for_ibuf(index, mtr)); + } + + new_page_no = btr_page_alloc_low( + index, hint_page_no, file_direction, level, mtr, init_mtr); + if (new_page_no == FIL_NULL) { return(NULL); @@ -950,9 +985,16 @@ btr_page_alloc( new_block = buf_page_get(dict_index_get_space(index), dict_table_zip_size(index->table), - new_page_no, RW_X_LATCH, mtr); + new_page_no, RW_X_LATCH, init_mtr); buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); + if (mtr->freed_clust_leaf) { + mtr_memo_release(mtr, new_block, MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(!mtr_memo_contains(mtr, new_block, + MTR_MEMO_FREE_CLUST_LEAF)); + } + + ut_ad(btr_freed_leaves_validate(mtr)); return(new_block); } @@ -1065,6 +1107,15 @@ btr_page_free_low( fseg_free_page(seg_header, buf_block_get_space(block), buf_block_get_page_no(block), mtr); + + /* The page was marked free in the allocation bitmap, but it + should remain buffer-fixed until mtr_commit(mtr) or until it + is explicitly freed from the mini-transaction. */ + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + /* TODO: Discard any operations on the page from the redo log + and remove the block from the flush list and the buffer pool. + This would free up buffer pool earlier and reduce writes to + both the tablespace and the redo log. */ } /**************************************************************//** @@ -1078,13 +1129,140 @@ btr_page_free( buf_block_t* block, /*!< in: block to be freed, x-latched */ mtr_t* mtr) /*!< in: mtr */ { - ulint level; - - level = btr_page_get_level(buf_block_get_frame(block), mtr); + const page_t* page = buf_block_get_frame(block); + ulint level = btr_page_get_level(page, mtr); + ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX); btr_page_free_low(index, block, level, mtr); + + /* The handling of MTR_MEMO_FREE_CLUST_LEAF assumes this. */ + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + + if (level == 0 && dict_index_is_clust(index)) { + /* We may have to call btr_mark_freed_leaves() to + temporarily mark the block nonfree for invoking + btr_store_big_rec_extern_fields_func() after an + update. Remember that the block was freed. */ + mtr->freed_clust_leaf = TRUE; + mtr_memo_push(mtr, block, MTR_MEMO_FREE_CLUST_LEAF); + } + + ut_ad(btr_freed_leaves_validate(mtr)); } +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ +UNIV_INTERN +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /*!< in/out: clustered index */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ +{ + /* This is loosely based on mtr_memo_release(). */ + + ulint offset; + + ut_ad(dict_index_is_clust(index)); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + if (!mtr->freed_clust_leaf) { + return; + } + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + mtr_memo_slot_t* slot; + buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(buf_block_get_space(block) + == dict_index_get_space(index)); + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(page_is_leaf(buf_block_get_frame(block))); + + if (nonfree) { + /* Allocate the same page again. */ + ulint page_no; + page_no = btr_page_alloc_low( + index, buf_block_get_page_no(block), + FSP_NO_DIR, 0, mtr, NULL); + ut_a(page_no == buf_block_get_page_no(block)); + } else { + /* Assert that the page is allocated and free it. */ + btr_page_free_low(index, block, 0, mtr); + } + } + + ut_ad(btr_freed_leaves_validate(mtr)); +} + +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +@see btr_mark_freed_leaves() +@return TRUE */ +UNIV_INTERN +ibool +btr_freed_leaves_validate( +/*======================*/ + mtr_t* mtr) /*!< in: mini-transaction */ +{ + ulint offset; + + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); + + offset = dyn_array_get_data_size(&mtr->memo); + + while (offset > 0) { + const mtr_memo_slot_t* slot; + const buf_block_t* block; + + offset -= sizeof *slot; + + slot = dyn_array_get_element(&mtr->memo, offset); + + if (slot->type != MTR_MEMO_FREE_CLUST_LEAF) { + continue; + } + + ut_a(mtr->freed_clust_leaf); + /* Because btr_page_alloc() does invoke + mtr_memo_release on MTR_MEMO_FREE_CLUST_LEAF, all + blocks tagged with MTR_MEMO_FREE_CLUST_LEAF in the + memo must still be clustered index leaf tree pages. */ + block = slot->object; + ut_a(fil_page_get_type(buf_block_get_frame(block)) + == FIL_PAGE_INDEX); + ut_a(page_is_leaf(buf_block_get_frame(block))); + } + + return(TRUE); +} +#endif /* UNIV_DEBUG */ + /**************************************************************//** Sets the child node file address in a node pointer. */ UNIV_INLINE @@ -1806,7 +1984,7 @@ btr_root_raise_and_insert( level = btr_page_get_level(root, mtr); - new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr); + new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); ut_a(!new_page_zip == !root_page_zip); @@ -2542,7 +2720,7 @@ func_start: /* 2. Allocate a new page to the index */ new_block = btr_page_alloc(cursor->index, hint_page_no, direction, - btr_page_get_level(page, mtr), mtr); + btr_page_get_level(page, mtr), mtr, mtr); new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); btr_page_create(new_block, new_page_zip, cursor->index, diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 5cefa51bcd5..f1c2c2ddd5e 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -2414,39 +2414,6 @@ return_after_reservations: return(err); } -/**************************************************************//** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ -UNIV_INTERN -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /*!< in: cursor */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - buf_block_t* block; - - block = btr_cur_get_block(cursor); - - ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); - /* Keep the locks across the mtr_commit(mtr). */ - rw_lock_x_lock(dict_index_get_lock(cursor->index)); - rw_lock_x_lock(&block->lock); - mutex_enter(&block->mutex); - buf_block_buf_fix_inc(block, __FILE__, __LINE__); - mutex_exit(&block->mutex); - /* Write out the redo log. */ - mtr_commit(mtr); - mtr_start(mtr); - /* Reassociate the locks with the mini-transaction. - They will be released on mtr_commit(mtr). */ - mtr_memo_push(mtr, dict_index_get_lock(cursor->index), - MTR_MEMO_X_LOCK); - mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); -} - /*==================== B-TREE DELETE MARK AND UNMARK ===============*/ /****************************************************************//** @@ -3901,6 +3868,9 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ + const big_rec_t*big_rec_vec, /*!< in: vector containing fields + to be stored externally */ + #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -3909,9 +3879,11 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - const big_rec_t*big_rec_vec) /*!< in: vector containing fields - to be stored externally */ - + mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ { ulint rec_page_no; byte* field_ref; @@ -3930,6 +3902,9 @@ btr_store_big_rec_extern_fields_func( ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); + ut_ad(local_mtr); + ut_ad(!alloc_mtr || alloc_mtr == local_mtr); + ut_ad(!update_in_place || alloc_mtr); ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); @@ -3945,6 +3920,25 @@ btr_store_big_rec_extern_fields_func( rec_page_no = buf_block_get_page_no(rec_block); ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX); + if (alloc_mtr) { + /* Because alloc_mtr will be committed after + mtr, it is possible that the tablespace has been + extended when the B-tree record was updated or + inserted, or it will be extended while allocating + pages for big_rec. + + TODO: In mtr (not alloc_mtr), write a redo log record + about extending the tablespace to its current size, + and remember the current size. Whenever the tablespace + grows as pages are allocated, write further redo log + records to mtr. (Currently tablespace extension is not + covered by the redo log. If it were, the record would + only be written to alloc_mtr, which is committed after + mtr.) */ + } else { + alloc_mtr = &mtr; + } + if (UNIV_LIKELY_NULL(page_zip)) { int err; @@ -4021,7 +4015,7 @@ btr_store_big_rec_extern_fields_func( } block = btr_page_alloc(index, hint_page_no, - FSP_NO_DIR, 0, &mtr); + FSP_NO_DIR, 0, alloc_mtr, &mtr); if (UNIV_UNLIKELY(block == NULL)) { mtr_commit(&mtr); @@ -4148,11 +4142,15 @@ btr_store_big_rec_extern_fields_func( goto next_zip_page; } - rec_block = buf_page_get(space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level(rec_block, - SYNC_NO_ORDER_CHECK); + if (alloc_mtr == &mtr) { + rec_block = buf_page_get( + space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level( + rec_block, + SYNC_NO_ORDER_CHECK); + } if (err == Z_STREAM_END) { mach_write_to_4(field_ref @@ -4186,7 +4184,8 @@ btr_store_big_rec_extern_fields_func( page_zip_write_blob_ptr( page_zip, rec, index, offsets, - big_rec_vec->fields[i].field_no, &mtr); + big_rec_vec->fields[i].field_no, + alloc_mtr); next_zip_page: prev_page_no = page_no; @@ -4231,19 +4230,23 @@ next_zip_page: extern_len -= store_len; - rec_block = buf_page_get(space_id, zip_size, - rec_page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level(rec_block, - SYNC_NO_ORDER_CHECK); + if (alloc_mtr == &mtr) { + rec_block = buf_page_get( + space_id, zip_size, + rec_page_no, + RW_X_LATCH, &mtr); + buf_block_dbg_add_level( + rec_block, + SYNC_NO_ORDER_CHECK); + } mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4, big_rec_vec->fields[i].len - extern_len, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, alloc_mtr); if (prev_page_no == FIL_NULL) { btr_blob_dbg_add_blob( @@ -4253,18 +4256,19 @@ next_zip_page: mlog_write_ulint(field_ref + BTR_EXTERN_SPACE_ID, - space_id, - MLOG_4BYTES, &mtr); + space_id, MLOG_4BYTES, + alloc_mtr); mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO, - page_no, - MLOG_4BYTES, &mtr); + page_no, MLOG_4BYTES, + alloc_mtr); mlog_write_ulint(field_ref + BTR_EXTERN_OFFSET, FIL_PAGE_DATA, - MLOG_4BYTES, &mtr); + MLOG_4BYTES, + alloc_mtr); } prev_page_no = page_no; diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index cd1461d22b7..47300627acc 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -1174,29 +1174,6 @@ buf_page_set_accessed_make_young( } } -/********************************************************************//** -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ -UNIV_INTERN -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /*!< in: space id */ - ulint offset) /*!< in: page number */ -{ - buf_block_t* block; - - buf_pool_mutex_enter(); - - block = (buf_block_t*) buf_page_hash_get(space, offset); - - if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) { - block->check_index_page_at_flush = FALSE; - } - - buf_pool_mutex_exit(); -} - /********************************************************************//** Returns the current state of is_hashed of a page. FALSE if the page is not in the pool. NOTE that this operation does not fix the page in the diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index d091a14c474..19846b63d5b 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -312,8 +312,9 @@ fsp_fill_free_list( descriptor page and ibuf bitmap page; then we do not allocate more extents */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in: space header */ - mtr_t* mtr); /*!< in: mtr */ + fsp_header_t* header, /*!< in/out: space header */ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -326,14 +327,20 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in: segment inode */ + fseg_inode_t* seg_inode, /*!< in/out: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr); /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ + __attribute__((warn_unused_result, nonnull(3,6))); #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** @@ -701,17 +708,18 @@ list, if not free limit == space size. This adding is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -UNIV_INLINE +UNIV_INLINE __attribute__((nonnull, warn_unused_result)) xdes_t* xdes_get_descriptor_with_space_hdr( /*===============================*/ - fsp_header_t* sp_header,/*!< in/out: space header, x-latched */ - ulint space, /*!< in: space id */ - ulint offset, /*!< in: page offset; - if equal to the free limit, - we try to add new extents to - the space free list */ - mtr_t* mtr) /*!< in: mtr handle */ + fsp_header_t* sp_header, /*!< in/out: space header, x-latched + in mtr */ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: page offset; if equal + to the free limit, we try to + add new extents to the space + free list */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint limit; ulint size; @@ -719,11 +727,9 @@ xdes_get_descriptor_with_space_hdr( ulint descr_page_no; page_t* descr_page; - ut_ad(mtr); ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX) - || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX)); ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET); /* Read free limit and space size */ limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT); @@ -773,7 +779,7 @@ is necessary to make the descriptor defined, as they are uninitialized above the free limit. @return pointer to the extent descriptor, NULL if the page does not exist in the space or if the offset exceeds the free limit */ -static +static __attribute__((nonnull, warn_unused_result)) xdes_t* xdes_get_descriptor( /*================*/ @@ -782,7 +788,7 @@ xdes_get_descriptor( or 0 for uncompressed pages */ ulint offset, /*!< in: page offset; if equal to the free limit, we try to add new extents to the space free list */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { buf_block_t* block; fsp_header_t* sp_header; @@ -1160,14 +1166,14 @@ fsp_header_get_tablespace_size(void) Tries to extend a single-table tablespace so that a page would fit in the data file. @return TRUE if success */ -static +static __attribute__((nonnull, warn_unused_result)) ibool fsp_try_extend_data_file_with_pages( /*================================*/ ulint space, /*!< in: space */ ulint page_no, /*!< in: page number */ - fsp_header_t* header, /*!< in: space header */ - mtr_t* mtr) /*!< in: mtr */ + fsp_header_t* header, /*!< in/out: space header */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ibool success; ulint actual_size; @@ -1192,7 +1198,7 @@ fsp_try_extend_data_file_with_pages( /***********************************************************************//** Tries to extend the last data file of a tablespace if it is auto-extending. @return FALSE if not auto-extending */ -static +static __attribute__((nonnull)) ibool fsp_try_extend_data_file( /*=====================*/ @@ -1202,8 +1208,8 @@ fsp_try_extend_data_file( the actual file size rounded down to megabyte */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in: space header */ - mtr_t* mtr) /*!< in: mtr */ + fsp_header_t* header, /*!< in/out: space header */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint size; ulint zip_size; @@ -1339,7 +1345,7 @@ fsp_fill_free_list( then we do not allocate more extents */ ulint space, /*!< in: space */ fsp_header_t* header, /*!< in/out: space header */ - mtr_t* mtr) /*!< in: mtr */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint limit; ulint size; @@ -1537,10 +1543,47 @@ fsp_alloc_free_extent( return(descr); } +/**********************************************************************//** +Allocates a single free page from a space. */ +static __attribute__((nonnull)) +void +fsp_alloc_from_free_frag( +/*=====================*/ + fsp_header_t* header, /*!< in/out: tablespace header */ + xdes_t* descr, /*!< in/out: extent descriptor */ + ulint bit, /*!< in: slot to allocate in the extent */ + mtr_t* mtr) /*!< in/out: mini-transaction */ +{ + ulint frag_n_used; + + ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr)); + xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr); + + /* Update the FRAG_N_USED field */ + frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, + mtr); + frag_n_used++; + mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, + mtr); + if (xdes_is_full(descr, mtr)) { + /* The fragment is full: move it to another list */ + flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, + mtr); + xdes_set_state(descr, XDES_FULL_FRAG, mtr); + + flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, + mtr); + mlog_write_ulint(header + FSP_FRAG_N_USED, + frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, + mtr); + } +} + /**********************************************************************//** Allocates a single free page from a space. The page is marked as used. @return the page offset, FIL_NULL if no page could be allocated */ -static +static __attribute__((nonnull, warn_unused_result)) ulint fsp_alloc_free_page( /*================*/ @@ -1548,19 +1591,22 @@ fsp_alloc_free_page( ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint hint, /*!< in: hint of which page would be desirable */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr) */ { fsp_header_t* header; fil_addr_t first; xdes_t* descr; buf_block_t* block; ulint free; - ulint frag_n_used; ulint page_no; ulint space_size; ibool success; ut_ad(mtr); + ut_ad(init_mtr); header = fsp_get_space_header(space, zip_size, mtr); @@ -1642,38 +1688,19 @@ fsp_alloc_free_page( } } - xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); - - /* Update the FRAG_N_USED field */ - frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES, - mtr); - frag_n_used++; - mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES, - mtr); - if (xdes_is_full(descr, mtr)) { - /* The fragment is full: move it to another list */ - flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE, - mtr); - xdes_set_state(descr, XDES_FULL_FRAG, mtr); - - flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE, - mtr); - mlog_write_ulint(header + FSP_FRAG_N_USED, - frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES, - mtr); - } + fsp_alloc_from_free_frag(header, descr, free, mtr); /* Initialize the allocated page to the buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read. */ - buf_page_create(space, page_no, zip_size, mtr); + buf_page_create(space, page_no, zip_size, init_mtr); - block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); + block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, init_mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); /* Prior contents of the page should be ignored */ - fsp_init_file_page(block, mtr); + fsp_init_file_page(block, init_mtr); return(page_no); } @@ -1909,7 +1936,7 @@ fsp_alloc_seg_inode_page( zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); - page_no = fsp_alloc_free_page(space, zip_size, 0, mtr); + page_no = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr); if (page_no == FIL_NULL) { @@ -2323,7 +2350,7 @@ fseg_create_general( if (page == 0) { page = fseg_alloc_free_page_low(space, zip_size, - inode, 0, FSP_UP, mtr); + inode, 0, FSP_UP, mtr, mtr); if (page == FIL_NULL) { @@ -2572,14 +2599,19 @@ fseg_alloc_free_page_low( ulint space, /*!< in: space */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - fseg_inode_t* seg_inode, /*!< in: segment inode */ + fseg_inode_t* seg_inode, /*!< in/out: segment inode */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction, /*!< in: if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mini-transaction in which the + page should be initialized + (may be the same as mtr), or NULL if it + should not be initialized (the page at hint + was previously freed in mtr) */ { fsp_header_t* space_header; ulint space_size; @@ -2590,7 +2622,6 @@ fseg_alloc_free_page_low( ulint ret_page; /*!< the allocated page offset, FIL_NULL if could not be allocated */ xdes_t* ret_descr; /*!< the extent of the allocated page */ - ibool frag_page_allocated = FALSE; ibool success; ulint n; @@ -2612,6 +2643,8 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ + ut_a(init_mtr); + /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, zip_size, hint, mtr); } @@ -2623,15 +2656,20 @@ fseg_alloc_free_page_low( mtr), seg_id)) && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { - +take_hinted_page: /* 1. We can take the hinted page =================================*/ ret_descr = descr; ret_page = hint; + /* Skip the check for extending the tablespace. If the + page hint were not within the size of the tablespace, + we would have got (descr == NULL) above and reset the hint. */ + goto got_hinted_page; /*-----------------------------------------------------------*/ - } else if ((xdes_get_state(descr, mtr) == XDES_FREE) - && ((reserved - used) < reserved / FSEG_FILLFACTOR) - && (used >= FSEG_FRAG_LIMIT)) { + } else if (xdes_get_state(descr, mtr) == XDES_FREE + && (!init_mtr + || ((reserved - used < reserved / FSEG_FILLFACTOR) + && used >= FSEG_FRAG_LIMIT))) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2649,8 +2687,20 @@ fseg_alloc_free_page_low( /* Try to fill the segment free list */ fseg_fill_free_list(seg_inode, space, zip_size, hint + FSP_EXTENT_SIZE, mtr); - ret_page = hint; + goto take_hinted_page; /*-----------------------------------------------------------*/ + } else if (!init_mtr) { + ut_a(xdes_get_state(descr, mtr) == XDES_FREE_FRAG); + fsp_alloc_from_free_frag(space_header, descr, + hint % FSP_EXTENT_SIZE, mtr); + ret_page = hint; + ret_descr = NULL; + + /* Put the page in the fragment page array of the segment */ + n = fseg_find_free_frag_page_slot(seg_inode, mtr); + ut_a(n != FIL_NULL); + fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); + goto got_hinted_page; } else if ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) && (used >= FSEG_FRAG_LIMIT) @@ -2710,11 +2760,10 @@ fseg_alloc_free_page_low( } else if (used < FSEG_FRAG_LIMIT) { /* 6. We allocate an individual page from the space ===================================================*/ - ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr); + ret_page = fsp_alloc_free_page(space, zip_size, hint, + mtr, init_mtr); ret_descr = NULL; - frag_page_allocated = TRUE; - if (ret_page != FIL_NULL) { /* Put the page in the fragment page array of the segment */ @@ -2724,6 +2773,10 @@ fseg_alloc_free_page_low( fseg_set_nth_frag_page_no(seg_inode, n, ret_page, mtr); } + + /* fsp_alloc_free_page() invoked fsp_init_file_page() + already. */ + return(ret_page); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2771,26 +2824,34 @@ fseg_alloc_free_page_low( } } - if (!frag_page_allocated) { +got_hinted_page: + { /* Initialize the allocated page to buffer pool, so that it can be obtained immediately with buf_page_get without need for a disk read */ buf_block_t* block; ulint zip_size = dict_table_flags_to_zip_size( mach_read_from_4(FSP_SPACE_FLAGS + space_header)); + mtr_t* block_mtr = init_mtr ? init_mtr : mtr; - block = buf_page_create(space, ret_page, zip_size, mtr); + block = buf_page_create(space, ret_page, zip_size, block_mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size, ret_page, RW_X_LATCH, - mtr))) { + block_mtr))) { ut_error; } - /* The prior contents of the page should be ignored */ - fsp_init_file_page(block, mtr); + if (init_mtr) { + /* The prior contents of the page should be ignored */ + fsp_init_file_page(block, init_mtr); + } + } + /* ret_descr == NULL if the block was allocated from free_frag + (XDES_FREE_FRAG) */ + if (ret_descr != NULL) { /* At this point we know the extent and the page offset. The extent is still in the appropriate list (FSEG_NOT_FULL or FSEG_FREE), and the page is not yet marked as used. */ @@ -2803,8 +2864,6 @@ fseg_alloc_free_page_low( fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr); } - buf_reset_check_index_page_at_flush(space, ret_page); - return(ret_page); } @@ -2817,7 +2876,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in: segment header */ + fseg_header_t* seg_header,/*!< in/out: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -2829,7 +2888,11 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr) /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction handle */ + mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ { fseg_inode_t* inode; ulint space; @@ -2871,7 +2934,8 @@ fseg_alloc_free_page_general( } page_no = fseg_alloc_free_page_low(space, zip_size, - inode, hint, direction, mtr); + inode, hint, direction, + mtr, init_mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } @@ -2879,28 +2943,6 @@ fseg_alloc_free_page_general( return(page_no); } -/**********************************************************************//** -Allocates a single free page from a segment. This function implements -the intelligent allocation strategy which tries to minimize file space -fragmentation. -@return allocated page offset, FIL_NULL if no page could be allocated */ -UNIV_INTERN -ulint -fseg_alloc_free_page( -/*=================*/ - fseg_header_t* seg_header,/*!< in: segment header */ - ulint hint, /*!< in: hint of which page would be desirable */ - byte direction,/*!< in: if the new page is needed because - of an index page split, and records are - inserted there in order, into which - direction they go alphabetically: FSP_DOWN, - FSP_UP, FSP_NO_DIR */ - mtr_t* mtr) /*!< in: mtr handle */ -{ - return(fseg_alloc_free_page_general(seg_header, hint, direction, - FALSE, mtr)); -} - /**********************************************************************//** Checks that we have at least 2 frag pages free in the first extent of a single-table tablespace, and they are also physically initialized to the data diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h index c0a038dd21d..476ad29adac 100644 --- a/storage/innodb_plugin/include/btr0btr.h +++ b/storage/innodb_plugin/include/btr0btr.h @@ -557,7 +557,12 @@ btr_page_alloc( page split is made */ ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr); /*!< in: mtr */ + mtr_t* mtr, /*!< in/out: mini-transaction + for the allocation */ + mtr_t* init_mtr) /*!< in/out: mini-transaction + for x-latching and initializing + the page */ + __attribute__((nonnull, warn_unused_result)); /**************************************************************//** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ @@ -580,6 +585,33 @@ btr_page_free_low( buf_block_t* block, /*!< in: block to be freed, x-latched */ ulint level, /*!< in: page level */ mtr_t* mtr); /*!< in: mtr */ +/**************************************************************//** +Marks all MTR_MEMO_FREE_CLUST_LEAF pages nonfree or free. +For invoking btr_store_big_rec_extern_fields() after an update, +we must temporarily mark freed clustered index pages allocated, so +that off-page columns will not be allocated from them. Between the +btr_store_big_rec_extern_fields() and mtr_commit() we have to +mark the pages free again, so that no pages will be leaked. */ +UNIV_INTERN +void +btr_mark_freed_leaves( +/*==================*/ + dict_index_t* index, /*!< in/out: clustered index */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + ibool nonfree)/*!< in: TRUE=mark nonfree, FALSE=mark freed */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +/**************************************************************//** +Validates all pages marked MTR_MEMO_FREE_CLUST_LEAF. +@see btr_mark_freed_leaves() +@return TRUE */ +UNIV_INTERN +ibool +btr_freed_leaves_validate( +/*======================*/ + mtr_t* mtr) /*!< in: mini-transaction */ + __attribute__((nonnull, warn_unused_result)); +#endif /* UNIV_DEBUG */ #ifdef UNIV_BTR_PRINT /*************************************************************//** Prints size info of a B-tree. */ diff --git a/storage/innodb_plugin/include/btr0cur.h b/storage/innodb_plugin/include/btr0cur.h index 6094a2a6c7a..1d97c5b9452 100644 --- a/storage/innodb_plugin/include/btr0cur.h +++ b/storage/innodb_plugin/include/btr0cur.h @@ -326,16 +326,6 @@ btr_cur_pessimistic_update( que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr); /*!< in: mtr; must be committed before latching any further pages */ -/***************************************************************** -Commits and restarts a mini-transaction so that it will retain an -x-lock on index->lock and the cursor page. */ -UNIV_INTERN -void -btr_cur_mtr_commit_and_start( -/*=========================*/ - btr_cur_t* cursor, /*!< in: cursor */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - __attribute__((nonnull)); /***********************************************************//** Marks a clustered index record deleted. Writes an undo log record to undo log on this delete marking. Writes in the trx id field the id @@ -540,6 +530,8 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ + const big_rec_t*big_rec_vec, /*!< in: vector containing fields + to be stored externally */ #ifdef UNIV_DEBUG mtr_t* local_mtr, /*!< in: mtr containing the latch to rec and to the tree */ @@ -548,9 +540,12 @@ btr_store_big_rec_extern_fields_func( ibool update_in_place,/*! in: TRUE if the record is updated in place (not delete+insert) */ #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - const big_rec_t*big_rec_vec) /*!< in: vector containing fields - to be stored externally */ - __attribute__((nonnull)); + mtr_t* alloc_mtr) /*!< in/out: in an insert, NULL; + in an update, local_mtr for + allocating BLOB pages and + updating BLOB pointers; alloc_mtr + must not have freed any leaf pages */ + __attribute__((nonnull(1,2,3,4,5), warn_unused_result)); /** Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. @@ -559,21 +554,22 @@ file segment of the index tree. @param index in: clustered index; MUST be X-latched by mtr @param b in/out: block containing rec; MUST be X-latched by mtr @param rec in/out: clustered index record -@param offsets in: rec_get_offsets(rec, index); +@param offs in: rec_get_offsets(rec, index); the "external storage" flags in offsets will not be adjusted +@param big in: vector containing fields to be stored externally @param mtr in: mini-transaction that holds x-latch on index and b @param upd in: TRUE if the record is updated in place (not delete+insert) -@param big in: vector containing fields to be stored externally +@param rmtr in/out: in updates, the mini-transaction that holds rec @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ #ifdef UNIV_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big) +# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,mtr,upd,rmtr) #elif defined UNIV_BLOB_LIGHT_DEBUG -# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big) +# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,upd,rmtr) #else -# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \ - btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big) +# define btr_store_big_rec_extern_fields(index,b,rec,offs,big,mtr,upd,rmtr) \ + btr_store_big_rec_extern_fields_func(index,b,rec,offs,big,rmtr) #endif /*******************************************************************//** diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index 9856bfce409..557bc17d311 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -372,15 +372,6 @@ buf_page_peek( /*==========*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: page number */ -/********************************************************************//** -Resets the check_index_page_at_flush field of a page if found in the buffer -pool. */ -UNIV_INTERN -void -buf_reset_check_index_page_at_flush( -/*================================*/ - ulint space, /*!< in: space id */ - ulint offset);/*!< in: page number */ #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. diff --git a/storage/innodb_plugin/include/fsp0fsp.h b/storage/innodb_plugin/include/fsp0fsp.h index 7abd3914eda..2221380c9a2 100644 --- a/storage/innodb_plugin/include/fsp0fsp.h +++ b/storage/innodb_plugin/include/fsp0fsp.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -176,19 +176,18 @@ fseg_n_reserved_pages( Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space fragmentation. -@return the allocated page offset FIL_NULL if no page could be allocated */ -UNIV_INTERN -ulint -fseg_alloc_free_page( -/*=================*/ - fseg_header_t* seg_header, /*!< in: segment header */ - ulint hint, /*!< in: hint of which page would be desirable */ - byte direction, /*!< in: if the new page is needed because +@param[in/out] seg_header segment header +@param[in] hint hint of which page would be desirable +@param[in] direction if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, - FSP_UP, FSP_NO_DIR */ - mtr_t* mtr); /*!< in: mtr handle */ + FSP_UP, FSP_NO_DIR +@param[in/out] mtr mini-transaction +@return the allocated page offset FIL_NULL if no page could be allocated */ +#define fseg_alloc_free_page(seg_header, hint, direction, mtr) \ + fseg_alloc_free_page_general(seg_header, hint, direction, \ + FALSE, mtr, mtr) /**********************************************************************//** Allocates a single free page from a segment. This function implements the intelligent allocation strategy which tries to minimize file space @@ -198,7 +197,7 @@ UNIV_INTERN ulint fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in: segment header */ + fseg_header_t* seg_header,/*!< in/out: segment header */ ulint hint, /*!< in: hint of which page would be desirable */ byte direction,/*!< in: if the new page is needed because of an index page split, and records are @@ -210,7 +209,12 @@ fseg_alloc_free_page_general( with fsp_reserve_free_extents, then there is no need to do the check for this individual page */ - mtr_t* mtr); /*!< in: mtr handle */ + mtr_t* mtr, /*!< in/out: mini-transaction */ + mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction + in which the page should be initialized, + or NULL if this is a "fake allocation" of + a page that was previously freed in mtr */ + __attribute__((warn_unused_result, nonnull(1,5))); /**********************************************************************//** Reserves free pages from a tablespace. All mini-transactions which may use several pages from the tablespace should call this function beforehand diff --git a/storage/innodb_plugin/include/mtr0mtr.h b/storage/innodb_plugin/include/mtr0mtr.h index bc3f1951be9..2a561131c09 100644 --- a/storage/innodb_plugin/include/mtr0mtr.h +++ b/storage/innodb_plugin/include/mtr0mtr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -53,6 +53,8 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_MODIFY 54 #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 +/** The mini-transaction freed a clustered index leaf page. */ +#define MTR_MEMO_FREE_CLUST_LEAF 57 /** @name Log item types The log items are declared 'byte' so that the compiler can warn if val @@ -387,9 +389,12 @@ struct mtr_struct{ #endif dyn_array_t memo; /*!< memo stack for locks etc. */ dyn_array_t log; /*!< mini-transaction log */ - ibool modifications; - /* TRUE if the mtr made modifications to - buffer pool pages */ + unsigned modifications:1; + /*!< TRUE if the mini-transaction + modified buffer pool pages */ + unsigned freed_clust_leaf:1; + /*!< TRUE if MTR_MEMO_FREE_CLUST_LEAF + was logged in the mini-transaction */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ diff --git a/storage/innodb_plugin/include/mtr0mtr.ic b/storage/innodb_plugin/include/mtr0mtr.ic index 18f8e87b3cf..9c0ddff9132 100644 --- a/storage/innodb_plugin/include/mtr0mtr.ic +++ b/storage/innodb_plugin/include/mtr0mtr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -44,6 +44,7 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; + mtr->freed_clust_leaf = FALSE; mtr->n_log_recs = 0; ut_d(mtr->state = MTR_ACTIVE); @@ -67,7 +68,8 @@ mtr_memo_push( ut_ad(object); ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_X_LOCK); + ut_ad(type <= MTR_MEMO_FREE_CLUST_LEAF); + ut_ad(type != MTR_MEMO_FREE_CLUST_LEAF || mtr->freed_clust_leaf); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); diff --git a/storage/innodb_plugin/include/trx0undo.h b/storage/innodb_plugin/include/trx0undo.h index 4f15cd85833..c95f99d6417 100644 --- a/storage/innodb_plugin/include/trx0undo.h +++ b/storage/innodb_plugin/include/trx0undo.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -204,17 +204,51 @@ trx_undo_add_page( mtr_t* mtr); /*!< in: mtr which does not have a latch to any undo log page; the caller must have reserved the rollback segment mutex */ +/********************************************************************//** +Frees the last undo log page. +The caller must hold the rollback segment mutex. */ +UNIV_INTERN +void +trx_undo_free_last_page_func( +/*==========================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log memory copy */ + mtr_t* mtr) /*!< in/out: mini-transaction which does not + have a latch to any undo log page or which + has allocated the undo log page */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +# define trx_undo_free_last_page(trx,undo,mtr) \ + trx_undo_free_last_page_func(trx,undo,mtr) +#else /* UNIV_DEBUG */ +# define trx_undo_free_last_page(trx,undo,mtr) \ + trx_undo_free_last_page_func(undo,mtr) +#endif /* UNIV_DEBUG */ + /***********************************************************************//** Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end( -/*==================*/ - trx_t* trx, /*!< in: transaction whose undo log it is */ - trx_undo_t* undo, /*!< in: undo log */ - undo_no_t limit); /*!< in: all undo records with undo number +trx_undo_truncate_end_func( +/*=======================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction whose undo log it is */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log */ + undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ + __attribute__((nonnull)); +#ifdef UNIV_DEBUG +# define trx_undo_truncate_end(trx,undo,limit) \ + trx_undo_truncate_end_func(trx,undo,limit) +#else /* UNIV_DEBUG */ +# define trx_undo_truncate_end(trx,undo,limit) \ + trx_undo_truncate_end_func(undo,limit) +#endif /* UNIV_DEBUG */ + /***********************************************************************//** Truncates an undo log from the start. This function is used during a purge operation. */ diff --git a/storage/innodb_plugin/mtr/mtr0mtr.c b/storage/innodb_plugin/mtr/mtr0mtr.c index 417e97732bb..6dd5b6eb8c3 100644 --- a/storage/innodb_plugin/mtr/mtr0mtr.c +++ b/storage/innodb_plugin/mtr/mtr0mtr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -58,12 +58,11 @@ mtr_memo_slot_release( buf_page_release((buf_block_t*)object, type, mtr); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); -#ifdef UNIV_DEBUG } else if (type != MTR_MEMO_X_LOCK) { - ut_ad(type == MTR_MEMO_MODIFY); + ut_ad(type == MTR_MEMO_MODIFY + || type == MTR_MEMO_FREE_CLUST_LEAF); ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX)); -#endif /* UNIV_DEBUG */ } else { rw_lock_x_unlock((rw_lock_t*)object); } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index ea43cbfb5f1..0f158cdc706 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -2094,15 +2094,20 @@ row_ins_index_entry_low( if (big_rec) { ut_a(err == DB_SUCCESS); /* Write out the externally stored - columns while still x-latching - index->lock and block->lock. We have - to mtr_commit(mtr) first, so that the - redo log will be written in the - correct order. Otherwise, we would run - into trouble on crash recovery if mtr - freed B-tree pages on which some of - the big_rec fields will be written. */ - btr_cur_mtr_commit_and_start(&cursor, &mtr); + columns, but allocate the pages and + write the pointers using the + mini-transaction of the record update. + If any pages were freed in the update, + temporarily mark them allocated so + that off-page columns will not + overwrite them. We must do this, + because we will write the redo log for + the BLOB writes before writing the + redo log for the record update. Thus, + redo log application at crash recovery + will see BLOBs being written to free pages. */ + + btr_mark_freed_leaves(index, &mtr, TRUE); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets( @@ -2111,7 +2116,8 @@ row_ins_index_entry_low( err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, &mtr, FALSE, big_rec); + rec, offsets, big_rec, &mtr, + FALSE, &mtr); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if @@ -2124,6 +2130,9 @@ row_ins_index_entry_low( undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again + in order to avoid a leak. */ + btr_mark_freed_leaves(index, &mtr, FALSE); goto stored_big_rec; } } else { @@ -2165,7 +2174,7 @@ function_exit: err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, &mtr, FALSE, big_rec); + rec, offsets, big_rec, &mtr, FALSE, NULL); stored_big_rec: if (modify) { diff --git a/storage/innodb_plugin/row/row0row.c b/storage/innodb_plugin/row/row0row.c index 9cdbbe76e04..e476ffae84e 100644 --- a/storage/innodb_plugin/row/row0row.c +++ b/storage/innodb_plugin/row/row0row.c @@ -243,19 +243,20 @@ row_build( } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - /* This condition can occur during crash recovery before - trx_rollback_active() has completed execution. + if (rec_offs_any_null_extern(rec, offsets)) { + /* This condition can occur during crash recovery + before trx_rollback_active() has completed execution. - This condition is possible if the server crashed - during an insert or update before - btr_store_big_rec_extern_fields() did mtr_commit() all - BLOB pointers to the clustered index record. - - If the record contains a null BLOB pointer, look up the - transaction that holds the implicit lock on this record, and - assert that it was recovered (and will soon be rolled back). */ - ut_a(!rec_offs_any_null_extern(rec, offsets) - || trx_assert_recovered(row_get_rec_trx_id(rec, index, offsets))); + This condition is possible if the server crashed + during an insert or update-by-delete-and-insert before + btr_store_big_rec_extern_fields() did mtr_commit() all + BLOB pointers to the freshly inserted clustered index + record. */ + ut_a(trx_assert_recovered( + row_get_rec_trx_id(rec, index, offsets))); + ut_a(trx_undo_roll_ptr_is_insert( + row_get_rec_roll_ptr(rec, index, offsets))); + } #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c index b5952ff0a78..05856687015 100644 --- a/storage/innodb_plugin/row/row0upd.c +++ b/storage/innodb_plugin/row/row0upd.c @@ -1978,21 +1978,22 @@ row_upd_clust_rec( rec_offs_init(offsets_); ut_a(err == DB_SUCCESS); - /* Write out the externally stored columns while still - x-latching index->lock and block->lock. We have to - mtr_commit(mtr) first, so that the redo log will be - written in the correct order. Otherwise, we would run - into trouble on crash recovery if mtr freed B-tree - pages on which some of the big_rec fields will be - written. */ - btr_cur_mtr_commit_and_start(btr_cur, mtr); + /* Write out the externally stored columns, but + allocate the pages and write the pointers using the + mini-transaction of the record update. If any pages + were freed in the update, temporarily mark them + allocated so that off-page columns will not overwrite + them. We must do this, because we write the redo log + for the BLOB writes before writing the redo log for + the record update. */ + btr_mark_freed_leaves(index, mtr, TRUE); rec = btr_cur_get_rec(btr_cur); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(btr_cur), rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - mtr, TRUE, big_rec); + big_rec, mtr, TRUE, mtr); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if we did not update any externally stored @@ -2002,6 +2003,8 @@ row_upd_clust_rec( to the undo log, and thus the record cannot be rolled back. */ ut_a(err == DB_SUCCESS); + /* Free the pages again in order to avoid a leak. */ + btr_mark_freed_leaves(index, mtr, FALSE); } mtr_commit(mtr); diff --git a/storage/innodb_plugin/trx/trx0rec.c b/storage/innodb_plugin/trx/trx0rec.c index 9f2fd59d82b..a729a39d0cc 100644 --- a/storage/innodb_plugin/trx/trx0rec.c +++ b/storage/innodb_plugin/trx/trx0rec.c @@ -1097,22 +1097,29 @@ trx_undo_rec_get_partial_row( #endif /* !UNIV_HOTBACKUP */ /***********************************************************************//** -Erases the unused undo log page end. */ -static -void +Erases the unused undo log page end. +@return TRUE if the page contained something, FALSE if it was empty */ +static __attribute__((nonnull, warn_unused_result)) +ibool trx_undo_erase_page_end( /*====================*/ - page_t* undo_page, /*!< in: undo page whose end to erase */ - mtr_t* mtr) /*!< in: mtr */ + page_t* undo_page, /*!< in/out: undo page whose end to erase */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { ulint first_free; first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE); + if (first_free == TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) { + /* This was an empty page to begin with. + Do nothing here; the caller should free the page. */ + return(FALSE); + } memset(undo_page + first_free, 0xff, (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free); mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr); + return(TRUE); } /***********************************************************//** @@ -1134,7 +1141,11 @@ trx_undo_parse_erase_page_end( return(ptr); } - trx_undo_erase_page_end(page, mtr); + if (!trx_undo_erase_page_end(page, mtr)) { + /* The function trx_undo_erase_page_end() should not + have done anything to an empty page. */ + ut_ad(0); + } return(ptr); } @@ -1180,6 +1191,9 @@ trx_undo_report_row_operation( mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; +#ifdef UNIV_DEBUG + int loop_count = 0; +#endif /* UNIV_DEBUG */ rec_offs_init(offsets_); ut_a(dict_index_is_clust(index)); @@ -1242,7 +1256,7 @@ trx_undo_report_row_operation( mtr_start(&mtr); - for (;;) { + do { buf_block_t* undo_block; page_t* undo_page; ulint offset; @@ -1271,7 +1285,19 @@ trx_undo_report_row_operation( version the replicate page constructed using the log records stays identical to the original page */ - trx_undo_erase_page_end(undo_page, &mtr); + if (!trx_undo_erase_page_end(undo_page, &mtr)) { + /* The record did not fit on an empty + undo page. Discard the freshly allocated + page and return an error. */ + + mutex_enter(&rseg->mutex); + trx_undo_free_last_page(trx, undo, &mtr); + mutex_exit(&rseg->mutex); + + err = DB_TOO_BIG_RECORD; + goto err_exit; + } + mtr_commit(&mtr); } else { /* Success */ @@ -1291,16 +1317,15 @@ trx_undo_report_row_operation( *roll_ptr = trx_undo_build_roll_ptr( op_type == TRX_UNDO_INSERT_OP, rseg->id, page_no, offset); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - return(DB_SUCCESS); + err = DB_SUCCESS; + goto func_exit; } ut_ad(page_no == undo->last_page_no); /* We have to extend the undo log by one page */ + ut_ad(++loop_count < 2); mtr_start(&mtr); /* When we add a page to an undo log, this is analogous to @@ -1312,18 +1337,19 @@ trx_undo_report_row_operation( page_no = trx_undo_add_page(trx, undo, &mtr); mutex_exit(&(rseg->mutex)); + } while (UNIV_LIKELY(page_no != FIL_NULL)); - if (UNIV_UNLIKELY(page_no == FIL_NULL)) { - /* Did not succeed: out of space */ + /* Did not succeed: out of space */ + err = DB_OUT_OF_FILE_SPACE; - mutex_exit(&(trx->undo_mutex)); - mtr_commit(&mtr); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - return(DB_OUT_OF_FILE_SPACE); - } +err_exit: + mutex_exit(&trx->undo_mutex); + mtr_commit(&mtr); +func_exit: + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); } + return(err); } /*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*/ diff --git a/storage/innodb_plugin/trx/trx0undo.c b/storage/innodb_plugin/trx/trx0undo.c index 7f03b68fb55..c36f55fbd9c 100644 --- a/storage/innodb_plugin/trx/trx0undo.c +++ b/storage/innodb_plugin/trx/trx0undo.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -912,7 +912,7 @@ trx_undo_add_page( page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, undo->top_page_no + 1, FSP_UP, - TRUE, mtr); + TRUE, mtr, mtr); fil_space_release_free_extents(undo->space, n_reserved); @@ -998,29 +998,28 @@ trx_undo_free_page( } /********************************************************************//** -Frees an undo log page when there is also the memory object for the undo -log. */ -static +Frees the last undo log page. +The caller must hold the rollback segment mutex. */ +UNIV_INTERN void -trx_undo_free_page_in_rollback( -/*===========================*/ - trx_t* trx __attribute__((unused)), /*!< in: transaction */ - trx_undo_t* undo, /*!< in: undo log memory copy */ - ulint page_no,/*!< in: page number to free: must not be the - header page */ - mtr_t* mtr) /*!< in: mtr which does not have a latch to any - undo log page; the caller must have reserved - the rollback segment mutex */ +trx_undo_free_last_page_func( +/*==========================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction */ +#endif /* UNIV_DEBUG */ + trx_undo_t* undo, /*!< in/out: undo log memory copy */ + mtr_t* mtr) /*!< in/out: mini-transaction which does not + have a latch to any undo log page or which + has allocated the undo log page */ { - ulint last_page_no; + ut_ad(mutex_own(&trx->undo_mutex)); + ut_ad(undo->hdr_page_no != undo->last_page_no); + ut_ad(undo->size > 0); - ut_ad(undo->hdr_page_no != page_no); - ut_ad(mutex_own(&(trx->undo_mutex))); + undo->last_page_no = trx_undo_free_page( + undo->rseg, FALSE, undo->space, + undo->hdr_page_no, undo->last_page_no, mtr); - last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space, - undo->hdr_page_no, page_no, mtr); - - undo->last_page_no = last_page_no; undo->size--; } @@ -1056,9 +1055,11 @@ Truncates an undo log from the end. This function is used during a rollback to free space from an undo log. */ UNIV_INTERN void -trx_undo_truncate_end( -/*==================*/ - trx_t* trx, /*!< in: transaction whose undo log it is */ +trx_undo_truncate_end_func( +/*=======================*/ +#ifdef UNIV_DEBUG + const trx_t* trx, /*!< in: transaction whose undo log it is */ +#endif /* UNIV_DEBUG */ trx_undo_t* undo, /*!< in: undo log */ undo_no_t limit) /*!< in: all undo records with undo number >= this value should be truncated */ @@ -1084,18 +1085,7 @@ trx_undo_truncate_end( rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no, undo->hdr_offset); - for (;;) { - if (rec == NULL) { - if (last_page_no == undo->hdr_page_no) { - - goto function_exit; - } - - trx_undo_free_page_in_rollback( - trx, undo, last_page_no, &mtr); - break; - } - + while (rec) { if (ut_dulint_cmp(trx_undo_rec_get_undo_no(rec), limit) >= 0) { /* Truncate at least this record off, maybe @@ -1110,6 +1100,14 @@ trx_undo_truncate_end( undo->hdr_offset); } + if (last_page_no == undo->hdr_page_no) { + + goto function_exit; + } + + ut_ad(last_page_no == undo->last_page_no); + trx_undo_free_last_page(trx, undo, &mtr); + mtr_commit(&mtr); } From f610c5658748ae97a5e2c1e1afbd229f2121a082 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Mon, 29 Aug 2011 11:24:36 +0200 Subject: [PATCH 16/49] BUG#12911710 - VALGRIND FAILURE IN ROW-DEBUG:PERFSCHEMA.SOCKET_SUMMARY_BY_INSTANCE_FUNC Converting the number zero to binary and back yielded the number zero, but with no digits, i.e. zero precision. This made the multiply algorithm go haywire in various ways. include/decimal.h: Document struct st_decimal_t mysql-test/r/type_newdecimal.result: New test case (valgrind warnings) mysql-test/t/type_newdecimal.test: New test case (valgrind warnings) sql/my_decimal.h: Remove the HAVE_purify enabled/disabled code. strings/decimal.c: Make a proper zero, with non-zero precision. --- include/decimal.h | 9 +++++++++ mysql-test/r/type_newdecimal.result | 11 +++++++++++ mysql-test/t/type_newdecimal.test | 14 ++++++++++++++ sql/my_decimal.h | 6 +----- strings/decimal.c | 9 ++++++++- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/decimal.h b/include/decimal.h index 530ed9e1757..c377bd4a400 100644 --- a/include/decimal.h +++ b/include/decimal.h @@ -21,6 +21,15 @@ typedef enum decimal_round_mode; typedef int32 decimal_digit_t; +/** + intg is the number of *decimal* digits (NOT number of decimal_digit_t's !) + before the point + frac is the number of decimal digits after the point + len is the length of buf (length of allocated space) in decimal_digit_t's, + not in bytes + sign false means positive, true means negative + buf is an array of decimal_digit_t's + */ typedef struct st_decimal_t { int intg, frac, len; my_bool sign; diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index c301a7dd629..0c6c1333e9b 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1927,3 +1927,14 @@ f1 0.000000000000000000000000 DROP TABLE IF EXISTS t1; End of 5.1 tests +# +# BUG#12911710 - VALGRIND FAILURE IN +# ROW-DEBUG:PERFSCHEMA.SOCKET_SUMMARY_BY_INSTANCE_FUNC +# +CREATE TABLE t1(d1 DECIMAL(60,0) NOT NULL, +d2 DECIMAL(60,0) NOT NULL); +INSERT INTO t1 (d1, d2) VALUES(0.0, 0.0); +SELECT d1 * d2 FROM t1; +d1 * d2 +0 +DROP TABLE t1; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 31a8808da55..567d6c0b6a1 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1526,3 +1526,17 @@ DROP TABLE IF EXISTS t1; --echo End of 5.1 tests + +--echo # +--echo # BUG#12911710 - VALGRIND FAILURE IN +--echo # ROW-DEBUG:PERFSCHEMA.SOCKET_SUMMARY_BY_INSTANCE_FUNC +--echo # + +CREATE TABLE t1(d1 DECIMAL(60,0) NOT NULL, + d2 DECIMAL(60,0) NOT NULL); + +INSERT INTO t1 (d1, d2) VALUES(0.0, 0.0); +SELECT d1 * d2 FROM t1; + +DROP TABLE t1; + diff --git a/sql/my_decimal.h b/sql/my_decimal.h index c7a99e10233..21f485560da 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -101,12 +101,8 @@ public: { len= DECIMAL_BUFF_LENGTH; buf= buffer; -#if !defined (HAVE_purify) && !defined(DBUG_OFF) - /* Set buffer to 'random' value to find wrong buffer usage */ - for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) - buffer[i]= i; -#endif } + my_decimal() { init(); diff --git a/strings/decimal.c b/strings/decimal.c index 43957c7dc19..6c89657004c 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1423,11 +1423,18 @@ int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale) buf++; } my_afree(d_copy); + + /* + No digits? We have read the number zero, of unspecified precision. + Make it a proper zero, with non-zero precision. + */ + if (to->intg == 0 && to->frac == 0) + decimal_make_zero(to); return error; err: my_afree(d_copy); - decimal_make_zero(((decimal_t*) to)); + decimal_make_zero(to); return(E_DEC_BAD_NUM); } From c6de8c8c05d020f16817fb0bfb05c9c3df475a76 Mon Sep 17 00:00:00 2001 From: "Norvald H. Ryeng" Date: Tue, 30 Aug 2011 09:56:07 +0200 Subject: [PATCH 17/49] Bug#11765254 - 58200: ASSERTION FAILED: PARAM.SORT_LENGTH WHEN GROUPING BY FUNCTIONS.... (PART The bug was introduced in a patch for bug 49897. Problem: The assertion inserted by the original patch to guard against zero-lenght sort keys during merge phase triggers also when the whole set fits in memory. Fix: Move assert so that it does not trigger if the whole set is in memory. mysql-test/r/group_by.result: Add test for bug#11765254 mysql-test/t/group_by.test: Add test for bug#11765254 sql/filesort.cc: Move assertion --- mysql-test/r/group_by.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/group_by.test | 14 ++++++++++++++ sql/filesort.cc | 5 +++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 1dfb0f5860a..2c9f6116eed 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -1891,4 +1891,36 @@ a AVG(t1.b) t11c t12c 1 4.0000 6 6 2 2.0000 7 7 DROP TABLE t1; +# +# Bug#11765254 (58200): Assertion failed: param.sort_length when grouping +# by functions +# +SET SQL_BIG_TABLES=1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0),(0); +SELECT 1 FROM t1 GROUP BY IF(`a`,'',''); +1 +1 +SELECT 1 FROM t1 GROUP BY TRIM(LEADING RAND() FROM ''); +1 +1 +SELECT 1 FROM t1 GROUP BY SUBSTRING('',SLEEP(0),''); +1 +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' +Warning 1292 Truncated incorrect INTEGER value: '' +Warning 1292 Truncated incorrect INTEGER value: '' +SELECT 1 FROM t1 GROUP BY SUBSTRING(SYSDATE() FROM 'K' FOR 'jxW<'); +1 +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'K' +Warning 1292 Truncated incorrect INTEGER value: 'jxW<' +Warning 1292 Truncated incorrect INTEGER value: 'K' +Warning 1292 Truncated incorrect INTEGER value: 'jxW<' +Warning 1292 Truncated incorrect INTEGER value: 'K' +Warning 1292 Truncated incorrect INTEGER value: 'jxW<' +DROP TABLE t1; +SET SQL_BIG_TABLES=0; # End of 5.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 1a4b9a3bab7..29ed26215bf 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -1283,5 +1283,19 @@ FROM t1 GROUP BY a; DROP TABLE t1; +--echo # +--echo # Bug#11765254 (58200): Assertion failed: param.sort_length when grouping +--echo # by functions +--echo # + +SET SQL_BIG_TABLES=1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0),(0); +SELECT 1 FROM t1 GROUP BY IF(`a`,'',''); +SELECT 1 FROM t1 GROUP BY TRIM(LEADING RAND() FROM ''); +SELECT 1 FROM t1 GROUP BY SUBSTRING('',SLEEP(0),''); +SELECT 1 FROM t1 GROUP BY SUBSTRING(SYSDATE() FROM 'K' FOR 'jxW<'); +DROP TABLE t1; +SET SQL_BIG_TABLES=0; --echo # End of 5.1 tests diff --git a/sql/filesort.cc b/sql/filesort.cc index 0ff354b334c..715528bcd52 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -144,8 +144,6 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, error= 1; bzero((char*) ¶m,sizeof(param)); param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset); - /* filesort cannot handle zero-length records. */ - DBUG_ASSERT(param.sort_length); param.ref_length= table->file->ref_length; param.addon_field= 0; param.addon_length= 0; @@ -257,6 +255,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, } else { + /* filesort cannot handle zero-length records during merge. */ + DBUG_ASSERT(param.sort_length != 0); + if (table_sort.buffpek && table_sort.buffpek_len < maxbuffer) { x_free(table_sort.buffpek); From 034db5cb82c4dbb71262b783afae293d67da4a05 Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Tue, 30 Aug 2011 10:19:36 +0200 Subject: [PATCH 18/49] Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX Post-push fix: The functions write_keys() and find_all_keys() may have a slightly different function signature, depending on compiler/platform/flags. --- mysql-test/valgrind.supp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 3751a339a1a..e2fdc727da5 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -792,6 +792,9 @@ fun:row_drop_table_for_mysql } +# Note the wildcard in the (mangled) function signatures of +# write_keys() and find_all_keys(). +# They both return ha_rows, which is platform dependent. { Bug#12856915 VALGRIND FAILURE IN FILESORT/CREATE_SORT_INDEX / one Memcheck:Param @@ -800,8 +803,8 @@ fun:my_write fun:my_b_flush_io_cache fun:_my_b_write - fun:_ZL10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ - fun:_ZL13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_S6_ + fun:_Z*10write_keysP13st_sort_paramPPhjP11st_io_cacheS4_ + fun:_Z*13find_all_keysP13st_sort_paramP10SQL_SELECTPPhP11st_io_cacheS6_S6_ fun:_Z8filesortP3THDP8st_tableP13st_sort_fieldjP10SQL_SELECTybPy } From 52d9e13ffcacee74e42bc436877f5f4eb1999e66 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 5 Sep 2011 14:38:20 +0200 Subject: [PATCH 19/49] Bug #11750417 40942: UNABLE TO INSTALL FEDERATED PLUGIN Link plugin with a copy of string.o Copied test from 5.5 but this was dysfunctional, made it work Also tested on Windows --- mysql-test/include/have_federated_plugin.inc | 5 +++ mysql-test/mysql-test-run.pl | 18 ++++++++++ .../federated/federated_plugin-master.opt | 2 ++ .../suite/federated/federated_plugin.result | 19 +++++++++++ .../suite/federated/federated_plugin.test | 34 +++++++++++++++++++ storage/federated/Makefile.am | 4 +-- 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 mysql-test/include/have_federated_plugin.inc create mode 100644 mysql-test/suite/federated/federated_plugin-master.opt create mode 100644 mysql-test/suite/federated/federated_plugin.result create mode 100644 mysql-test/suite/federated/federated_plugin.test diff --git a/mysql-test/include/have_federated_plugin.inc b/mysql-test/include/have_federated_plugin.inc new file mode 100644 index 00000000000..5c7549de53f --- /dev/null +++ b/mysql-test/include/have_federated_plugin.inc @@ -0,0 +1,5 @@ +if (`select plugin_library IS NULL from information_schema.plugins where plugin_name LIKE '%federated%'`) +{ + --skip federated plugin not available +} + diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1c7efccc69d..7661714eb03 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1979,6 +1979,24 @@ sub environment_setup { $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=EXAMPLE=".$plugin_filename; } + # -------------------------------------------------------------------------- + # Add the path where mysqld will find ha_federated.so + # -------------------------------------------------------------------------- + my $fedplug_filename; + if (IS_WINDOWS) { + $fedplug_filename = "ha_federated.dll"; + } else { + $fedplug_filename = "ha_federated.so"; + } + my $lib_fed_plugin= + mtr_file_exists(vs_config_dirs('storage/federated',$fedplug_filename), + "$basedir/storage/federated/.libs/".$fedplug_filename, + "$basedir/lib/mysql/plugin/".$fedplug_filename); + + $ENV{'FEDERATED_PLUGIN'}= $fedplug_filename; + $ENV{'FEDERATED_PLUGIN_DIR'}= + ($lib_fed_plugin ? dirname($lib_fed_plugin) : ""); + # ---------------------------------------------------- # Add the path where mysqld will find mypluglib.so # ---------------------------------------------------- diff --git a/mysql-test/suite/federated/federated_plugin-master.opt b/mysql-test/suite/federated/federated_plugin-master.opt new file mode 100644 index 00000000000..027a6d949c0 --- /dev/null +++ b/mysql-test/suite/federated/federated_plugin-master.opt @@ -0,0 +1,2 @@ +--plugin_dir=$FEDERATED_PLUGIN_DIR +--loose-federated=ON diff --git a/mysql-test/suite/federated/federated_plugin.result b/mysql-test/suite/federated/federated_plugin.result new file mode 100644 index 00000000000..b49a977d9df --- /dev/null +++ b/mysql-test/suite/federated/federated_plugin.result @@ -0,0 +1,19 @@ +CREATE TABLE t2(a int); +CREATE TABLE t1(a int) ENGINE=FEDERATED +CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +Warnings: +Warning 1286 Unknown table engine 'FEDERATED' +Warning 1266 Using storage engine MyISAM for table 't1' +DROP TABLE t1; +INSTALL PLUGIN federated SONAME 'FEDERATED_PLUGIN'; +INSTALL PLUGIN FEDERATED SONAME 'FEDERATED_PLUGIN'; +ERROR HY000: Function 'FEDERATED' already exists +UNINSTALL PLUGIN federated; +INSTALL PLUGIN federated SONAME 'FEDERATED_PLUGIN'; +CREATE TABLE t1(a int) ENGINE=FEDERATED +CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +DROP TABLE t1; +UNINSTALL PLUGIN federated; +UNINSTALL PLUGIN federated; +ERROR 42000: PLUGIN federated does not exist +DROP TABLE t2; diff --git a/mysql-test/suite/federated/federated_plugin.test b/mysql-test/suite/federated/federated_plugin.test new file mode 100644 index 00000000000..6e5152df17c --- /dev/null +++ b/mysql-test/suite/federated/federated_plugin.test @@ -0,0 +1,34 @@ +--source include/have_federated_plugin.inc + +connect (master,localhost,root,,test,$MASTER_MYPORT,); +connect (slave,localhost,root,,test,$SLAVE_MYPORT,); + +connection master; +CREATE TABLE t2(a int); + +connection slave; +CREATE TABLE t1(a int) ENGINE=FEDERATED + CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +DROP TABLE t1; + +--replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN +eval INSTALL PLUGIN federated SONAME '$FEDERATED_PLUGIN'; +--replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN +--error ER_UDF_EXISTS +eval INSTALL PLUGIN FEDERATED SONAME '$FEDERATED_PLUGIN'; + +UNINSTALL PLUGIN federated; + +--replace_result $FEDERATED_PLUGIN FEDERATED_PLUGIN +eval INSTALL PLUGIN federated SONAME '$FEDERATED_PLUGIN'; + +CREATE TABLE t1(a int) ENGINE=FEDERATED + CONNECTION='mysql://root@localhost:$MASTER_MYPORT/test/t2'; +DROP TABLE t1; + +UNINSTALL PLUGIN federated; +--error ER_SP_DOES_NOT_EXIST +UNINSTALL PLUGIN federated; + +connection master; +DROP TABLE t2; diff --git a/storage/federated/Makefile.am b/storage/federated/Makefile.am index e0dae69539e..9b4e74af0a7 100644 --- a/storage/federated/Makefile.am +++ b/storage/federated/Makefile.am @@ -37,14 +37,14 @@ pkgplugin_LTLIBRARIES = @plugin_federated_shared_target@ ha_federated_la_LDFLAGS = -module -rpath $(pkgplugindir) ha_federated_la_CXXFLAGS= $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN ha_federated_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN -ha_federated_la_SOURCES = ha_federated.cc +ha_federated_la_SOURCES = ha_federated.cc $(top_srcdir)/mysys/string.c EXTRA_LIBRARIES = libfederated.a noinst_LIBRARIES = @plugin_federated_static_target@ libfederated_a_CXXFLAGS = $(AM_CXXFLAGS) libfederated_a_CFLAGS = $(AM_CFLAGS) -libfederated_a_SOURCES= ha_federated.cc +libfederated_a_SOURCES= ha_federated.cc $(top_srcdir)/mysys/string.c EXTRA_DIST = CMakeLists.txt plug.in From 2f49da3fdc4b4dc727794d346d0de1bc2f6d5244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 6 Sep 2011 10:04:21 +0300 Subject: [PATCH 20/49] Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE - take 2 The original fix was accidentally pushed to mysql-5.1 after the 5.1.59 clone-off in bzr revision id marko.makela@oracle.com-20110829081642-z0w992a0mrc62s6w with thne fix of Bug#12704861 Corruption after a crash during BLOB update. It was pushed separately to mysql-5.5 in bzr revision id marko.makela@oracle.com-20110901184804-2901f6qmuro3jas8. trx_undo_report_row_operation(): If the page for which the undo log was too big was empty, commit and start the mini-transaction before acquiring the rollback segment mutex and freeing the undo page. This is necessary, because the mini-transaction may be holding lower-order latches in the levels SYNC_FSP and SYNC_FSP_PAGE. trx_undo_erase_page_end(): Erase also empty pages, because trx_undo_report_row_operation() needs to commit the mini-transaction before freeing the empty page. rb:756 approved by Sunny Bains --- storage/innodb_plugin/ChangeLog | 10 +++++----- storage/innodb_plugin/trx/trx0rec.c | 27 +++++++++++++++------------ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 96b6a47085a..328cafff58f 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-06 The InnoDB Team + + * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: + Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE + 2011-08-29 The InnoDB Team * btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, @@ -7,11 +12,6 @@ Fix Bug#12704861 Corruption after a crash during BLOB update and other regressions from the fix of Bug#12612184 -2011-08-23 The InnoDB Team - - * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: - Fix Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE - 2011-08-15 The InnoDB Team * btr/btr0btr.c, btr/btr0cur.c, btr/btr0pcur.c, btr/btr0sea.c, diff --git a/storage/innodb_plugin/trx/trx0rec.c b/storage/innodb_plugin/trx/trx0rec.c index a729a39d0cc..2db98e029df 100644 --- a/storage/innodb_plugin/trx/trx0rec.c +++ b/storage/innodb_plugin/trx/trx0rec.c @@ -1099,7 +1099,7 @@ trx_undo_rec_get_partial_row( /***********************************************************************//** Erases the unused undo log page end. @return TRUE if the page contained something, FALSE if it was empty */ -static __attribute__((nonnull, warn_unused_result)) +static __attribute__((nonnull)) ibool trx_undo_erase_page_end( /*====================*/ @@ -1110,16 +1110,11 @@ trx_undo_erase_page_end( first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE); - if (first_free == TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) { - /* This was an empty page to begin with. - Do nothing here; the caller should free the page. */ - return(FALSE); - } memset(undo_page + first_free, 0xff, (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free); mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr); - return(TRUE); + return(first_free != TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); } /***********************************************************//** @@ -1141,11 +1136,7 @@ trx_undo_parse_erase_page_end( return(ptr); } - if (!trx_undo_erase_page_end(page, mtr)) { - /* The function trx_undo_erase_page_end() should not - have done anything to an empty page. */ - ut_ad(0); - } + trx_undo_erase_page_end(page, mtr); return(ptr); } @@ -1290,6 +1281,18 @@ trx_undo_report_row_operation( undo page. Discard the freshly allocated page and return an error. */ + /* When we remove a page from an undo + log, this is analogous to a + pessimistic insert in a B-tree, and we + must reserve the counterpart of the + tree latch, which is the rseg + mutex. We must commit the mini-transaction + first, because it may be holding lower-level + latches, such as SYNC_FSP and SYNC_FSP_PAGE. */ + + mtr_commit(&mtr); + mtr_start(&mtr); + mutex_enter(&rseg->mutex); trx_undo_free_last_page(trx, undo, &mtr); mutex_exit(&rseg->mutex); From 7f48c174f0b589f307c54f2bab28a465ffc92468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 6 Sep 2011 10:08:52 +0300 Subject: [PATCH 21/49] Bug #12950803 62294: BUF_BUDDY_RELOCATE CALLS GETTIMEOFDAY ... buf_buddy_relocate(): The ut_time_us() function is needed for statistics, calculating the total time spent on relocating blocks. Until now, we invoked ut_time_us() every time buf_buddy_relocate() was called. Fix: Only call ut_time_us() when the block can be relocated. After this fix, the reported relocated_usec will no longer include the time for the page_hash lookup and for acquiring the block mutex. Approved by Sunny Bains on IM --- storage/innodb_plugin/ChangeLog | 6 ++++++ storage/innodb_plugin/buf/buf0buddy.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 328cafff58f..a29aaf2077e 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2011-09-06 The InnoDB Team + + * buf/buf0buddy.c: + Fix Bug#12950803 62294: BUF_BUDDY_RELOCATE CALLS GETTIMEOFDAY + WHILE HOLDING BUFFER POOL MUTEX + 2011-09-06 The InnoDB Team * include/trx0undo.h, trx/trx0rec.c, trx/trx0undo.c: diff --git a/storage/innodb_plugin/buf/buf0buddy.c b/storage/innodb_plugin/buf/buf0buddy.c index de571743361..efc4fd46e90 100644 --- a/storage/innodb_plugin/buf/buf0buddy.c +++ b/storage/innodb_plugin/buf/buf0buddy.c @@ -327,7 +327,6 @@ buf_buddy_relocate( { buf_page_t* bpage; const ulint size = BUF_BUDDY_LOW << i; - ullint usec = ut_time_us(NULL); mutex_t* mutex; ulint space; ulint page_no; @@ -394,6 +393,7 @@ buf_buddy_relocate( if (buf_page_can_relocate(bpage)) { /* Relocate the compressed page. */ + ullint usec = ut_time_us(NULL); ut_a(bpage->zip.data == src); memcpy(dst, src, size); bpage->zip.data = dst; From 079d3cc6a6d19c2baf98c703ba28af47b45b0f4f Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 6 Sep 2011 21:06:09 +0530 Subject: [PATCH 22/49] Bug#11765888 58898: MYSQL_INSTALL_DB: NOT ALL OPTIONS DOCUMENTED (EG: --DEFAULTS-FILE ) Added help message for the missing options (--no-defaults, --defaults-file and --defaults-extra-file). --- scripts/mysql_install_db.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index b9b31a2d78e..6fe9712b23a 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -46,10 +46,16 @@ Usage: $0 [OPTIONS] --cross-bootstrap For internal use. Used when building the MySQL system tables on a different host than the target. --datadir=path The path to the MySQL data directory. + --defaults-extra-file=name + Read this file after the global files are read. + + --defaults-file=name Only read default options from the given file name. --force Causes mysql_install_db to run even if DNS does not work. In that case, grant table entries that normally use hostnames will use IP addresses. + --help Display this help and exit. --ldata=path The path to the MySQL data directory. Same as --datadir. + --no-defaults Don't read default options from any option file. --rpm For internal use. This option is used by RPM files during the MySQL installation process. --skip-name-resolve Use IP addresses rather than hostnames when creating From d24953af5cbef54222c14325d75a34f598f1e25f Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 6 Sep 2011 21:25:28 +0530 Subject: [PATCH 23/49] Removing a stray line, went into the last push. --- scripts/mysql_install_db.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 6fe9712b23a..9782a37c462 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -48,7 +48,6 @@ Usage: $0 [OPTIONS] --datadir=path The path to the MySQL data directory. --defaults-extra-file=name Read this file after the global files are read. - --defaults-file=name Only read default options from the given file name. --force Causes mysql_install_db to run even if DNS does not work. In that case, grant table entries that normally From a667fe030b2b03370b2f0eb39e2fa2ed8f13ddf5 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Tue, 6 Sep 2011 21:50:04 +0530 Subject: [PATCH 24/49] Bug#11765888 58898: MYSQL_INSTALL_DB: NOT ALL OPTIONS DOCUMENTED (EG: --DEFAULTS-FILE ) Updating help message in scripts/mysql_install_db.pl.in file. scripts/mysql_install_db.pl.in: Bug#11765888 58898: MYSQL_INSTALL_DB: NOT ALL OPTIONS DOCUMENTED (EG: --DEFAULTS-FILE ) Updating help message. --- scripts/mysql_install_db.pl.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/mysql_install_db.pl.in b/scripts/mysql_install_db.pl.in index 18bd713c041..7bc1e97e7be 100644 --- a/scripts/mysql_install_db.pl.in +++ b/scripts/mysql_install_db.pl.in @@ -61,10 +61,15 @@ Usage: $0 [OPTIONS] --cross-bootstrap For internal use. Used when building the MySQL system tables on a different host than the target. --datadir=path The path to the MySQL data directory. + --defaults-extra-file=name + Read this file after the global files are read. + --defaults-file=name Only read default options from the given file name. --force Causes mysql_install_db to run even if DNS does not work. In that case, grant table entries that normally use hostnames will use IP addresses. + --help Display this help and exit. --ldata=path The path to the MySQL data directory. Same as --datadir. + --no-defaults Don't read default options from any option file. --rpm For internal use. This option is used by RPM files during the MySQL installation process. --skip-name-resolve Use IP addresses rather than hostnames when creating From 10e7b94834e09411367482e07926fd6907e69067 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Wed, 7 Sep 2011 17:58:10 +0300 Subject: [PATCH 25/49] Use cursors for seeking records in SYS_FOREIGN and SYS_INDEXES from DROP_TABLE_PROC(). With this change I observe a speedup from 6.2s to 0.1s when executing DROP_TABLE_PROC() during DROP TABLE with 512 foreign keys, like what is being done in innodb_bug56143.test This fixes "Bug#11765460 DROP TABLE USES INEFFICIENT METHODS TO REMOVE FKS/INDEXES FROM INNODB SYS TABLES" Reviewed by: Marko --- storage/innodb_plugin/row/row0mysql.c | 29 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index c4911400cee..4e6a49cf8b0 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -3221,6 +3221,19 @@ check_next_foreign: "index_id CHAR;\n" "foreign_id CHAR;\n" "found INT;\n" + + "DECLARE CURSOR cur_fk IS\n" + "SELECT ID FROM SYS_FOREIGN\n" + "WHERE FOR_NAME = :table_name\n" + "AND TO_BINARY(FOR_NAME)\n" + " = TO_BINARY(:table_name)\n" + "LOCK IN SHARE MODE;\n" + + "DECLARE CURSOR cur_idx IS\n" + "SELECT ID FROM SYS_INDEXES\n" + "WHERE TABLE_ID = table_id\n" + "LOCK IN SHARE MODE;\n" + "BEGIN\n" "SELECT ID INTO table_id\n" "FROM SYS_TABLES\n" @@ -3243,13 +3256,9 @@ check_next_foreign: "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n" " found := 0;\n" "END IF;\n" + "OPEN cur_fk;\n" "WHILE found = 1 LOOP\n" - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = :table_name\n" - " AND TO_BINARY(FOR_NAME)\n" - " = TO_BINARY(:table_name)\n" - " LOCK IN SHARE MODE;\n" + " FETCH cur_fk INTO foreign_id;\n" " IF (SQL % NOTFOUND) THEN\n" " found := 0;\n" " ELSE\n" @@ -3259,12 +3268,11 @@ check_next_foreign: " WHERE ID = foreign_id;\n" " END IF;\n" "END LOOP;\n" + "CLOSE cur_fk;\n" "found := 1;\n" + "OPEN cur_idx;\n" "WHILE found = 1 LOOP\n" - " SELECT ID INTO index_id\n" - " FROM SYS_INDEXES\n" - " WHERE TABLE_ID = table_id\n" - " LOCK IN SHARE MODE;\n" + " FETCH cur_idx INTO index_id;\n" " IF (SQL % NOTFOUND) THEN\n" " found := 0;\n" " ELSE\n" @@ -3275,6 +3283,7 @@ check_next_foreign: " AND TABLE_ID = table_id;\n" " END IF;\n" "END LOOP;\n" + "CLOSE cur_idx;\n" "DELETE FROM SYS_COLUMNS\n" "WHERE TABLE_ID = table_id;\n" "DELETE FROM SYS_TABLES\n" From 132f023b087da9bdf2c1c9c53d4e3da80bcd5f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 8 Sep 2011 15:54:15 +0300 Subject: [PATCH 26/49] Bug#11766591 59733: POSSIBLE DEADLOCK WHEN BUFFERED CHANGES ARE DISCARDED Tweak the faulty UNIV_SYNC_DEBUG diagnostics a little bit more. ibuf_add_free_page(): Lower the latching order of the newly allocated page only after acquiring the ibuf_mutex. --- storage/innobase/ibuf/ibuf0ibuf.c | 8 ++++---- storage/innodb_plugin/ibuf/ibuf0ibuf.c | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 71ecc7ec49f..8f151e39958 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1683,14 +1683,14 @@ ibuf_add_free_page( page = buf_page_get(space, page_no, RW_X_LATCH, &mtr); -#ifdef UNIV_SYNC_DEBUG - buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW); -#endif /* UNIV_SYNC_DEBUG */ - ibuf_enter(); mutex_enter(&ibuf_mutex); +#ifdef UNIV_SYNC_DEBUG + buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW); +#endif /* UNIV_SYNC_DEBUG */ + root = ibuf_tree_root_get(ibuf_data, space, &mtr); /* Add the page to the free list and update the ibuf size data */ diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index effd7b9572b..7aaf8f95bc5 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c @@ -1766,16 +1766,15 @@ ibuf_add_free_page(void) block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); + ibuf_enter(); + mutex_enter(&ibuf_mutex); + + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); page = buf_block_get_frame(block); } - ibuf_enter(); - - mutex_enter(&ibuf_mutex); - root = ibuf_tree_root_get(&mtr); /* Add the page to the free list and update the ibuf size data */ From 8c545acd5367950d3d03590880781089040016e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 8 Sep 2011 16:10:24 +0300 Subject: [PATCH 27/49] Bug#12948130 UNNECESSARY X-LOCKING OF ADAPTIVE HASH INDEX (BTR_SEARCH_LATCH) InnoDB acquires an x-latch on btr_search_latch for certain in-place updates that do affect the adaptive hash index. These operations do not really need to be protected by the btr_search_latch: * updating DB_TRX_ID * updating DB_ROLL_PTR * updating PAGE_MAX_TRX_ID * updating the delete-mark flag rb:750 approved by Sunny Bains --- storage/innodb_plugin/ChangeLog | 5 ++ storage/innodb_plugin/btr/btr0cur.c | 61 ++++++++++++----------- storage/innodb_plugin/include/page0page.h | 5 +- storage/innodb_plugin/include/row0upd.ic | 5 -- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index a29aaf2077e..130a0f9afa2 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-08 The InnoDB Team + + * btr/btr0cur.c, include/page0page.h, include/row0upd.ic: + Fix Bug#12948130 UNNECESSARY X-LOCKING OF ADAPTIVE HASH INDEX + 2011-09-06 The InnoDB Team * buf/buf0buddy.c: diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index f1c2c2ddd5e..4baa21d7c71 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -1727,6 +1727,7 @@ btr_cur_update_in_place( roll_ptr_t roll_ptr = ut_dulint_zero; trx_t* trx; ulint was_delete_marked; + ibool is_hashed; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; @@ -1768,7 +1769,21 @@ btr_cur_update_in_place( return(err); } - if (block->is_hashed) { + if (!(flags & BTR_KEEP_SYS_FLAG)) { + row_upd_rec_sys_fields(rec, NULL, + index, offsets, trx, roll_ptr); + } + + was_delete_marked = rec_get_deleted_flag( + rec, page_is_comp(buf_block_get_frame(block))); + + is_hashed = block->is_hashed; + + if (is_hashed) { + /* TO DO: Can we skip this if none of the fields + index->search_info->curr_n_fields + are being updated? */ + /* The function row_upd_changes_ord_field_binary works only if the update vector was built for a clustered index, we must NOT call it if index is secondary */ @@ -1784,17 +1799,9 @@ btr_cur_update_in_place( rw_lock_x_lock(&btr_search_latch); } - if (!(flags & BTR_KEEP_SYS_FLAG)) { - row_upd_rec_sys_fields(rec, NULL, - index, offsets, trx, roll_ptr); - } - - was_delete_marked = rec_get_deleted_flag( - rec, page_is_comp(buf_block_get_frame(block))); - row_upd_rec_in_place(rec, index, offsets, update, page_zip); - if (block->is_hashed) { + if (is_hashed) { rw_lock_x_unlock(&btr_search_latch); } @@ -2520,7 +2527,8 @@ btr_cur_parse_del_mark_set_clust_rec( /* We do not need to reserve btr_search_latch, as the page is only being recovered, and there cannot be a hash index to - it. */ + it. Besides, these fields are being updated in place + and the adaptive hash index does not depend on them. */ btr_rec_set_deleted_flag(rec, page_zip, val); @@ -2600,9 +2608,9 @@ btr_cur_del_mark_set_clust_rec( return(err); } - if (block->is_hashed) { - rw_lock_x_lock(&btr_search_latch); - } + /* The btr_search_latch is not needed here, because + the adaptive hash index does not depend on the delete-mark + and the delete-mark is being updated in place. */ page_zip = buf_block_get_page_zip(block); @@ -2616,10 +2624,6 @@ btr_cur_del_mark_set_clust_rec( index, offsets, trx, roll_ptr); } - if (block->is_hashed) { - rw_lock_x_unlock(&btr_search_latch); - } - btr_cur_del_mark_set_clust_rec_log(flags, rec, index, val, trx, roll_ptr, mtr); @@ -2695,7 +2699,8 @@ btr_cur_parse_del_mark_set_sec_rec( /* We do not need to reserve btr_search_latch, as the page is only being recovered, and there cannot be a hash index to - it. */ + it. Besides, the delete-mark flag is being updated in place + and the adaptive hash index does not depend on it. */ btr_rec_set_deleted_flag(rec, page_zip, val); } @@ -2743,16 +2748,11 @@ btr_cur_del_mark_set_sec_rec( ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(cursor->index->table)); - if (block->is_hashed) { - rw_lock_x_lock(&btr_search_latch); - } - + /* We do not need to reserve btr_search_latch, as the + delete-mark flag is being updated in place and the adaptive + hash index does not depend on it. */ btr_rec_set_deleted_flag(rec, buf_block_get_page_zip(block), val); - if (block->is_hashed) { - rw_lock_x_unlock(&btr_search_latch); - } - btr_cur_del_mark_set_sec_rec_log(rec, val, mtr); return(DB_SUCCESS); @@ -2772,8 +2772,11 @@ btr_cur_del_unmark_for_ibuf( uncompressed */ mtr_t* mtr) /*!< in: mtr */ { - /* We do not need to reserve btr_search_latch, as the page has just - been read to the buffer pool and there cannot be a hash index to it. */ + /* We do not need to reserve btr_search_latch, as the page + has just been read to the buffer pool and there cannot be + a hash index to it. Besides, the delete-mark flag is being + updated in place and the adaptive hash index does not depend + on it. */ btr_rec_set_deleted_flag(rec, page_zip, FALSE); diff --git a/storage/innodb_plugin/include/page0page.h b/storage/innodb_plugin/include/page0page.h index 9099fd7b65d..caf4cee2c57 100644 --- a/storage/innodb_plugin/include/page0page.h +++ b/storage/innodb_plugin/include/page0page.h @@ -68,10 +68,7 @@ typedef byte page_header_t; #define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified a record on the page; a dulint; defined only in secondary indexes and in the insert buffer - tree; NOTE: this may be modified only - when the thread has an x-latch to the page, - and ALSO an x-latch to btr_search_latch - if there is a hash index to the page! */ + tree */ #define PAGE_HEADER_PRIV_END 26 /* end of private data structure of the page header which are set in a page create */ /*----*/ diff --git a/storage/innodb_plugin/include/row0upd.ic b/storage/innodb_plugin/include/row0upd.ic index 0894ed373b0..11db82f64da 100644 --- a/storage/innodb_plugin/include/row0upd.ic +++ b/storage/innodb_plugin/include/row0upd.ic @@ -157,11 +157,6 @@ row_upd_rec_sys_fields( { ut_ad(dict_index_is_clust(index)); ut_ad(rec_offs_validate(rec, index, offsets)); -#ifdef UNIV_SYNC_DEBUG - if (!rw_lock_own(&btr_search_latch, RW_LOCK_EX)) { - ut_ad(!buf_block_align(rec)->is_hashed); - } -#endif /* UNIV_SYNC_DEBUG */ if (UNIV_LIKELY_NULL(page_zip)) { ulint pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID); From 13fefeb04ade34418cd9d99aa93bffb69fdae27e Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Fri, 9 Sep 2011 10:07:24 +0300 Subject: [PATCH 28/49] Disable the prefetch code in the InnoDB internal SQL parser. This change is a followup to vasil.dimov@oracle.com-20110907145810-v98kldmho23vhhic which triggered the usage of the prefetch and valgrind tests spat lots of warnings. The prefetch code will be removed. Discussed with: Marko (over IM) --- storage/innodb_plugin/row/row0sel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innodb_plugin/row/row0sel.c b/storage/innodb_plugin/row/row0sel.c index 241584eaa20..aa3f6283c4f 100644 --- a/storage/innodb_plugin/row/row0sel.c +++ b/storage/innodb_plugin/row/row0sel.c @@ -63,7 +63,13 @@ Created 12/19/1997 Heikki Tuuri /* Number of rows fetched, after which to start prefetching; MySQL interface has another parameter */ -#define SEL_PREFETCH_LIMIT 1 +/* The prefetch code in the internal SQL is disabled because it has probably +never been used and has been found to contain a memory leak and a bug of +accessing uninitialized memory. Some simple performance tests show that +disabling it makes no difference in performance. It will be removed, but +until the removal happens we disable it by setting SEL_PREFETCH_LIMIT to a +high value. */ +#define SEL_PREFETCH_LIMIT 1000000000 /* When a select has accessed about this many pages, it returns control back to que_run_threads: this is to allow canceling runaway queries */ From cc496eb7466487747d26d272f0559df9a07f2e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 12 Sep 2011 10:12:15 +0300 Subject: [PATCH 29/49] Bug#12601439 CONSISTENT READ FAILURE IN COLUMN PREFIX INDEX When there is a secondary index on a column prefix of an externally stored column and an entry in the secondary index is shorter than the reserved prefix length, it should mean that the secondary index entry is holding the complete column value. When comparing this secondary index column value to the column in the clustered index row, we must compare the entire prefix that was fetched from the clustered index. The bug was that we would just compare that the column in the clustered index starts with the value found in the secondary index column. This bug affects only the InnoDB Barracuda formats (ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED), in which columns that are stored off-page in the clustered index do not contain any prefix in the clustered index record. row_sel_sec_rec_is_for_blob(): Add the parameter prefix_len, for ifield->prefix_len. Add some assertions. Sorry, I did not manage to produce a test case. This patch does produce correct results on the data set that Michael isolated on our test machine. That was with the purge and background rollback suspended, because they would make the bug go away. rb:760 approved by Sunny Bains --- storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/row/row0sel.c | 20 +++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 130a0f9afa2..ff6bd10dbe6 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-12 The InnoDB Team + + * row/row0sel.c: + Fix Bug#12601439 CONSISTENT READ FAILURE IN COLUMN PREFIX INDEX + 2011-09-08 The InnoDB Team * btr/btr0cur.c, include/page0page.h, include/row0upd.ic: diff --git a/storage/innodb_plugin/row/row0sel.c b/storage/innodb_plugin/row/row0sel.c index aa3f6283c4f..c9b409cbedd 100644 --- a/storage/innodb_plugin/row/row0sel.c +++ b/storage/innodb_plugin/row/row0sel.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -107,12 +107,17 @@ row_sel_sec_rec_is_for_blob( ulint clust_len, /*!< in: length of clust_field */ const byte* sec_field, /*!< in: column in secondary index */ ulint sec_len, /*!< in: length of sec_field */ + ulint prefix_len, /*!< in: index column prefix length + in bytes */ ulint zip_size) /*!< in: compressed page size, or 0 */ { ulint len; byte buf[DICT_MAX_INDEX_COL_LEN]; ut_a(clust_len >= BTR_EXTERN_FIELD_REF_SIZE); + ut_ad(prefix_len >= sec_len); + ut_ad(prefix_len > 0); + ut_a(prefix_len <= sizeof buf); if (UNIV_UNLIKELY (!memcmp(clust_field + clust_len - BTR_EXTERN_FIELD_REF_SIZE, @@ -124,7 +129,7 @@ row_sel_sec_rec_is_for_blob( return(FALSE); } - len = btr_copy_externally_stored_field_prefix(buf, sizeof buf, + len = btr_copy_externally_stored_field_prefix(buf, prefix_len, zip_size, clust_field, clust_len); @@ -138,7 +143,7 @@ row_sel_sec_rec_is_for_blob( } len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen, - sec_len, len, (const char*) buf); + prefix_len, len, (const char*) buf); return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len)); } @@ -225,11 +230,20 @@ row_sel_sec_rec_is_for_clust_rec( if (rec_offs_nth_extern(clust_offs, clust_pos) && len < sec_len) { + /* This function should never be + invoked on an Antelope format table, + because they should always contain + enough prefix in the clustered index + record. */ + ut_ad(dict_table_get_format(clust_index->table) + >= DICT_TF_FORMAT_ZIP); + if (!row_sel_sec_rec_is_for_blob( col->mtype, col->prtype, col->mbminlen, col->mbmaxlen, clust_field, clust_len, sec_field, sec_len, + ifield->prefix_len, dict_table_zip_size( clust_index->table))) { goto inequal; From 3436169892e8aa57128d8046631bf381b75b113d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 13 Sep 2011 09:18:34 +0300 Subject: [PATCH 30/49] Hopefully final fix of Bug#11766591 59733: Possible deadlock when buffered changes are to be discarded ibuf_add_free_page(): Lower the latching order of the newly allocated page to SYNC_IBUF_TREE_NODE_NEW after latching the insert buffer tree root. This bug always was bogus UNIV_SYNC_DEBUG alarm. The function buf_block_dbg_add_level() is a no-op unless UNIV_SYNC_DEBUG is defined. --- storage/innobase/ibuf/ibuf0ibuf.c | 4 ++-- storage/innodb_plugin/ibuf/ibuf0ibuf.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 8f151e39958..1406b2de4e9 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1687,12 +1687,12 @@ ibuf_add_free_page( mutex_enter(&ibuf_mutex); + root = ibuf_tree_root_get(ibuf_data, space, &mtr); + #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW); #endif /* UNIV_SYNC_DEBUG */ - root = ibuf_tree_root_get(ibuf_data, space, &mtr); - /* Add the page to the free list and update the ibuf size data */ flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, diff --git a/storage/innodb_plugin/ibuf/ibuf0ibuf.c b/storage/innodb_plugin/ibuf/ibuf0ibuf.c index 7aaf8f95bc5..e4d8f79a944 100644 --- a/storage/innodb_plugin/ibuf/ibuf0ibuf.c +++ b/storage/innodb_plugin/ibuf/ibuf0ibuf.c @@ -1770,13 +1770,13 @@ ibuf_add_free_page(void) mutex_enter(&ibuf_mutex); + root = ibuf_tree_root_get(&mtr); + buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW); page = buf_block_get_frame(block); } - root = ibuf_tree_root_get(&mtr); - /* Add the page to the free list and update the ibuf size data */ flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, From 37f4deccd0f3c23e7af6c2e5f5f45d5225e1c01d Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 13 Sep 2011 17:18:06 +0300 Subject: [PATCH 31/49] Re-enable the prefetch code in InnoDB internal SQL parser and fix two bugs in it - accessing uninitialized ::len member (thanks, Jimmy!) and a memory leak. This is a followup to vasil.dimov@oracle.com-20110909070724-jvirxnpkbxieauz5 which disabled the prefetch code. --- storage/innodb_plugin/row/row0sel.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/storage/innodb_plugin/row/row0sel.c b/storage/innodb_plugin/row/row0sel.c index c9b409cbedd..32f21dbe198 100644 --- a/storage/innodb_plugin/row/row0sel.c +++ b/storage/innodb_plugin/row/row0sel.c @@ -63,13 +63,7 @@ Created 12/19/1997 Heikki Tuuri /* Number of rows fetched, after which to start prefetching; MySQL interface has another parameter */ -/* The prefetch code in the internal SQL is disabled because it has probably -never been used and has been found to contain a memory leak and a bug of -accessing uninitialized memory. Some simple performance tests show that -disabling it makes no difference in performance. It will be removed, but -until the removal happens we disable it by setting SEL_PREFETCH_LIMIT to a -high value. */ -#define SEL_PREFETCH_LIMIT 1000000000 +#define SEL_PREFETCH_LIMIT 1 /* When a select has accessed about this many pages, it returns control back to que_run_threads: this is to allow canceling runaway queries */ @@ -514,7 +508,7 @@ sel_col_prefetch_buf_alloc( sel_buf = column->prefetch_buf + i; sel_buf->data = NULL; - + sel_buf->len = 0; sel_buf->val_buf_size = 0; } } @@ -539,6 +533,8 @@ sel_col_prefetch_buf_free( mem_free(sel_buf->data); } } + + mem_free(prefetch_buf); } /*********************************************************************//** From d60cdefc0da9e2d5a49499763fdf5577d9fbb609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 14 Sep 2011 15:39:36 +0300 Subject: [PATCH 32/49] Hopefully really final fix of Bug#11766591 59733: Possible deadlock when buffered changes are to be discarded sync_thread_add_level(level = SYNC_IBUF_INDEX_TREE): Relax a too strict condition that the thread must not be holding locks below SYNC_FSP_PAGE. It is perfectly valid to hold any latch above SYNC_IBUF_INDEX_TREE when acquiring the insert buffer tree latch. --- storage/innodb_plugin/sync/sync0sync.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 64aadffdfad..3640e204525 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -1258,8 +1258,7 @@ sync_thread_add_level( break; case SYNC_IBUF_INDEX_TREE: if (sync_thread_levels_contain(array, SYNC_FSP)) { - ut_a(sync_thread_levels_g( - array, SYNC_FSP_PAGE - 1, TRUE)); + ut_a(sync_thread_levels_g(array, level - 1, TRUE)); } else { ut_a(sync_thread_levels_g( array, SYNC_IBUF_TREE_NODE - 1, TRUE)); From 52960624d350359c67a333fb09c3a93465116668 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 14 Sep 2011 15:19:24 +0200 Subject: [PATCH 33/49] Bug #12793118 MYSQLTEST: --ERROR AND --DISABLE_ABORT_ON_ERROR DO NOT WORK FOR SQL IN COMMANDS Call handle_error() instead of die() when evaluating these Must remember "current command" with link to errors to ignore Added test cases to mysqltest.test --- client/mysqltest.cc | 27 ++++++++++++++++++++++----- mysql-test/r/mysqltest.result | 11 +++++++++-- mysql-test/t/mysqltest.test | 25 +++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 9985b70fcbc..593bb8ea290 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -451,6 +451,7 @@ TYPELIB command_typelib= {array_elements(command_names),"", command_names, 0}; DYNAMIC_STRING ds_res; +struct st_command *curr_command= 0; char builtin_echo[FN_REFLEN]; @@ -2212,9 +2213,16 @@ void var_query_set(VAR *var, const char *query, const char** query_end) init_dynamic_string(&ds_query, 0, (end - query) + 32, 256); do_eval(&ds_query, query, end, FALSE); - if (mysql_real_query(mysql, ds_query.str, ds_query.length)) - die("Error running query '%s': %d %s", ds_query.str, - mysql_errno(mysql), mysql_error(mysql)); + if (mysql_real_query(mysql, ds_query.str, ds_query.length)) + { + handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), &ds_res); + /* If error was acceptable, return empty string */ + dynstr_free(&ds_query); + eval_expr(var, "", 0); + DBUG_VOID_RETURN; + } + if (!(res= mysql_store_result(mysql))) die("Query '%s' didn't return a result set", ds_query.str); dynstr_free(&ds_query); @@ -2315,8 +2323,15 @@ void var_set_query_get_value(struct st_command *command, VAR *var) /* Run the query */ if (mysql_real_query(mysql, ds_query.str, ds_query.length)) - die("Error running query '%s': %d %s", ds_query.str, - mysql_errno(mysql), mysql_error(mysql)); + { + handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), &ds_res); + /* If error was acceptable, return empty string */ + dynstr_free(&ds_query); + eval_expr(var, "", 0); + DBUG_VOID_RETURN; + } + if (!(res= mysql_store_result(mysql))) die("Query '%s' didn't return a result set", ds_query.str); @@ -8147,6 +8162,8 @@ int main(int argc, char **argv) { command->last_argument= command->first_argument; processed = 1; + /* Need to remember this for handle_error() */ + curr_command= command; switch (command->type) { case Q_CONNECT: do_connect(command); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index a16b3ec2670..ecfd526ebc9 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -135,6 +135,10 @@ select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1000... +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 + is empty +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'nonsense' at line 1 + is empty garbage ; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 select 1064 as "after_--enable_abort_on_error" ; @@ -143,6 +147,9 @@ after_--enable_abort_on_error select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1064... + is empty + is empty +"Yes it's empty" hello hello ;;;;;;;; @@ -315,7 +322,7 @@ insert into t1 values ('$dollar'); $dollar `select 42` drop table t1; -mysqltest: At line 1: Error running query 'failing query': 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'failing query' at line 1 +mysqltest: At line 1: query 'let $var2= `failing query`' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'failing query' at line 1 mysqltest: At line 1: Missing required argument 'filename' to command 'source' mysqltest: At line 1: Could not open './non_existingFile' for reading, errno: 2 mysqltest: In included file "MYSQLTEST_VARDIR/tmp/recursive.sql": @@ -813,7 +820,7 @@ mysqltest: At line 1: Could not find column 'column_not_exists' in the result of mysqltest: At line 1: Query 'SET @A = 1' didn't return a result set mysqltest: At line 1: Could not find column '1 AS B' in the result of 'SELECT 1 AS A' value= No such row -mysqltest: At line 1: Error running query 'SHOW COLNS FROM t1': 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'COLNS FROM t1' at line 1 +mysqltest: At line 1: query 'let $value= query_get_value(SHOW COLNS FROM t1, Field, 1)' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'COLNS FROM t1' at line 1 Field Type Null Key Default Extra a int(11) YES -><- NULL diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 52dfd8e86d3..7b897117b9b 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -334,6 +334,14 @@ eval select $mysql_errno as "after_!errno_masked_error" ; exit(2); EOF +# ---------------------------------------------------------------------------- +# Check backtick and query_get_value, result should be empty +# ---------------------------------------------------------------------------- +let $empty= `garbage`; +echo $empty is empty; +let $empty= query_get_value(nonsense, blabla, 1); +echo $empty is empty; + # ---------------------------------------------------------------------------- # Switch the abort on error on and check the effect on $mysql_errno # ---------------------------------------------------------------------------- @@ -364,6 +372,23 @@ select 3 from t1 ; --exec echo "disable_abort_on_error; enable_abort_on_error; error 1064; select 3 from t1; select 3 from t1;" | $MYSQL_TEST 2>&1 +# ---------------------------------------------------------------------------- +# Test --error with backtick operator or query_get_value +# ---------------------------------------------------------------------------- + +--error 0,ER_NO_SUCH_TABLE +let $empty= `SELECT foo from bar`; +echo $empty is empty; + +--error 0,ER_BAD_FIELD_ERROR +let $empty= query_get_value(SELECT bar as foo, baz, 1); +echo $empty is empty; + +--error 0,ER_NO_SUCH_TABLE +if (!`SELECT foo from bar`) { + echo "Yes it's empty"; +} + # ---------------------------------------------------------------------------- # Test comments # ---------------------------------------------------------------------------- From 6e2adc9fb4770f1151f8ce7b7e0353f9c0358fc9 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 14 Sep 2011 15:26:53 +0200 Subject: [PATCH 34/49] Bug #12912120 MTR SHOULD EXPORT MYSQLD'S PATH TO TEST CASES Export $MYSQLD as full path to executable $MYSQLD_CMD is executable with minimum required args --- mysql-test/mysql-test-run.pl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7661714eb03..148339c3890 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2130,6 +2130,12 @@ sub environment_setup { $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= mysql_fix_arguments(); $ENV{'EXE_MYSQL'}= $exe_mysql; + my $exe_mysqld= find_mysqld($basedir); + $ENV{'MYSQLD'}= $exe_mysqld; + my $extra_opts= join (" ", @opt_extra_mysqld_opt); + $ENV{'MYSQLD_CMD'}= "$exe_mysqld --defaults-group-suffix=.1 ". + "--defaults-file=$path_config_file $extra_opts"; + # ---------------------------------------------------- # bug25714 executable may _not_ exist in # some versions, test using it should be skipped From e24d8bbf0af4d1312f431cf5274fd0fa38646d9f Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Thu, 15 Sep 2011 12:20:43 +0200 Subject: [PATCH 35/49] Test federated_plugin must have ps-protocol off --- mysql-test/suite/federated/federated_plugin.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/suite/federated/federated_plugin.test b/mysql-test/suite/federated/federated_plugin.test index 6e5152df17c..8c465095cfa 100644 --- a/mysql-test/suite/federated/federated_plugin.test +++ b/mysql-test/suite/federated/federated_plugin.test @@ -1,5 +1,8 @@ --source include/have_federated_plugin.inc +# Uninstall will not uninstall if ps has been used +--disable_ps_protocol + connect (master,localhost,root,,test,$MASTER_MYPORT,); connect (slave,localhost,root,,test,$SLAVE_MYPORT,); From 3f9cbd7731fa268575242095cd29d00be2a222f2 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 16 Sep 2011 15:30:31 +0400 Subject: [PATCH 36/49] BUG#11761180 - 53646: MYISAMPACK CORRUPTS TABLES WITH FULLTEXT INDEXES myisamchk may create incorrect fulltext index for compressed tables. Incorrect data pointer size was used while creating fulltext index. mysql-test/r/myisampack.result: A test case for BUG#11761180. mysql-test/t/myisampack.test: A test case for BUG#11761180. storage/myisam/ft_boolean_search.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. storage/myisam/ft_nlq_search.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. storage/myisam/mi_check.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. storage/myisam/mi_write.c: rec_reflength on share may have adjustments required for compressed tables and must be used instead of rec_reflength on base info. --- mysql-test/r/myisampack.result | 32 +++++++++++++++++++++ mysql-test/t/myisampack.test | 45 ++++++++++++++++++++++++++++++ storage/myisam/ft_boolean_search.c | 2 +- storage/myisam/ft_nlq_search.c | 2 +- storage/myisam/mi_check.c | 4 +-- storage/myisam/mi_write.c | 2 +- 6 files changed, 82 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/myisampack.result b/mysql-test/r/myisampack.result index fbcd8aed17a..f19a9c49427 100644 --- a/mysql-test/r/myisampack.result +++ b/mysql-test/r/myisampack.result @@ -87,3 +87,35 @@ COUNT(*) 128 DROP TABLE mysql_db1.t1; DROP DATABASE mysql_db1; +# +# BUG#11761180 - 53646: MYISAMPACK CORRUPTS TABLES WITH FULLTEXT INDEXES +# +CREATE TABLE t1(a CHAR(4), FULLTEXT(a)); +INSERT INTO t1 VALUES('aaaa'),('bbbb'),('cccc'); +FLUSH TABLE t1; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa' IN BOOLEAN MODE); +a +aaaa +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa'); +a +aaaa +DROP TABLE t1; +# Test table with key_reflength > rec_reflength +CREATE TABLE t1(a CHAR(30), FULLTEXT(a)); +# Populating a table, so it's index file exceeds 65K +# Populating a table, so index file has second level fulltext tree +FLUSH TABLE t1; +# Compressing table +# Fixing index (repair by sort) +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +FLUSH TABLE t1; +# Fixing index (repair with keycache) +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; diff --git a/mysql-test/t/myisampack.test b/mysql-test/t/myisampack.test index 9d27ed53254..3bce8cfcfb8 100644 --- a/mysql-test/t/myisampack.test +++ b/mysql-test/t/myisampack.test @@ -107,3 +107,48 @@ SELECT COUNT(*) FROM mysql_db1.t1 WHERE c2 < 5; # DROP TABLE mysql_db1.t1; DROP DATABASE mysql_db1; + +--echo # +--echo # BUG#11761180 - 53646: MYISAMPACK CORRUPTS TABLES WITH FULLTEXT INDEXES +--echo # +CREATE TABLE t1(a CHAR(4), FULLTEXT(a)); +INSERT INTO t1 VALUES('aaaa'),('bbbb'),('cccc'); +FLUSH TABLE t1; +--exec $MYISAMPACK -sf $MYSQLD_DATADIR/test/t1 +--exec $MYISAMCHK -srq $MYSQLD_DATADIR/test/t1 +CHECK TABLE t1; +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa' IN BOOLEAN MODE); +SELECT * FROM t1 WHERE MATCH(a) AGAINST('aaaa'); +DROP TABLE t1; + +--echo # Test table with key_reflength > rec_reflength +CREATE TABLE t1(a CHAR(30), FULLTEXT(a)); +--disable_query_log +--echo # Populating a table, so it's index file exceeds 65K +let $1=1700; +while ($1) +{ + eval INSERT INTO t1 VALUES('$1aaaaaaaaaaaaaaaaaaaaaaaaaa'); + dec $1; +} + +--echo # Populating a table, so index file has second level fulltext tree +let $1=60; +while ($1) +{ + eval INSERT INTO t1 VALUES('aaaa'),('aaaa'),('aaaa'),('aaaa'),('aaaa'); + dec $1; +} +--enable_query_log + +FLUSH TABLE t1; +--echo # Compressing table +--exec $MYISAMPACK -sf $MYSQLD_DATADIR/test/t1 +--echo # Fixing index (repair by sort) +--exec $MYISAMCHK -srnq $MYSQLD_DATADIR/test/t1 +CHECK TABLE t1; +FLUSH TABLE t1; +--echo # Fixing index (repair with keycache) +--exec $MYISAMCHK -soq $MYSQLD_DATADIR/test/t1 +CHECK TABLE t1; +DROP TABLE t1; diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c index fb1a03a2bd6..ac5da800ae3 100644 --- a/storage/myisam/ft_boolean_search.c +++ b/storage/myisam/ft_boolean_search.c @@ -361,7 +361,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) int subkeys=1; my_bool can_go_down; MI_INFO *info=ftb->info; - uint UNINIT_VAR(off), extra=HA_FT_WLEN+info->s->base.rec_reflength; + uint UNINIT_VAR(off), extra= HA_FT_WLEN + info->s->rec_reflength; uchar *lastkey_buf=ftbw->word+ftbw->off; if (ftbw->flags & FTB_FLAG_TRUNC) diff --git a/storage/myisam/ft_nlq_search.c b/storage/myisam/ft_nlq_search.c index cd2c7f61a66..567b1044995 100644 --- a/storage/myisam/ft_nlq_search.c +++ b/storage/myisam/ft_nlq_search.c @@ -74,7 +74,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) uchar *keybuff=aio->keybuff; MI_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr; my_off_t key_root=info->s->state.key_root[aio->keynr]; - uint extra=HA_FT_WLEN+info->s->base.rec_reflength; + uint extra= HA_FT_WLEN + info->s->rec_reflength; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT float tmp_weight; #else diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 3bbd2fb0469..4a0c2da5559 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -3913,7 +3913,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a) SORT_FT_BUF *ft_buf=sort_info->ft_buf; SORT_KEY_BLOCKS *key_block=sort_info->key_block; - val_len=HA_FT_WLEN+sort_info->info->s->base.rec_reflength; + val_len= HA_FT_WLEN + sort_info->info->s->rec_reflength; get_key_full_length_rdonly(a_len, (uchar *)a); if (!ft_buf) @@ -3923,7 +3923,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a) and row format is NOT static - for _mi_dpointer not to garble offsets */ if ((sort_info->info->s->base.key_reflength <= - sort_info->info->s->base.rec_reflength) && + sort_info->info->s->rec_reflength) && (sort_info->info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))) ft_buf=(SORT_FT_BUF *)my_malloc(sort_param->keyinfo->block_length + diff --git a/storage/myisam/mi_write.c b/storage/myisam/mi_write.c index 70487f397f1..81262c229ce 100644 --- a/storage/myisam/mi_write.c +++ b/storage/myisam/mi_write.c @@ -528,7 +528,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, { if (keyinfo->block_length - a_length < 32 && keyinfo->flag & HA_FULLTEXT && key_pos == endpos && - info->s->base.key_reflength <= info->s->base.rec_reflength && + info->s->base.key_reflength <= info->s->rec_reflength && info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) { /* From 4896fc11b70274f903b89e329464bea122991192 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 19 Sep 2011 16:06:35 +0200 Subject: [PATCH 37/49] Bug #12916194 MTR SHOULD CUT OFF ANALYSIS OF SERVER LOG IF THERE IS TOO MUCH Added simple cut-off w/warning if > one million lines --- mysql-test/mysql-test-run.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 148339c3890..4e4333767da 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3855,6 +3855,11 @@ sub extract_server_log ($$) { else { push(@lines, $line); + if (scalar(@lines) > 1000000) { + $Ferr = undef; + mtr_warning("Too much log from test, bailing out from extracting"); + return (); + } } } else From 265737d141d3490497746ac16b625f5883f5856d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2011 18:12:36 -0600 Subject: [PATCH 38/49] Bug 12963823 - Crash in Purge thread under unusual circumstances. The problem occurred when indexes are added between the time that an UNDO record is created and the time that the purge thread comes around and deletes the old secondary index entries. The purge thread would hit an assert when trying to build a secondary index entry for searching. The problem was that the old value of those fields were not in the UNDO record since they were not part of an index when the UPDATE occured. A test case was added to innodb-index.test. --- .../suite/innodb_plugin/r/innodb-index.result | 91 ++++++++++++++++--- .../suite/innodb_plugin/t/innodb-index.test | 87 ++++++++++++++---- storage/innodb_plugin/row/row0purge.c | 17 ++-- 3 files changed, 154 insertions(+), 41 deletions(-) diff --git a/mysql-test/suite/innodb_plugin/r/innodb-index.result b/mysql-test/suite/innodb_plugin/r/innodb-index.result index 5be1460d2b7..8640ff94d9e 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-index.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-index.result @@ -39,6 +39,81 @@ DELETE FROM t1_purge; DELETE FROM t2_purge; DELETE FROM t3_purge; DELETE FROM t4_purge; +SET @r=REPEAT('a',500); +CREATE TABLE t12637786(a INT, +v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), +v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), +v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), +v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), +v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), +v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +CREATE INDEX idx1 ON t12637786(a,v1); +INSERT INTO t12637786 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); +UPDATE t12637786 SET a=1000; +DELETE FROM t12637786; +create table t12963823(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob, +i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob) +engine=innodb row_format=dynamic; +SET @r = repeat('a', 767); +insert into t12963823 values (@r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r); +create index ndx_a on t12963823 (a(500)); +create index ndx_b on t12963823 (b(500)); +create index ndx_c on t12963823 (c(500)); +create index ndx_d on t12963823 (d(500)); +create index ndx_e on t12963823 (e(500)); +create index ndx_f on t12963823 (f(500)); +create index ndx_k on t12963823 (k(500)); +create index ndx_l on t12963823 (l(500)); +SET @r = repeat('b', 500); +update t12963823 set a=@r,b=@r,c=@r,d=@r; +update t12963823 set e=@r,f=@r,g=@r,h=@r; +update t12963823 set i=@r,j=@r,k=@r,l=@r; +update t12963823 set m=@r,n=@r,o=@r,p=@r; +alter table t12963823 drop index ndx_a; +alter table t12963823 drop index ndx_b; +create index ndx_g on t12963823 (g(500)); +create index ndx_h on t12963823 (h(500)); +create index ndx_i on t12963823 (i(500)); +create index ndx_j on t12963823 (j(500)); +create index ndx_m on t12963823 (m(500)); +create index ndx_n on t12963823 (n(500)); +create index ndx_o on t12963823 (o(500)); +create index ndx_p on t12963823 (p(500)); +show create table t12963823; +Table Create Table +t12963823 CREATE TABLE `t12963823` ( + `a` blob, + `b` blob, + `c` blob, + `d` blob, + `e` blob, + `f` blob, + `g` blob, + `h` blob, + `i` blob, + `j` blob, + `k` blob, + `l` blob, + `m` blob, + `n` blob, + `o` blob, + `p` blob, + KEY `ndx_c` (`c`(500)), + KEY `ndx_d` (`d`(500)), + KEY `ndx_e` (`e`(500)), + KEY `ndx_f` (`f`(500)), + KEY `ndx_k` (`k`(500)), + KEY `ndx_l` (`l`(500)), + KEY `ndx_g` (`g`(500)), + KEY `ndx_h` (`h`(500)), + KEY `ndx_i` (`i`(500)), + KEY `ndx_j` (`j`(500)), + KEY `ndx_m` (`m`(500)), + KEY `ndx_n` (`n`(500)), + KEY `ndx_o` (`o`(500)), + KEY `ndx_p` (`p`(500)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC set global innodb_file_per_table=0; set global innodb_file_format=Antelope; create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; @@ -1010,20 +1085,6 @@ ERROR HY000: Too big row alter table t1 row_format=compact; create index t1u on t1 (u(1)); drop table t1; -SET @r=REPEAT('a',500); -CREATE TABLE t1(a INT, -v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), -v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), -v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), -v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), -v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), -v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -CREATE INDEX idx1 ON t1(a,v1); -INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); -UPDATE t1 SET a=1000; -DELETE FROM t1; -DROP TABLE t1; CREATE TABLE bug12547647( a INT NOT NULL, b BLOB NOT NULL, c TEXT, PRIMARY KEY (b(10), a), INDEX (c(10)) @@ -1237,3 +1298,5 @@ a b 3 b DROP TABLE t1; DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; +DROP TABLE t12637786; +DROP TABLE t12963823; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index b4e2aae09e9..a671b48a9c1 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -9,7 +9,7 @@ let $format=`select @@innodb_file_format`; set global innodb_file_per_table=on; set global innodb_file_format='Barracuda'; -# Test an assertion failure on purge. +# Bug #12429576 - Test an assertion failure on purge. CREATE TABLE t1_purge ( A INT, B BLOB, C BLOB, D BLOB, E BLOB, @@ -59,6 +59,68 @@ DELETE FROM t1_purge; DELETE FROM t2_purge; DELETE FROM t3_purge; DELETE FROM t4_purge; +# Instead of doing a --sleep 10, wait until the rest of the tests in +# this file complete before dropping the tables. By then, the purge thread +# will have delt with the updates above. + +# Bug#12637786 - Bad assert by purge thread for records with external data +# used in secondary indexes. +SET @r=REPEAT('a',500); +CREATE TABLE t12637786(a INT, + v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), + v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), + v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), + v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), + v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), + v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +CREATE INDEX idx1 ON t12637786(a,v1); +INSERT INTO t12637786 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); +UPDATE t12637786 SET a=1000; +DELETE FROM t12637786; +# We need to activate the purge thread at this point to make sure it does not +# assert and is able to clean up the old versions of secondary index entries. +# But instead of doing a --sleep 10, wait until the rest of the tests in +# this file complete before dropping the table. By then, the purge thread +# will have delt with the updates above. + +# Bug#12963823 - Test that the purge thread does not crash when +# the number of indexes has changed since the UNDO record was logged. +create table t12963823(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob, + i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob) + engine=innodb row_format=dynamic; +SET @r = repeat('a', 767); +insert into t12963823 values (@r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r); +create index ndx_a on t12963823 (a(500)); +create index ndx_b on t12963823 (b(500)); +create index ndx_c on t12963823 (c(500)); +create index ndx_d on t12963823 (d(500)); +create index ndx_e on t12963823 (e(500)); +create index ndx_f on t12963823 (f(500)); +create index ndx_k on t12963823 (k(500)); +create index ndx_l on t12963823 (l(500)); + +SET @r = repeat('b', 500); +update t12963823 set a=@r,b=@r,c=@r,d=@r; +update t12963823 set e=@r,f=@r,g=@r,h=@r; +update t12963823 set i=@r,j=@r,k=@r,l=@r; +update t12963823 set m=@r,n=@r,o=@r,p=@r; +alter table t12963823 drop index ndx_a; +alter table t12963823 drop index ndx_b; +create index ndx_g on t12963823 (g(500)); +create index ndx_h on t12963823 (h(500)); +create index ndx_i on t12963823 (i(500)); +create index ndx_j on t12963823 (j(500)); +create index ndx_m on t12963823 (m(500)); +create index ndx_n on t12963823 (n(500)); +create index ndx_o on t12963823 (o(500)); +create index ndx_p on t12963823 (p(500)); +show create table t12963823; +# We need to activate the purge thread at this point to see if it crashes +# but instead of doing a --sleep 10, wait until the rest of the tests in +# this file complete before dropping the table. By then, the purge thread +# will have delt with the updates above. + eval set global innodb_file_per_table=$per_table; eval set global innodb_file_format=$format; @@ -462,24 +524,6 @@ create index t1u on t1 (u(1)); drop table t1; -# Bug#12637786 -SET @r=REPEAT('a',500); -CREATE TABLE t1(a INT, - v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500), - v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500), - v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500), - v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500), - v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500), - v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500) -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -CREATE INDEX idx1 ON t1(a,v1); -INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r); -UPDATE t1 SET a=1000; -DELETE FROM t1; -# Let the purge thread clean up this file. --- sleep 10 -DROP TABLE t1; - # Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE CREATE TABLE bug12547647( a INT NOT NULL, b BLOB NOT NULL, c TEXT, @@ -630,7 +674,12 @@ disconnect a; disconnect b; DROP TABLE t1; + +# Drop these tables since the purge thread must have run by now +# and did not crash. DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; +DROP TABLE t12637786; +DROP TABLE t12963823; # # restore environment to the state it was before this test execution diff --git a/storage/innodb_plugin/row/row0purge.c b/storage/innodb_plugin/row/row0purge.c index 752a2ec9e83..e1df40978a4 100644 --- a/storage/innodb_plugin/row/row0purge.c +++ b/storage/innodb_plugin/row/row0purge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ @@ -530,14 +530,14 @@ row_purge_parse_undo_rec( roll_ptr_t roll_ptr; ulint info_bits; ulint type; - ulint cmpl_info; ut_ad(node && thr); trx = thr_get_trx(thr); - ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info, - updated_extern, &undo_no, &table_id); + ptr = trx_undo_rec_get_pars( + node->undo_rec, &type, &node->cmpl_info, + updated_extern, &undo_no, &table_id); node->rec_type = type; if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) { @@ -550,7 +550,8 @@ row_purge_parse_undo_rec( node->table = NULL; if (type == TRX_UNDO_UPD_EXIST_REC - && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) { + && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE + && !(*updated_extern)) { /* Purge requires no changes to indexes: we may return */ @@ -600,7 +601,7 @@ err_exit: /* Read to the partial row the fields that occur in indexes */ - if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { + if (!(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { ptr = trx_undo_rec_get_partial_row( ptr, clust_index, &node->row, type == TRX_UNDO_UPD_DEL_REC, From 7f729cfac492ecc6e581f2d07c41a49726fa2e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 22 Sep 2011 13:35:02 +0300 Subject: [PATCH 39/49] Bug#12963823 CRASH IN PURGE THREAD UNDER UNUSUAL CIRCUMSTANCES Replace part of the patch that Kevin apparently forgot to push. Fix the bug also in the built-in InnoDB of MySQL 5.1. I cannot explain why the test case was not failing without the full patch. This was rb:762, approved by me. --- storage/innobase/row/row0purge.c | 14 ++++++++------ storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/row/row0purge.c | 3 ++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index deec3b0a454..506d92f052e 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -379,7 +379,8 @@ row_purge_upd_exist_or_extern( ut_ad(node); - if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { + if (node->rec_type == TRX_UNDO_UPD_DEL_REC + || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { goto skip_secondaries; } @@ -488,14 +489,14 @@ row_purge_parse_undo_rec( dulint roll_ptr; ulint info_bits; ulint type; - ulint cmpl_info; ut_ad(node && thr); trx = thr_get_trx(thr); - ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info, - updated_extern, &undo_no, &table_id); + ptr = trx_undo_rec_get_pars( + node->undo_rec, &type, &node->cmpl_info, + updated_extern, &undo_no, &table_id); node->rec_type = type; if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) { @@ -508,7 +509,8 @@ row_purge_parse_undo_rec( node->table = NULL; if (type == TRX_UNDO_UPD_EXIST_REC - && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) { + && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE + && !(*updated_extern)) { /* Purge requires no changes to indexes: we may return */ @@ -563,7 +565,7 @@ row_purge_parse_undo_rec( /* Read to the partial row the fields that occur in indexes */ - if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { + if (!(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { ptr = trx_undo_rec_get_partial_row(ptr, clust_index, &(node->row), node->heap); } diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index ff6bd10dbe6..171f1edd7ba 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-20 The InnoDB Team + + * row/row0purge.c: + Fix Bug#12963823 CRASH IN PURGE THREAD UNDER UNUSUAL CIRCUMSTANCES + 2011-09-12 The InnoDB Team * row/row0sel.c: diff --git a/storage/innodb_plugin/row/row0purge.c b/storage/innodb_plugin/row/row0purge.c index e1df40978a4..4d4c1afc458 100644 --- a/storage/innodb_plugin/row/row0purge.c +++ b/storage/innodb_plugin/row/row0purge.c @@ -406,7 +406,8 @@ row_purge_upd_exist_or_extern_func( ut_ad(node); - if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { + if (node->rec_type == TRX_UNDO_UPD_DEL_REC + || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { goto skip_secondaries; } From da756ef676100c3257a07394106d6c573ddc0225 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 27 Sep 2011 12:56:05 +0200 Subject: [PATCH 40/49] Bug #12844282 62075: MTR TESTS SHOULD NOT HAVE TO SAVE & RESET INNODB_FILE_FORMAT_CHECK Added 'innodb_file_format_check' as variable to ignore change to. Tests that had to restore this amended Two tests assumed it to be Antelope, make sure these run on a freshly started server For 5.5, apparently innodb_file_format_max is the one to ignore --- mysql-test/include/mtr_check.sql | 3 ++- mysql-test/r/partition_innodb_plugin.result | 2 -- mysql-test/suite/innodb_plugin/r/innodb_bug52745.result | 1 - mysql-test/suite/innodb_plugin/r/innodb_bug53591.result | 1 - .../suite/innodb_plugin/t/innodb-autoinc-18274.test | 9 --------- .../suite/innodb_plugin/t/innodb-autoinc-44030.test | 9 --------- .../suite/innodb_plugin/t/innodb-autoinc-56228.test | 9 --------- mysql-test/suite/innodb_plugin/t/innodb-autoinc.test | 9 --------- .../suite/innodb_plugin/t/innodb-create-options.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb-index.test | 9 --------- mysql-test/suite/innodb_plugin/t/innodb-zip.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug36172.test | 2 -- .../suite/innodb_plugin/t/innodb_bug47167-master.opt | 1 + mysql-test/suite/innodb_plugin/t/innodb_bug52745.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug53591.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug56680.test | 2 -- mysql-test/suite/innodb_plugin/t/innodb_bug59641.test | 4 ---- .../suite/innodb_plugin/t/innodb_file_format-master.opt | 1 + mysql-test/t/partition_innodb_plugin.test | 2 -- 19 files changed, 4 insertions(+), 68 deletions(-) create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql index 699a35a1831..64bb7c01544 100644 --- a/mysql-test/include/mtr_check.sql +++ b/mysql-test/include/mtr_check.sql @@ -27,7 +27,8 @@ BEGIN -- Dump all global variables except those -- that are supposed to change SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES - WHERE variable_name != 'timestamp' ORDER BY VARIABLE_NAME; + WHERE variable_name NOT IN ('timestamp', 'innodb_file_format_check') + ORDER BY VARIABLE_NAME; -- Dump all databases, there should be none -- except those that was created during bootstrap diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result index f6b5ce84338..43838170501 100644 --- a/mysql-test/r/partition_innodb_plugin.result +++ b/mysql-test/r/partition_innodb_plugin.result @@ -2,7 +2,6 @@ call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB # # Bug#55091: Server crashes on ADD PARTITION after a failed attempt # -SET @old_innodb_file_format_check = @@global.innodb_file_format_check; SET @old_innodb_file_format = @@global.innodb_file_format; SET @old_innodb_file_per_table = @@global.innodb_file_per_table; SET @old_innodb_strict_mode = @@global.innodb_strict_mode; @@ -70,7 +69,6 @@ DROP TABLE t1; SET @@global.innodb_strict_mode = @old_innodb_strict_mode; SET @@global.innodb_file_format = @old_innodb_file_format; SET @@global.innodb_file_per_table = @old_innodb_file_per_table; -SET @@global.innodb_file_format_check = @old_innodb_file_format_check; SET NAMES utf8; CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) ENGINE=InnoDB diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result index 254c6525257..74db8b0c20a 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug52745.result @@ -126,5 +126,4 @@ Warning 1265 Data truncated for column 'col79' at row 1 Warning 1264 Out of range value for column 'col84' at row 1 DROP TABLE bug52745; SET GLOBAL innodb_file_format=Antelope; -SET GLOBAL innodb_file_format_check=Antelope; SET GLOBAL innodb_file_per_table=0; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result b/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result index 1f05b6d2a57..29f9d09a71c 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug53591.result @@ -12,5 +12,4 @@ Error 1118 Row size too large. The maximum row size for the used table type, not Error 1030 Got error 139 from storage engine DROP TABLE bug53591; SET GLOBAL innodb_file_format=Antelope; -SET GLOBAL innodb_file_format_check=Antelope; SET GLOBAL innodb_file_per_table=0; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test index 8734311dd7a..9ac24c9e349 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-18274.test @@ -2,8 +2,6 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - --disable_warnings drop table if exists t1; --enable_warnings @@ -20,10 +18,3 @@ SHOW CREATE TABLE t1; INSERT INTO t1 VALUES(null); SELECT * FROM t1; DROP TABLE t1; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test index 99cdac72e2e..150f6bb4f66 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-44030.test @@ -2,8 +2,6 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - --disable_warnings drop table if exists t1; --enable_warnings @@ -34,10 +32,3 @@ SHOW CREATE TABLE t1; INSERT INTO t1 VALUES(null); SELECT * FROM t1; DROP TABLE t1; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test index eb38b21861d..41b8ac90fad 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc-56228.test @@ -1,7 +1,5 @@ -- source include/have_innodb_plugin.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - ## # Bug #56228: dropping tables from within an active statement crashes server # @@ -33,10 +31,3 @@ SELECT bug56228(); DROP FUNCTION bug56228; DROP TEMPORARY TABLE t2_56228; DROP TEMPORARY TABLE IF EXISTS t1_56228; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test b/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test index 4967a6efbb9..633b0ef360b 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-autoinc.test @@ -2,8 +2,6 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - --disable_warnings drop table if exists t1; --enable_warnings @@ -639,10 +637,3 @@ INSERT INTO t1 VALUES (18446744073709551615); -- source include/restart_mysqld.inc SHOW CREATE TABLE t1; DROP TABLE t1; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-create-options.test b/mysql-test/suite/innodb_plugin/t/innodb-create-options.test index 2f95ccc45cb..85f214177aa 100755 --- a/mysql-test/suite/innodb_plugin/t/innodb-create-options.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-create-options.test @@ -61,7 +61,6 @@ SET storage_engine=InnoDB; --disable_query_log # These values can change during the test LET $innodb_file_format_orig=`select @@innodb_file_format`; -LET $innodb_file_format_check_orig=`select @@innodb_file_format_check`; LET $innodb_file_per_table_orig=`select @@innodb_file_per_table`; LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`; --enable_query_log @@ -568,7 +567,6 @@ DROP TABLE IF EXISTS t1; --disable_query_log EVAL SET GLOBAL innodb_file_format=$innodb_file_format_orig; -EVAL SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig; EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig; --enable_query_log diff --git a/mysql-test/suite/innodb_plugin/t/innodb-index.test b/mysql-test/suite/innodb_plugin/t/innodb-index.test index a671b48a9c1..568661c67f1 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-index.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test @@ -2,8 +2,6 @@ let $MYSQLD_DATADIR= `select @@datadir`; -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - let $per_table=`select @@innodb_file_per_table`; let $format=`select @@innodb_file_format`; set global innodb_file_per_table=on; @@ -680,10 +678,3 @@ DROP TABLE t1; DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; DROP TABLE t12637786; DROP TABLE t12963823; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-zip.test b/mysql-test/suite/innodb_plugin/t/innodb-zip.test index 5ed101b7f20..760ab67ca54 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-zip.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-zip.test @@ -2,7 +2,6 @@ let $per_table=`select @@innodb_file_per_table`; let $format=`select @@innodb_file_format`; -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; set global innodb_file_per_table=off; set global innodb_file_format=`0`; @@ -337,4 +336,3 @@ drop table normal_table, zip_table; -- disable_query_log eval set global innodb_file_format=$format; eval set global innodb_file_per_table=$per_table; -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test b/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test index fbd6d5605df..85a90f3785d 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug36172.test @@ -15,7 +15,6 @@ SET storage_engine=InnoDB; -- disable_result_log let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=on; @@ -28,5 +27,4 @@ INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.90 CHECK TABLE table0 EXTENDED; DROP TABLE table0; EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt b/mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug47167-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test b/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test index b20a993a2d1..c1af389afbd 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug52745.test @@ -1,7 +1,6 @@ -- source include/have_innodb_plugin.inc let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=on; @@ -105,5 +104,4 @@ SHOW WARNINGS; DROP TABLE bug52745; EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test b/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test index 760b4630383..f32aace83b2 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug53591.test @@ -1,7 +1,6 @@ -- source include/have_innodb_plugin.inc let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; @@ -18,5 +17,4 @@ SHOW WARNINGS; DROP TABLE bug53591; EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test b/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test index 8d0f685c723..fa8fa39b895 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug56680.test @@ -7,7 +7,6 @@ SET @tx_isolation_orig = @@tx_isolation; SET @innodb_file_per_table_orig = @@innodb_file_per_table; SET @innodb_file_format_orig = @@innodb_file_format; -SET @innodb_file_format_check_orig = @@innodb_file_format_check; # The flag innodb_change_buffering_debug is only available in debug builds. # It instructs InnoDB to try to evict pages from the buffer pool when # change buffering is possible, so that the change buffer will be used @@ -137,6 +136,5 @@ DROP TABLE bug56680; SET GLOBAL tx_isolation = @tx_isolation_orig; SET GLOBAL innodb_file_per_table = @innodb_file_per_table_orig; SET GLOBAL innodb_file_format = @innodb_file_format_orig; -SET GLOBAL innodb_file_format_check = @innodb_file_format_check_orig; -- error 0, ER_UNKNOWN_SYSTEM_VARIABLE SET GLOBAL innodb_change_buffering_debug = @innodb_change_buffering_debug_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test index 0fb24e47a54..028c21afe4a 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug59641.test @@ -3,8 +3,6 @@ -- source include/not_embedded.inc -- source include/have_innodb_plugin.inc -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB; INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32); COMMIT; @@ -66,5 +64,3 @@ XA COMMIT '789'; SELECT * FROM t; DROP TABLE t; ---disable_query_log -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt b/mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_file_format-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test index 626e5d19b99..98504469243 100644 --- a/mysql-test/t/partition_innodb_plugin.test +++ b/mysql-test/t/partition_innodb_plugin.test @@ -9,7 +9,6 @@ call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB --echo # --echo # Bug#55091: Server crashes on ADD PARTITION after a failed attempt --echo # -SET @old_innodb_file_format_check = @@global.innodb_file_format_check; SET @old_innodb_file_format = @@global.innodb_file_format; SET @old_innodb_file_per_table = @@global.innodb_file_per_table; SET @old_innodb_strict_mode = @@global.innodb_strict_mode; @@ -68,7 +67,6 @@ DROP TABLE t1; SET @@global.innodb_strict_mode = @old_innodb_strict_mode; SET @@global.innodb_file_format = @old_innodb_file_format; SET @@global.innodb_file_per_table = @old_innodb_file_per_table; -SET @@global.innodb_file_format_check = @old_innodb_file_format_check; # # Bug#32430 - show engine innodb status causes errors From 5dbcff9b9c86dc9608252d270b6ebff7a6066040 Mon Sep 17 00:00:00 2001 From: Ashish Agarwal Date: Tue, 27 Sep 2011 17:38:51 +0530 Subject: [PATCH 41/49] BUG#11759349 - 51655: CREATE TABLE IN MEMORY ENGINE DOESN'T STORE CREATE_TIME IN INFORMATION_SC It was impossible to determine MEMORY table creation time, since it wasn't stored/exposed. With this patch creation time is saved and it is available via I_S.TABLES.CREATE_TIME. Note: it was decided that additional analysis is required before implementing UPDATE_TIME. Thus this patch doesn't store UPDATE_TIME. --- include/heap.h | 2 ++ mysql-test/r/heap.result | 4 ++-- mysql-test/r/show_check.result | 44 +++++++++++++++++----------------- mysql-test/t/heap.test | 2 +- mysql-test/t/show_check.test | 20 ++++++++-------- storage/heap/ha_heap.cc | 1 + storage/heap/hp_create.c | 1 + storage/heap/hp_info.c | 1 + 8 files changed, 40 insertions(+), 35 deletions(-) diff --git a/include/heap.h b/include/heap.h index 0abdd71461e..7adaac33096 100644 --- a/include/heap.h +++ b/include/heap.h @@ -50,6 +50,7 @@ typedef struct st_heapinfo /* Struct from heap_info */ uint reclength; /* Length of one record */ int errkey; ulonglong auto_increment; + time_t create_time; } HEAPINFO; @@ -146,6 +147,7 @@ typedef struct st_heap_share uint open_count; uchar *del_link; /* Link to next block with del. rec */ char * name; /* Name of "memory-file" */ + time_t create_time; #ifdef THREAD THR_LOCK lock; pthread_mutex_t intern_lock; /* Locking for use with _locking */ diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index ddf675e2f73..fd072bbab5d 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -715,8 +715,8 @@ create table t1 (c char(10)) engine=memory; create table t2 (c varchar(10)) engine=memory; show table status like 't_'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL # NULL NULL latin1_swedish_ci NULL drop table t1, t2; CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256), KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 7cb3f696449..7b633d42f44 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -458,57 +458,57 @@ insert into t2 values (1),(2); insert into t3 values (1,1),(2,2); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 2 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 2 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 2 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 2 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL insert into t1 values (3),(4); insert into t2 values (3),(4); insert into t3 values (3,3),(4,4); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 4 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 4 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 4 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 4 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 5 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 5 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 5 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 5 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL delete from t1 where a=3; delete from t2 where b=3; delete from t3 where a=3; show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 4 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 4 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 4 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 4 # # # # # NULL # NULL NULL latin1_swedish_ci NULL truncate table t1; truncate table t2; truncate table t3; show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 0 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 0 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 0 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 1 # # # # 0 NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 1 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 1 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 1 # # # # 0 NULL # NULL NULL latin1_swedish_ci NULL delete from t1 where a=5; delete from t2 where b=5; delete from t3 where a=5; show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t2 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL -t3 MEMORY 10 Fixed 0 # # # # # NULL NULL NULL NULL latin1_swedish_ci NULL +t1 MEMORY 10 Fixed 0 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t2 MEMORY 10 Fixed 0 # # # # # NULL # NULL NULL latin1_swedish_ci NULL +t3 MEMORY 10 Fixed 0 # # # # # NULL # NULL NULL latin1_swedish_ci NULL drop table t1, t2, t3; create database mysqltest; show create database mysqltest; @@ -659,7 +659,7 @@ DROP TABLE t1; flush tables; SHOW TABLE STATUS like 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 NULL NULL NULL NULL # # # # NULL NULL NULL NULL NULL NULL NULL NULL Incorrect information in file: './test/t1.frm' +t1 NULL NULL NULL NULL # # # # NULL NULL # NULL NULL NULL NULL NULL Incorrect information in file: './test/t1.frm' Warnings: Warning 1033 Incorrect information in file: './test/t1.frm' show create table t1; diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index 3f91b9966e7..1e69b43d79b 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -454,7 +454,7 @@ drop table t1; # create table t1 (c char(10)) engine=memory; create table t2 (c varchar(10)) engine=memory; ---replace_column 8 # +--replace_column 8 # 12 # show table status like 't_'; drop table t1, t2; diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index e5ca35bda32..1c1bf9fa6d3 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -230,7 +230,7 @@ DROP TABLE """a"; #set names latin1; #create database `ä`; #create table `ä`.`ä` (a int) engine=heap; -#--replace_column 7 # 8 # 9 # +#--replace_column 7 # 8 # 9 # 12 # #show table status from `ä` LIKE 'ä'; #drop database `ä`; @@ -276,37 +276,37 @@ CREATE TABLE t3 ( insert into t1 values (1),(2); insert into t2 values (1),(2); insert into t3 values (1,1),(2,2); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; insert into t1 values (3),(4); insert into t2 values (3),(4); insert into t3 values (3,3),(4,4); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; delete from t1 where a=3; delete from t2 where b=3; delete from t3 where a=3; ---replace_column 6 # 7 # 8 # 9 # 10 # +--replace_column 6 # 7 # 8 # 9 # 10 # 12 # show table status; truncate table t1; truncate table t2; truncate table t3; ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; insert into t1 values (5); insert into t2 values (5); insert into t3 values (5,5); ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # show table status; delete from t1 where a=5; delete from t2 where b=5; delete from t3 where a=5; ---replace_column 6 # 7 # 8 # 9 # 10 # +--replace_column 6 # 7 # 8 # 9 # 10 # 12 # show table status; drop table t1, t2, t3; @@ -367,7 +367,7 @@ flush privileges; #set names latin1; #create database `ä`; #create table `ä`.`ä` (a int) engine=heap; -#--replace_column 7 # 8 # 9 # +#--replace_column 7 # 8 # 9 # 12 # #show table status from `ä` LIKE 'ä'; #drop database `ä`; @@ -430,7 +430,7 @@ flush tables; # Create a junk frm file on disk let $MYSQLD_DATADIR= `select @@datadir`; system echo "this is a junk file for test" >> $MYSQLD_DATADIR/test/t1.frm ; ---replace_column 6 # 7 # 8 # 9 # +--replace_column 6 # 7 # 8 # 9 # 12 # SHOW TABLE STATUS like 't1'; --error ER_NOT_FORM_FILE show create table t1; diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index d805fac2783..5d819722b6e 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -382,6 +382,7 @@ int ha_heap::info(uint flag) stats.index_file_length= hp_info.index_length; stats.max_data_file_length= hp_info.max_records * hp_info.reclength; stats.delete_length= hp_info.deleted * hp_info.reclength; + stats.create_time= (ulong) hp_info.create_time; if (flag & HA_STATUS_AUTO) stats.auto_increment_value= hp_info.auto_increment; /* diff --git a/storage/heap/hp_create.c b/storage/heap/hp_create.c index b6814fc1614..5208d4676c3 100644 --- a/storage/heap/hp_create.c +++ b/storage/heap/hp_create.c @@ -186,6 +186,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, share->auto_key= create_info->auto_key; share->auto_key_type= create_info->auto_key_type; share->auto_increment= create_info->auto_increment; + share->create_time= (long) time((time_t*) 0); /* Must be allocated separately for rename to work */ if (!(share->name= my_strdup(name,MYF(0)))) { diff --git a/storage/heap/hp_info.c b/storage/heap/hp_info.c index ea78c53fd40..c72dbaf2065 100644 --- a/storage/heap/hp_info.c +++ b/storage/heap/hp_info.c @@ -53,6 +53,7 @@ int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x, int flag ) x->index_length = info->s->index_length; x->max_records = info->s->max_records; x->errkey = info->errkey; + x->create_time = info->s->create_time; if (flag & HA_STATUS_AUTO) x->auto_increment= info->s->auto_increment + 1; DBUG_RETURN(0); From ffd0a785f4e235c5fc633467b793686a79cf5237 Mon Sep 17 00:00:00 2001 From: Raghav Kapoor Date: Wed, 28 Sep 2011 15:39:21 +0530 Subject: [PATCH 42/49] BUG#11758062 - 50206: ER_TOO_BIG_SELECT REFERS TO OUTMODED SYSTEM VARIABLE NAME SQL_MAX_JOIN_SI BACKGROUND: ER_TOO_BIG_SELECT refers to SQL_MAX_JOIN_SIZE, which is the old name for MAX_JOIN_SIZE. FIX: Support for old name SQL_MAX_JOIN_SIZE is removed in MySQL 5.6 and is renamed as MAX_JOIN_SIZE.So the errmsg.txt and mysql.cc files have been updated and the corresponding result files have also been updated. --- client/mysql.cc | 2 +- mysql-test/r/select_safe.result | 12 ++++++------ .../suite/sys_vars/r/max_join_size_func.result | 4 ++-- .../suite/sys_vars/r/sql_big_selects_func.result | 2 +- .../suite/sys_vars/r/sql_max_join_size_func.result | 2 +- sql/share/errmsg.txt | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 0a6b4da34b0..49d58a832a2 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -4290,7 +4290,7 @@ sql_real_connect(char *host,char *database,char *user,char *password, { char init_command[100]; sprintf(init_command, - "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,SQL_MAX_JOIN_SIZE=%lu", + "SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=%lu,MAX_JOIN_SIZE=%lu", select_limit,max_join_size); mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command); } diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index feac9efcb13..d810271e337 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -30,7 +30,7 @@ ERROR HY000: You are using safe update mode and you tried to update a table with delete from t1 where a+0=1; ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay update t1 set b="a" limit 1; update t1 set b="a" where b="b" limit 2; delete from t1 where b="test" limit 1; @@ -42,7 +42,7 @@ SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; 2 0 insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); SELECT * from t1 order by a; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay SET SQL_BIG_SELECTS=1; SELECT * from t1 order by a; a b @@ -52,7 +52,7 @@ a b 5 a SET MAX_JOIN_SIZE=2; SELECT * from t1; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay SET MAX_JOIN_SIZE=DEFAULT; SELECT * from t1; a b @@ -82,12 +82,12 @@ insert into t1 select * from t1; insert into t1 select * from t1; set local max_join_size=8; select * from (select * from t1) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; select * from (select a.a as aa, b.a as ba from t1 a, t1 b) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay set local max_join_size=1; select * from (select 1 union select 2 union select 3) x; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/suite/sys_vars/r/max_join_size_func.result b/mysql-test/suite/sys_vars/r/max_join_size_func.result index bf535579433..0bf4f507b0c 100644 --- a/mysql-test/suite/sys_vars/r/max_join_size_func.result +++ b/mysql-test/suite/sys_vars/r/max_join_size_func.result @@ -41,7 +41,7 @@ id name id name SET @@session.max_join_size=8; ## Since total joins are more than max_join_size value so error will occur ## SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay '#--------------------FN_DYNVARS_079_03-------------------------#' ## Setting global value of variable ## SET @@global.max_join_size=8; @@ -52,7 +52,7 @@ SELECT @@global.max_join_size; 8 ## Since total joins are more than max_join_size value so error will occur ## SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay ## Dropping both the tables ## Drop table t1, t2; ## Restoring values ## diff --git a/mysql-test/suite/sys_vars/r/sql_big_selects_func.result b/mysql-test/suite/sys_vars/r/sql_big_selects_func.result index fc7e1f32e00..6d7138a1a99 100644 --- a/mysql-test/suite/sys_vars/r/sql_big_selects_func.result +++ b/mysql-test/suite/sys_vars/r/sql_big_selects_func.result @@ -19,7 +19,7 @@ INSERT INTO t2 VALUES('aa4','bb'); '#--------------------FN_DYNVARS_154_01-------------------------#' Expected error "Too big select" SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.a; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay Expected error The SELECT would examine more than MAX_JOIN_SIZE rows. '#--------------------FN_DYNVARS_154_02-------------------------#' SET SESSION SQL_BIG_SELECTS = 1; diff --git a/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result b/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result index 0e406f6611e..32a1c2f31e5 100644 --- a/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result +++ b/mysql-test/suite/sys_vars/r/sql_max_join_size_func.result @@ -17,7 +17,7 @@ INSERT INTO t2 VALUES('aa4','bb'); '#--------------------FN_DYNVARS_161_01-------------------------#' SET SESSION sql_max_join_size=9; SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.a; -ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay +ERROR 42000: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay Expected error The SELECT would examine more than MAX_JOIN_SIZE rows. '#--------------------FN_DYNVARS_161_02-------------------------#' SET SESSION SQL_BIG_SELECTS = 1; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index bbae17c4327..7cb9d9ebcc1 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -2494,10 +2494,10 @@ ER_TOO_BIG_SELECT 42000 cze "Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET SQL_BIG_SELECTS=1" dan "SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt" nla "Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is." - eng "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay" + eng "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okay" est "SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET SQL_BIG_SELECTS=1" fre "SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien" - ger "Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel überprüfen und gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET SQL_MAX_JOIN_SIZE=# verwenden" + ger "Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange dauern. Bitte WHERE-Klausel überprüfen und gegebenenfalls SET SQL_BIG_SELECTS=1 oder SET MAX_JOIN_SIZE=# verwenden" greek "Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü" hun "A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT okay" ita "La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto." From 968e4363fd2efd4bbb86aefbc84f7398ec54b1f7 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Mon, 3 Oct 2011 13:41:59 +0200 Subject: [PATCH 43/49] backporting 11766169, fixing 13034450 --- mysql-test/lib/mtr_cases.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 3dcd99f235f..9b5608241a3 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -222,8 +222,11 @@ sub collect_test_cases ($$$) { sub split_testname { my ($test_name)= @_; - # Get rid of directory part and split name on .'s - my @parts= split(/\./, basename($test_name)); + # If .test file name is used, get rid of directory part + $test_name= basename($test_name) if $test_name =~ /\.test$/; + + # Now split name on .'s + my @parts= split(/\./, $test_name); if (@parts == 1){ # Only testname given, ex: alias From 4836c66d3cf8f32491d8d256d6cc03a9339716a2 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Tue, 4 Oct 2011 15:58:19 +0200 Subject: [PATCH 44/49] Fix bug#11886309: RPM UPGRADE OF MYSQL ADVANCED GPL TO MYSQL SERVER ADVANCED DOES NOT WORK Change the RPM spec file so that each RPM "obsoletes" the corresponding RPMs of all (other) configurations, so a "server" RPM of any configuration can replace the "server" RPM of any other configuration on a "rpm -U". --- support-files/mysql.spec.sh | 73 ++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 28f2b0f773a..ee0211fd3e0 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -170,9 +170,11 @@ documentation and the manual for more information. %package server Summary: MySQL: a very fast and reliable SQL database server Group: Applications/Databases -Requires: coreutils grep procps /usr/sbin/useradd /usr/sbin/groupadd /sbin/chkconfig -Provides: msqlormysql mysql-server mysql MySQL -Obsoletes: MySQL mysql mysql-server +Requires: coreutils grep procps /usr/sbin/useradd /usr/sbin/groupadd /sbin/chkconfig +Provides: msqlormysql mysql MySQL mysql-server MySQL-server +Obsoletes: mysql MySQL mysql-server MySQL-server +Obsoletes: MySQL-server-classic MySQL-server-community MySQL-server-enterprise +Obsoletes: MySQL-server-advanced MySQL-server-advanced-gpl MySQL-server-enterprise-gpl %description server The MySQL(TM) software delivers a very fast, multi-threaded, multi-user, @@ -202,10 +204,12 @@ package "MySQL-client" as well! # ------------------------------------------------------------------------------ %package client -Summary: MySQL - Client -Group: Applications/Databases -Obsoletes: mysql-client -Provides: mysql-client +Summary: MySQL - Client +Group: Applications/Databases +Provides: mysql-client MySQL-client +Obsoletes: mysql-client MySQL-client +Obsoletes: MySQL-client-classic MySQL-client-community MySQL-client-enterprise +Obsoletes: MySQL-client-advanced MySQL-client-advanced-gpl MySQL-client-enterprise-gpl %description client This package contains the standard MySQL clients and administration tools. @@ -266,11 +270,14 @@ They should be used with caution. # ------------------------------------------------------------------------------ %package test -Requires: %{name}-client perl -Summary: MySQL - Test suite -Group: Applications/Databases -Provides: mysql-test -Obsoletes: mysql-bench mysql-test +Summary: MySQL - Test suite +Group: Applications/Databases +Requires: %{name}-client perl +Provides: mysql-test MySQL-test +Obsoletes: mysql-test MySQL-test +Obsoletes: mysql-bench MySQL-bench +Obsoletes: MySQL-test-classic MySQL-test-community MySQL-test-enterprise +Obsoletes: MySQL-test-advanced MySQL-test-advanced-gpl MySQL-test-enterprise-gpl AutoReqProv: no %description test @@ -281,10 +288,12 @@ This package contains the MySQL regression test suite. # ------------------------------------------------------------------------------ %package devel -Summary: MySQL - Development header files and libraries -Group: Applications/Databases -Provides: mysql-devel -Obsoletes: mysql-devel +Summary: MySQL - Development header files and libraries +Group: Applications/Databases +Provides: mysql-devel MySQL-devel +Obsoletes: mysql-devel MySQL-devel +Obsoletes: MySQL-devel-classic MySQL-devel-community MySQL-devel-enterprise +Obsoletes: MySQL-devel-advanced MySQL-devel-advanced-gpl MySQL-devel-enterprise-gpl %description devel This package contains the development header files and libraries @@ -295,8 +304,14 @@ necessary to develop MySQL client applications. # ------------------------------------------------------------------------------ %package shared -Summary: MySQL - Shared libraries -Group: Applications/Databases +Summary: MySQL - Shared libraries +Group: Applications/Databases +Provides: mysql-shared MySQL-shared +Obsoletes: mysql-shared MySQL-shared-standard MySQL-shared-pro +Obsoletes: MySQL-shared-pro-cert MySQL-shared-pro-gpl +Obsoletes: MySQL-shared-pro-gpl-cert MySQL-shared +Obsoletes: MySQL-shared-classic MySQL-shared-community MySQL-shared-enterprise +Obsoletes: MySQL-shared-advanced MySQL-shared-advanced-gpl MySQL-shared-enterprise-gpl %description shared This package contains the shared libraries (*.so*) which certain @@ -307,10 +322,14 @@ languages and applications need to dynamically load and use MySQL. %if %{EMBEDDED_BUILD} %package embedded -Requires: %{name}-devel -Summary: MySQL - embedded library -Group: Applications/Databases -Obsoletes: mysql-embedded +Summary: MySQL - Embedded library +Group: Applications/Databases +Requires: %{name}-devel +Provides: mysql-embedded MySQL-embedded +Obsoletes: mysql-embedded MySQL-embedded +Obsoletes: MySQL-embedded-pro +Obsoletes: MySQL-embedded-classic MySQL-embedded-community MySQL-embedded-enterprise +Obsoletes: MySQL-embedded-advanced MySQL-embedded-advanced-gpl MySQL-embedded-enterprise-gpl %description embedded This package contains the MySQL server as an embedded library. @@ -1172,6 +1191,16 @@ fi # merging BK trees) ############################################################################## %changelog +* Wed Sep 14 2011 Joerg Bruehe + +- Let the RPM capabilities ("obsoletes" etc) ensure that an upgrade may replace + the RPMs of any configuration (of the current or the preceding release series) + by the new ones. This is done by not using the implicitly generated capabilities + (which include the configuration name) and relying on more generic ones which + just list the function ("server", "client", ...). + The implicit generation cannot be prevented, so all these capabilities must be + explicitly listed in "Obsoletes:" + * Fri Aug 19 2011 Joerg Bruehe - Fix bug#37165 "((Generic rpm)) fail to install on Fedora 9 x86_64" From c6d47e6e01e9f9dcb0ea1d7b3582136b65face32 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Oct 2011 09:21:47 -0500 Subject: [PATCH 45/49] Bug#12980094 and Bug#13034534 Bug 12980094 - ASSERTION IN INNODB DETECTED IN RQG_PARTITION_DDL Bug 13034534 - RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR RW_LOCK_DEBUG_PRINT All access to struct rw_lock_debug_struct must be protected by rw_lock_debug_mutex_enter(). --- storage/innobase/include/sync0rw.h | 3 ++- storage/innobase/sync/sync0rw.c | 10 +++++++--- storage/innodb_plugin/ChangeLog | 5 +++++ storage/innodb_plugin/include/sync0rw.h | 3 ++- storage/innodb_plugin/sync/sync0rw.c | 4 ++++ 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index dd898557d6e..6bd81623ad2 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -484,7 +484,8 @@ struct rw_lock_struct { #define RW_LOCK_MAGIC_N 22643 #ifdef UNIV_SYNC_DEBUG -/* The structure for storing debug info of an rw-lock */ +/** The structure for storing debug info of an rw-lock. All access to this +structure must be protected by rw_lock_debug_mutex_enter(). */ struct rw_lock_debug_struct { os_thread_id_t thread_id; /* The thread id of the thread which diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 089e87a8a5c..d82baaace69 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -732,7 +732,7 @@ rw_lock_own( ut_ad(lock); ut_ad(rw_lock_validate(lock)); - mutex_enter(&(lock->mutex)); + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); @@ -742,7 +742,7 @@ rw_lock_own( && (info->pass == 0) && (info->lock_type == lock_type)) { - mutex_exit(&(lock->mutex)); + rw_lock_debug_mutex_exit(); /* Found! */ return(TRUE); @@ -750,7 +750,7 @@ rw_lock_own( info = UT_LIST_GET_NEXT(list, info); } - mutex_exit(&(lock->mutex)); + rw_lock_debug_mutex_exit(); return(FALSE); } @@ -830,11 +830,13 @@ rw_lock_list_print_info( putc('\n', file); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } mutex_exit(&(lock->mutex)); @@ -870,11 +872,13 @@ rw_lock_print( putc('\n', stderr); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } } diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 171f1edd7ba..379d37fdedd 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-09-29 The InnoDB Team + + * sync/sync0rw.c: + Fix Bug#13034534 RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR RW_LOCK_DEBUG_PRINT + 2011-09-20 The InnoDB Team * row/row0purge.c: diff --git a/storage/innodb_plugin/include/sync0rw.h b/storage/innodb_plugin/include/sync0rw.h index 47f7dbfe0eb..40be1396a4c 100644 --- a/storage/innodb_plugin/include/sync0rw.h +++ b/storage/innodb_plugin/include/sync0rw.h @@ -564,7 +564,8 @@ struct rw_lock_struct { }; #ifdef UNIV_SYNC_DEBUG -/** The structure for storing debug info of an rw-lock */ +/** The structure for storing debug info of an rw-lock. All access to this +structure must be protected by rw_lock_debug_mutex_enter(). */ struct rw_lock_debug_struct { os_thread_id_t thread_id; /*!< The thread id of the thread which diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c index 3df2b4e9bbd..0127c12a5e4 100644 --- a/storage/innodb_plugin/sync/sync0rw.c +++ b/storage/innodb_plugin/sync/sync0rw.c @@ -928,11 +928,13 @@ rw_lock_list_print_info( putc('\n', file); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_exit(&(lock->mutex)); @@ -976,11 +978,13 @@ rw_lock_print( putc('\n', stderr); } + rw_lock_debug_mutex_enter(); info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } + rw_lock_debug_mutex_exit(); } } From 96c2c18e4f6b484aea7cbce5646c1280661f73a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 4 Oct 2011 21:01:40 +0300 Subject: [PATCH 46/49] Correct the ChangeLog --- storage/innodb_plugin/ChangeLog | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 379d37fdedd..cdf8e8351a8 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,7 +1,8 @@ -2011-09-29 The InnoDB Team +2011-10-04 The InnoDB Team - * sync/sync0rw.c: - Fix Bug#13034534 RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR RW_LOCK_DEBUG_PRINT + * include/sync0rw.h, sync/sync0rw.c: + Fix Bug#13034534 RQG TESTS FAIL ON WINDOWS WITH CRASH NEAR + RW_LOCK_DEBUG_PRINT 2011-09-20 The InnoDB Team From 16c919527fbedf373d7cbc34415b87cacea18993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 5 Oct 2011 12:01:47 +0300 Subject: [PATCH 47/49] Add InnoDB UNIV_SYNC_DEBUG assertions to rw-lock code. rw_lock_x_lock_func(): Assert that the thread is not already holding the lock in a conflicting mode (RW_LOCK_SHARED). rw_lock_s_lock_func(): Assert that the thread is not already holding the lock in a conflicting mode (RW_LOCK_EX). --- storage/innobase/include/sync0rw.ic | 1 + storage/innobase/sync/sync0rw.c | 3 +++ storage/innodb_plugin/include/sync0rw.ic | 1 + storage/innodb_plugin/sync/sync0rw.c | 3 +++ 4 files changed, 8 insertions(+) diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index eea639f26f4..2a674f00262 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -238,6 +238,7 @@ rw_lock_s_lock_func( #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ + ut_ad(!rw_lock_own(lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ mutex_enter(rw_lock_get_mutex(lock)); diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index d82baaace69..05ea8ff0fe9 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -476,6 +476,9 @@ rw_lock_x_lock_func( ulint i; /* spin round count */ ut_ad(rw_lock_validate(lock)); +#ifdef UNIV_SYNC_DEBUG + ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ lock_loop: /* Acquire the mutex protecting the rw-lock fields */ diff --git a/storage/innodb_plugin/include/sync0rw.ic b/storage/innodb_plugin/include/sync0rw.ic index 485a63a1b18..5eb3d017eca 100644 --- a/storage/innodb_plugin/include/sync0rw.ic +++ b/storage/innodb_plugin/include/sync0rw.ic @@ -406,6 +406,7 @@ rw_lock_s_lock_func( #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); /* see NOTE above */ + ut_ad(!rw_lock_own(lock, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ /* TODO: study performance of UNIV_LIKELY branch prediction hints. */ diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c index 0127c12a5e4..bc060319246 100644 --- a/storage/innodb_plugin/sync/sync0rw.c +++ b/storage/innodb_plugin/sync/sync0rw.c @@ -612,6 +612,9 @@ rw_lock_x_lock_func( ibool spinning = FALSE; ut_ad(rw_lock_validate(lock)); +#ifdef UNIV_SYNC_DEBUG + ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ i = 0; From 14dc91ff83001809fc40380ab22fc4e606f611de Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 5 Oct 2011 13:28:20 +0400 Subject: [PATCH 48/49] Bug#11747970 34660: CRASH WHEN FEDERATED TABLE LOSES CONNECTION DURING INSERT ... SELECT Problematic query: insert ignore into `t1_federated` (`c1`) select `c1` from `t1_local` a where not exists (select 1 from `t1_federated` b where a.c1 = b.c1); When this query is killed in another connection it could lead to crash. The problem is follwing: An attempt to obtain table statistics for subselect table in killed query fails with an error. So JOIN::optimize() for subquery is failed but it does not prevent further subquery evaluation. At the first subquery execution JOIN::optimize() is called (see subselect_single_select_engine::exec()) and fails with an error. 'executed' flag is set to TRUE and it prevents further subquery evaluation. At the second call JOIN::optimize() does not happen as 'JOIN::optimized' is TRUE and in case of uncacheable subquery the 'executed' flag is set to FALSE before subquery evaluation. So we loose 'optimize stage' error indication (see subselect_single_select_engine::exec()). In other words 'executed' flag is used for two purposes, for error indication at JOIN::optimize() stage and for an indication of subquery execution. And it seems it's wrong as the flag could be reset. mysql-test/r/error_simulation.result: test case mysql-test/t/error_simulation.test: test case sql/item_subselect.cc: added new flag subselect_single_select_engine::optimize_error which is used for error detection which could happen at optimize stage. sql/item_subselect.h: added new flag subselect_single_select_engine::optimize_error sql/sql_select.cc: test case --- mysql-test/r/error_simulation.result | 13 +++++++++++++ mysql-test/t/error_simulation.test | 14 ++++++++++++++ sql/item_subselect.cc | 13 ++++++++++--- sql/item_subselect.h | 1 + sql/sql_select.cc | 10 ++++++++++ 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/error_simulation.result b/mysql-test/r/error_simulation.result index b6b79cb596b..f1835186787 100644 --- a/mysql-test/r/error_simulation.result +++ b/mysql-test/r/error_simulation.result @@ -83,5 +83,18 @@ a a b filler SET SESSION debug = DEFAULT; DROP TABLE t1, t2; # +# Bug#11747970 34660: CRASH WHEN FEDERATED TABLE LOSES CONNECTION DURING INSERT ... SELECT +# +CREATE TABLE t1(f1 INT, KEY(f1)); +CREATE TABLE t2(f1 INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SET SESSION debug='d,bug11747970_simulate_error'; +INSERT IGNORE INTO t2 SELECT f1 FROM t1 a WHERE NOT EXISTS (SELECT 1 FROM t2 b WHERE a.f1 = b.f1); +Warnings: +Error 1105 Unknown error +SET SESSION debug = DEFAULT; +DROP TABLE t1,t2; +# # End of 5.1 tests # diff --git a/mysql-test/t/error_simulation.test b/mysql-test/t/error_simulation.test index f6edacfaa29..95ec2c5b21d 100644 --- a/mysql-test/t/error_simulation.test +++ b/mysql-test/t/error_simulation.test @@ -89,6 +89,20 @@ SET SESSION debug = DEFAULT; DROP TABLE t1, t2; + +--echo # +--echo # Bug#11747970 34660: CRASH WHEN FEDERATED TABLE LOSES CONNECTION DURING INSERT ... SELECT +--echo # +CREATE TABLE t1(f1 INT, KEY(f1)); +CREATE TABLE t2(f1 INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SET SESSION debug='d,bug11747970_simulate_error'; +INSERT IGNORE INTO t2 SELECT f1 FROM t1 a WHERE NOT EXISTS (SELECT 1 FROM t2 b WHERE a.f1 = b.f1); +SET SESSION debug = DEFAULT; +DROP TABLE t1,t2; + + --echo # --echo # End of 5.1 tests --echo # diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 10dd6c93717..2fa0178ed8c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1679,7 +1679,7 @@ subselect_single_select_engine(st_select_lex *select, select_subselect *result_arg, Item_subselect *item_arg) :subselect_engine(item_arg, result_arg), - prepared(0), optimized(0), executed(0), + prepared(0), optimized(0), executed(0), optimize_error(0), select_lex(select), join(0) { select_lex->master_unit()->item= item_arg; @@ -1689,7 +1689,7 @@ subselect_single_select_engine(st_select_lex *select, void subselect_single_select_engine::cleanup() { DBUG_ENTER("subselect_single_select_engine::cleanup"); - prepared= optimized= executed= 0; + prepared= optimized= executed= optimize_error= 0; join= 0; result->cleanup(); DBUG_VOID_RETURN; @@ -1885,6 +1885,10 @@ int join_read_next_same_or_null(READ_RECORD *info); int subselect_single_select_engine::exec() { DBUG_ENTER("subselect_single_select_engine::exec"); + + if (optimize_error) + DBUG_RETURN(1); + char const *save_where= thd->where; SELECT_LEX *save_select= thd->lex->current_select; thd->lex->current_select= select_lex; @@ -1892,12 +1896,15 @@ int subselect_single_select_engine::exec() { SELECT_LEX_UNIT *unit= select_lex->master_unit(); + DBUG_EXECUTE_IF("bug11747970_simulate_error", + DBUG_SET("+d,bug11747970_raise_error");); + optimized= 1; unit->set_limit(unit->global_parameters); if (join->optimize()) { thd->where= save_where; - executed= 1; + optimize_error= 1; thd->lex->current_select= save_select; DBUG_RETURN(join->error ? join->error : 1); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 74bbec626c1..65b415b44e9 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -419,6 +419,7 @@ class subselect_single_select_engine: public subselect_engine my_bool prepared; /* simple subselect is prepared */ my_bool optimized; /* simple subselect is optimized */ my_bool executed; /* simple subselect is executed */ + my_bool optimize_error; ///< simple subselect optimization failed st_select_lex *select_lex; /* corresponding select_lex */ JOIN * join; /* corresponding JOIN structure */ public: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 516c9c37473..bf0cd7c9db8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2677,6 +2677,16 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, table_vector[i]=s->table=table=tables->table; table->pos_in_table_list= tables; error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + + DBUG_EXECUTE_IF("bug11747970_raise_error", + { + if (!error) + { + my_error(ER_UNKNOWN_ERROR, MYF(0)); + goto error; + } + }); + if (error) { table->file->print_error(error, MYF(0)); From 73db2a1504188611c3348e1bd55d181aea6ab533 Mon Sep 17 00:00:00 2001 From: Vinay Fisrekar Date: Wed, 12 Oct 2011 10:10:52 +0530 Subject: [PATCH 49/49] bug#11766457 - adjusting/modifying the the tests as tests were failing if system time zone is set differently. --- mysql-test/suite/engines/funcs/r/de_calendar_range.result | 2 ++ .../in_calendar_2_unique_constraints_duplicate_update.result | 2 ++ .../r/in_calendar_pk_constraint_duplicate_update.result | 2 ++ .../engines/funcs/r/in_calendar_pk_constraint_error.result | 2 ++ .../engines/funcs/r/in_calendar_pk_constraint_ignore.result | 2 ++ .../r/in_calendar_unique_constraint_duplicate_update.result | 2 ++ .../funcs/r/in_calendar_unique_constraint_error.result | 2 ++ .../funcs/r/in_calendar_unique_constraint_ignore.result | 2 ++ ...ulticolumn_calendar_pk_constraint_duplicate_update.result | 2 ++ .../r/in_multicolumn_calendar_pk_constraint_error.result | 2 ++ .../r/in_multicolumn_calendar_pk_constraint_ignore.result | 2 ++ ...column_calendar_unique_constraint_duplicate_update.result | 2 ++ .../r/in_multicolumn_calendar_unique_constraint_error.result | 2 ++ .../in_multicolumn_calendar_unique_constraint_ignore.result | 2 ++ ..._multicolumn_number_pk_constraint_duplicate_update.result | 2 ++ mysql-test/suite/engines/funcs/r/up_calendar_range.result | 2 ++ mysql-test/suite/engines/funcs/t/de_calendar_range.test | 5 ++++- .../t/in_calendar_2_unique_constraints_duplicate_update.test | 4 ++++ .../funcs/t/in_calendar_pk_constraint_duplicate_update.test | 5 ++++- .../engines/funcs/t/in_calendar_pk_constraint_error.test | 5 ++++- .../engines/funcs/t/in_calendar_pk_constraint_ignore.test | 4 ++++ .../t/in_calendar_unique_constraint_duplicate_update.test | 5 ++++- .../engines/funcs/t/in_calendar_unique_constraint_error.test | 5 ++++- .../funcs/t/in_calendar_unique_constraint_ignore.test | 5 ++++- ..._multicolumn_calendar_pk_constraint_duplicate_update.test | 4 ++++ .../funcs/t/in_multicolumn_calendar_pk_constraint_error.test | 5 ++++- .../t/in_multicolumn_calendar_pk_constraint_ignore.test | 5 ++++- ...ticolumn_calendar_unique_constraint_duplicate_update.test | 5 ++++- .../t/in_multicolumn_calendar_unique_constraint_error.test | 5 ++++- .../t/in_multicolumn_calendar_unique_constraint_ignore.test | 4 ++++ ...in_multicolumn_number_pk_constraint_duplicate_update.test | 4 ++++ mysql-test/suite/engines/funcs/t/up_calendar_range.test | 5 ++++- 32 files changed, 96 insertions(+), 11 deletions(-) diff --git a/mysql-test/suite/engines/funcs/r/de_calendar_range.result b/mysql-test/suite/engines/funcs/r/de_calendar_range.result index 904b14c06b5..07543e0c8c4 100644 --- a/mysql-test/suite/engines/funcs/r/de_calendar_range.result +++ b/mysql-test/suite/engines/funcs/r/de_calendar_range.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1,t2,t3; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -89,3 +90,4 @@ c1 2007-02-16 12:10:34 2007-02-17 13:10:34 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result index 7479cf3ea0b..9c56e23574d 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_2_unique_constraints_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NULL, c3 DATE NULL, PRIMARY KEY(c1), UNIQUE(c2)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),ADDTIME(NOW(),'4 04:01:01'),NOW()); @@ -128,3 +129,4 @@ c1 c2 c3 2003 2001 2000 2004 2000 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result index 763e9f564c6..47355681eae 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -82,3 +83,4 @@ c1 2000 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result index 3f2b1546995..f8bff355901 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result index 3f2b1546995..f8bff355901 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_pk_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result index 154c44426bc..5c4307158fa 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -82,3 +83,4 @@ c1 2000 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result index 6c395c5f6b9..9f6a205530c 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -87,3 +88,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result index 58802aab0b2..5469527b762 100644 --- a/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_calendar_unique_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -81,3 +82,4 @@ c1 1999 2000 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result index f2cafdfce52..d7dfc9d794c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result index b630d3f519f..d71af8d6375 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result index b630d3f519f..d71af8d6375 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_pk_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result index 3b40a2f57ab..edad4bb218d 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result index 84f626d3347..4d7cadac70c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_error.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -147,3 +148,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result index f34b39ec1b4..31f7db1dc9a 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_calendar_unique_constraint_ignore.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -139,3 +140,4 @@ c1 c2 c3 1999 2000 1999 2000 1999 1999 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result b/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result index f2cafdfce52..d7dfc9d794c 100644 --- a/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result +++ b/mysql-test/suite/engines/funcs/r/in_multicolumn_number_pk_constraint_duplicate_update.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -144,3 +145,4 @@ c1 c2 c3 2011 2011 2000 2011 2011 2011 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/r/up_calendar_range.result b/mysql-test/suite/engines/funcs/r/up_calendar_range.result index 7185fc3c6ee..dbd6e2cf8a6 100644 --- a/mysql-test/suite/engines/funcs/r/up_calendar_range.result +++ b/mysql-test/suite/engines/funcs/r/up_calendar_range.result @@ -1,4 +1,5 @@ DROP TABLE IF EXISTS t1,t2,t3; +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL); SET TIMESTAMP=1171346973; INSERT INTO t1 (c1) VALUES(NOW()); @@ -104,3 +105,4 @@ c1 2007-02-13 09:09:33 2007-02-14 10:10:34 DROP TABLE t1; +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/de_calendar_range.test b/mysql-test/suite/engines/funcs/t/de_calendar_range.test index c1e191fdd97..6e3f1915e9a 100644 --- a/mysql-test/suite/engines/funcs/t/de_calendar_range.test +++ b/mysql-test/suite/engines/funcs/t/de_calendar_range.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -45,4 +47,5 @@ SELECT * FROM t1 ORDER BY c1; DELETE FROM t1 WHERE c1 <= ADDTIME(NOW(),'2 02:01:01'); SELECT * FROM t1 ORDER BY c1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test index 8c6f960b60d..5ae519abdc8 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_2_unique_constraints_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NULL, c3 DATE NULL, PRIMARY KEY(c1), UNIQUE(c2)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),ADDTIME(NOW(),'4 04:01:01'),NOW()); @@ -70,4 +72,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(2000,2000,2000) ON DUPLICATE KEY UPDATE c3=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test index 65c7c34f907..fdfb6edb139 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(1999) ON DUPLICATE KEY UPDATE c1=2011; --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test index 36a8ef3a0a7..f65c705031b 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test index 36a8ef3a0a7..bac71b99a97 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_pk_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL PRIMARY KEY); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,6 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test index 20da85f5b66..e6235e77603 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(1999) ON DUPLICATE KEY UPDATE c1=2011; --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test index 73b8c3d0775..f9d101d8327 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -61,4 +63,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test index 91e4f8faef9..a4e96a7ccc3 100644 --- a/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_calendar_unique_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL UNIQUE); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -53,4 +55,5 @@ INSERT INTO t1 (c1) VALUES(2000); INSERT IGNORE INTO t1 (c1) VALUES(1999); SELECT * FROM t1; DROP TABLE t1; - +#restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test index a7648a55128..12307232d64 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test index 9678ddd716b..8d994cb3d7a 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test index 9678ddd716b..8d994cb3d7a 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_pk_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test index 13575722c1f..3d455bcb5d8 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test index 916b0c527eb..9cbafd3b8d0 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_error.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,5 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,1999); INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); SELECT * FROM t1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test index b43ff52abe3..e313f29edfb 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_calendar_unique_constraint_ignore.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NULL, c2 DATE NULL, c3 DATE NULL, UNIQUE(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -85,4 +87,6 @@ INSERT IGNORE INTO t1 (c1,c2,c3) VALUES(1999,1999,2000); --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test b/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test index 71848c1ac38..df4a194a2cf 100644 --- a/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test +++ b/mysql-test/suite/engines/funcs/t/in_multicolumn_number_pk_constraint_duplicate_update.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL, c2 DATE NOT NULL, c3 DATE NOT NULL, PRIMARY KEY(c1,c2,c3)); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1,c2,c3) VALUES(NOW(),NOW(),NOW()); @@ -93,4 +95,6 @@ INSERT INTO t1 (c1,c2,c3) VALUES(1999,1999,2000) ON DUPLICATE KEY UPDATE c1=2011 --sorted_result SELECT * FROM t1; DROP TABLE t1; +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone; diff --git a/mysql-test/suite/engines/funcs/t/up_calendar_range.test b/mysql-test/suite/engines/funcs/t/up_calendar_range.test index 9c88d52f826..d4aca03199d 100644 --- a/mysql-test/suite/engines/funcs/t/up_calendar_range.test +++ b/mysql-test/suite/engines/funcs/t/up_calendar_range.test @@ -1,6 +1,8 @@ --disable_warnings DROP TABLE IF EXISTS t1,t2,t3; --enable_warnings +# Set Correct timezone to match result +SET TIME_ZONE="+03:00"; CREATE TABLE t1(c1 DATE NOT NULL); SET TIMESTAMP=1171346973; # 2007-02-13 15:09:33 INSERT INTO t1 (c1) VALUES(NOW()); @@ -53,4 +55,5 @@ UPDATE t1 SET c1 = NOW() WHERE c1 >= ADDTIME(NOW(),'2 02:01:01'); --sorted_result SELECT * FROM t1 ORDER BY c1; DROP TABLE t1; - +# Restore timezone to default +SET TIME_ZONE= @@global.time_zone;