From 983fcfaf62fbd4169afd0a3e6182ea46705fa3f5 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Wed, 20 Jun 2012 13:10:13 +0200 Subject: [PATCH 01/11] Version for this release build is 5.1.64 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 4e7a3303353..84295a15f4a 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.65], [], [mysql]) +AC_INIT([MySQL Server], [5.1.64], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 5c724f7b9430bb3794f6e12709268ce5502104e5 Mon Sep 17 00:00:00 2001 From: Joerg Bruehe Date: Thu, 21 Jun 2012 16:26:50 +0200 Subject: [PATCH 02/11] Fixing wrong comment syntax (discovered by Kent) --- sql/rpl_utility.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 81a10cca814..b2577643add 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -300,7 +300,7 @@ private: public: Deferred_log_events(Relay_log_info *rli); ~Deferred_log_events(); - /* queue for exection at Query-log-event time prior the Query */; + /* queue for exection at Query-log-event time prior the Query */ int add(Log_event *ev); bool is_empty(); bool execute(Relay_log_info *rli); From 5f86ecbf362bc32ec86d7118288b305af74e2fb3 Mon Sep 17 00:00:00 2001 From: Kent Boortz Date: Tue, 26 Jun 2012 16:30:15 +0200 Subject: [PATCH 03/11] Solve a linkage problem with "libmysqld" on several Solaris platforms: a multiple definition of 'THD::clear_error()' in (at least) libmysqld.a(lib_sql.o) and libmysqld.a(libfederated_a-ha_federated.o). Patch provided by Ramil Kalimullin. --- libmysqld/lib_sql.cc | 6 ------ sql/sql_class.h | 3 +-- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 4afe02efbdb..18b8383406a 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -756,12 +756,6 @@ void THD::clear_data_list() cur_data= 0; } -void THD::clear_error() -{ - if (main_da.is_error()) - main_da.reset_diagnostics_area(); -} - static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { diff --git a/sql/sql_class.h b/sql/sql_class.h index 3ecf032db71..5cdb005b517 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2089,7 +2089,6 @@ public: void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); int send_explain_fields(select_result *result); -#ifndef EMBEDDED_LIBRARY /** Clear the current error, if any. We do not clear is_fatal_error or is_fatal_sub_stmt_error since we @@ -2105,9 +2104,9 @@ public: is_slave_error= 0; DBUG_VOID_RETURN; } +#ifndef EMBEDDED_LIBRARY inline bool vio_ok() const { return net.vio != 0; } #else - void clear_error(); inline bool vio_ok() const { return true; } #endif /** From 115a2967563d3ac734ce371260098710ba42cdf0 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 22 Aug 2012 16:10:31 +0200 Subject: [PATCH 04/11] merge with XtraDB as of Percona-Server-5.1.63-rel13.4 --- mysql-test/suite/innodb/t/disabled.def | 5 - mysql-test/suite/innodb_plugin/t/disabled.def | 6 - storage/xtradb/ChangeLog | 178 ++++++- storage/xtradb/btr/btr0btr.c | 244 ++++++---- storage/xtradb/btr/btr0cur.c | 357 +++++++------- storage/xtradb/btr/btr0pcur.c | 78 ++- storage/xtradb/btr/btr0sea.c | 262 ++++++----- storage/xtradb/buf/buf0buddy.c | 2 +- storage/xtradb/buf/buf0buf.c | 183 ++------ storage/xtradb/buf/buf0lru.c | 8 +- storage/xtradb/compile-innodb | 24 + storage/xtradb/compile-innodb-debug | 24 + storage/xtradb/dict/dict0crea.c | 4 +- storage/xtradb/dict/dict0dict.c | 82 +++- storage/xtradb/dict/dict0load.c | 4 +- storage/xtradb/fil/fil0fil.c | 107 +++-- storage/xtradb/fsp/fsp0fsp.c | 444 ++++++++++-------- storage/xtradb/ha/ha0ha.c | 69 +-- storage/xtradb/handler/ha_innodb.cc | 269 +++++++++-- storage/xtradb/handler/ha_innodb.h | 1 + storage/xtradb/handler/handler0alter.cc | 12 +- storage/xtradb/handler/i_s.cc | 2 +- storage/xtradb/ibuf/ibuf0ibuf.c | 87 ++-- storage/xtradb/include/btr0btr.h | 59 ++- storage/xtradb/include/btr0btr.ic | 10 +- storage/xtradb/include/btr0cur.h | 84 ++-- storage/xtradb/include/btr0cur.ic | 29 +- storage/xtradb/include/btr0pcur.h | 8 - storage/xtradb/include/btr0pcur.ic | 32 -- storage/xtradb/include/btr0sea.h | 34 +- storage/xtradb/include/btr0types.h | 25 +- storage/xtradb/include/buf0buf.h | 59 +-- storage/xtradb/include/buf0buf.ic | 6 +- storage/xtradb/include/db0err.h | 2 + storage/xtradb/include/dict0dict.h | 14 +- storage/xtradb/include/dict0dict.ic | 21 +- storage/xtradb/include/dict0mem.h | 10 +- storage/xtradb/include/fil0fil.h | 20 +- storage/xtradb/include/fsp0fsp.h | 44 +- storage/xtradb/include/ha0ha.h | 23 +- storage/xtradb/include/ha0ha.ic | 54 +-- storage/xtradb/include/log0log.h | 6 +- storage/xtradb/include/mem0mem.ic | 4 - storage/xtradb/include/mtr0mtr.h | 17 +- storage/xtradb/include/mtr0mtr.ic | 7 +- storage/xtradb/include/page0page.h | 15 +- storage/xtradb/include/page0page.ic | 6 +- storage/xtradb/include/row0upd.ic | 6 - storage/xtradb/include/sync0rw.h | 3 +- storage/xtradb/include/sync0rw.ic | 5 +- storage/xtradb/include/sync0sync.h | 10 +- storage/xtradb/include/trx0purge.h | 4 +- storage/xtradb/include/trx0rec.ic | 7 +- storage/xtradb/include/trx0rseg.ic | 9 +- storage/xtradb/include/trx0sys.h | 6 + storage/xtradb/include/trx0undo.h | 57 ++- storage/xtradb/include/univ.i | 17 - storage/xtradb/include/ut0mem.h | 31 +- storage/xtradb/include/ut0rnd.ic | 2 +- storage/xtradb/lock/lock0lock.c | 14 +- storage/xtradb/log/log0log.c | 6 +- storage/xtradb/mem/mem0pool.c | 6 +- storage/xtradb/mtr/mtr0mtr.c | 4 +- storage/xtradb/mysql-test/patches/README | 30 ++ .../patches/index_merge_innodb-explain.diff | 31 ++ .../patches/information_schema.diff | 124 +++++ .../patches/innodb_file_per_table.diff | 47 ++ .../patches/innodb_lock_wait_timeout.diff | 55 +++ .../innodb_thread_concurrency_basic.diff | 31 ++ .../mysql-test/patches/partition_innodb.diff | 59 +++ storage/xtradb/os/os0file.c | 7 +- storage/xtradb/os/os0proc.c | 3 - storage/xtradb/page/page0cur.c | 6 +- storage/xtradb/page/page0page.c | 20 +- storage/xtradb/revert_gen.sh | 8 + storage/xtradb/row/row0ins.c | 79 +++- storage/xtradb/row/row0merge.c | 35 +- storage/xtradb/row/row0mysql.c | 106 ++++- storage/xtradb/row/row0purge.c | 20 +- storage/xtradb/row/row0row.c | 29 +- storage/xtradb/row/row0sel.c | 24 +- storage/xtradb/row/row0upd.c | 61 ++- storage/xtradb/scripts/export.sh | 74 +++ .../xtradb/scripts/install_innodb_plugins.sql | 8 - .../scripts/install_innodb_plugins_win.sql | 8 - storage/xtradb/setup.sh | 47 ++ storage/xtradb/sync/sync0rw.c | 7 + storage/xtradb/sync/sync0sync.c | 37 +- storage/xtradb/trx/trx0purge.c | 4 +- storage/xtradb/trx/trx0rec.c | 105 +++-- storage/xtradb/trx/trx0sys.c | 42 +- storage/xtradb/trx/trx0trx.c | 2 + storage/xtradb/trx/trx0undo.c | 109 +++-- .../ut/ut0auxconf_atomic_pthread_t_gcc.c | 43 ++ .../ut/ut0auxconf_atomic_pthread_t_solaris.c | 54 +++ .../xtradb/ut/ut0auxconf_have_gcc_atomics.c | 61 +++ .../ut/ut0auxconf_have_solaris_atomics.c | 39 ++ storage/xtradb/ut/ut0auxconf_pause.c | 32 ++ .../xtradb/ut/ut0auxconf_sizeof_pthread_t.c | 35 ++ storage/xtradb/ut/ut0mem.c | 82 +--- 100 files changed, 3124 insertions(+), 1668 deletions(-) create mode 100644 storage/xtradb/compile-innodb create mode 100644 storage/xtradb/compile-innodb-debug create mode 100644 storage/xtradb/mysql-test/patches/README create mode 100644 storage/xtradb/mysql-test/patches/index_merge_innodb-explain.diff create mode 100644 storage/xtradb/mysql-test/patches/information_schema.diff create mode 100644 storage/xtradb/mysql-test/patches/innodb_file_per_table.diff create mode 100644 storage/xtradb/mysql-test/patches/innodb_lock_wait_timeout.diff create mode 100644 storage/xtradb/mysql-test/patches/innodb_thread_concurrency_basic.diff create mode 100644 storage/xtradb/mysql-test/patches/partition_innodb.diff create mode 100644 storage/xtradb/revert_gen.sh create mode 100644 storage/xtradb/scripts/export.sh create mode 100644 storage/xtradb/setup.sh create mode 100644 storage/xtradb/ut/ut0auxconf_atomic_pthread_t_gcc.c create mode 100644 storage/xtradb/ut/ut0auxconf_atomic_pthread_t_solaris.c create mode 100644 storage/xtradb/ut/ut0auxconf_have_gcc_atomics.c create mode 100644 storage/xtradb/ut/ut0auxconf_have_solaris_atomics.c create mode 100644 storage/xtradb/ut/ut0auxconf_pause.c create mode 100644 storage/xtradb/ut/ut0auxconf_sizeof_pthread_t.c diff --git a/mysql-test/suite/innodb/t/disabled.def b/mysql-test/suite/innodb/t/disabled.def index 1d25fbf14c0..6795892ecae 100644 --- a/mysql-test/suite/innodb/t/disabled.def +++ b/mysql-test/suite/innodb/t/disabled.def @@ -10,10 +10,5 @@ # ############################################################################## -innodb_bug13635833: Disabled until merging with XtraDB 5.1.63 - -innodb-lock: Disabled until merging with XtraDB 5.1.60 -innodb_replace: Disabled until merging with XtraDB 5.1.60 - innodb_bug14007649: Disabled until merging with XtraDB 5.1.65 diff --git a/mysql-test/suite/innodb_plugin/t/disabled.def b/mysql-test/suite/innodb_plugin/t/disabled.def index a849d589fb2..d692eccac74 100644 --- a/mysql-test/suite/innodb_plugin/t/disabled.def +++ b/mysql-test/suite/innodb_plugin/t/disabled.def @@ -10,11 +10,5 @@ # ############################################################################## -innodb_bug13635833: Disabled until merging with XtraDB 5.1.63 - innodb_bug52745: Disabled as this has valgrind failures (also in MySQL 5.1.50) -innodb-index: Disabled until merging with XtraDB 5.1.60 -innodb-lock: Disabled until merging with XtraDB 5.1.60 -innodb_replace: Disabled until merging with XtraDB 5.1.60 -innodb-blob: Disabled until merging with XtraDB 5.1.63 innodb_bug14007649: Disabled until merging with XtraDB 5.1.65 diff --git a/storage/xtradb/ChangeLog b/storage/xtradb/ChangeLog index 7a4cacb5b43..1588132fc8b 100644 --- a/storage/xtradb/ChangeLog +++ b/storage/xtradb/ChangeLog @@ -1,8 +1,182 @@ +2012-03-15 The InnoDB Team + + * fil/fil0fil.c, ibuf/ibuf0ibuf.c, include/fil0fil.h, + lock/lock0lock.c: + Fix Bug#13825266 RACE IN LOCK_VALIDATE() WHEN ACCESSING PAGES + DIRECTLY FROM BUFFER POOL + +2012-03-15 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#13851171STRING OVERFLOW IN INNODB CODE FOUND BY STATIC + ANALYSIS + +2012-03-15 The InnoDB Team + + * include/sync0rw.ic: + Fix Bug#13537504 VALGRIND: COND. JUMP/MOVE DEPENDS ON + UNINITIALISED VALUES IN OS_THREAD_EQ + +2012-03-08 The InnoDB Team + + * btr/btr0pcur.c: + Fix Bug#13807811 BTR_PCUR_RESTORE_POSITION() CAN SKIP A RECORD + +2012-02-28 The InnoDB Team + + * btr/btr0btr.c, dict/dict0dict.c, include/btr0btr.h, + include/dict0dict.h, include/dict0dict.ic, include/dict0mem.h, + handler/handler0alter.cc, row/row0mysql.c: + Fix Bug#12861864 RACE CONDITION IN BTR_GET_SIZE() AND + DROP INDEX/TABLE/DATABASE + +2012-02-15 The InnoDB Team + + * btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, ibuf/ibuf0ibuf.c, + include/btr0btr.h, include/btr0cur.h, include/btr0cur.ic, + include/buf0buf.h, include/buf0buf.ic, include/fsp0fsp.h, + include/mtr0mtr.h, include/mtr0mtr.ic, include/page0page.h, + include/page0page.ic, include/trx0rec.ic, include/trx0undo.h, + mtr/mtr0mtr.c, page/page0cur.c, page/page0page.c, row/row0ins.c, + row/row0row.c, row/row0upd.c, trx/trx0rec.c, trx/trx0sys.c, + trx/trx0undo.c: + Fix Bug#13721257 RACE CONDITION IN UPDATES OR INSERTS OF WIDE RECORDS + +2012-02-06 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#11754376 45976: INNODB LOST FILES FOR TEMPORARY TABLES ON + GRACEFUL SHUTDOWN + +2012-01-30 The InnoDB Team + + * fil/fil0fil.c: + Fix Bug#13636122 THE ORIGINAL TABLE MISSING WHILE EXECUTE THE + DDL 'ALTER TABLE ADD COLUMN' + +2012-01-16 The InnoDB Team + + * ibuf/ibuf0ibuf.c: + Fix Bug#13496818 ASSERTION: REC_PAGE_NO > 4 IN IBUF CONTRACTION + +2012-01-16 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#11765438: 58406: ISSUES WITH COPYING PARTITIONED INNODB + TABLES FROM LINUX TO WINDOWS + +2012-01-04 The InnoDB Team + + * row/row0mysql.c: + Fix Bug#12400341: INNODB CAN LEAVE ORPHAN IBD FILES AROUND + +2011-12-22 The InnoDB Team + + * row/row0sel.c: + Fix Bug#63775 Server crash on handler read next after delete record. +2011-12-21 The InnoDB Team + + * include/ut0rnd.ic: + Fix Bug#11866367:FPE WHEN SETTING INNODB_SPIN_WAIT_DELAY + +2011-12-13 The InnoDB Team + + * handler/ha_innodb.cc, innodb.test, innodb.result: + Fix Bug#13117023: InnoDB was incrementing the handler_read_key, + also the SSV::ha_read_key_count, at the wrong place. + +2011-12-10 The InnoDB Team + + * include/page0page.h, page/page0page.c: + Fix Bug#13418887 ERROR IN DIAGNOSTIC FUNCTION PAGE_REC_PRINT() + +2011-11-10 The InnoDB Team + + * handler/ha_innodb.cc, row/row0ins.c, innodb_replace.test: + Fix Bug#11759688 52020: InnoDB can still deadlock + on just INSERT...ON DUPLICATE KEY a.k.a. the reintroduction of + Bug#7975 deadlock without any locking, simple select and update + +2011-11-08 The InnoDB Team + + * btr/btr0pcur.c, include/btr0pcur.h, include/btr0pcur.ic: + Fix Bug#13358468 ASSERTION FAILURE IN BTR_PCUR_GET_BLOCK + +2011-10-27 The InnoDB Team + + * row/row0mysql.c: + Fix Bug #12884631 62146: TABLES ARE LOST FOR DDL + 2011-10-25 The InnoDB Team * handler/ha_innodb.cc, row/row0ins.c: Fix Bug#13002783 PARTIALLY UNINITIALIZED CASCADE UPDATE VECTOR +2011-10-20 The InnoDB Team + + * btr/btr0cur.c: + Fix Bug#13116045 Compilation failure using GCC 4.6.1 in btr/btr0cur.c + +2011-10-12 The InnoDB Team + + * btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c, + ha/ha0ha.c, handler/ha_innodb.cc, ibuf/ibuf0ibuf.c, include/btr0sea.h, + include/btr0types.h, include/buf0buf.h, include/ha0ha.h, + include/ha0ha.ic, include/row0upd.ic, include/sync0sync.h, + page/page0page.c, sync/sync0sync.c: + Fix Bug#13006367 62487: innodb takes 3 minutes to clean up + the adaptive hash index at shutdown + +2011-10-04 The InnoDB Team + + * 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 + + * row/row0purge.c: + Fix Bug#12963823 CRASH IN PURGE THREAD UNDER UNUSUAL CIRCUMSTANCES + +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: + Fix Bug#12948130 UNNECESSARY X-LOCKING OF ADAPTIVE HASH INDEX + +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: + 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, + 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-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: @@ -170,7 +344,7 @@ 2011-01-06 The InnoDB Team * dict/dict0dict.c, handler/ha_innodb.cc, handler/i_s.cc, - include/univ.i: + include/univ.i: Fix Bug#58643 InnoDB: too long table name 2011-01-06 The InnoDB Team @@ -436,7 +610,7 @@ * handler/ha_innodb.cc, include/row0mysql.h, row/row0mysql.c: Fix Bug#53592: crash replacing duplicates into table after fast - alter table added unique key + alter table added unique key 2010-05-24 The InnoDB Team diff --git a/storage/xtradb/btr/btr0btr.c b/storage/xtradb/btr/btr0btr.c index 396ad422010..75cc80d0967 100644 --- a/storage/xtradb/btr/btr0btr.c +++ b/storage/xtradb/btr/btr0btr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ @@ -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); if (srv_pass_corrupt_table && !block) { return(0); @@ -897,7 +898,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, @@ -911,28 +912,31 @@ 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 +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ +static __attribute__((nonnull, warn_unused_result)) buf_block_t* -btr_page_alloc( -/*===========*/ +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: mtr or another + mini-transaction in which the + page should be initialized. + If init_mtr!=mtr, but the page + is already X-latched in mtr, do + not initialize the page. */ { 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); @@ -946,45 +950,81 @@ 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); - if (new_page_no == FIL_NULL) { + return(fseg_alloc_free_page_general( + seg_header, hint_page_no, file_direction, + TRUE, mtr, init_mtr)); +} - return(NULL); +/**************************************************************//** +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! +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ +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; + + if (dict_index_is_ibuf(index)) { + + return(btr_page_alloc_for_ibuf(index, mtr)); } - new_block = buf_page_get(dict_index_get_space(index), - dict_table_zip_size(index->table), - new_page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); + new_block = btr_page_alloc_low( + index, hint_page_no, file_direction, level, mtr, init_mtr); + + if (new_block) { + buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW); + } return(new_block); } /**************************************************************//** Gets the number of pages in a B-tree. -@return number of pages */ +@return number of pages, or ULINT_UNDEFINED if the index is unavailable */ UNIV_INTERN ulint btr_get_size( /*=========*/ dict_index_t* index, /*!< in: index */ - ulint flag) /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ + ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ + mtr_t* mtr) /*!< in/out: mini-transaction where index + is s-latched */ { fseg_header_t* seg_header; page_t* root; ulint n; ulint dummy; - mtr_t mtr; - mtr_start(&mtr); + ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), + MTR_MEMO_S_LOCK)); - mtr_s_lock(dict_index_get_lock(index), &mtr); + if (index->page == FIL_NULL + || index->to_be_dropped + || *index->name == TEMP_INDEX_PREFIX) { + return(ULINT_UNDEFINED); + } - root = btr_root_get(index, &mtr); + root = btr_root_get(index, mtr); if (srv_pass_corrupt_table && !root) { - mtr_commit(&mtr); + mtr_commit(mtr); return(0); } ut_a(root); @@ -992,22 +1032,20 @@ btr_get_size( if (flag == BTR_N_LEAF_PAGES) { seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; - fseg_n_reserved_pages(seg_header, &n, &mtr); + fseg_n_reserved_pages(seg_header, &n, mtr); } else if (flag == BTR_TOTAL_SIZE) { seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP; - n = fseg_n_reserved_pages(seg_header, &dummy, &mtr); + n = fseg_n_reserved_pages(seg_header, &dummy, mtr); seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF; - n += fseg_n_reserved_pages(seg_header, &dummy, &mtr); + n += fseg_n_reserved_pages(seg_header, &dummy, mtr); } else { ut_error; } - mtr_commit(&mtr); - return(n); } @@ -1076,6 +1114,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. */ } /**************************************************************//** @@ -1089,10 +1136,10 @@ 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); } @@ -1151,7 +1198,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)); } /************************************************************//** @@ -1323,23 +1370,20 @@ 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); /* Allocate then the next page to the segment: it will be the tree root page */ - page_no = fseg_alloc_free_page(buf_block_get_frame( - ibuf_hdr_block) - + IBUF_HEADER - + IBUF_TREE_SEG_HEADER, - IBUF_TREE_ROOT_PAGE_NO, - FSP_UP, mtr); - ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO); - - block = buf_page_get(space, zip_size, page_no, - RW_X_LATCH, mtr); + block = fseg_alloc_free_page( + buf_block_get_frame(ibuf_hdr_block) + + IBUF_HEADER + IBUF_TREE_SEG_HEADER, + IBUF_TREE_ROOT_PAGE_NO, + FSP_UP, mtr); + ut_ad(buf_block_get_page_no(block) == IBUF_TREE_ROOT_PAGE_NO); } else { #ifdef UNIV_BLOB_DEBUG if ((type & DICT_CLUSTERED) && !index->blobs) { @@ -1360,10 +1404,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); @@ -1371,6 +1414,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 @@ -1442,14 +1487,15 @@ 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); if (srv_pass_corrupt_table && !root) { mtr_commit(&mtr); return; } ut_a(root); - + #ifdef UNIV_BTR_DEBUG ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF + root, space)); @@ -1471,7 +1517,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); if (srv_pass_corrupt_table && !root) { mtr_commit(&mtr); @@ -1503,13 +1550,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); if (srv_pass_corrupt_table && !block) { return; @@ -1831,7 +1878,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); @@ -2392,9 +2439,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) @@ -2407,9 +2453,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) @@ -2569,7 +2614,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, @@ -2831,17 +2876,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; @@ -2859,7 +2929,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 @@ -2876,7 +2946,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 @@ -3202,7 +3272,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) @@ -3211,7 +3281,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) @@ -3300,7 +3370,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); @@ -3357,7 +3427,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 */ @@ -3549,7 +3619,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) @@ -3557,7 +3627,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) @@ -3592,7 +3662,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 @@ -4110,7 +4180,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))) { @@ -4336,7 +4406,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/xtradb/btr/btr0cur.c b/storage/xtradb/btr/btr0cur.c index 51a2f784fbf..4161be93a90 100644 --- a/storage/xtradb/btr/btr0cur.c +++ b/storage/xtradb/btr/btr0cur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -18,8 +18,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 *****************************************************************************/ @@ -238,7 +238,9 @@ 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); if (srv_pass_corrupt_table && !get_block) { return; @@ -254,9 +256,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); if (srv_pass_corrupt_table && !get_block) { return; @@ -271,8 +273,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); if (srv_pass_corrupt_table && !get_block) { return; @@ -286,9 +289,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); if (srv_pass_corrupt_table && !get_block) { return; @@ -312,8 +315,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; if (srv_pass_corrupt_table && !get_block) { @@ -329,7 +333,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); if (srv_pass_corrupt_table && !get_block) { return; @@ -419,7 +424,12 @@ btr_cur_search_to_nth_level( ut_ad(dict_index_check_search_tuple(index, tuple)); ut_ad(!dict_index_is_ibuf(index) || ibuf_inside()); ut_ad(dtuple_check_typed(tuple)); + ut_ad(index->page != FIL_NULL); + UNIV_MEM_INVALID(&cursor->up_match, sizeof cursor->up_match); + UNIV_MEM_INVALID(&cursor->up_bytes, sizeof cursor->up_bytes); + UNIV_MEM_INVALID(&cursor->low_match, sizeof cursor->low_match); + UNIV_MEM_INVALID(&cursor->low_bytes, sizeof cursor->low_bytes); #ifdef UNIV_DEBUG cursor->up_match = ULINT_UNDEFINED; cursor->low_match = ULINT_UNDEFINED; @@ -622,7 +632,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, @@ -680,8 +692,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)); } @@ -1822,6 +1834,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_; @@ -1846,7 +1859,7 @@ btr_cur_update_in_place( page_zip = buf_block_get_page_zip(block); /* Check that enough space is available on the compressed page. */ - if (UNIV_LIKELY_NULL(page_zip) + if (page_zip && !btr_cur_update_alloc_zip(page_zip, block, index, rec_offs_size(offsets), FALSE, mtr)) { return(DB_ZIP_OVERFLOW); @@ -1871,7 +1884,21 @@ btr_cur_update_in_place( return(err); /* == DB_SUCCESS */ } - 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->index != NULL); + + 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 */ @@ -1887,17 +1914,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); } @@ -2039,7 +2058,7 @@ any_extern: ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ - if (UNIV_LIKELY_NULL(page_zip) + if (page_zip && !btr_cur_update_alloc_zip(page_zip, block, index, new_rec_size, TRUE, mtr)) { err = DB_ZIP_OVERFLOW; @@ -2347,7 +2366,7 @@ btr_cur_pessimistic_update( ut_ad(rec_offs_validate(rec, index, offsets)); n_ext += btr_push_update_extern_fields(new_entry, update, *heap); - if (UNIV_LIKELY_NULL(page_zip)) { + if (page_zip) { ut_ad(page_is_comp(page)); if (page_zip_rec_needs_ext( rec_get_converted_size(index, new_entry, n_ext), @@ -2531,39 +2550,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 ===============*/ /****************************************************************//** @@ -2670,7 +2656,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); @@ -2755,9 +2742,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); @@ -2771,10 +2758,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); @@ -2850,7 +2833,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); } @@ -2903,16 +2887,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); @@ -2932,8 +2911,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); @@ -3581,7 +3563,6 @@ static void btr_record_not_null_field_in_rec( /*=============================*/ - rec_t* rec __attribute__ ((unused)),/*!< in: physical record */ ulint n_unique, /*!< in: dict_index_get_n_unique(index), number of columns uniquely determine an index entry */ @@ -3600,16 +3581,11 @@ btr_record_not_null_field_in_rec( } for (i = 0; i < n_unique; i++) { - ulint rec_len; - - rec_get_nth_field_offs(offsets, i, &rec_len); - - if (rec_len != UNIV_SQL_NULL) { - n_not_null[i]++; - } else { + if (rec_offs_nth_sql_null(offsets, i)) { /* Break if we hit the first NULL value */ break; } + n_not_null[i]++; } } @@ -3722,7 +3698,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - rec, n_cols, offsets_rec, n_not_null); + n_cols, offsets_rec, n_not_null); } } @@ -3757,8 +3733,7 @@ btr_estimate_number_of_different_key_vals( if (n_not_null) { btr_record_not_null_field_in_rec( - next_rec, n_cols, offsets_next_rec, - n_not_null); + n_cols, offsets_next_rec, n_not_null); } total_external_size @@ -3949,10 +3924,10 @@ btr_cur_set_ownership_of_extern_field( byte_val = byte_val | BTR_EXTERN_OWNER_FLAG; } - if (UNIV_LIKELY_NULL(page_zip)) { + if (page_zip) { mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val); page_zip_write_blob_ptr(page_zip, rec, index, offsets, i, mtr); - } else if (UNIV_LIKELY(mtr != NULL)) { + } else if (mtr != NULL) { mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, byte_val, MLOG_1BYTE, mtr); @@ -4190,9 +4165,9 @@ The fields are stored on pages allocated from leaf node file segment of the index tree. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ UNIV_INTERN -ulint -btr_store_big_rec_extern_fields_func( -/*=================================*/ +enum db_err +btr_store_big_rec_extern_fields( +/*============================*/ dict_index_t* index, /*!< in: index of rec; the index tree MUST be X-latched */ buf_block_t* rec_block, /*!< in/out: block containing rec */ @@ -4201,38 +4176,37 @@ btr_store_big_rec_extern_fields_func( the "external storage" flags in offsets will not correspond to rec when this function returns */ -#ifdef UNIV_DEBUG - mtr_t* local_mtr, /*!< in: mtr containing the - latch to rec and to the tree */ -#endif /* UNIV_DEBUG */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - 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 + const big_rec_t*big_rec_vec, /*!< in: vector containing fields to be stored externally */ - + mtr_t* btr_mtr, /*!< in: mtr containing the + latches to the clustered index */ + enum blob_op op) /*! in: operation code */ { - ulint rec_page_no; - byte* field_ref; - ulint extern_len; - ulint store_len; - ulint page_no; - ulint space_id; - ulint zip_size; - ulint prev_page_no; - ulint hint_page_no; - ulint i; - mtr_t mtr; - mem_heap_t* heap = NULL; + ulint rec_page_no; + byte* field_ref; + ulint extern_len; + ulint store_len; + ulint page_no; + ulint space_id; + ulint zip_size; + ulint prev_page_no; + ulint hint_page_no; + ulint i; + mtr_t mtr; + mtr_t* alloc_mtr; + mem_heap_t* heap = NULL; page_zip_des_t* page_zip; - z_stream c_stream; + z_stream c_stream; + buf_block_t** freed_pages = NULL; + ulint n_freed_pages = 0; + enum db_err error = DB_SUCCESS; ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_any_extern(offsets)); - ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), + ut_ad(btr_mtr); + ut_ad(mtr_memo_contains(btr_mtr, dict_index_get_lock(index), MTR_MEMO_X_LOCK)); - ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mtr_memo_contains(btr_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); ut_ad(buf_block_get_frame(rec_block) == page_align(rec)); ut_a(dict_index_is_clust(index)); @@ -4245,7 +4219,7 @@ 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 (UNIV_LIKELY_NULL(page_zip)) { + if (page_zip) { int err; /* Zlib deflate needs 128 kilobytes for the default @@ -4261,6 +4235,42 @@ btr_store_big_rec_extern_fields_func( ut_a(err == Z_OK); } + if (btr_blob_op_is_update(op)) { + /* Avoid reusing pages that have been previously freed + in btr_mtr. */ + if (btr_mtr->n_freed_pages) { + if (heap == NULL) { + heap = mem_heap_create( + btr_mtr->n_freed_pages + * sizeof *freed_pages); + } + + freed_pages = mem_heap_alloc( + heap, + btr_mtr->n_freed_pages + * sizeof *freed_pages); + n_freed_pages = 0; + } + + /* Because btr_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 btr_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 btr_mtr, which is committed after + mtr.) */ + alloc_mtr = btr_mtr; + } else { + /* Use the local mtr for allocations. */ + alloc_mtr = &mtr; + } + #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG /* All pointers to externally stored columns in the record must either be zero or they must be pointers to inherited @@ -4275,7 +4285,7 @@ btr_store_big_rec_extern_fields_func( /* Either this must be an update in place, or the BLOB must be inherited, or the BLOB pointer must be zero (will be written in this function). */ - ut_a(update_in_place + ut_a(op == BTR_STORE_UPDATE || (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG) || !memcmp(field_ref, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE)); @@ -4300,7 +4310,7 @@ btr_store_big_rec_extern_fields_func( prev_page_no = FIL_NULL; - if (UNIV_LIKELY_NULL(page_zip)) { + if (page_zip) { int err = deflateReset(&c_stream); ut_a(err == Z_OK); @@ -4320,18 +4330,24 @@ btr_store_big_rec_extern_fields_func( hint_page_no = prev_page_no + 1; } +alloc_another: 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); + error = DB_OUT_OF_FILE_SPACE; + goto func_exit; + } - if (UNIV_LIKELY_NULL(page_zip)) { - deflateEnd(&c_stream); - mem_heap_free(heap); - } - - return(DB_OUT_OF_FILE_SPACE); + if (rw_lock_get_x_lock_count(&block->lock) > 1) { + /* This page must have been freed in + btr_mtr previously. Put it aside, and + allocate another page for the BLOB data. */ + ut_ad(alloc_mtr == btr_mtr); + ut_ad(btr_blob_op_is_update(op)); + ut_ad(n_freed_pages < btr_mtr->n_freed_pages); + freed_pages[n_freed_pages++] = block; + goto alloc_another; } page_no = buf_block_get_page_no(block); @@ -4348,7 +4364,7 @@ btr_store_big_rec_extern_fields_func( SYNC_EXTERN_STORAGE); prev_page = buf_block_get_frame(prev_block); - if (UNIV_LIKELY_NULL(page_zip)) { + if (page_zip) { mlog_write_ulint( prev_page + FIL_PAGE_NEXT, page_no, MLOG_4BYTES, &mtr); @@ -4365,7 +4381,7 @@ btr_store_big_rec_extern_fields_func( } - if (UNIV_LIKELY_NULL(page_zip)) { + if (page_zip) { int err; page_zip_des_t* blob_page_zip; @@ -4448,11 +4464,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 @@ -4486,7 +4506,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; @@ -4531,19 +4552,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( @@ -4553,18 +4578,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; @@ -4578,8 +4604,23 @@ next_zip_page: } } - if (UNIV_LIKELY_NULL(page_zip)) { +func_exit: + if (page_zip) { deflateEnd(&c_stream); + } + + if (n_freed_pages) { + ulint i; + + ut_ad(alloc_mtr == btr_mtr); + ut_ad(btr_blob_op_is_update(op)); + + for (i = 0; i < n_freed_pages; i++) { + btr_page_free_low(index, freed_pages[i], 0, alloc_mtr); + } + } + + if (heap != NULL) { mem_heap_free(heap); } @@ -4600,7 +4641,7 @@ next_zip_page: ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG)); } #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ - return(DB_SUCCESS); + return(error); } /*******************************************************************//** @@ -4805,7 +4846,7 @@ btr_free_externally_stored_field( btr_page_free_low(index, ext_block, 0, &mtr); - if (UNIV_LIKELY(page_zip != NULL)) { + if (page_zip) { mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO, next_page_no); mach_write_to_4(field_ref + BTR_EXTERN_LEN + 4, diff --git a/storage/xtradb/btr/btr0pcur.c b/storage/xtradb/btr/btr0pcur.c index 97fe06f0f5e..be1a6cbd8ee 100644 --- a/storage/xtradb/btr/btr0pcur.c +++ b/storage/xtradb/btr/btr0pcur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2012, 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 @@ -127,6 +127,8 @@ btr_pcur_store_position( ut_a(btr_page_get_next(page, mtr) == FIL_NULL); ut_a(btr_page_get_prev(page, mtr) == FIL_NULL); + ut_ad(page_is_leaf(page)); + ut_ad(page_get_page_no(page) == index->page); cursor->old_stored = BTR_PCUR_OLD_STORED; @@ -253,6 +255,8 @@ btr_pcur_restore_position_func( cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE, index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr); + cursor->latch_mode = latch_mode; + cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->block_when_stored = btr_pcur_get_block(cursor); return(FALSE); @@ -272,8 +276,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 @@ -315,13 +321,19 @@ btr_pcur_restore_position_func( /* Save the old search mode of the cursor */ old_mode = cursor->search_mode; - if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) { + switch (cursor->rel_pos) { + case BTR_PCUR_ON: mode = PAGE_CUR_LE; - } else if (cursor->rel_pos == BTR_PCUR_AFTER) { + break; + case BTR_PCUR_AFTER: mode = PAGE_CUR_G; - } else { - ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE); + break; + case BTR_PCUR_BEFORE: mode = PAGE_CUR_L; + break; + default: + ut_error; + mode = 0; } btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode, @@ -330,25 +342,44 @@ btr_pcur_restore_position_func( /* Restore the old search mode */ cursor->search_mode = old_mode; - if (cursor->rel_pos == BTR_PCUR_ON - && btr_pcur_is_on_user_rec(cursor) - && 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor), - rec_get_offsets( - btr_pcur_get_rec(cursor), index, - NULL, ULINT_UNDEFINED, &heap))) { + if (btr_pcur_is_on_user_rec(cursor)) { + switch (cursor->rel_pos) { + case BTR_PCUR_ON: + if (!cmp_dtuple_rec( + tuple, btr_pcur_get_rec(cursor), + rec_get_offsets(btr_pcur_get_rec(cursor), + index, NULL, + ULINT_UNDEFINED, &heap))) { - /* We have to store the NEW value for the modify clock, since - the cursor can now be on a different page! But we can retain - the value of old_rec */ + /* We have to store the NEW value for + the modify clock, since the cursor can + now be on a different page! But we can + retain the value of old_rec */ - cursor->block_when_stored = btr_pcur_get_block(cursor); - cursor->modify_clock = buf_block_get_modify_clock( - cursor->block_when_stored); - cursor->old_stored = BTR_PCUR_OLD_STORED; + cursor->block_when_stored = + btr_pcur_get_block(cursor); + cursor->modify_clock = + buf_block_get_modify_clock( + cursor->block_when_stored); + cursor->old_stored = BTR_PCUR_OLD_STORED; - mem_heap_free(heap); + mem_heap_free(heap); - return(TRUE); + return(TRUE); + } + + break; + case BTR_PCUR_BEFORE: + page_cur_move_to_next(btr_pcur_get_page_cur(cursor)); + break; + case BTR_PCUR_AFTER: + page_cur_move_to_prev(btr_pcur_get_page_cur(cursor)); + break; +#ifdef UNIV_DEBUG + default: + ut_error; +#endif /* UNIV_DEBUG */ + } } mem_heap_free(heap); @@ -396,7 +427,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); if (srv_pass_corrupt_table && !next_page) { diff --git a/storage/xtradb/btr/btr0sea.c b/storage/xtradb/btr/btr0sea.c index 6e6c533f4af..3d710b653c0 100644 --- a/storage/xtradb/btr/btr0sea.c +++ b/storage/xtradb/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 @@ -44,12 +44,8 @@ Created 2/17/1996 Heikki Tuuri #include "ha0ha.h" #include "srv0srv.h" /** Flag: has the search system been enabled? -Protected by btr_search_latch and btr_search_enabled_mutex. */ +Protected by btr_search_latch. */ UNIV_INTERN char btr_search_enabled = TRUE; -UNIV_INTERN ibool btr_search_fully_disabled = FALSE; - -/** Mutex protecting btr_search_enabled */ -static mutex_t btr_search_enabled_mutex; /** A dummy variable to fool the compiler */ UNIV_INTERN ulint btr_search_this_is_zero = 0; @@ -169,7 +165,6 @@ btr_search_sys_create( btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t)); rw_lock_create(&btr_search_latch, SYNC_SEARCH_SYS); - mutex_create(&btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF); btr_search_sys = mem_alloc(sizeof(btr_search_sys_t)); @@ -199,27 +194,37 @@ void btr_search_disable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); + dict_table_t* table; + + mutex_enter(&dict_sys->mutex); rw_lock_x_lock(&btr_search_latch); - /* Disable access to hash index, also tell ha_insert_for_fold() - stop adding new nodes to hash index, but still allow updating - existing nodes */ btr_search_enabled = FALSE; - /* Clear all block->is_hashed flags and remove all entries - from btr_search_sys->hash_index. */ - buf_pool_drop_hash_index(); + /* Clear the index->search_info->ref_count of every index in + the data dictionary cache. */ + for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); table; + table = UT_LIST_GET_NEXT(table_LRU, table)) { - /* hash index has been cleaned up, disallow any operation to - the hash index */ - btr_search_fully_disabled = TRUE; + dict_index_t* index; - /* btr_search_enabled_mutex should guarantee this. */ - ut_ad(!btr_search_enabled); + for (index = dict_table_get_first_index(table); index; + index = dict_table_get_next_index(index)) { + + index->search_info->ref_count = 0; + } + } + + mutex_exit(&dict_sys->mutex); + + /* Set all block->index = NULL. */ + buf_pool_clear_hash_index(); + + /* Clear the adaptive hash index. */ + hash_table_clear(btr_search_sys->hash_index); + mem_heap_empty(btr_search_sys->hash_index->heap); rw_lock_x_unlock(&btr_search_latch); - mutex_exit(&btr_search_enabled_mutex); } /********************************************************************//** @@ -229,14 +234,11 @@ void btr_search_enable(void) /*====================*/ { - mutex_enter(&btr_search_enabled_mutex); rw_lock_x_lock(&btr_search_latch); btr_search_enabled = TRUE; - btr_search_fully_disabled = FALSE; rw_lock_x_unlock(&btr_search_latch); - mutex_exit(&btr_search_enabled_mutex); } /*****************************************************************//** @@ -459,7 +461,7 @@ btr_search_update_block_hash_info( && (block->n_bytes == info->n_bytes) && (block->left_side == info->left_side)) { - if ((block->is_hashed) + if ((block->index) && (block->curr_n_fields == info->n_fields) && (block->curr_n_bytes == info->n_bytes) && (block->curr_left_side == info->left_side)) { @@ -488,7 +490,7 @@ btr_search_update_block_hash_info( / BTR_SEARCH_PAGE_BUILD_LIMIT) && (info->n_hash_potential >= BTR_SEARCH_BUILD_LIMIT)) { - if ((!block->is_hashed) + if ((!block->index) || (block->n_hash_helps > 2 * page_get_n_recs(block->frame)) || (block->n_fields != block->curr_n_fields) @@ -520,9 +522,9 @@ btr_search_update_hash_ref( buf_block_t* block, /*!< in: buffer block where cursor positioned */ btr_cur_t* cursor) /*!< in: cursor */ { - ulint fold; - rec_t* rec; - dulint index_id; + dict_index_t* index; + ulint fold; + const rec_t* rec; ut_ad(cursor->flag == BTR_CUR_HASH_FAIL); #ifdef UNIV_SYNC_DEBUG @@ -533,13 +535,15 @@ btr_search_update_hash_ref( ut_ad(page_align(btr_cur_get_rec(cursor)) == buf_block_get_frame(block)); - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(index == cursor->index); + ut_a(!dict_index_is_ibuf(index)); if ((info->n_hash_potential > 0) && (block->curr_n_fields == info->n_fields) @@ -556,12 +560,11 @@ btr_search_update_hash_ref( return; } - index_id = cursor->index->id; fold = rec_fold(rec, - rec_get_offsets(rec, cursor->index, offsets_, + rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), block->curr_n_fields, - block->curr_n_bytes, index_id); + block->curr_n_bytes, index->id); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -829,7 +832,7 @@ btr_search_guess_on_hash( mtr_t* mtr) /*!< in: mtr */ { buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; dulint index_id; #ifdef notdefined @@ -837,6 +840,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)); @@ -914,7 +918,7 @@ btr_search_guess_on_hash( ut_ad(page_rec_is_user_rec(rec)); - btr_cur_position(index, rec, block, cursor); + btr_cur_position(index, (rec_t*) rec, block, cursor); /* Check the validity of the guess within the page */ @@ -1045,15 +1049,16 @@ btr_search_drop_page_hash_index( retry: rw_lock_s_lock(&btr_search_latch); - page = block->frame; + index = block->index; - if (UNIV_LIKELY(!block->is_hashed)) { + if (UNIV_LIKELY(!index)) { rw_lock_s_unlock(&btr_search_latch); return; } + ut_a(!dict_index_is_ibuf(index)); table = btr_search_sys->hash_index; #ifdef UNIV_SYNC_DEBUG @@ -1064,8 +1069,6 @@ retry: n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; - index = block->index; - ut_a(!dict_index_is_ibuf(index)); /* NOTE: The fields of block must not be accessed after releasing btr_search_latch, as the index page might only @@ -1075,6 +1078,7 @@ retry: ut_a(n_fields + n_bytes > 0); + page = block->frame; n_recs = page_get_n_recs(page); /* Calculate and cache fold values into an array for fast deletion @@ -1123,7 +1127,7 @@ next_rec: rw_lock_x_lock(&btr_search_latch); - if (UNIV_UNLIKELY(!block->is_hashed)) { + if (UNIV_UNLIKELY(!block->index)) { /* Someone else has meanwhile dropped the hash index */ goto cleanup; @@ -1151,9 +1155,8 @@ next_rec: ut_a(index->search_info->ref_count > 0); index->search_info->ref_count--; - block->is_hashed = FALSE; block->index = NULL; - + cleanup: #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG if (UNIV_UNLIKELY(block->n_pointers)) { @@ -1223,7 +1226,7 @@ retry: if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE || block->index != index - || !block->is_hashed) { + || !(block->index != NULL)) { continue; } @@ -1289,7 +1292,7 @@ next_rec: rw_lock_x_lock(&btr_search_latch); - if (UNIV_UNLIKELY(!block->is_hashed)) { + if (UNIV_UNLIKELY(!(block->index != NULL))) { goto cleanup; } @@ -1314,7 +1317,6 @@ next_rec: ut_a(index->search_info->ref_count > 0); index->search_info->ref_count--; - block->is_hashed = FALSE; block->index = NULL; cleanup: @@ -1346,8 +1348,8 @@ cleanup: } /********************************************************************//** -Drops a page hash index when a page is freed from a fseg to the file system. -Drops possible hash index if the page happens to be in the buffer pool. */ +Drops a possible page hash index when a page is evicted from the buffer pool +or freed in a file segment. */ UNIV_INTERN void btr_search_drop_page_hash_when_freed( @@ -1360,28 +1362,19 @@ btr_search_drop_page_hash_when_freed( buf_block_t* block; mtr_t mtr; - if (!buf_page_peek_if_search_hashed(space, page_no)) { - - return; - } - mtr_start(&mtr); - /* We assume that if the caller has a latch on the page, then the - caller has already dropped the hash index for the page, and we never - get here. Therefore we can acquire the s-latch to the page without - having to fear a deadlock. */ + /* If the caller has a latch on the page, then the caller must + have a x-latch on the page and it must have already dropped + the hash index for the page. Because of the x-latch that we + are possibly holding, we cannot s-latch the page, but must + (recursively) x-latch it, even though we are only reading. */ - block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH, NULL, + block = buf_page_get_gen(space, zip_size, page_no, RW_X_LATCH, NULL, BUF_PEEK_IF_IN_POOL, __FILE__, __LINE__, &mtr); - /* Because the buffer pool mutex was released by - buf_page_peek_if_search_hashed(), it is possible that the - block was removed from the buffer pool by another thread - before buf_page_get_gen() got a chance to acquire the buffer - pool mutex again. Thus, we must check for a NULL return. */ - if (UNIV_LIKELY(block != NULL)) { + if (block && block->index) { buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH); @@ -1413,7 +1406,6 @@ btr_search_build_page_hash_index( rec_t* next_rec; ulint fold; ulint next_fold; - dulint index_id; ulint n_cached; ulint n_recs; ulint* folds; @@ -1427,9 +1419,6 @@ btr_search_build_page_hash_index( ut_ad(index); ut_a(!dict_index_is_ibuf(index)); - table = btr_search_sys->hash_index; - page = buf_block_get_frame(block); - #ifdef UNIV_SYNC_DEBUG ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX)); ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED) @@ -1438,9 +1427,17 @@ btr_search_build_page_hash_index( rw_lock_s_lock(&btr_search_latch); - if (block->is_hashed && ((block->curr_n_fields != n_fields) - || (block->curr_n_bytes != n_bytes) - || (block->curr_left_side != left_side))) { + if (!btr_search_enabled) { + rw_lock_s_unlock(&btr_search_latch); + return; + } + + table = btr_search_sys->hash_index; + page = buf_block_get_frame(block); + + if (block->index && ((block->curr_n_fields != n_fields) + || (block->curr_n_bytes != n_bytes) + || (block->curr_left_side != left_side))) { rw_lock_s_unlock(&btr_search_latch); @@ -1477,7 +1474,7 @@ btr_search_build_page_hash_index( n_cached = 0; - index_id = btr_page_get_index_id(page); + ut_a(UT_DULINT_EQ(index->id, btr_page_get_index_id(page))); rec = page_rec_get_next(page_get_infimum_rec(page)); @@ -1492,7 +1489,7 @@ btr_search_build_page_hash_index( } } - fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); + fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); if (left_side) { @@ -1519,7 +1516,7 @@ btr_search_build_page_hash_index( offsets = rec_get_offsets(next_rec, index, offsets, n_fields + (n_bytes > 0), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, - n_bytes, index_id); + n_bytes, index->id); if (fold != next_fold) { /* Insert an entry into the hash index */ @@ -1544,13 +1541,13 @@ btr_search_build_page_hash_index( rw_lock_x_lock(&btr_search_latch); - if (UNIV_UNLIKELY(btr_search_fully_disabled)) { + if (UNIV_UNLIKELY(!btr_search_enabled)) { goto exit_func; } - if (block->is_hashed && ((block->curr_n_fields != n_fields) - || (block->curr_n_bytes != n_bytes) - || (block->curr_left_side != left_side))) { + if (block->index && ((block->curr_n_fields != n_fields) + || (block->curr_n_bytes != n_bytes) + || (block->curr_left_side != left_side))) { goto exit_func; } @@ -1559,11 +1556,10 @@ btr_search_build_page_hash_index( rebuild hash index for a page that is already hashed, we have to take care not to increment the counter in that case. */ - if (!block->is_hashed) { + if (!block->index) { index->search_info->ref_count++; } - block->is_hashed = TRUE; block->n_hash_helps = 0; block->curr_n_fields = n_fields; @@ -1611,14 +1607,15 @@ btr_search_move_or_delete_hash_entries( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - ut_a(!new_block->is_hashed || new_block->index == index); - ut_a(!block->is_hashed || block->index == index); - ut_a(!(new_block->is_hashed || block->is_hashed) - || !dict_index_is_ibuf(index)); rw_lock_s_lock(&btr_search_latch); - if (new_block->is_hashed) { + ut_a(!new_block->index || new_block->index == index); + ut_a(!block->index || block->index == index); + ut_a(!(new_block->index || block->index) + || !dict_index_is_ibuf(index)); + + if (new_block->index) { rw_lock_s_unlock(&btr_search_latch); @@ -1627,7 +1624,7 @@ btr_search_move_or_delete_hash_entries( return; } - if (block->is_hashed) { + if (block->index) { n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; @@ -1664,42 +1661,48 @@ btr_search_update_hash_on_delete( { hash_table_t* table; buf_block_t* block; - rec_t* rec; + const rec_t* rec; ulint fold; - dulint index_id; + dict_index_t* index; ulint offsets_[REC_OFFS_NORMAL_SIZE]; mem_heap_t* heap = NULL; rec_offs_init(offsets_); - rec = btr_cur_get_rec(cursor); - block = btr_cur_get_block(cursor); #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); + ut_a(index == cursor->index); ut_a(block->curr_n_fields + block->curr_n_bytes > 0); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(!dict_index_is_ibuf(index)); table = btr_search_sys->hash_index; - index_id = cursor->index->id; - fold = rec_fold(rec, rec_get_offsets(rec, cursor->index, offsets_, + rec = btr_cur_get_rec(cursor); + + fold = rec_fold(rec, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), - block->curr_n_fields, block->curr_n_bytes, index_id); + block->curr_n_fields, block->curr_n_bytes, index->id); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + rw_lock_x_lock(&btr_search_latch); - ha_search_and_delete_if_found(table, fold, rec); + if (block->index) { + ut_a(block->index == index); + + ha_search_and_delete_if_found(table, fold, rec); + } rw_lock_x_unlock(&btr_search_latch); } @@ -1717,6 +1720,7 @@ btr_search_update_hash_node_on_insert( { hash_table_t* table; buf_block_t* block; + dict_index_t* index; rec_t* rec; rec = btr_cur_get_rec(cursor); @@ -1727,16 +1731,25 @@ btr_search_update_hash_node_on_insert( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); + ut_a(cursor->index == index); + ut_a(!dict_index_is_ibuf(index)); rw_lock_x_lock(&btr_search_latch); + if (!block->index) { + + goto func_exit; + } + + ut_a(block->index == index); + if ((cursor->flag == BTR_CUR_HASH) && (cursor->n_fields == block->curr_n_fields) && (cursor->n_bytes == block->curr_n_bytes) @@ -1747,6 +1760,7 @@ btr_search_update_hash_node_on_insert( ha_search_and_update_if_found(table, cursor->fold, rec, block, page_rec_get_next(rec)); +func_exit: rw_lock_x_unlock(&btr_search_latch); } else { rw_lock_x_unlock(&btr_search_latch); @@ -1768,10 +1782,10 @@ btr_search_update_hash_on_insert( { hash_table_t* table; buf_block_t* block; + dict_index_t* index; rec_t* rec; rec_t* ins_rec; rec_t* next_rec; - dulint index_id; ulint fold; ulint ins_fold; ulint next_fold = 0; /* remove warning (??? bug ???) */ @@ -1796,15 +1810,15 @@ btr_search_update_hash_on_insert( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - if (!block->is_hashed) { + index = block->index; + + if (!index) { return; } - ut_a(block->index == cursor->index); - ut_a(!dict_index_is_ibuf(cursor->index)); - - index_id = cursor->index->id; + ut_a(index == cursor->index); + ut_a(!dict_index_is_ibuf(index)); n_fields = block->curr_n_fields; n_bytes = block->curr_n_bytes; @@ -1813,21 +1827,21 @@ btr_search_update_hash_on_insert( ins_rec = page_rec_get_next(rec); next_rec = page_rec_get_next(ins_rec); - offsets = rec_get_offsets(ins_rec, cursor->index, offsets, + offsets = rec_get_offsets(ins_rec, index, offsets, ULINT_UNDEFINED, &heap); - ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index_id); + ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index->id); if (!page_rec_is_supremum(next_rec)) { - offsets = rec_get_offsets(next_rec, cursor->index, offsets, + offsets = rec_get_offsets(next_rec, index, offsets, n_fields + (n_bytes > 0), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, - n_bytes, index_id); + n_bytes, index->id); } if (!page_rec_is_infimum(rec)) { - offsets = rec_get_offsets(rec, cursor->index, offsets, + offsets = rec_get_offsets(rec, index, offsets, n_fields + (n_bytes > 0), &heap); - fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); + fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); } else { if (left_side) { @@ -1835,6 +1849,10 @@ btr_search_update_hash_on_insert( locked = TRUE; + if (!btr_search_enabled) { + goto function_exit; + } + ha_insert_for_fold(table, ins_fold, block, ins_rec); } @@ -1848,6 +1866,10 @@ btr_search_update_hash_on_insert( rw_lock_x_lock(&btr_search_latch); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1866,6 +1888,10 @@ check_next_rec: rw_lock_x_lock(&btr_search_latch); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } ha_insert_for_fold(table, ins_fold, block, ins_rec); @@ -1881,6 +1907,10 @@ check_next_rec: rw_lock_x_lock(&btr_search_latch); locked = TRUE; + + if (!btr_search_enabled) { + goto function_exit; + } } if (!left_side) { @@ -1888,7 +1918,7 @@ check_next_rec: ha_insert_for_fold(table, ins_fold, block, ins_rec); /* fputs("Hash insert for ", stderr); - dict_index_name_print(stderr, cursor->index); + dict_index_name_print(stderr, index); fprintf(stderr, " fold %lu\n", ins_fold); */ } else { @@ -1995,7 +2025,7 @@ btr_search_validate(void) + (block->curr_n_bytes > 0), &heap); - if (!block->is_hashed || node->fold + if (!block->index || node->fold != rec_fold((rec_t*)(node->data), offsets, block->curr_n_fields, @@ -2030,10 +2060,10 @@ btr_search_validate(void) rec_print_new(stderr, (rec_t*)node->data, offsets); fprintf(stderr, "\nInnoDB: on that page." - " Page mem address %p, is hashed %lu," + " Page mem address %p, is hashed %p," " n fields %lu, n bytes %lu\n" "InnoDB: side %lu\n", - (void*) page, (ulong) block->is_hashed, + (void*) page, (void*) block->index, (ulong) block->curr_n_fields, (ulong) block->curr_n_bytes, (ulong) block->curr_left_side); diff --git a/storage/xtradb/buf/buf0buddy.c b/storage/xtradb/buf/buf0buddy.c index 673d6c55efc..71d897d367c 100644 --- a/storage/xtradb/buf/buf0buddy.c +++ b/storage/xtradb/buf/buf0buddy.c @@ -354,7 +354,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; @@ -442,6 +441,7 @@ buf_buddy_relocate( if (mutex && 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; diff --git a/storage/xtradb/buf/buf0buf.c b/storage/xtradb/buf/buf0buf.c index c76973a42ef..6998f1b53ac 100644 --- a/storage/xtradb/buf/buf0buf.c +++ b/storage/xtradb/buf/buf0buf.c @@ -57,7 +57,9 @@ Created 11/5/1995 Heikki Tuuri /* prototypes for new functions added to ha_innodb.cc */ trx_t* innobase_get_trx(); -inline void _increment_page_get_statistics(buf_block_t* block, trx_t* trx) +static inline +void +_increment_page_get_statistics(buf_block_t* block, trx_t* trx) { ulint block_hash; ulint block_hash_byte; @@ -829,11 +831,8 @@ buf_chunk_init( for (i = chunk->size; i--; ) { buf_block_init(block, frame); + UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE); -#ifdef HAVE_valgrind - /* Wipe contents of frame to eliminate a Purify warning */ - memset(block->frame, '\0', UNIV_PAGE_SIZE); -#endif /* Add the block to the free list */ mutex_enter(&free_list_mutex); UT_LIST_ADD_LAST(free, buf_pool->free, (&block->page)); @@ -1043,6 +1042,24 @@ buf_pool_free(void) { buf_chunk_t* chunk; buf_chunk_t* chunks; + buf_page_t* bpage; + + bpage = UT_LIST_GET_LAST(buf_pool->LRU); + while (bpage != NULL) { + buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage); + enum buf_page_state state = buf_page_get_state(bpage); + + ut_ad(buf_page_in_file(bpage)); + ut_ad(bpage->in_LRU_list); + + if (state != BUF_BLOCK_FILE_PAGE) { + /* We must not have any dirty block. */ + ut_ad(state == BUF_BLOCK_ZIP_PAGE); + buf_page_free_descriptor(bpage); + } + + bpage = prev_bpage; + } chunks = buf_pool->chunks; chunk = chunks + buf_pool->n_chunks; @@ -1059,86 +1076,42 @@ buf_pool_free(void) } /********************************************************************//** -Drops the adaptive hash index. To prevent a livelock, this function -is only to be called while holding btr_search_latch and while -btr_search_enabled == FALSE. */ +Clears the adaptive hash index on all pages in the buffer pool. */ UNIV_INTERN void -buf_pool_drop_hash_index(void) -/*==========================*/ +buf_pool_clear_hash_index(void) +/*===========================*/ { - ibool released_search_latch; + buf_chunk_t* chunks = buf_pool->chunks; + buf_chunk_t* chunk = chunks + buf_pool->n_chunks; #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(!btr_search_enabled); - do { - buf_chunk_t* chunks = buf_pool->chunks; - buf_chunk_t* chunk = chunks + buf_pool->n_chunks; + while (--chunk >= chunks) { + buf_block_t* block = chunk->blocks; + ulint i = chunk->size; - released_search_latch = FALSE; + for (; i--; block++) { + dict_index_t* index = block->index; - while (--chunk >= chunks) { - buf_block_t* block = chunk->blocks; - ulint i = chunk->size; + /* We can set block->index = NULL + when we have an x-latch on btr_search_latch; + see the comment in buf0buf.h */ - for (; i--; block++) { - /* block->is_hashed cannot be modified - when we have an x-latch on btr_search_latch; - see the comment in buf0buf.h */ - - if (buf_block_get_state(block) - != BUF_BLOCK_FILE_PAGE - || !block->is_hashed) { - continue; - } - - /* To follow the latching order, we - have to release btr_search_latch - before acquiring block->latch. */ - rw_lock_x_unlock(&btr_search_latch); - /* When we release the search latch, - we must rescan all blocks, because - some may become hashed again. */ - released_search_latch = TRUE; - - rw_lock_x_lock(&block->lock); - - /* This should be guaranteed by the - callers, which will be holding - btr_search_enabled_mutex. */ - ut_ad(!btr_search_enabled); - - /* Because we did not buffer-fix the - block by calling buf_block_get_gen(), - it is possible that the block has been - allocated for some other use after - btr_search_latch was released above. - We do not care which file page the - block is mapped to. All we want to do - is to drop any hash entries referring - to the page. */ - - /* It is possible that - block->page.state != BUF_FILE_PAGE. - Even that does not matter, because - btr_search_drop_page_hash_index() will - check block->is_hashed before doing - anything. block->is_hashed can only - be set on uncompressed file pages. */ - - btr_search_drop_page_hash_index(block); - - rw_lock_x_unlock(&block->lock); - - rw_lock_x_lock(&btr_search_latch); - - ut_ad(!btr_search_enabled); + if (!index) { + /* Not hashed */ + continue; } + + block->index = NULL; +# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG + block->n_pointers = 0; +# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ } - } while (released_search_latch); + } } /********************************************************************//** @@ -1283,63 +1256,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(); - rw_lock_s_lock(&page_hash_latch); - - 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(); - rw_lock_s_unlock(&page_hash_latch); -} - -/********************************************************************//** -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 -pool if it is found there. -@return TRUE if page hash index is built in search system */ -UNIV_INTERN -ibool -buf_page_peek_if_search_hashed( -/*===========================*/ - ulint space, /*!< in: space id */ - ulint offset) /*!< in: page number */ -{ - buf_block_t* block; - ibool is_hashed; - - //buf_pool_mutex_enter(); - rw_lock_s_lock(&page_hash_latch); - - block = (buf_block_t*) buf_page_hash_get(space, offset); - - if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { - is_hashed = FALSE; - } else { - is_hashed = block->is_hashed; - } - - //buf_pool_mutex_exit(); - rw_lock_s_unlock(&page_hash_latch); - - return(is_hashed); -} - #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG /********************************************************************//** Sets file_page_was_freed TRUE if the page is found in the buffer pool. @@ -1623,7 +1539,6 @@ buf_block_init_low( block->index = NULL; block->n_hash_helps = 0; - block->is_hashed = FALSE; block->n_fields = 1; block->n_bytes = 0; block->left_side = TRUE; @@ -2540,7 +2455,7 @@ buf_page_get_known_nowait( ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG - ut_a(block->page.file_page_was_freed == FALSE); + ut_a(mode == BUF_KEEP_OLD || !block->page.file_page_was_freed); #endif #ifdef UNIV_IBUF_COUNT_DEBUG @@ -3312,14 +3227,8 @@ corrupt: } } - //enum buf_flush flush_type; - //buf_pool_mutex_enter(); if (io_type == BUF_IO_WRITE) { - //flush_type = buf_page_get_flush_type(bpage); - /* to keep consistency at buf_LRU_insert_zip_clean() */ - //if (flush_type == BUF_FLUSH_LRU) { /* optimistic! */ - mutex_enter(&LRU_list_mutex); - //} + mutex_enter(&LRU_list_mutex); } block_mutex = buf_page_get_mutex_enter(bpage); ut_a(block_mutex); diff --git a/storage/xtradb/buf/buf0lru.c b/storage/xtradb/buf/buf0lru.c index df74ccf500f..c53b71632c2 100644 --- a/storage/xtradb/buf/buf0lru.c +++ b/storage/xtradb/buf/buf0lru.c @@ -292,7 +292,7 @@ next_page: //mutex_enter(&((buf_block_t*) bpage)->mutex); is_fixed = bpage->buf_fix_count > 0 - || !((buf_block_t*) bpage)->is_hashed; + || !((buf_block_t*) bpage)->index; //mutex_exit(&((buf_block_t*) bpage)->mutex); if (is_fixed) { @@ -451,7 +451,7 @@ scan_again: if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { /* This is a compressed-only block descriptor. Do nothing. */ - } else if (((buf_block_t*) bpage)->is_hashed) { + } else if (((buf_block_t*) bpage)->index) { ulint page_no; ulint zip_size; @@ -465,7 +465,7 @@ scan_again: mutex_exit(block_mutex); /* Note that the following call will acquire - an S-latch on the page */ + and release an X-latch on the page. */ btr_search_drop_page_hash_when_freed( id, zip_size, page_no); @@ -537,7 +537,7 @@ buf_LRU_mark_space_was_deleted( for (j = chunk->size; j--; block++) { if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE - || !block->is_hashed + || !(block->index != NULL) || buf_page_get_space(&block->page) != id) { continue; } diff --git a/storage/xtradb/compile-innodb b/storage/xtradb/compile-innodb new file mode 100644 index 00000000000..82601f03ae9 --- /dev/null +++ b/storage/xtradb/compile-innodb @@ -0,0 +1,24 @@ +#! /bin/sh +# +# Copyright (c) 2006, 2009, Innobase Oy. 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 +# Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# 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 +# + +path=`dirname $0` +. "$path/SETUP.sh" + +extra_flags="$pentium_cflags $fast_cflags -g" +extra_configs="$pentium_configs $static_link --with-plugins=innobase" + +. "$path/FINISH.sh" diff --git a/storage/xtradb/compile-innodb-debug b/storage/xtradb/compile-innodb-debug new file mode 100644 index 00000000000..efb4abf88d5 --- /dev/null +++ b/storage/xtradb/compile-innodb-debug @@ -0,0 +1,24 @@ +#! /bin/sh +# +# Copyright (c) 2005, 2009, Innobase Oy. 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 +# Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# 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 +# + +path=`dirname $0` +. "$path/SETUP.sh" $@ --with-debug=full + +extra_flags="$pentium_cflags $debug_cflags" +extra_configs="$pentium_configs $debug_configs --with-plugins=innobase" + +. "$path/FINISH.sh" diff --git a/storage/xtradb/dict/dict0crea.c b/storage/xtradb/dict/dict0crea.c index c6e7d588e72..a913d4f0840 100644 --- a/storage/xtradb/dict/dict0crea.c +++ b/storage/xtradb/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 @@ -899,7 +899,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/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c index a8a1d7a11e6..574b0e5d7da 100644 --- a/storage/xtradb/dict/dict0dict.c +++ b/storage/xtradb/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 @@ -24,6 +24,8 @@ Created 1/8/1996 Heikki Tuuri ***********************************************************************/ #include "dict0dict.h" +#include "m_string.h" +#include "my_sys.h" #ifdef UNIV_NONINL #include "dict0dict.ic" @@ -270,15 +272,39 @@ dict_table_stats_lock( ulint latch_mode) /*!< in: RW_S_LATCH or RW_X_LATCH */ { + rw_lock_t *want, *got; + ut_ad(table != NULL); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); switch (latch_mode) { case RW_S_LATCH: - rw_lock_s_lock(GET_TABLE_STATS_LATCH(table)); + /* Lock one of dict_table_stats_latches in S-mode. + Latch is picked using table->id. table->id might be + changed while we are waiting for lock to be grabbed */ + for (;;) { + want= GET_TABLE_STATS_LATCH(table); + rw_lock_s_lock(want); + got= GET_TABLE_STATS_LATCH(table); + if (want == got) { + break; + } + rw_lock_s_unlock(want); + } break; case RW_X_LATCH: - rw_lock_x_lock(GET_TABLE_STATS_LATCH(table)); + /* Lock one of dict_table_stats_latches in X-mode. + Latch is picked using table->id. table->id might be + changed while we are waiting for lock to be grabbed */ + for (;;) { + want= GET_TABLE_STATS_LATCH(table); + rw_lock_x_lock(want); + got= GET_TABLE_STATS_LATCH(table); + if (want == got) { + break; + } + rw_lock_x_unlock(want); + } break; case RW_NO_LATCH: /* fall through */ @@ -1164,12 +1190,21 @@ dict_table_change_id_in_cache( dict_table_t* table, /*!< in/out: table object already in cache */ dulint new_id) /*!< in: new id to set */ { + dict_table_t table_tmp; + ut_ad(table); ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); /* Remove the table from the hash table of id's */ + /* Lock is needed to prevent dict_table_stats_latches from + being leaked. dict_table_stats_lock picks one latch using + table->id. We are changing table->id below. That is why + we also should remember the old value to unlock table */ + dict_table_stats_lock(table, RW_X_LATCH); + table_tmp= *table; + HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash, ut_fold_dulint(table->id), table); table->id = new_id; @@ -1177,6 +1212,8 @@ dict_table_change_id_in_cache( /* Add the table back to the hash table */ HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, ut_fold_dulint(table->id), table); + + dict_table_stats_unlock(&table_tmp, RW_X_LATCH); } /**********************************************************************//** @@ -1724,7 +1761,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)) { @@ -2338,6 +2377,8 @@ dict_foreign_free( /*==============*/ dict_foreign_t* foreign) /*!< in, own: foreign key struct */ { + ut_a(foreign->foreign_table->n_foreign_key_checks_running == 0); + mem_heap_free(foreign->heap); } @@ -4306,19 +4347,26 @@ dict_reload_statistics( heap = mem_heap_create(1000); while (index) { + mtr_t mtr; + if (table->is_corrupt) { ut_a(srv_pass_corrupt_table); mem_heap_free(heap); return(FALSE); } - size = btr_get_size(index, BTR_TOTAL_SIZE); + mtr_start(&mtr); + mtr_s_lock(dict_index_get_lock(index), &mtr); + + size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); index->stat_index_size = size; *sum_of_index_sizes += size; - size = btr_get_size(index, BTR_N_LEAF_PAGES); + size = btr_get_size(index, BTR_N_LEAF_PAGES, &mtr); + + mtr_commit(&mtr); if (size == 0) { /* The root node of the tree is a leaf */ @@ -4668,16 +4716,27 @@ dict_update_statistics( (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO && dict_index_is_clust(index)))) { + mtr_t mtr; ulint size; - size = btr_get_size(index, BTR_TOTAL_SIZE); - index->stat_index_size = size; + mtr_start(&mtr); + mtr_s_lock(dict_index_get_lock(index), &mtr); - sum_of_index_sizes += size; + size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); - size = btr_get_size(index, BTR_N_LEAF_PAGES); + if (size != ULINT_UNDEFINED) { + sum_of_index_sizes += size; + index->stat_index_size = size; + size = btr_get_size( + index, BTR_N_LEAF_PAGES, &mtr); + } - if (size == 0) { + mtr_commit(&mtr); + + switch (size) { + case ULINT_UNDEFINED: + goto fake_statistics; + case 0: /* The root node of the tree is a leaf */ size = 1; } @@ -4694,6 +4753,7 @@ dict_update_statistics( various means, also via secondary indexes. */ ulint i; +fake_statistics: sum_of_index_sizes++; index->stat_index_size = index->stat_n_leaf_pages = 1; diff --git a/storage/xtradb/dict/dict0load.c b/storage/xtradb/dict/dict0load.c index 64d7fad3557..d026306a646 100644 --- a/storage/xtradb/dict/dict0load.c +++ b/storage/xtradb/dict/dict0load.c @@ -430,7 +430,7 @@ loop: object and check that the .ibd file exists. */ fil_open_single_table_tablespace(FALSE, space_id, - flags, name); + flags, name, NULL); } mem_free(name); @@ -1023,7 +1023,7 @@ err_exit: if (!fil_open_single_table_tablespace( TRUE, space, flags == DICT_TF_COMPACT ? 0 : - flags & ~(~0 << DICT_TF_BITS), name)) { + flags & ~(~0 << DICT_TF_BITS), name, NULL)) { /* We failed to find a sensible tablespace file */ diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c index 17ca4cb1745..1cc6654a88e 100644 --- a/storage/xtradb/fil/fil0fil.c +++ b/storage/xtradb/fil/fil0fil.c @@ -183,7 +183,7 @@ struct fil_space_struct { .ibd file of tablespace and want to stop temporarily posting of new i/o requests on the file */ - ibool stop_ibuf_merges; + ibool stop_new_ops; /*!< we set this TRUE when we start deleting a single-table tablespace */ ibool is_being_deleted; @@ -208,12 +208,13 @@ struct fil_space_struct { ulint n_pending_flushes; /*!< this is positive when flushing the tablespace to disk; dropping of the tablespace is forbidden if this is positive */ - ulint n_pending_ibuf_merges;/*!< this is positive - when merging insert buffer entries to - a page so that we may need to access - the ibuf bitmap page in the - tablespade: dropping of the tablespace - is forbidden if this is positive */ + ulint n_pending_ops;/*!< this is positive when we + have pending operations against this + tablespace. The pending operations can + be ibuf merges or lock validation code + trying to read a block. + Dropping of the tablespace is forbidden + if this is positive */ hash_node_t hash; /*!< hash chain node */ hash_node_t name_hash;/*!< hash chain the name_hash table */ #ifndef UNIV_HOTBACKUP @@ -928,11 +929,6 @@ retry: return; } - if (fil_system->n_open < fil_system->max_n_open) { - - return; - } - space = fil_space_get_by_id(space_id); if (space != NULL && space->stop_ios) { @@ -949,6 +945,25 @@ retry: mutex_exit(&fil_system->mutex); +#ifndef UNIV_HOTBACKUP + + /* Wake the i/o-handler threads to make sure pending + i/o's are performed */ + os_aio_simulated_wake_handler_threads(); + + /* The sleep here is just to give IO helper threads a + bit of time to do some work. It is not required that + all IO related to the tablespace being renamed must + be flushed here as we do fil_flush() in + fil_rename_tablespace() as well. */ + os_thread_sleep(20000); + +#endif /* UNIV_HOTBACKUP */ + + /* Flush tablespaces so that we can close modified + files in the LRU list */ + fil_flush_file_spaces(FIL_TABLESPACE); + os_thread_sleep(20000); count2++; @@ -956,6 +971,11 @@ retry: goto retry; } + if (fil_system->n_open < fil_system->max_n_open) { + + return; + } + /* If the file is already open, no need to do anything; if the space does not exist, we handle the situation in the function which called this function */ @@ -1228,7 +1248,7 @@ try_again: } space->stop_ios = FALSE; - space->stop_ibuf_merges = FALSE; + space->stop_new_ops = FALSE; space->is_being_deleted = FALSE; space->purpose = purpose; space->size = 0; @@ -1237,7 +1257,7 @@ try_again: space->n_reserved_extents = 0; space->n_pending_flushes = 0; - space->n_pending_ibuf_merges = 0; + space->n_pending_ops = 0; UT_LIST_INIT(space->chain); space->magic_n = FIL_SPACE_MAGIC_N; @@ -1840,13 +1860,12 @@ fil_read_flushed_lsn_and_arch_log_no( #ifndef UNIV_HOTBACKUP /*******************************************************************//** -Increments the count of pending insert buffer page merges, if space is not -being deleted. -@return TRUE if being deleted, and ibuf merges should be skipped */ +Increments the count of pending operation, if space is not being deleted. +@return TRUE if being deleted, and operation should be skipped */ UNIV_INTERN ibool -fil_inc_pending_ibuf_merges( -/*========================*/ +fil_inc_pending_ops( +/*================*/ ulint id) /*!< in: space id */ { fil_space_t* space; @@ -1862,13 +1881,13 @@ fil_inc_pending_ibuf_merges( (ulong) id); } - if (space == NULL || space->stop_ibuf_merges) { + if (space == NULL || space->stop_new_ops) { mutex_exit(&fil_system->mutex); return(TRUE); } - space->n_pending_ibuf_merges++; + space->n_pending_ops++; mutex_exit(&fil_system->mutex); @@ -1876,11 +1895,11 @@ fil_inc_pending_ibuf_merges( } /*******************************************************************//** -Decrements the count of pending insert buffer page merges. */ +Decrements the count of pending operations. */ UNIV_INTERN void -fil_decr_pending_ibuf_merges( -/*=========================*/ +fil_decr_pending_ops( +/*=================*/ ulint id) /*!< in: space id */ { fil_space_t* space; @@ -1891,13 +1910,13 @@ fil_decr_pending_ibuf_merges( if (space == NULL) { fprintf(stderr, - "InnoDB: Error: decrementing ibuf merge of a" - " dropped tablespace %lu\n", + "InnoDB: Error: decrementing pending operation" + " of a dropped tablespace %lu\n", (ulong) id); } if (space != NULL) { - space->n_pending_ibuf_merges--; + space->n_pending_ops--; } mutex_exit(&fil_system->mutex); @@ -2187,15 +2206,15 @@ fil_delete_tablespace( char* path; ut_a(id != 0); -stop_ibuf_merges: +stop_new_ops: mutex_enter(&fil_system->mutex); space = fil_space_get_by_id(id); if (space != NULL) { - space->stop_ibuf_merges = TRUE; + space->stop_new_ops = TRUE; - if (space->n_pending_ibuf_merges == 0) { + if (space->n_pending_ops == 0) { mutex_exit(&fil_system->mutex); count = 0; @@ -2209,9 +2228,10 @@ stop_ibuf_merges: ut_print_filename(stderr, space->name); fprintf(stderr, ",\n" "InnoDB: but there are %lu pending" - " ibuf merges on it.\n" + " operations (most likely ibuf merges)" + " on it.\n" "InnoDB: Loop %lu.\n", - (ulong) space->n_pending_ibuf_merges, + (ulong) space->n_pending_ops, (ulong) count); } @@ -2220,7 +2240,7 @@ stop_ibuf_merges: os_thread_sleep(20000); count++; - goto stop_ibuf_merges; + goto stop_new_ops; } } @@ -2246,7 +2266,7 @@ try_again: } ut_a(space); - ut_a(space->n_pending_ibuf_merges == 0); + ut_a(space->n_pending_ops == 0); space->is_being_deleted = TRUE; @@ -2523,7 +2543,7 @@ fil_rename_tablespace( retry: count++; - if (count > 1000) { + if (!(count % 1000)) { ut_print_timestamp(stderr); fputs(" InnoDB: Warning: problems renaming ", stderr); ut_print_filename(stderr, old_name); @@ -3124,8 +3144,11 @@ fil_open_single_table_tablespace( accessing the first page of the file */ ulint id, /*!< in: space id */ ulint flags, /*!< in: tablespace flags */ - const char* name) /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + trx_t* trx) /*!< in: transaction. This is only used + for IMPORT TABLESPACE, must be NULL + otherwise */ { os_file_t file; char* filepath; @@ -3342,6 +3365,11 @@ skip_info: /* over write space id of all pages */ rec_offs_init(offsets_); + /* Unlock the data dictionary to not block queries + accessing other tables */ + ut_a(trx); + row_mysql_unlock_data_dictionary(trx); + fprintf(stderr, "InnoDB: Progress in %%:"); for (offset = 0; offset < free_limit_bytes; @@ -3543,6 +3571,9 @@ skip_write: fprintf(stderr, " done.\n"); + /* Reacquire the data dictionary lock */ + row_mysql_lock_data_dictionary(trx); + /* update SYS_INDEXES set root page */ index = dict_table_get_first_index(table); while (index) { @@ -3835,7 +3866,7 @@ convert_err_exit: level = btr_page_get_level(page, &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); btr_page_create(new_block, new_page_zip, index, level, &mtr); @@ -3883,7 +3914,7 @@ convert_err_exit: split_rec = page_get_middle_rec(page); new_block = btr_page_alloc(index, page_no + 1, FSP_UP, - 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, index, diff --git a/storage/xtradb/fsp/fsp0fsp.c b/storage/xtradb/fsp/fsp0fsp.c index c8e4f8e269c..1b437c226a7 100644 --- a/storage/xtradb/fsp/fsp0fsp.c +++ b/storage/xtradb/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2012, 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 *****************************************************************************/ @@ -273,15 +273,13 @@ fseg_n_reserved_pages_low( /********************************************************************//** Marks a page used. The page must reside within the extents of the given segment. */ -static +static __attribute__((nonnull)) void fseg_mark_page_used( /*================*/ fseg_inode_t* seg_inode,/*!< in: segment inode */ - ulint space, /*!< in: space id */ - ulint zip_size,/*!< in: compressed page size in bytes - or 0 for uncompressed pages */ ulint page, /*!< in: page offset */ + xdes_t* descr, /* extent descriptor */ mtr_t* mtr); /*!< in: mtr */ /**********************************************************************//** Returns the first extent descriptor for a segment. We think of the extent @@ -312,28 +310,38 @@ 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 fragmentation. -@return the allocated page number, FIL_NULL if no page could be allocated */ +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ static -ulint +buf_block_t* 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 */ - ulint hint, /*!< in: hint of which page would be desirable */ + 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: mtr or another mini-transaction + in which the page should be initialized. + If init_mtr!=mtr, but the page is already + latched in mtr, do not initialize the page. */ + __attribute__((warn_unused_result, nonnull)); #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** @@ -703,23 +711,22 @@ xdes_calc_descriptor_index( /********************************************************************//** Gets pointer to a the extent descriptor of a page. The page where the extent -descriptor resides is x-locked. If the page offset is equal to the free limit -of the space, adds new extents from above the free limit to the space free -list, if not free limit == space size. This adding is necessary to make the -descriptor defined, as they are uninitialized above the free limit. +descriptor resides is x-locked. This function no longer extends the data +file. @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 +exist in the space or if the offset is >= the free limit */ +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; @@ -727,11 +734,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); @@ -739,19 +744,10 @@ xdes_get_descriptor_with_space_hdr( zip_size = dict_table_flags_to_zip_size( mach_read_from_4(sp_header + FSP_SPACE_FLAGS)); - /* If offset is >= size or > limit, return NULL */ - - if ((offset >= size) || (offset > limit)) { - + if ((offset >= size) || (offset >= limit)) { return(NULL); } - /* If offset is == limit, fill free list of the space. */ - - if (offset == limit) { - fsp_fill_free_list(FALSE, space, sp_header, mtr); - } - descr_page_no = xdes_calc_descriptor_page(zip_size, offset); if (descr_page_no == 0) { @@ -781,7 +777,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( /*================*/ @@ -790,7 +786,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; @@ -1174,14 +1170,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; @@ -1206,7 +1202,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( /*=====================*/ @@ -1216,8 +1212,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; @@ -1353,7 +1349,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; @@ -1552,29 +1548,120 @@ fsp_alloc_free_extent( } /**********************************************************************//** -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 */ +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); + } +} + +/**********************************************************************//** +Gets a buffer block for an allocated page. + +NOTE: If init_mtr != mtr, the block will only be initialized if it was +not previously x-latched. It is assumed that the block has been +x-latched only by mtr, and freed in mtr in that case. + +@return block, initialized if init_mtr==mtr +or rw_lock_x_lock_count(&block->lock) == 1 */ static -ulint +buf_block_t* +fsp_page_create( +/*============*/ + ulint space, /*!< in: space id of the allocated page */ + ulint zip_size, /*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + ulint page_no, /*!< in: page number of the allocated page */ + mtr_t* mtr, /*!< in: mini-transaction of the allocation */ + mtr_t* init_mtr) /*!< in: mini-transaction for initializing + the page */ +{ + buf_block_t* block + = buf_page_create(space, page_no, zip_size, init_mtr); +#ifdef UNIV_SYNC_DEBUG + ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX) + == rw_lock_own(&block->lock, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + + /* Mimic buf_page_get(), but avoid the buf_pool->page_hash lookup. */ + rw_lock_x_lock(&block->lock); + mutex_enter(&block->mutex); + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + mutex_exit(&block->mutex); + mtr_memo_push(init_mtr, block, MTR_MEMO_PAGE_X_FIX); + + if (init_mtr == mtr + || rw_lock_get_x_lock_count(&block->lock) == 1) { + + /* Initialize the page, unless it was already + X-latched in mtr. (In this case, we would want to + allocate another page that has not been freed in mtr.) */ + ut_ad(init_mtr == mtr + || !mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); + + fsp_init_file_page(block, init_mtr); + } + + return(block); +} + +/**********************************************************************//** +Allocates a single free page from a space. The page is marked as used. +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ +static __attribute__((nonnull, warn_unused_result)) +buf_block_t* fsp_alloc_free_page( /*================*/ ulint space, /*!< in: space id */ 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); @@ -1601,7 +1688,7 @@ fsp_alloc_free_page( if (descr == NULL) { /* No free space left */ - return(FIL_NULL); + return(NULL); } xdes_set_state(descr, XDES_FREE_FRAG, mtr); @@ -1646,50 +1733,18 @@ fsp_alloc_free_page( " space size %lu. Page no %lu.\n", (ulong) space, (ulong) space_size, (ulong) page_no); - return(FIL_NULL); + return(NULL); } - success = fsp_try_extend_data_file_with_pages(space, page_no, - header, mtr); - if (!success) { + if (!fsp_try_extend_data_file_with_pages(space, page_no, + header, mtr)) { /* No disk space left */ - return(FIL_NULL); + return(NULL); } } - xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr); + fsp_alloc_from_free_frag(header, descr, free, 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); - } - - /* 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); - - block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); - buf_block_dbg_add_level(block, SYNC_FSP_PAGE); - - /* Prior contents of the page should be ignored */ - fsp_init_file_page(block, mtr); - - return(page_no); + return(fsp_page_create(space, zip_size, page_no, mtr, init_mtr)); } /**********************************************************************//** @@ -1728,6 +1783,9 @@ fsp_free_page( fputs("InnoDB: Dump of descriptor: ", stderr); ut_print_buf(stderr, ((byte*)descr) - 50, 200); putc('\n', stderr); + /* Crash in debug version, so that we get a core dump + of this corruption. */ + ut_ad(0); if (state == XDES_FREE) { /* We put here some fault tolerance: if the page @@ -1746,6 +1804,9 @@ fsp_free_page( "InnoDB: Dump of descriptor: ", (ulong) page); ut_print_buf(stderr, ((byte*)descr) - 50, 200); putc('\n', stderr); + /* Crash in debug version, so that we get a core dump + of this corruption. */ + ut_ad(0); /* We put here some fault tolerance: if the page is already free, return without doing anything! */ @@ -1780,6 +1841,8 @@ fsp_free_page( mtr); fsp_free_extent(space, zip_size, page, mtr); } + + mtr->n_freed_pages++; } /**********************************************************************//** @@ -1917,7 +1980,6 @@ fsp_alloc_seg_inode_page( fseg_inode_t* inode; buf_block_t* block; page_t* page; - ulint page_no; ulint space; ulint zip_size; ulint i; @@ -1928,15 +1990,15 @@ 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); + block = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr); - if (page_no == FIL_NULL) { + if (block == NULL) { return(FALSE); } - block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); + ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); block->check_index_page_at_flush = FALSE; @@ -2351,19 +2413,20 @@ fseg_create_general( } if (page == 0) { - page = fseg_alloc_free_page_low(space, zip_size, - inode, 0, FSP_UP, mtr); + block = fseg_alloc_free_page_low(space, zip_size, + inode, 0, FSP_UP, mtr, mtr); - if (page == FIL_NULL) { + if (block == NULL) { fsp_free_seg_inode(space, zip_size, inode, mtr); goto funct_exit; } - block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr); + ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); + header = byte_offset + buf_block_get_frame(block); - mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE, + mlog_write_ulint(buf_block_get_frame(block) + FIL_PAGE_TYPE, FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr); } @@ -2540,8 +2603,10 @@ fseg_fill_free_list( Allocates a free extent for the segment: looks first in the free list of the segment, then tries to allocate from the space free list. NOTE that the extent returned still resides in the segment free list, it is not yet taken off it! -@return allocated extent, still placed in the segment free list, NULL -if could not be allocated */ +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ static xdes_t* fseg_alloc_free_extent( @@ -2593,22 +2658,30 @@ fseg_alloc_free_extent( 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 number, FIL_NULL if no page could be allocated */ +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ static -ulint +buf_block_t* 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 */ - ulint hint, /*!< in: hint of which page would be desirable */ + 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: mtr or another mini-transaction + in which the page should be initialized. + If init_mtr!=mtr, but the page is already + latched in mtr, do not initialize the page. */ { fsp_header_t* space_header; ulint space_size; @@ -2619,7 +2692,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; @@ -2641,6 +2713,7 @@ fseg_alloc_free_page_low( if (descr == NULL) { /* Hint outside space or too high above free limit: reset hint */ + /* The file space header page is always allocated. */ hint = 0; descr = xdes_get_descriptor(space, zip_size, hint, mtr); } @@ -2652,15 +2725,19 @@ 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 + && reserved - used < reserved / FSEG_FILLFACTOR + && used >= FSEG_FRAG_LIMIT) { /* 2. We allocate the free extent from space and can take ========================================================= @@ -2678,7 +2755,7 @@ 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 ((direction != FSP_NO_DIR) && ((reserved - used) < reserved / FSEG_FILLFACTOR) @@ -2727,7 +2804,7 @@ fseg_alloc_free_page_low( first = flst_get_first(seg_inode + FSEG_FREE, mtr); } else { ut_error; - return(FIL_NULL); + return(NULL); } ret_descr = xdes_lst_get_descriptor(space, zip_size, @@ -2739,20 +2816,23 @@ 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_descr = NULL; + buf_block_t* block = fsp_alloc_free_page( + space, zip_size, hint, mtr, init_mtr); - frag_page_allocated = TRUE; - - if (ret_page != FIL_NULL) { + if (block != 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); + ut_a(n != ULINT_UNDEFINED); - fseg_set_nth_frag_page_no(seg_inode, n, ret_page, - mtr); + fseg_set_nth_frag_page_no( + seg_inode, n, buf_block_get_page_no(block), + mtr); } + + /* fsp_alloc_free_page() invoked fsp_init_file_page() + already. */ + return(block); /*-----------------------------------------------------------*/ } else { /* 7. We allocate a new extent and take its first page @@ -2770,7 +2850,7 @@ fseg_alloc_free_page_low( if (ret_page == FIL_NULL) { /* Page could not be allocated */ - return(FIL_NULL); + return(NULL); } if (space != 0) { @@ -2788,38 +2868,22 @@ fseg_alloc_free_page_low( " the space size %lu. Page no %lu.\n", (ulong) space, (ulong) space_size, (ulong) ret_page); - return(FIL_NULL); + return(NULL); } success = fsp_try_extend_data_file_with_pages( space, ret_page, space_header, mtr); if (!success) { /* No disk space left */ - return(FIL_NULL); + return(NULL); } } } - if (!frag_page_allocated) { - /* 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)); - - block = buf_page_create(space, ret_page, zip_size, 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))) { - ut_error; - } - - /* The prior contents of the page should be ignored */ - fsp_init_file_page(block, mtr); - +got_hinted_page: + /* 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. */ @@ -2829,25 +2893,31 @@ fseg_alloc_free_page_low( ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT, ret_page % FSP_EXTENT_SIZE, mtr) == TRUE); - fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr); + fseg_mark_page_used(seg_inode, ret_page, ret_descr, mtr); } - buf_reset_check_index_page_at_flush(space, ret_page); - - return(ret_page); + return(fsp_page_create( + space, dict_table_flags_to_zip_size( + mach_read_from_4(FSP_SPACE_FLAGS + + space_header)), + ret_page, mtr, init_mtr)); } /**********************************************************************//** 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 */ +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ UNIV_INTERN -ulint +buf_block_t* fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in: segment header */ - ulint hint, /*!< in: hint of which page would be desirable */ + 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 inserted there in order, into which @@ -2858,15 +2928,18 @@ 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. + If init_mtr!=mtr, but the page is already + latched in mtr, do not initialize the page. */ { fseg_inode_t* inode; ulint space; ulint flags; ulint zip_size; rw_lock_t* latch; - ibool success; - ulint page_no; + buf_block_t* block; ulint n_reserved; space = page_get_space_id(page_align(seg_header)); @@ -2891,43 +2964,20 @@ fseg_alloc_free_page_general( inode = fseg_inode_get(seg_header, space, zip_size, mtr); - if (!has_done_reservation) { - success = fsp_reserve_free_extents(&n_reserved, space, 2, - FSP_NORMAL, mtr); - if (!success) { - return(FIL_NULL); - } + if (!has_done_reservation + && !fsp_reserve_free_extents(&n_reserved, space, 2, + FSP_NORMAL, mtr)) { + return(NULL); } - page_no = fseg_alloc_free_page_low(space, zip_size, - inode, hint, direction, mtr); + block = fseg_alloc_free_page_low(space, zip_size, + inode, hint, direction, + mtr, init_mtr); if (!has_done_reservation) { fil_space_release_free_extents(space, n_reserved); } - 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)); + return(block); } /**********************************************************************//** @@ -3249,27 +3299,21 @@ fsp_get_available_space_in_free_extents( /********************************************************************//** Marks a page used. The page must reside within the extents of the given segment. */ -static +static __attribute__((nonnull)) void fseg_mark_page_used( /*================*/ fseg_inode_t* seg_inode,/*!< in: segment inode */ - ulint space, /*!< in: space id */ - ulint zip_size,/*!< in: compressed page size in bytes - or 0 for uncompressed pages */ ulint page, /*!< in: page offset */ + xdes_t* descr, /* extent descriptor */ mtr_t* mtr) /*!< in: mtr */ { - xdes_t* descr; ulint not_full_n_used; - ut_ad(seg_inode && mtr); ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); - descr = xdes_get_descriptor(space, zip_size, page, mtr); - ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr) == mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr)); @@ -3448,6 +3492,8 @@ crash: descr + XDES_FLST_NODE, mtr); fsp_free_extent(space, zip_size, page, mtr); } + + mtr->n_freed_pages++; } /**********************************************************************//** diff --git a/storage/xtradb/ha/ha0ha.c b/storage/xtradb/ha/ha0ha.c index 7f11917de0a..65046138275 100644 --- a/storage/xtradb/ha/ha0ha.c +++ b/storage/xtradb/ha/ha0ha.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, 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 @@ -88,40 +88,6 @@ ha_create_func( return(table); } -/*************************************************************//** -Empties a hash table and frees the memory heaps. */ -UNIV_INTERN -void -ha_clear( -/*=====*/ - hash_table_t* table) /*!< in, own: hash table */ -{ - ulint i; - ulint n; - - ut_ad(table); - ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); -#ifdef UNIV_SYNC_DEBUG - ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE)); -#endif /* UNIV_SYNC_DEBUG */ - -#ifndef UNIV_HOTBACKUP - /* Free the memory heaps. */ - n = table->n_mutexes; - - for (i = 0; i < n; i++) { - mem_heap_free(table->heaps[i]); - } -#endif /* !UNIV_HOTBACKUP */ - - /* Clear the hash table. */ - n = hash_get_n_cells(table); - - for (i = 0; i < n; i++) { - hash_get_nth_cell(table, i)->node = NULL; - } -} - /*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node @@ -140,7 +106,7 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data) /*!< in: data, must not be NULL */ + const rec_t* data) /*!< in: data, must not be NULL */ { hash_cell_t* cell; ha_node_t* node; @@ -153,7 +119,11 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(block->frame == page_align(data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ ASSERT_HASH_MUTEX_OWN(table, fold); + ut_ad(btr_search_enabled); hash = hash_calc_hash(fold, table); @@ -173,7 +143,6 @@ ha_insert_for_fold_func( prev_block->n_pointers--; block->n_pointers++; } - ut_ad(!btr_search_fully_disabled); # endif /* !UNIV_HOTBACKUP */ prev_node->block = block; @@ -186,13 +155,6 @@ ha_insert_for_fold_func( prev_node = prev_node->next; } - /* We are in the process of disabling hash index, do not add - new chain node */ - if (!btr_search_enabled) { - ut_ad(!btr_search_fully_disabled); - return(TRUE); - } - /* We have to allocate a new chain node */ node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)); @@ -250,6 +212,10 @@ ha_delete_hash_node( { ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG # ifndef UNIV_HOTBACKUP if (table->adaptive) { @@ -272,11 +238,11 @@ ha_search_and_update_if_found_func( /*===============================*/ hash_table_t* table, /*!< in/out: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data, /*!< in: pointer to the data */ + const rec_t* data, /*!< in: pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* new_block,/*!< in: block containing new_data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* new_data)/*!< in: new pointer to the data */ + const rec_t* new_data)/*!< in: new pointer to the data */ { ha_node_t* node; @@ -286,6 +252,13 @@ ha_search_and_update_if_found_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(new_block->frame == page_align(new_data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + + if (!btr_search_enabled) { + return; + } node = ha_search_with_data(table, fold, data); @@ -322,6 +295,10 @@ ha_remove_all_nodes_to_page( ut_ad(table); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_chain_get_first(table, fold); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 34e25b59ac4..3dacac1e258 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -26,8 +26,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 *****************************************************************************/ @@ -778,6 +778,12 @@ thd_to_trx( return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr)); } +my_bool +ha_innobase::is_fake_change_enabled(THD* thd) +{ + trx_t* trx = thd_to_trx(thd); + return (trx && trx->fake_changes); +} /********************************************************************//** Call this function when mysqld passes control to the client. That is to avoid deadlocks on the adaptive hash S-latch possibly held by thd. For more @@ -924,6 +930,9 @@ convert_error_code_to_mysql( case DB_OUT_OF_FILE_SPACE: return(HA_ERR_RECORD_FILE_FULL); + case DB_TABLE_IN_FK_CHECK: + return(HA_ERR_TABLE_IN_FK_CHECK); + case DB_TABLE_IS_BEING_USED: return(HA_ERR_WRONG_COMMAND); @@ -1094,6 +1103,20 @@ innobase_get_charset( return(thd_charset((THD*) mysql_thd)); } +/**********************************************************************//** +Get the current setting of the lower_case_table_names global parameter from +mysqld.cc. We do a dirty read because for one there is no synchronization +object and secondly there is little harm in doing so even if we get a torn +read. +@return value of lower_case_table_names */ +ulint +innobase_get_lower_case_table_names(void) +/*=====================================*/ +{ + return(lower_case_table_names); +} + + /**********************************************************************//** Determines the current SQL statement. @return SQL statement string */ @@ -2634,7 +2657,6 @@ skip_overwrite: /* Get the current high water mark format. */ innobase_file_format_check = (char*) trx_sys_file_format_max_get(); - btr_search_fully_disabled = (!btr_search_enabled); DBUG_RETURN(FALSE); error: DBUG_RETURN(TRUE); @@ -3366,52 +3388,140 @@ ha_innobase::primary_key_is_clustered() return(true); } +/** Always normalize table name to lower case on Windows */ +#ifdef __WIN__ +#define normalize_table_name(norm_name, name) \ + normalize_table_name_low(norm_name, name, TRUE) +#else +#define normalize_table_name(norm_name, name) \ + normalize_table_name_low(norm_name, name, FALSE) +#endif /* __WIN__ */ + /*****************************************************************//** Normalizes a table name string. A normalized name consists of the database name catenated to '/' and table name. An example: test/mytable. On Windows normalization puts both the database name and the -table name always to lower case. */ +table name always to lower case if "set_lower_case" is set to TRUE. */ static void -normalize_table_name( -/*=================*/ +normalize_table_name_low( +/*=====================*/ char* norm_name, /*!< out: normalized name as a null-terminated string */ - const char* name) /*!< in: table name string */ + const char* name, /*!< in: table name string */ + ibool set_lower_case) /*!< in: TRUE if we want to set + name to lower case */ { char* name_ptr; char* db_ptr; + ulint db_len; char* ptr; /* Scan name from the end */ - ptr = strend(name)-1; + ptr = strend(name) - 1; + /* seek to the last path separator */ while (ptr >= name && *ptr != '\\' && *ptr != '/') { ptr--; } name_ptr = ptr + 1; - DBUG_ASSERT(ptr > name); + /* skip any number of path separators */ + while (ptr >= name && (*ptr == '\\' || *ptr == '/')) { + ptr--; + } - ptr--; + DBUG_ASSERT(ptr >= name); + /* seek to the last but one path separator or one char before + the beginning of name */ + db_len = 0; while (ptr >= name && *ptr != '\\' && *ptr != '/') { ptr--; + db_len++; } db_ptr = ptr + 1; - memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name)); + memcpy(norm_name, db_ptr, db_len); - norm_name[name_ptr - db_ptr - 1] = '/'; + norm_name[db_len] = '/'; -#ifdef __WIN__ - innobase_casedn_str(norm_name); -#endif + memcpy(norm_name + db_len + 1, name_ptr, strlen(name_ptr) + 1); + + if (set_lower_case) { + innobase_casedn_str(norm_name); + } } +#if !defined(DBUG_OFF) +/********************************************************************* +Test normalize_table_name_low(). */ +static +void +test_normalize_table_name_low() +/*===========================*/ +{ + char norm_name[128]; + const char* test_data[][2] = { + /* input, expected result */ + {"./mysqltest/t1", "mysqltest/t1"}, + {"./test/#sql-842b_2", "test/#sql-842b_2"}, + {"./test/#sql-85a3_10", "test/#sql-85a3_10"}, + {"./test/#sql2-842b-2", "test/#sql2-842b-2"}, + {"./test/bug29807", "test/bug29807"}, + {"./test/foo", "test/foo"}, + {"./test/innodb_bug52663", "test/innodb_bug52663"}, + {"./test/t", "test/t"}, + {"./test/t1", "test/t1"}, + {"./test/t10", "test/t10"}, + {"/a/b/db/table", "db/table"}, + {"/a/b/db///////table", "db/table"}, + {"/a/b////db///////table", "db/table"}, + {"/var/tmp/mysqld.1/#sql842b_2_10", "mysqld.1/#sql842b_2_10"}, + {"db/table", "db/table"}, + {"ddd/t", "ddd/t"}, + {"d/ttt", "d/ttt"}, + {"d/t", "d/t"}, + {".\\mysqltest\\t1", "mysqltest/t1"}, + {".\\test\\#sql-842b_2", "test/#sql-842b_2"}, + {".\\test\\#sql-85a3_10", "test/#sql-85a3_10"}, + {".\\test\\#sql2-842b-2", "test/#sql2-842b-2"}, + {".\\test\\bug29807", "test/bug29807"}, + {".\\test\\foo", "test/foo"}, + {".\\test\\innodb_bug52663", "test/innodb_bug52663"}, + {".\\test\\t", "test/t"}, + {".\\test\\t1", "test/t1"}, + {".\\test\\t10", "test/t10"}, + {"C:\\a\\b\\db\\table", "db/table"}, + {"C:\\a\\b\\db\\\\\\\\\\\\\\table", "db/table"}, + {"C:\\a\\b\\\\\\\\db\\\\\\\\\\\\\\table", "db/table"}, + {"C:\\var\\tmp\\mysqld.1\\#sql842b_2_10", "mysqld.1/#sql842b_2_10"}, + {"db\\table", "db/table"}, + {"ddd\\t", "ddd/t"}, + {"d\\ttt", "d/ttt"}, + {"d\\t", "d/t"}, + }; + + for (size_t i = 0; i < UT_ARR_SIZE(test_data); i++) { + printf("test_normalize_table_name_low(): " + "testing \"%s\", expected \"%s\"... ", + test_data[i][0], test_data[i][1]); + + normalize_table_name_low(norm_name, test_data[i][0], FALSE); + + if (strcmp(norm_name, test_data[i][1]) == 0) { + printf("ok\n"); + } else { + printf("got \"%s\"\n", norm_name); + ut_error; + } + } +} +#endif /* !DBUG_OFF */ + /********************************************************************//** Get the upper limit of the MySQL integral and floating-point type. @return maximum allowed value for the field */ @@ -3803,6 +3913,8 @@ ha_innobase::open( THD* thd; ulint retries = 0; char* is_part = NULL; + ibool par_case_name_set = FALSE; + char par_case_name[MAX_FULL_NAME_LEN + 1]; DBUG_ENTER("ha_innobase::open"); @@ -3855,11 +3967,16 @@ ha_innobase::open( workaround for http://bugs.mysql.com/bug.php?id=33349. Look at support issue https://support.mysql.com/view.php?id=21080 for more details. */ +#ifdef __WIN__ + is_part = strstr(norm_name, "#p#"); +#else is_part = strstr(norm_name, "#P#"); +#endif /* __WIN__ */ + retry: /* Get pointer to a table object in InnoDB dictionary cache */ ib_table = dict_table_get(norm_name, TRUE); - + if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) { free_share(share); my_free(upd_buff, MYF(0)); @@ -3869,15 +3986,77 @@ retry: share->ib_table = ib_table; - - - - if (NULL == ib_table) { if (is_part && retries < 10) { - ++retries; - os_thread_sleep(100000); - goto retry; + /* MySQL partition engine hard codes the file name + separator as "#P#". The text case is fixed even if + lower_case_table_names is set to 1 or 2. This is true + for sub-partition names as well. InnoDB always + normalises file names to lower case on Windows, this + can potentially cause problems when copying/moving + tables between platforms. + + 1) If boot against an installation from Windows + platform, then its partition table name could + be all be in lower case in system tables. So we + will need to check lower case name when load table. + + 2) If we boot an installation from other case + sensitive platform in Windows, we might need to + check the existence of table name without lowering + case them in the system table. */ + if (innobase_get_lower_case_table_names() == 1) { + + if (!par_case_name_set) { +#ifndef __WIN__ + /* Check for the table using lower + case name, including the partition + separator "P" */ + memcpy(par_case_name, norm_name, + strlen(norm_name)); + par_case_name[strlen(norm_name)] = 0; + innobase_casedn_str(par_case_name); +#else + /* On Windows platfrom, check + whether there exists table name in + system table whose name is + not being normalized to lower case */ + normalize_table_name_low( + par_case_name, name, FALSE); +#endif + par_case_name_set = TRUE; + } + + ib_table = dict_table_get( + par_case_name, FALSE); + } + if (!ib_table) { + ++retries; + os_thread_sleep(100000); + goto retry; + } else { +#ifndef __WIN__ + sql_print_warning("Partition table %s opened " + "after converting to lower " + "case. The table may have " + "been moved from a case " + "in-sensitive file system. " + "Please recreate table in " + "the current file system\n", + norm_name); +#else + sql_print_warning("Partition table %s opened " + "after skipping the step to " + "lower case the table name. " + "The table may have been " + "moved from a case sensitive " + "file system. Please " + "recreate table in the " + "current file system\n", + norm_name); +#endif + goto table_opened; + } } if (is_part) { @@ -3908,6 +4087,8 @@ retry: DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); } +table_opened: + if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) { sql_print_error("MySQL is trying to open a table handle but " "the .ibd file for\ntable %s does not exist.\n" @@ -5178,8 +5359,7 @@ no_commit: switch (sql_command) { case SQLCOM_LOAD: - if ((trx->duplicates - & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) { + if (trx->duplicates) { goto set_max_autoinc; } @@ -5463,8 +5643,7 @@ ha_innobase::update_row( && table->next_number_field && new_row == table->record[0] && thd_sql_command(user_thd) == SQLCOM_INSERT - && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) - == TRX_DUP_IGNORE) { + && trx->duplicates) { ulonglong auto_inc; ulonglong col_max_value; @@ -5810,6 +5989,7 @@ ha_innobase::index_read( DBUG_ENTER("index_read"); ut_a(prebuilt->trx == thd_to_trx(user_thd)); + ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT); ha_statistic_increment(&SSV::ha_read_key_count); @@ -5846,6 +6026,7 @@ ha_innobase::index_read( (byte*) key_ptr, (ulint) key_len, prebuilt->trx); + DBUG_ASSERT(prebuilt->search_tuple->n_fields > 0); } else { /* We position the cursor to the last or the first entry in the index */ @@ -6986,6 +7167,8 @@ ha_innobase::create( DBUG_RETURN(HA_ERR_TO_BIG_ROW); } + ut_a(strlen(name) < sizeof(name2)); + strcpy(name2, name); normalize_table_name(norm_name, name2); @@ -7418,6 +7601,11 @@ ha_innobase::delete_table( DBUG_ENTER("ha_innobase::delete_table"); + DBUG_EXECUTE_IF( + "test_normalize_table_name_low", + test_normalize_table_name_low(); + ); + /* Strangely, MySQL passes the table name without the '.frm' extension, in contrast to ::create */ normalize_table_name(norm_name, name); @@ -7715,6 +7903,7 @@ ha_innobase::records_in_range( mem_heap_t* heap; DBUG_ENTER("records_in_range"); + DBUG_ASSERT(min_key || max_key); ut_a(prebuilt->trx == thd_to_trx(ha_thd())); @@ -7760,6 +7949,9 @@ ha_innobase::records_in_range( (const uchar*) 0), (ulint) (min_key ? min_key->length : 0), prebuilt->trx); + DBUG_ASSERT(min_key + ? range_start->n_fields > 0 + : range_start->n_fields == 0); row_sel_convert_mysql_key_to_innobase( range_end, (byte*) key_val_buff2, @@ -7768,6 +7960,9 @@ ha_innobase::records_in_range( (const uchar*) 0), (ulint) (max_key ? max_key->length : 0), prebuilt->trx); + DBUG_ASSERT(max_key + ? range_end->n_fields > 0 + : range_end->n_fields == 0); mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag : HA_READ_KEY_EXACT); @@ -8950,6 +9145,7 @@ ha_innobase::extra( break; case HA_EXTRA_RESET_STATE: reset_template(prebuilt); + thd_to_trx(ha_thd())->duplicates = 0; break; case HA_EXTRA_NO_KEYREAD: prebuilt->read_just_key = 0; @@ -8967,19 +9163,18 @@ ha_innobase::extra( parameters below. We must not invoke update_thd() either, because the calling threads may change. CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */ - case HA_EXTRA_IGNORE_DUP_KEY: + case HA_EXTRA_INSERT_WITH_UPDATE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE; break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE; + break; case HA_EXTRA_WRITE_CAN_REPLACE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE; break; case HA_EXTRA_WRITE_CANNOT_REPLACE: thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE; break; - case HA_EXTRA_NO_IGNORE_DUP_KEY: - thd_to_trx(ha_thd())->duplicates &= - ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE); - break; default:/* Do nothing */ ; } @@ -11894,6 +12089,13 @@ static MYSQL_SYSVAR_ULINT(lazy_drop_table, srv_lazy_drop_table, "e.g. for http://bugs.mysql.com/51325", NULL, NULL, 0, 0, 1, 0); +#ifdef UNIV_DEBUG +static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug, + PLUGIN_VAR_RQCMDARG, + "Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()", + NULL, NULL, 0, 0, 1024, 0); +#endif /* UNIV_DEBUG */ + static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(page_size), MYSQL_SYSVAR(log_block_size), @@ -11990,6 +12192,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(pass_corrupt_table), MYSQL_SYSVAR(lazy_drop_table), MYSQL_SYSVAR(fake_changes), +#ifdef UNIV_DEBUG + MYSQL_SYSVAR(trx_rseg_n_slots_debug), +#endif /* UNIV_DEBUG */ NULL }; diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index bfe7432b32d..1e18b3a22b9 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -136,6 +136,7 @@ class ha_innobase: public handler int close(void); double scan_time(); double read_time(uint index, uint ranges, ha_rows rows); + my_bool is_fake_change_enabled(THD *thd); bool is_corrupt() const; int write_row(uchar * buf); diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 37fddf71cbc..5efc3f96fa3 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 2005, 2012, 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 *****************************************************************************/ @@ -1024,7 +1024,9 @@ ha_innobase::prepare_drop_index( goto func_exit; } + rw_lock_x_lock(dict_index_get_lock(index)); index->to_be_dropped = TRUE; + rw_lock_x_unlock(dict_index_get_lock(index)); } /* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined @@ -1143,7 +1145,9 @@ func_exit: = dict_table_get_first_index(prebuilt->table); do { + rw_lock_x_lock(dict_index_get_lock(index)); index->to_be_dropped = FALSE; + rw_lock_x_unlock(dict_index_get_lock(index)); index = dict_table_get_next_index(index); } while (index); } @@ -1209,7 +1213,9 @@ ha_innobase::final_drop_index( for (index = dict_table_get_first_index(prebuilt->table); index; index = dict_table_get_next_index(index)) { + rw_lock_x_lock(dict_index_get_lock(index)); index->to_be_dropped = FALSE; + rw_lock_x_unlock(dict_index_get_lock(index)); } goto func_exit; diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc index fc7cd1c9b8f..b6e7da50bcf 100644 --- a/storage/xtradb/handler/i_s.cc +++ b/storage/xtradb/handler/i_s.cc @@ -768,7 +768,7 @@ i_s_innodb_buffer_pool_pages_index_fill( table->field[2]->store(block->page.offset); table->field[3]->store(page_get_n_recs(frame)); table->field[4]->store(page_get_data_size(frame)); - table->field[5]->store(block->is_hashed); + table->field[5]->store(block->index != NULL); /* is_hashed */ table->field[6]->store(block->page.access_time); table->field[7]->store(block->page.newest_modification != 0); table->field[8]->store(block->page.oldest_modification != 0); diff --git a/storage/xtradb/ibuf/ibuf0ibuf.c b/storage/xtradb/ibuf/ibuf0ibuf.c index 64dc9a5591d..ee9b85fa38c 100644 --- a/storage/xtradb/ibuf/ibuf0ibuf.c +++ b/storage/xtradb/ibuf/ibuf0ibuf.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2012, 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 *****************************************************************************/ @@ -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)); } @@ -498,7 +498,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); } @@ -1725,14 +1725,14 @@ ulint ibuf_add_free_page(void) /*====================*/ { - mtr_t mtr; - page_t* header_page; - ulint flags; - ulint zip_size; - ulint page_no; - page_t* page; - page_t* root; - page_t* bitmap_page; + mtr_t mtr; + page_t* header_page; + ulint flags; + ulint zip_size; + buf_block_t* block; + page_t* page; + page_t* root; + page_t* bitmap_page; mtr_start(&mtr); @@ -1753,34 +1753,24 @@ ibuf_add_free_page(void) of a deadlock. This is the reason why we created a special ibuf header page apart from the ibuf tree. */ - page_no = fseg_alloc_free_page( + block = fseg_alloc_free_page( header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP, &mtr); - if (page_no == FIL_NULL) { + if (block == NULL) { mtr_commit(&mtr); return(DB_STRONG_FAIL); } - { - buf_block_t* block; - - block = buf_page_get( - IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); - - - page = buf_block_get_frame(block); - } - + ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); ibuf_enter(); - 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); + /* Add the page to the free list and update the ibuf size data */ flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, @@ -1796,10 +1786,11 @@ ibuf_add_free_page(void) (level 2 page) */ bitmap_page = ibuf_bitmap_get_map_page( - IBUF_SPACE_ID, page_no, zip_size, &mtr); + IBUF_SPACE_ID, buf_block_get_page_no(block), zip_size, &mtr); ibuf_bitmap_page_set_bits( - bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr); + bitmap_page, buf_block_get_page_no(block), zip_size, + IBUF_BITMAP_IBUF, TRUE, &mtr); mtr_commit(&mtr); @@ -1900,8 +1891,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); } @@ -2095,7 +2085,15 @@ ibuf_get_merge_page_nos( } else { rec_page_no = ibuf_rec_get_page_no(rec); rec_space_id = ibuf_rec_get_space(rec); - ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO); + /* In the system tablespace, the smallest + possible secondary index leaf page number is + bigger than IBUF_TREE_ROOT_PAGE_NO (4). In + other tablespaces, the clustered index tree is + created at page 3, which makes page 4 the + smallest possible secondary index leaf page + (and that only after DROP INDEX). */ + ut_ad(rec_page_no + > IBUF_TREE_ROOT_PAGE_NO - (rec_space_id != 0)); } #ifdef UNIV_IBUF_DEBUG @@ -2413,7 +2411,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); @@ -2487,7 +2485,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); @@ -2980,7 +2978,7 @@ ibuf_insert_to_index_page( ut_ad(ibuf_inside()); ut_ad(dtuple_check_typed(entry)); - ut_ad(!buf_block_align(page)->is_hashed); + ut_ad(!buf_block_align(page)->index); if (UNIV_UNLIKELY(dict_table_is_comp(index->table) != (ibool)!!page_is_comp(page))) { @@ -3255,6 +3253,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)) { @@ -3289,7 +3288,7 @@ ibuf_merge_or_delete_for_page( function. When the counter is > 0, that prevents tablespace from being dropped. */ - tablespace_being_deleted = fil_inc_pending_ibuf_merges(space); + tablespace_being_deleted = fil_inc_pending_ops(space); if (UNIV_UNLIKELY(tablespace_being_deleted)) { /* Do not try to read the bitmap page from space; @@ -3313,7 +3312,7 @@ ibuf_merge_or_delete_for_page( mtr_commit(&mtr); if (!tablespace_being_deleted) { - fil_decr_pending_ibuf_merges(space); + fil_decr_pending_ops(space); } return; @@ -3410,7 +3409,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 @@ -3539,7 +3544,7 @@ reset_bit: if (update_ibuf_bitmap && !tablespace_being_deleted) { - fil_decr_pending_ibuf_merges(space); + fil_decr_pending_ops(space); } ibuf_exit(); diff --git a/storage/xtradb/include/btr0btr.h b/storage/xtradb/include/btr0btr.h index 1fe40965c0f..827f81eab97 100644 --- a/storage/xtradb/include/btr0btr.h +++ b/storage/xtradb/include/btr0btr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ @@ -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)) /**************************************************************//** Sets the index id field of a page. */ UNIV_INLINE @@ -378,8 +397,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. @@ -588,17 +606,23 @@ btr_parse_page_reorganize( #ifndef UNIV_HOTBACKUP /**************************************************************//** Gets the number of pages in a B-tree. -@return number of pages */ +@return number of pages, or ULINT_UNDEFINED if the index is unavailable */ UNIV_INTERN ulint btr_get_size( /*=========*/ dict_index_t* index, /*!< in: index */ - ulint flag); /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ + ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ + mtr_t* mtr) /*!< in/out: mini-transaction where index + is s-latched */ + __attribute__((nonnull, warn_unused_result)); /**************************************************************//** 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 */ +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ UNIV_INTERN buf_block_t* btr_page_alloc( @@ -609,7 +633,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. */ diff --git a/storage/xtradb/include/btr0btr.ic b/storage/xtradb/include/btr0btr.ic index e19c863300a..d729a58f9c7 100644 --- a/storage/xtradb/include/btr0btr.ic +++ b/storage/xtradb/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; @@ -59,7 +63,9 @@ btr_block_get_func( if (block && 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/xtradb/include/btr0cur.h b/storage/xtradb/include/btr0cur.h index 6f4ce95d72f..a8ec0a88867 100644 --- a/storage/xtradb/include/btr0cur.h +++ b/storage/xtradb/include/btr0cur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ @@ -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 @@ -522,6 +512,27 @@ btr_cur_disown_inherited_fields( const upd_t* update, /*!< in: update vector */ mtr_t* mtr) /*!< in/out: mini-transaction */ __attribute__((nonnull(2,3,4,5,6))); + +/** Operation code for btr_store_big_rec_extern_fields(). */ +enum blob_op { + /** Store off-page columns for a freshly inserted record */ + BTR_STORE_INSERT = 0, + /** Store off-page columns for an insert by update */ + BTR_STORE_INSERT_UPDATE, + /** Store off-page columns for an update */ + BTR_STORE_UPDATE +}; + +/*******************************************************************//** +Determine if an operation on off-page columns is an update. +@return TRUE if op != BTR_STORE_INSERT */ +UNIV_INLINE +ibool +btr_blob_op_is_update( +/*==================*/ + enum blob_op op) /*!< in: operation */ + __attribute__((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. @@ -529,52 +540,23 @@ The fields are stored on pages allocated from leaf node file segment of the index tree. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ UNIV_INTERN -ulint -btr_store_big_rec_extern_fields_func( -/*=================================*/ +enum db_err +btr_store_big_rec_extern_fields( +/*============================*/ dict_index_t* index, /*!< in: index of rec; the index tree MUST be X-latched */ buf_block_t* rec_block, /*!< in/out: block containing rec */ - rec_t* rec, /*!< in: record */ + rec_t* rec, /*!< in/out: record */ const ulint* offsets, /*!< in: rec_get_offsets(rec, index); the "external storage" flags in offsets will not correspond to rec when this function returns */ -#ifdef UNIV_DEBUG - mtr_t* local_mtr, /*!< in: mtr containing the - latch to rec and to the tree */ -#endif /* UNIV_DEBUG */ -#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG - 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 + const big_rec_t*big_rec_vec, /*!< in: vector containing fields to be stored externally */ - __attribute__((nonnull)); - -/** 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. -The fields are stored on pages allocated from leaf node -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); - the "external storage" flags in offsets will not be adjusted -@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 -@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) -#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) -#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) -#endif + mtr_t* btr_mtr, /*!< in: mtr containing the + latches to the clustered index */ + enum blob_op op) /*! in: operation code */ + __attribute__((nonnull, warn_unused_result)); /*******************************************************************//** Frees the space in an externally stored field to the file space diff --git a/storage/xtradb/include/btr0cur.ic b/storage/xtradb/include/btr0cur.ic index c833b3e8572..e31f77c77eb 100644 --- a/storage/xtradb/include/btr0cur.ic +++ b/storage/xtradb/include/btr0cur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ @@ -139,7 +139,7 @@ btr_cur_compress_recommendation( btr_cur_t* cursor, /*!< in: btr cursor */ mtr_t* mtr) /*!< in: mtr */ { - const page_t* page; + const page_t* page; ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor), MTR_MEMO_PAGE_X_FIX)); @@ -197,4 +197,25 @@ btr_cur_can_delete_without_compress( return(TRUE); } + +/*******************************************************************//** +Determine if an operation on off-page columns is an update. +@return TRUE if op != BTR_STORE_INSERT */ +UNIV_INLINE +ibool +btr_blob_op_is_update( +/*==================*/ + enum blob_op op) /*!< in: operation */ +{ + switch (op) { + case BTR_STORE_INSERT: + return(FALSE); + case BTR_STORE_INSERT_UPDATE: + case BTR_STORE_UPDATE: + return(TRUE); + } + + ut_ad(0); + return(FALSE); +} #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/xtradb/include/btr0pcur.h b/storage/xtradb/include/btr0pcur.h index f59514d04b3..40ecc77dcd1 100644 --- a/storage/xtradb/include/btr0pcur.h +++ b/storage/xtradb/include/btr0pcur.h @@ -279,14 +279,6 @@ btr_pcur_commit_specify_mtr( /*========================*/ btr_pcur_t* pcur, /*!< in: persistent cursor */ mtr_t* mtr); /*!< in: mtr to commit */ -/**************************************************************//** -Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES. -@return TRUE if detached */ -UNIV_INLINE -ibool -btr_pcur_is_detached( -/*=================*/ - btr_pcur_t* pcur); /*!< in: persistent cursor */ /*********************************************************//** Moves the persistent cursor to the next record in the tree. If no records are left, the cursor stays 'after last in tree'. diff --git a/storage/xtradb/include/btr0pcur.ic b/storage/xtradb/include/btr0pcur.ic index 0f9b969e7c5..f49e155f97e 100644 --- a/storage/xtradb/include/btr0pcur.ic +++ b/storage/xtradb/include/btr0pcur.ic @@ -415,38 +415,6 @@ btr_pcur_commit_specify_mtr( pcur->pos_state = BTR_PCUR_WAS_POSITIONED; } -/**************************************************************//** -Sets the pcur latch mode to BTR_NO_LATCHES. */ -UNIV_INLINE -void -btr_pcur_detach( -/*============*/ - btr_pcur_t* pcur) /*!< in: persistent cursor */ -{ - ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED); - - pcur->latch_mode = BTR_NO_LATCHES; - - pcur->pos_state = BTR_PCUR_WAS_POSITIONED; -} - -/**************************************************************//** -Tests if a cursor is detached: that is the latch mode is BTR_NO_LATCHES. -@return TRUE if detached */ -UNIV_INLINE -ibool -btr_pcur_is_detached( -/*=================*/ - btr_pcur_t* pcur) /*!< in: persistent cursor */ -{ - if (pcur->latch_mode == BTR_NO_LATCHES) { - - return(TRUE); - } - - return(FALSE); -} - /**************************************************************//** Sets the old_rec_buf field to NULL. */ UNIV_INLINE diff --git a/storage/xtradb/include/btr0sea.h b/storage/xtradb/include/btr0sea.h index f6d194319ae..9281be63f67 100644 --- a/storage/xtradb/include/btr0sea.h +++ b/storage/xtradb/include/btr0sea.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 @@ -148,8 +148,8 @@ btr_search_drop_page_hash_index_on_index( /*=====================================*/ dict_index_t* index); /* in: record descriptor */ /********************************************************************//** -Drops a page hash index when a page is freed from a fseg to the file system. -Drops possible hash index if the page happens to be in the buffer pool. */ +Drops a possible page hash index when a page is evicted from the buffer pool +or freed in a file segment. */ UNIV_INTERN void btr_search_drop_page_hash_when_freed( @@ -199,16 +199,6 @@ btr_search_validate(void); # define btr_search_validate() TRUE #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */ -/** Flag: has the search system been enabled? -Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern char btr_search_enabled; - -/** Flag: whether the search system has completed its disabling process, -It is set to TRUE right after buf_pool_drop_hash_index() in -btr_search_disable(), indicating hash index entries are cleaned up. -Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern ibool btr_search_fully_disabled; - /** The search info struct in an index */ struct btr_search_struct{ ulint ref_count; /*!< Number of blocks in this index tree @@ -277,24 +267,6 @@ struct btr_search_sys_struct{ /** The adaptive hash index */ extern btr_search_sys_t* btr_search_sys; -/** @brief The latch protecting the adaptive search system - -This latch protects the -(1) hash index; -(2) columns of a record to which we have a pointer in the hash index; - -but does NOT protect: - -(3) next record offset field in a record; -(4) next or previous records on the same page. - -Bear in mind (3) and (4) when using the hash index. -*/ -extern rw_lock_t* btr_search_latch_temp; - -/** The latch protecting the adaptive search system */ -#define btr_search_latch (*btr_search_latch_temp) - #ifdef UNIV_SEARCH_PERF_STAT /** Number of successful adaptive hash index lookups */ extern ulint btr_search_n_succ; diff --git a/storage/xtradb/include/btr0types.h b/storage/xtradb/include/btr0types.h index 07c06fb18d7..5adc858b931 100644 --- a/storage/xtradb/include/btr0types.h +++ b/storage/xtradb/include/btr0types.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 @@ -30,6 +30,7 @@ Created 2/17/1996 Heikki Tuuri #include "rem0types.h" #include "page0types.h" +#include "sync0rw.h" /** Persistent cursor */ typedef struct btr_pcur_struct btr_pcur_t; @@ -38,6 +39,28 @@ typedef struct btr_cur_struct btr_cur_t; /** B-tree search information for the adaptive hash index */ typedef struct btr_search_struct btr_search_t; +/** @brief The latch protecting the adaptive search system + +This latch protects the +(1) hash index; +(2) columns of a record to which we have a pointer in the hash index; + +but does NOT protect: + +(3) next record offset field in a record; +(4) next or previous records on the same page. + +Bear in mind (3) and (4) when using the hash index. +*/ +extern rw_lock_t* btr_search_latch_temp; + +/** The latch protecting the adaptive search system */ +#define btr_search_latch (*btr_search_latch_temp) + +/** Flag: has the search system been enabled? +Protected by btr_search_latch. */ +extern char btr_search_enabled; + #ifdef UNIV_BLOB_DEBUG # include "buf0types.h" /** An index->blobs entry for keeping track of off-page column references */ diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h index 838dd7f3900..e3039fe520c 100644 --- a/storage/xtradb/include/buf0buf.h +++ b/storage/xtradb/include/buf0buf.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2012, 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 *****************************************************************************/ @@ -120,13 +120,11 @@ buf_pool_free(void); /*===============*/ /********************************************************************//** -Drops the adaptive hash index. To prevent a livelock, this function -is only to be called while holding btr_search_latch and while -btr_search_enabled == FALSE. */ +Clears the adaptive hash index on all pages in the buffer pool. */ UNIV_INTERN void -buf_pool_drop_hash_index(void); -/*==========================*/ +buf_pool_clear_hash_index(void); +/*===========================*/ /********************************************************************//** Relocate a buffer control block. Relocates the block on the LRU list @@ -372,15 +370,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. @@ -449,17 +438,6 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage); /*!< in: block to make younger */ /********************************************************************//** -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 -pool if it is found there. -@return TRUE if page hash index is built in search system */ -UNIV_INTERN -ibool -buf_page_peek_if_search_hashed( -/*===========================*/ - ulint space, /*!< in: space id */ - ulint offset);/*!< in: page number */ -/********************************************************************//** Gets the youngest modification log sequence number for a frame. Returns zero if not file page or no modification occurred yet. @return newest modification to page */ @@ -1296,13 +1274,16 @@ struct buf_block_struct{ /* @} */ /** @name Hash search fields - These 6 fields may only be modified when we have + These 5 fields may only be modified when we have an x-latch on btr_search_latch AND - we are holding an s-latch or x-latch on buf_block_struct::lock or - we know that buf_block_struct::buf_fix_count == 0. An exception to this is when we init or create a page - in the buffer pool in buf0buf.c. */ + in the buffer pool in buf0buf.c. + + Another exception is that assigning block->index = NULL + is allowed whenever holding an x-latch on btr_search_latch. */ /* @{ */ @@ -1311,20 +1292,20 @@ struct buf_block_struct{ pointers in the adaptive hash index pointing to this frame */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - unsigned is_hashed:1; /*!< TRUE if hash index has - already been built on this - page; note that it does not - guarantee that the index is - complete, though: there may - have been hash collisions, - record deletions, etc. */ unsigned curr_n_fields:10;/*!< prefix length for hash indexing: number of full fields */ unsigned curr_n_bytes:15;/*!< number of bytes in hash indexing */ unsigned curr_left_side:1;/*!< TRUE or FALSE in hash indexing */ - dict_index_t* index; /*!< Index for which the adaptive - hash index has been created. */ + dict_index_t* index; /*!< Index for which the + adaptive hash index has been + created, or NULL if the page + does not exist in the + index. Note that it does not + guarantee that the index is + complete, though: there may + have been hash collisions, + record deletions, etc. */ /* @} */ # ifdef UNIV_SYNC_DEBUG /** @name Debug fields */ diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic index a081d6a34c0..92e0edf0444 100644 --- a/storage/xtradb/include/buf0buf.ic +++ b/storage/xtradb/include/buf0buf.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -18,8 +18,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 *****************************************************************************/ diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h index c7fa6d2a444..e4a3844cd22 100644 --- a/storage/xtradb/include/db0err.h +++ b/storage/xtradb/include/db0err.h @@ -97,6 +97,8 @@ enum db_err { DB_FOREIGN_EXCEED_MAX_CASCADE, /* Foreign key constraint related cascading delete/update exceeds maximum allowed depth */ + DB_TABLE_IN_FK_CHECK, /* table is being used in foreign + key check */ /* The following are partial failure codes */ DB_FAIL = 1000, diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h index 2baecdc958a..be8bd20dba9 100644 --- a/storage/xtradb/include/dict0dict.h +++ b/storage/xtradb/include/dict0dict.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -1018,14 +1018,6 @@ dict_index_get_page( /*================*/ const dict_index_t* tree); /*!< in: index */ /*********************************************************************//** -Sets the page number of the root of index tree. */ -UNIV_INLINE -void -dict_index_set_page( -/*================*/ - dict_index_t* index, /*!< in/out: index */ - ulint page); /*!< in: page number */ -/*********************************************************************//** Gets the read-write lock of the index tree. @return read-write lock */ UNIV_INLINE diff --git a/storage/xtradb/include/dict0dict.ic b/storage/xtradb/include/dict0dict.ic index bd7534dc7e2..1c1c3d7f202 100644 --- a/storage/xtradb/include/dict0dict.ic +++ b/storage/xtradb/include/dict0dict.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -722,21 +722,6 @@ dict_index_get_page( return(index->page); } -/*********************************************************************//** -Sets the page number of the root of index tree. */ -UNIV_INLINE -void -dict_index_set_page( -/*================*/ - dict_index_t* index, /*!< in/out: index */ - ulint page) /*!< in: page number */ -{ - ut_ad(index); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - index->page = page; -} - /*********************************************************************//** Gets the read-write lock of the index tree. @return read-write lock */ diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h index 3554274847c..a729ed8816f 100644 --- a/storage/xtradb/include/dict0mem.h +++ b/storage/xtradb/include/dict0mem.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -305,7 +305,9 @@ struct dict_index_struct{ unsigned to_be_dropped:1; /*!< TRUE if this index is marked to be dropped in ha_innobase::prepare_drop_index(), - otherwise FALSE */ + otherwise FALSE. Protected by + dict_sys->mutex, dict_operation_lock and + index->lock.*/ dict_field_t* fields; /*!< array of field descriptions */ #ifndef UNIV_HOTBACKUP UT_LIST_NODE_T(dict_index_t) diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index 11c4cb4ba03..d3300b6b8aa 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -341,20 +341,19 @@ fil_read_flushed_lsn_and_arch_log_no( ib_uint64_t* min_flushed_lsn, /*!< in/out: */ ib_uint64_t* max_flushed_lsn); /*!< in/out: */ /*******************************************************************//** -Increments the count of pending insert buffer page merges, if space is not -being deleted. -@return TRUE if being deleted, and ibuf merges should be skipped */ +Increments the count of pending operation, if space is not being deleted. +@return TRUE if being deleted, and operation should be skipped */ UNIV_INTERN ibool -fil_inc_pending_ibuf_merges( -/*========================*/ +fil_inc_pending_ops( +/*================*/ ulint id); /*!< in: space id */ /*******************************************************************//** -Decrements the count of pending insert buffer page merges. */ +Decrements the count of pending operations. */ UNIV_INTERN void -fil_decr_pending_ibuf_merges( -/*=========================*/ +fil_decr_pending_ops( +/*=================*/ ulint id); /*!< in: space id */ #endif /* !UNIV_HOTBACKUP */ /*******************************************************************//** @@ -473,8 +472,11 @@ fil_open_single_table_tablespace( accessing the first page of the file */ ulint id, /*!< in: space id */ ulint flags, /*!< in: tablespace flags */ - const char* name); /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + trx_t* trx); /*!< in: transaction. This is only + used for IMPORT TABLESPACE, must be NULL + otherwise */ /********************************************************************//** It is possible, though very improbable, that the lsn's in the tablespace to be imported have risen above the current system lsn, if a lengthy purge, ibuf diff --git a/storage/xtradb/include/fsp0fsp.h b/storage/xtradb/include/fsp0fsp.h index 7abd3914eda..8506748ae03 100644 --- a/storage/xtradb/include/fsp0fsp.h +++ b/storage/xtradb/include/fsp0fsp.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2012, 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 *****************************************************************************/ @@ -176,30 +176,33 @@ 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 X-latched block, or 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 fragmentation. -@return allocated page offset, FIL_NULL if no page could be allocated */ +@retval NULL if no page could be allocated +@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded +(init_mtr == mtr, or the page was not previously freed in mtr) +@retval block (not allocated or initialized) otherwise */ UNIV_INTERN -ulint +buf_block_t* fseg_alloc_free_page_general( /*=========================*/ - fseg_header_t* seg_header,/*!< in: segment header */ - ulint hint, /*!< in: hint of which page would be desirable */ + 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 inserted there in order, into which @@ -210,7 +213,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. + If init_mtr!=mtr, but the page is already + latched in mtr, do not initialize the page. */ + __attribute__((warn_unused_result, nonnull)); /**********************************************************************//** 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/xtradb/include/ha0ha.h b/storage/xtradb/include/ha0ha.h index 3299000bf3c..8bba564d153 100644 --- a/storage/xtradb/include/ha0ha.h +++ b/storage/xtradb/include/ha0ha.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, 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 @@ -31,13 +31,14 @@ Created 8/18/1994 Heikki Tuuri #include "hash0hash.h" #include "page0types.h" #include "buf0types.h" +#include "rem0types.h" /*************************************************************//** Looks for an element in a hash table. @return pointer to the data of the first hash table node in chain having the fold number, NULL if not found */ UNIV_INLINE -void* +const rec_t* ha_search_and_get_data( /*===================*/ hash_table_t* table, /*!< in: hash table */ @@ -51,11 +52,11 @@ ha_search_and_update_if_found_func( /*===============================*/ hash_table_t* table, /*!< in/out: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data, /*!< in: pointer to the data */ + const rec_t* data, /*!< in: pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* new_block,/*!< in: block containing new_data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* new_data);/*!< in: new pointer to the data */ + const rec_t* new_data);/*!< in: new pointer to the data */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG /** Looks for an element when we know the pointer to the data and @@ -113,14 +114,6 @@ chosen to be a slightly bigger prime number. # define ha_create(n_c,n_m,level) ha_create_func(n_c,n_m) #endif /* UNIV_SYNC_DEBUG */ -/*************************************************************//** -Empties a hash table and frees the memory heaps. */ -UNIV_INTERN -void -ha_clear( -/*=====*/ - hash_table_t* table); /*!< in, own: hash table */ - /*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node @@ -138,7 +131,7 @@ ha_insert_for_fold_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data); /*!< in: data, must not be NULL */ + const rec_t* data); /*!< in: data, must not be NULL */ #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG /** @@ -174,7 +167,7 @@ ha_search_and_delete_if_found( /*==========================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data); /*!< in: pointer to the data */ + const rec_t* data); /*!< in: pointer to the data */ #ifndef UNIV_HOTBACKUP /*****************************************************************//** Removes from the chain determined by fold all nodes whose data pointer @@ -217,7 +210,7 @@ struct ha_node_struct { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block; /*!< buffer block containing the data, or NULL */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data; /*!< pointer to the data */ + const rec_t* data; /*!< pointer to the data */ ulint fold; /*!< fold value for the data */ }; diff --git a/storage/xtradb/include/ha0ha.ic b/storage/xtradb/include/ha0ha.ic index 734403c4cd9..5656e9b7eba 100644 --- a/storage/xtradb/include/ha0ha.ic +++ b/storage/xtradb/include/ha0ha.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, 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 @@ -25,6 +25,7 @@ Created 8/18/1994 Heikki Tuuri #include "ut0rnd.h" #include "mem0mem.h" +#include "btr0types.h" /***********************************************************//** Deletes a hash node. */ @@ -39,10 +40,10 @@ ha_delete_hash_node( Gets a hash node data. @return pointer to the data */ UNIV_INLINE -void* +const rec_t* ha_node_get_data( /*=============*/ - ha_node_t* node) /*!< in: hash chain node */ + const ha_node_t* node) /*!< in: hash chain node */ { return(node->data); } @@ -57,7 +58,7 @@ ha_node_set_data_func( #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG buf_block_t* block, /*!< in: buffer block containing the data */ #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG node->block = block; @@ -105,41 +106,12 @@ ha_chain_get_first( hash_get_nth_cell(table, hash_calc_hash(fold, table))->node); } -/*************************************************************//** -Looks for an element in a hash table. -@return pointer to the first hash table node in chain having the fold -number, NULL if not found */ -UNIV_INLINE -ha_node_t* -ha_search( -/*======*/ - hash_table_t* table, /*!< in: hash table */ - ulint fold) /*!< in: folded value of the searched data */ -{ - ha_node_t* node; - - ASSERT_HASH_MUTEX_OWN(table, fold); - - node = ha_chain_get_first(table, fold); - - while (node) { - if (node->fold == fold) { - - return(node); - } - - node = ha_chain_get_next(node); - } - - return(NULL); -} - /*************************************************************//** Looks for an element in a hash table. @return pointer to the data of the first hash table node in chain having the fold number, NULL if not found */ UNIV_INLINE -void* +const rec_t* ha_search_and_get_data( /*===================*/ hash_table_t* table, /*!< in: hash table */ @@ -148,6 +120,10 @@ ha_search_and_get_data( ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_chain_get_first(table, fold); @@ -172,12 +148,14 @@ ha_search_with_data( /*================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); + ut_ad(btr_search_enabled); + node = ha_chain_get_first(table, fold); while (node) { @@ -202,11 +180,15 @@ ha_search_and_delete_if_found( /*==========================*/ hash_table_t* table, /*!< in: hash table */ ulint fold, /*!< in: folded value of the searched data */ - void* data) /*!< in: pointer to the data */ + const rec_t* data) /*!< in: pointer to the data */ { ha_node_t* node; ASSERT_HASH_MUTEX_OWN(table, fold); +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX)); +#endif /* UNIV_SYNC_DEBUG */ + ut_ad(btr_search_enabled); node = ha_search_with_data(table, fold, data); diff --git a/storage/xtradb/include/log0log.h b/storage/xtradb/include/log0log.h index 2b4b34f2600..152d83a191f 100644 --- a/storage/xtradb/include/log0log.h +++ b/storage/xtradb/include/log0log.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -18,8 +18,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 *****************************************************************************/ diff --git a/storage/xtradb/include/mem0mem.ic b/storage/xtradb/include/mem0mem.ic index cbce2edc661..bf7b1c20cb4 100644 --- a/storage/xtradb/include/mem0mem.ic +++ b/storage/xtradb/include/mem0mem.ic @@ -208,10 +208,6 @@ mem_heap_alloc( caller */ buf = (byte*)buf + MEM_FIELD_HEADER_SIZE; -#endif -#ifdef UNIV_SET_MEM_TO_ZERO - UNIV_MEM_ALLOC(buf, n); - memset(buf, '\0', n); #endif UNIV_MEM_ALLOC(buf, n); return(buf); diff --git a/storage/xtradb/include/mtr0mtr.h b/storage/xtradb/include/mtr0mtr.h index 8a9ec8ea7f0..ecbfe750577 100644 --- a/storage/xtradb/include/mtr0mtr.h +++ b/storage/xtradb/include/mtr0mtr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2012, 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 *****************************************************************************/ @@ -50,7 +50,9 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ #define MTR_MEMO_PAGE_S_FIX RW_S_LATCH #define MTR_MEMO_PAGE_X_FIX RW_X_LATCH #define MTR_MEMO_BUF_FIX RW_NO_LATCH -#define MTR_MEMO_MODIFY 54 +#ifdef UNIV_DEBUG +# define MTR_MEMO_MODIFY 54 +#endif /* UNIV_DEBUG */ #define MTR_MEMO_S_LOCK 55 #define MTR_MEMO_X_LOCK 56 @@ -378,11 +380,14 @@ struct mtr_struct{ 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 */ + /*!< TRUE if the mini-transaction + modified buffer pool pages */ ulint n_log_recs; /* count of how many page initial log records have been written to the mtr log */ + ulint n_freed_pages; + /* number of pages that have been freed in + this mini-transaction */ ulint log_mode; /* specifies which operations should be logged; default value MTR_LOG_ALL */ ib_uint64_t start_lsn;/* start lsn of the possible log entry for diff --git a/storage/xtradb/include/mtr0mtr.ic b/storage/xtradb/include/mtr0mtr.ic index 18f8e87b3cf..4489e8e1c1e 100644 --- a/storage/xtradb/include/mtr0mtr.ic +++ b/storage/xtradb/include/mtr0mtr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2012, 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 *****************************************************************************/ @@ -45,6 +45,7 @@ mtr_start( mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; mtr->n_log_recs = 0; + mtr->n_freed_pages = 0; ut_d(mtr->state = MTR_ACTIVE); ut_d(mtr->magic_n = MTR_MAGIC_N); diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h index aeaef030505..512f9ca0834 100644 --- a/storage/xtradb/include/page0page.h +++ b/storage/xtradb/include/page0page.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ @@ -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 */ /*----*/ @@ -922,6 +919,7 @@ page_parse_create( ulint comp, /*!< in: nonzero=compact page format */ buf_block_t* block, /*!< in: block or NULL */ mtr_t* mtr); /*!< in: mtr or NULL */ +#ifndef UNIV_HOTBACKUP /************************************************************//** Prints record contents including the data relevant only in the index page context. */ @@ -931,6 +929,7 @@ page_rec_print( /*===========*/ const rec_t* rec, /*!< in: physical record */ const ulint* offsets);/*!< in: record descriptor */ +# ifdef UNIV_BTR_PRINT /***************************************************************//** This is used to print the contents of the directory for debugging purposes. */ @@ -970,6 +969,8 @@ page_print( in directory */ ulint rn); /*!< in: print rn first and last records in directory */ +# endif /* UNIV_BTR_PRINT */ +#endif /* !UNIV_HOTBACKUP */ /***************************************************************//** The following is used to validate a record on a page. This function differs from rec_validate as it can also check the n_owned field and diff --git a/storage/xtradb/include/page0page.ic b/storage/xtradb/include/page0page.ic index b34408aed17..005fba2e5a1 100644 --- a/storage/xtradb/include/page0page.ic +++ b/storage/xtradb/include/page0page.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ diff --git a/storage/xtradb/include/row0upd.ic b/storage/xtradb/include/row0upd.ic index 0894ed373b0..10646241125 100644 --- a/storage/xtradb/include/row0upd.ic +++ b/storage/xtradb/include/row0upd.ic @@ -28,7 +28,6 @@ Created 12/27/1996 Heikki Tuuri # include "trx0trx.h" # include "trx0undo.h" # include "row0row.h" -# include "btr0sea.h" #endif /* !UNIV_HOTBACKUP */ #include "page0zip.h" @@ -157,11 +156,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); diff --git a/storage/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h index 22de1bfdd93..bf365e502c4 100644 --- a/storage/xtradb/include/sync0rw.h +++ b/storage/xtradb/include/sync0rw.h @@ -565,7 +565,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/xtradb/include/sync0rw.ic b/storage/xtradb/include/sync0rw.ic index 485a63a1b18..cd997febc30 100644 --- a/storage/xtradb/include/sync0rw.ic +++ b/storage/xtradb/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. */ @@ -563,8 +564,6 @@ rw_lock_x_unlock_func( if (lock->lock_word == 0) { /* Last caller in a possible recursive chain. */ lock->recursive = FALSE; - UNIV_MEM_INVALID(&lock->writer_thread, - sizeof lock->writer_thread); } #ifdef UNIV_SYNC_DEBUG @@ -605,8 +604,6 @@ rw_lock_x_unlock_direct( if (lock->lock_word == 0) { lock->recursive = FALSE; - UNIV_MEM_INVALID(&lock->writer_thread, - sizeof lock->writer_thread); } #ifdef UNIV_SYNC_DEBUG diff --git a/storage/xtradb/include/sync0sync.h b/storage/xtradb/include/sync0sync.h index 8b9a075e875..bb3c21f40f5 100644 --- a/storage/xtradb/include/sync0sync.h +++ b/storage/xtradb/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 */ @@ -482,7 +481,6 @@ or row lock! */ #define SYNC_LOG 170 #define SYNC_RECV 168 #define SYNC_WORK_QUEUE 162 -#define SYNC_SEARCH_SYS_CONF 161 /* for assigning btr_search_enabled */ #define SYNC_SEARCH_SYS 160 /* NOTE that if we have a memory heap that can be extended to the buffer pool, its logical level is diff --git a/storage/xtradb/include/trx0purge.h b/storage/xtradb/include/trx0purge.h index ae5bc6f90be..264e91b2432 100644 --- a/storage/xtradb/include/trx0purge.h +++ b/storage/xtradb/include/trx0purge.h @@ -164,9 +164,9 @@ struct trx_purge_struct{ read_view_t* view; /*!< The purge will not remove undo logs which are >= this view (purge view) */ mutex_t mutex; /*!< Mutex protecting the fields below */ - ulint n_pages_handled;/*!< Approximate number of undo log + ulonglong n_pages_handled;/*!< Approximate number of undo log pages processed in purge */ - ulint handle_limit; /*!< Target of how many pages to get + ulonglong handle_limit; /*!< Target of how many pages to get processed in the current purge */ /*------------------------------*/ /* The following two fields form the 'purge pointer' which advances diff --git a/storage/xtradb/include/trx0rec.ic b/storage/xtradb/include/trx0rec.ic index e7e41d6d9f6..6c411047dc6 100644 --- a/storage/xtradb/include/trx0rec.ic +++ b/storage/xtradb/include/trx0rec.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -107,6 +107,7 @@ trx_undo_rec_copy( len = mach_read_from_2(undo_rec) - ut_align_offset(undo_rec, UNIV_PAGE_SIZE); + ut_ad(len < UNIV_PAGE_SIZE); return(mem_heap_dup(heap, undo_rec, len)); } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/xtradb/include/trx0rseg.ic b/storage/xtradb/include/trx0rseg.ic index daffa92fc7d..5e8d2b41120 100644 --- a/storage/xtradb/include/trx0rseg.ic +++ b/storage/xtradb/include/trx0rseg.ic @@ -25,6 +25,7 @@ Created 3/26/1996 Heikki Tuuri #include "srv0srv.h" #include "mtr0log.h" +#include "trx0sys.h" /******************************************************************//** Gets a rollback segment header. @@ -131,7 +132,13 @@ trx_rsegf_undo_find_free( ulint i; ulint page_no; - for (i = 0; i < TRX_RSEG_N_SLOTS; i++) { + for (i = 0; +#ifndef UNIV_DEBUG + i < TRX_RSEG_N_SLOTS; +#else + i < (trx_rseg_n_slots_debug ? trx_rseg_n_slots_debug : TRX_RSEG_N_SLOTS); +#endif + i++) { page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr); diff --git a/storage/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h index eafa1ab6409..8341592feb7 100644 --- a/storage/xtradb/include/trx0sys.h +++ b/storage/xtradb/include/trx0sys.h @@ -262,6 +262,12 @@ trx_id_t trx_sys_get_new_trx_no(void); /*========================*/ #endif /* !UNIV_HOTBACKUP */ + +#ifdef UNIV_DEBUG +/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ +extern uint trx_rseg_n_slots_debug; +#endif + /*****************************************************************//** Writes a trx id to an index page. In case that the id size changes in some future version, this function should be used instead of diff --git a/storage/xtradb/include/trx0undo.h b/storage/xtradb/include/trx0undo.h index 4f15cd85833..585b5f36696 100644 --- a/storage/xtradb/include/trx0undo.h +++ b/storage/xtradb/include/trx0undo.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -194,27 +194,62 @@ trx_undo_get_first_rec( mtr_t* mtr); /*!< in: mtr */ /********************************************************************//** Tries to add a page to the undo log segment where the undo log is placed. -@return page number if success, else FIL_NULL */ +@return X-latched block if success, else NULL */ UNIV_INTERN -ulint +buf_block_t* trx_undo_add_page( /*==============*/ trx_t* trx, /*!< in: transaction */ trx_undo_t* undo, /*!< in: undo log memory object */ - mtr_t* mtr); /*!< in: mtr which does not have a latch to any + 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 */ + __attribute__((nonnull, warn_unused_result)); +/********************************************************************//** +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/xtradb/include/univ.i b/storage/xtradb/include/univ.i index 902d0c94ddd..ee515b7ca17 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -149,14 +149,6 @@ Sun Studio */ /* DEBUG VERSION CONTROL ===================== */ -/* The following flag will make InnoDB to initialize -all memory it allocates to zero. It hides Purify -warnings about reading unallocated memory unless -memory is read outside the allocated blocks. */ -/* -#define UNIV_INIT_MEM_TO_ZERO -*/ - /* When this macro is defined then additional test functions will be compiled. These functions live at the end of each relevant source file and have "test_" prefix. These functions are not called from anywhere in @@ -221,15 +213,6 @@ operations (very slow); also UNIV_DEBUG must be defined */ #define UNIV_BTR_DEBUG /* check B-tree links */ #define UNIV_LIGHT_MEM_DEBUG /* light memory debugging */ -#ifdef HAVE_valgrind -/* The following sets all new allocated memory to zero before use: -this can be used to eliminate unnecessary Purify warnings, but note that -it also masks many bugs Purify could detect. For detailed Purify analysis it -is best to remove the define below and look through the warnings one -by one. */ -#define UNIV_SET_MEM_TO_ZERO -#endif - /* #define UNIV_SQL_DEBUG #define UNIV_LOG_DEBUG diff --git a/storage/xtradb/include/ut0mem.h b/storage/xtradb/include/ut0mem.h index 9c6ee9049ec..5002c9e3801 100644 --- a/storage/xtradb/include/ut0mem.h +++ b/storage/xtradb/include/ut0mem.h @@ -78,40 +78,19 @@ ut_mem_init(void); /*=============*/ /**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined and set_to_zero is TRUE. +Allocates memory. @return own: allocated memory */ UNIV_INTERN void* ut_malloc_low( /*==========*/ ulint n, /*!< in: number of bytes to allocate */ - ibool set_to_zero, /*!< in: TRUE if allocated memory - should be set to zero if - UNIV_SET_MEM_TO_ZERO is defined */ - ibool assert_on_error); /*!< in: if TRUE, we crash mysqld if + ibool assert_on_error) /*!< in: if TRUE, we crash mysqld if the memory cannot be allocated */ + __attribute__((malloc)); /**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined. -@return own: allocated memory */ -UNIV_INTERN -void* -ut_malloc( -/*======*/ - ulint n); /*!< in: number of bytes to allocate */ -#ifndef UNIV_HOTBACKUP -/**********************************************************************//** -Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs -out. It cannot be used if we want to return an error message. Prints to -stderr a message if fails. -@return TRUE if succeeded */ -UNIV_INTERN -ibool -ut_test_malloc( -/*===========*/ - ulint n); /*!< in: try to allocate this many bytes */ -#endif /* !UNIV_HOTBACKUP */ +Allocates memory. */ +#define ut_malloc(n) ut_malloc_low(n, TRUE) /**********************************************************************//** Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is a nop. */ diff --git a/storage/xtradb/include/ut0rnd.ic b/storage/xtradb/include/ut0rnd.ic index d17036d83fc..1e62a7771ef 100644 --- a/storage/xtradb/include/ut0rnd.ic +++ b/storage/xtradb/include/ut0rnd.ic @@ -114,7 +114,7 @@ ut_rnd_interval( rnd = ut_rnd_gen_ulint(); - return(low + (rnd % (high - low + 1))); + return(low + (rnd % (high - low))); } /*********************************************************//** diff --git a/storage/xtradb/lock/lock0lock.c b/storage/xtradb/lock/lock0lock.c index e5da4f46ec9..d5ab6836134 100644 --- a/storage/xtradb/lock/lock0lock.c +++ b/storage/xtradb/lock/lock0lock.c @@ -5059,9 +5059,17 @@ lock_validate(void) lock_mutex_exit_kernel(); - lock_rec_validate_page(space, - fil_space_get_zip_size(space), - page_no); + /* Make sure that the tablespace is not + deleted while we are trying to access + the page. */ + if (!fil_inc_pending_ops(space)) { + lock_rec_validate_page( + space, + fil_space_get_zip_size(space), + page_no); + + fil_decr_pending_ops(space); + } lock_mutex_enter_kernel(); diff --git a/storage/xtradb/log/log0log.c b/storage/xtradb/log/log0log.c index fc8745629d6..a1da38c4579 100644 --- a/storage/xtradb/log/log0log.c +++ b/storage/xtradb/log/log0log.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -18,8 +18,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 *****************************************************************************/ diff --git a/storage/xtradb/mem/mem0pool.c b/storage/xtradb/mem/mem0pool.c index 3291453eeb5..8a01be66506 100644 --- a/storage/xtradb/mem/mem0pool.c +++ b/storage/xtradb/mem/mem0pool.c @@ -223,11 +223,7 @@ mem_pool_create( pool = ut_malloc(sizeof(mem_pool_t)); - /* We do not set the memory to zero (FALSE) in the pool, - but only when allocated at a higher level in mem0mem.c. - This is to avoid masking useful Purify warnings. */ - - pool->buf = ut_malloc_low(size, FALSE, TRUE); + pool->buf = ut_malloc_low(size, TRUE); pool->size = size; mutex_create(&pool->mutex, SYNC_MEM_POOL); diff --git a/storage/xtradb/mtr/mtr0mtr.c b/storage/xtradb/mtr/mtr0mtr.c index a9f1c35f84c..3b6dfa7bd26 100644 --- a/storage/xtradb/mtr/mtr0mtr.c +++ b/storage/xtradb/mtr/mtr0mtr.c @@ -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 *****************************************************************************/ diff --git a/storage/xtradb/mysql-test/patches/README b/storage/xtradb/mysql-test/patches/README new file mode 100644 index 00000000000..122d756e9e3 --- /dev/null +++ b/storage/xtradb/mysql-test/patches/README @@ -0,0 +1,30 @@ +This directory contains patches that need to be applied to the MySQL +source tree in order to get the mysql-test suite to succeed (when +storage/innobase is replaced with this InnoDB branch). Things to keep +in mind when adding new patches here: + +* The patch must be appliable from the mysql top-level source directory. + +* The patch filename must end in ".diff". + +* All patches here are expected to apply cleanly to the latest MySQL 5.1 + tree when storage/innobase is replaced with this InnoDB branch. If + changes to either of those cause the patch to fail, then please check + whether the patch is still needed and, if yes, adjust it so it applies + cleanly. + +* If applicable, always submit the patch at http://bugs.mysql.com and + name the file here like bug%d.diff. Once the patch is committed to + MySQL remove the file from here. + +* If the patch cannot be proposed for inclusion in the MySQL source tree + (via http://bugs.mysql.com) then add a comment at the beginning of the + patch, explaining the problem it is solving, how it does solve it and + why it is not applicable for inclusion in the MySQL source tree. + Obviously this is a very bad situation and should be avoided at all + costs, especially for files that are in the MySQL source repository + (not in storage/innobase). + +* If you ever need to add a patch here that is not related to mysql-test + suite, then please move this directory from ./mysql-test/patches to + ./patches and remove this text. diff --git a/storage/xtradb/mysql-test/patches/index_merge_innodb-explain.diff b/storage/xtradb/mysql-test/patches/index_merge_innodb-explain.diff new file mode 100644 index 00000000000..d1ed8afc778 --- /dev/null +++ b/storage/xtradb/mysql-test/patches/index_merge_innodb-explain.diff @@ -0,0 +1,31 @@ +InnoDB's estimate for the index cardinality depends on a pseudo random +number generator (it picks up random pages to sample). After an +optimization that was made in r2625 the following EXPLAINs started +returning a different number of rows (3 instead of 4). + +This patch adjusts the result file. + +This patch cannot be proposed to MySQL because the failures occur only +in this tree and do not occur in the standard InnoDB 5.1. Furthermore, +the file index_merge2.inc is used by other engines too. + +--- mysql-test/r/index_merge_innodb.result.orig 2008-09-30 18:32:13.000000000 +0300 ++++ mysql-test/r/index_merge_innodb.result 2008-09-30 18:33:01.000000000 +0300 +@@ -111,7 +111,7 @@ + explain select count(*) from t1 where + key1a = 2 and key1b is null and key2a = 2 and key2b is null; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL 4 Using intersect(i1,i2); Using where; Using index ++1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL 3 Using intersect(i1,i2); Using where; Using index + select count(*) from t1 where + key1a = 2 and key1b is null and key2a = 2 and key2b is null; + count(*) +@@ -119,7 +119,7 @@ + explain select count(*) from t1 where + key1a = 2 and key1b is null and key3a = 2 and key3b is null; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL 4 Using intersect(i1,i3); Using where; Using index ++1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL 3 Using intersect(i1,i3); Using where; Using index + select count(*) from t1 where + key1a = 2 and key1b is null and key3a = 2 and key3b is null; + count(*) diff --git a/storage/xtradb/mysql-test/patches/information_schema.diff b/storage/xtradb/mysql-test/patches/information_schema.diff new file mode 100644 index 00000000000..a3a21f7a08d --- /dev/null +++ b/storage/xtradb/mysql-test/patches/information_schema.diff @@ -0,0 +1,124 @@ +--- mysql-test/r/information_schema.result.orig 2009-01-31 03:38:50.000000000 +0200 ++++ mysql-test/r/information_schema.result 2009-01-31 07:51:58.000000000 +0200 +@@ -71,6 +71,13 @@ + TRIGGERS + USER_PRIVILEGES + VIEWS ++INNODB_CMP_RESET ++INNODB_TRX ++INNODB_CMPMEM_RESET ++INNODB_LOCK_WAITS ++INNODB_CMPMEM ++INNODB_CMP ++INNODB_LOCKS + columns_priv + db + event +@@ -799,6 +806,8 @@ + TABLES UPDATE_TIME datetime + TABLES CHECK_TIME datetime + TRIGGERS CREATED datetime ++INNODB_TRX trx_started datetime ++INNODB_TRX trx_wait_started datetime + event execute_at datetime + event last_executed datetime + event starts datetime +@@ -852,7 +861,7 @@ + flush privileges; + SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; + table_schema count(*) +-information_schema 28 ++information_schema 35 + mysql 22 + create table t1 (i int, j int); + create trigger trg1 before insert on t1 for each row +@@ -1267,6 +1276,13 @@ + TRIGGERS TRIGGER_SCHEMA + USER_PRIVILEGES GRANTEE + VIEWS TABLE_SCHEMA ++INNODB_CMP_RESET page_size ++INNODB_TRX trx_id ++INNODB_CMPMEM_RESET page_size ++INNODB_LOCK_WAITS requesting_trx_id ++INNODB_CMPMEM page_size ++INNODB_CMP page_size ++INNODB_LOCKS lock_id + SELECT t.table_name, c1.column_name + FROM information_schema.tables t + INNER JOIN +@@ -1310,6 +1326,13 @@ + TRIGGERS TRIGGER_SCHEMA + USER_PRIVILEGES GRANTEE + VIEWS TABLE_SCHEMA ++INNODB_CMP_RESET page_size ++INNODB_TRX trx_id ++INNODB_CMPMEM_RESET page_size ++INNODB_LOCK_WAITS requesting_trx_id ++INNODB_CMPMEM page_size ++INNODB_CMP page_size ++INNODB_LOCKS lock_id + SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'); + MAX(table_name) + VIEWS +@@ -1386,6 +1409,13 @@ + FILES information_schema.FILES 1 + GLOBAL_STATUS information_schema.GLOBAL_STATUS 1 + GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1 ++INNODB_CMP information_schema.INNODB_CMP 1 ++INNODB_CMPMEM information_schema.INNODB_CMPMEM 1 ++INNODB_CMPMEM_RESET information_schema.INNODB_CMPMEM_RESET 1 ++INNODB_CMP_RESET information_schema.INNODB_CMP_RESET 1 ++INNODB_LOCKS information_schema.INNODB_LOCKS 1 ++INNODB_LOCK_WAITS information_schema.INNODB_LOCK_WAITS 1 ++INNODB_TRX information_schema.INNODB_TRX 1 + KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1 + PARTITIONS information_schema.PARTITIONS 1 + PLUGINS information_schema.PLUGINS 1 +diff mysql-test/r/information_schema_db.result.orig mysql-test/r/information_schema_db.result +--- mysql-test/r/information_schema_db.result.orig 2008-08-04 09:27:49.000000000 +0300 ++++ mysql-test/r/information_schema_db.result 2008-10-07 12:26:31.000000000 +0300 +@@ -33,6 +33,13 @@ + TRIGGERS + USER_PRIVILEGES + VIEWS ++INNODB_CMP_RESET ++INNODB_TRX ++INNODB_CMPMEM_RESET ++INNODB_LOCK_WAITS ++INNODB_CMPMEM ++INNODB_CMP ++INNODB_LOCKS + show tables from INFORMATION_SCHEMA like 'T%'; + Tables_in_information_schema (T%) + TABLES +diff mysql-test/r/mysqlshow.result.orig mysql-test/r/mysqlshow.result +--- mysql-test/r/mysqlshow.result.orig 2008-08-04 09:27:51.000000000 +0300 ++++ mysql-test/r/mysqlshow.result 2008-10-07 12:35:39.000000000 +0300 +@@ -107,6 +107,13 @@ + | TRIGGERS | + | USER_PRIVILEGES | + | VIEWS | ++| INNODB_CMP_RESET | ++| INNODB_TRX | ++| INNODB_CMPMEM_RESET | ++| INNODB_LOCK_WAITS | ++| INNODB_CMPMEM | ++| INNODB_CMP | ++| INNODB_LOCKS | + +---------------------------------------+ + Database: INFORMATION_SCHEMA + +---------------------------------------+ +@@ -140,6 +147,13 @@ + | TRIGGERS | + | USER_PRIVILEGES | + | VIEWS | ++| INNODB_CMP_RESET | ++| INNODB_TRX | ++| INNODB_CMPMEM_RESET | ++| INNODB_LOCK_WAITS | ++| INNODB_CMPMEM | ++| INNODB_CMP | ++| INNODB_LOCKS | + +---------------------------------------+ + Wildcard: inf_rmation_schema + +--------------------+ diff --git a/storage/xtradb/mysql-test/patches/innodb_file_per_table.diff b/storage/xtradb/mysql-test/patches/innodb_file_per_table.diff new file mode 100644 index 00000000000..8b7ae2036c9 --- /dev/null +++ b/storage/xtradb/mysql-test/patches/innodb_file_per_table.diff @@ -0,0 +1,47 @@ +diff mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test.orig mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test +--- mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test.orig 2008-10-07 11:32:30.000000000 +0300 ++++ mysql-test/suite/sys_vars/t/innodb_file_per_table_basic.test 2008-10-07 11:52:14.000000000 +0300 +@@ -37,10 +37,6 @@ + # Check if Value can set # + #################################################################### + +---error ER_INCORRECT_GLOBAL_LOCAL_VAR +-SET @@GLOBAL.innodb_file_per_table=1; +---echo Expected error 'Read only variable' +- + SELECT COUNT(@@GLOBAL.innodb_file_per_table); + --echo 1 Expected + +@@ -52,7 +48,7 @@ + # Check if the value in GLOBAL Table matches value in variable # + ################################################################# + +-SELECT @@GLOBAL.innodb_file_per_table = VARIABLE_VALUE ++SELECT IF(@@GLOBAL.innodb_file_per_table,'ON','OFF') = VARIABLE_VALUE + FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME='innodb_file_per_table'; + --echo 1 Expected +diff mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result.orig mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result +--- mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result.orig 2008-10-07 11:32:02.000000000 +0300 ++++ mysql-test/suite/sys_vars/r/innodb_file_per_table_basic.result 2008-10-07 11:52:47.000000000 +0300 +@@ -4,18 +4,15 @@ + 1 + 1 Expected + '#---------------------BS_STVARS_028_02----------------------#' +-SET @@GLOBAL.innodb_file_per_table=1; +-ERROR HY000: Variable 'innodb_file_per_table' is a read only variable +-Expected error 'Read only variable' + SELECT COUNT(@@GLOBAL.innodb_file_per_table); + COUNT(@@GLOBAL.innodb_file_per_table) + 1 + 1 Expected + '#---------------------BS_STVARS_028_03----------------------#' +-SELECT @@GLOBAL.innodb_file_per_table = VARIABLE_VALUE ++SELECT IF(@@GLOBAL.innodb_file_per_table,'ON','OFF') = VARIABLE_VALUE + FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME='innodb_file_per_table'; +-@@GLOBAL.innodb_file_per_table = VARIABLE_VALUE ++IF(@@GLOBAL.innodb_file_per_table,'ON','OFF') = VARIABLE_VALUE + 1 + 1 Expected + SELECT COUNT(@@GLOBAL.innodb_file_per_table); diff --git a/storage/xtradb/mysql-test/patches/innodb_lock_wait_timeout.diff b/storage/xtradb/mysql-test/patches/innodb_lock_wait_timeout.diff new file mode 100644 index 00000000000..bc61a0f5841 --- /dev/null +++ b/storage/xtradb/mysql-test/patches/innodb_lock_wait_timeout.diff @@ -0,0 +1,55 @@ +--- mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test.orig 2008-08-04 09:28:16.000000000 +0300 ++++ mysql-test/suite/sys_vars/t/innodb_lock_wait_timeout_basic.test 2008-10-07 11:14:15.000000000 +0300 +@@ -37,10 +37,6 @@ + # Check if Value can set # + #################################################################### + +---error ER_INCORRECT_GLOBAL_LOCAL_VAR +-SET @@GLOBAL.innodb_lock_wait_timeout=1; +---echo Expected error 'Read only variable' +- + SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); + --echo 1 Expected + +@@ -84,13 +80,9 @@ + SELECT COUNT(@@innodb_lock_wait_timeout); + --echo 1 Expected + +---Error ER_INCORRECT_GLOBAL_LOCAL_VAR + SELECT COUNT(@@local.innodb_lock_wait_timeout); +---echo Expected error 'Variable is a GLOBAL variable' + +---Error ER_INCORRECT_GLOBAL_LOCAL_VAR + SELECT COUNT(@@SESSION.innodb_lock_wait_timeout); +---echo Expected error 'Variable is a GLOBAL variable' + + SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); + --echo 1 Expected +--- mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result.orig 2008-08-04 09:27:50.000000000 +0300 ++++ mysql-test/suite/sys_vars/r/innodb_lock_wait_timeout_basic.result 2008-10-07 11:15:14.000000000 +0300 +@@ -4,9 +4,6 @@ + 1 + 1 Expected + '#---------------------BS_STVARS_032_02----------------------#' +-SET @@GLOBAL.innodb_lock_wait_timeout=1; +-ERROR HY000: Variable 'innodb_lock_wait_timeout' is a read only variable +-Expected error 'Read only variable' + SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); + COUNT(@@GLOBAL.innodb_lock_wait_timeout) + 1 +@@ -39,11 +36,11 @@ + 1 + 1 Expected + SELECT COUNT(@@local.innodb_lock_wait_timeout); +-ERROR HY000: Variable 'innodb_lock_wait_timeout' is a GLOBAL variable +-Expected error 'Variable is a GLOBAL variable' ++COUNT(@@local.innodb_lock_wait_timeout) ++1 + SELECT COUNT(@@SESSION.innodb_lock_wait_timeout); +-ERROR HY000: Variable 'innodb_lock_wait_timeout' is a GLOBAL variable +-Expected error 'Variable is a GLOBAL variable' ++COUNT(@@SESSION.innodb_lock_wait_timeout) ++1 + SELECT COUNT(@@GLOBAL.innodb_lock_wait_timeout); + COUNT(@@GLOBAL.innodb_lock_wait_timeout) + 1 diff --git a/storage/xtradb/mysql-test/patches/innodb_thread_concurrency_basic.diff b/storage/xtradb/mysql-test/patches/innodb_thread_concurrency_basic.diff new file mode 100644 index 00000000000..72e5457905f --- /dev/null +++ b/storage/xtradb/mysql-test/patches/innodb_thread_concurrency_basic.diff @@ -0,0 +1,31 @@ +--- mysql-test/suite/sys_vars/r/innodb_thread_concurrency_basic.result.orig 2008-12-04 18:45:52 -06:00 ++++ mysql-test/suite/sys_vars/r/innodb_thread_concurrency_basic.result 2009-02-12 02:05:48 -06:00 +@@ -1,19 +1,19 @@ + SET @global_start_value = @@global.innodb_thread_concurrency; + SELECT @global_start_value; + @global_start_value +-8 ++0 + '#--------------------FN_DYNVARS_046_01------------------------#' + SET @@global.innodb_thread_concurrency = 0; + SET @@global.innodb_thread_concurrency = DEFAULT; + SELECT @@global.innodb_thread_concurrency; + @@global.innodb_thread_concurrency +-8 ++0 + '#---------------------FN_DYNVARS_046_02-------------------------#' + SET innodb_thread_concurrency = 1; + ERROR HY000: Variable 'innodb_thread_concurrency' is a GLOBAL variable and should be set with SET GLOBAL + SELECT @@innodb_thread_concurrency; + @@innodb_thread_concurrency +-8 ++0 + SELECT local.innodb_thread_concurrency; + ERROR 42S02: Unknown table 'local' in field list + SET global innodb_thread_concurrency = 0; +@@ -93,4 +93,4 @@ + SET @@global.innodb_thread_concurrency = @global_start_value; + SELECT @@global.innodb_thread_concurrency; + @@global.innodb_thread_concurrency +-8 ++0 diff --git a/storage/xtradb/mysql-test/patches/partition_innodb.diff b/storage/xtradb/mysql-test/patches/partition_innodb.diff new file mode 100644 index 00000000000..01bc073008e --- /dev/null +++ b/storage/xtradb/mysql-test/patches/partition_innodb.diff @@ -0,0 +1,59 @@ +The partition_innodb test only fails if run immediately after innodb_trx_weight. +The reason for this failure is that innodb_trx_weight creates deadlocks and +leaves something like this in the SHOW ENGINE INNODB STATUS output: + + ------------------------ + LATEST DETECTED DEADLOCK + ------------------------ + 090213 10:26:25 + *** (1) TRANSACTION: + TRANSACTION 313, ACTIVE 0 sec, OS thread id 13644672 inserting + mysql tables in use 1, locked 1 + LOCK WAIT 4 lock struct(s), heap size 488, 3 row lock(s) + MySQL thread id 3, query id 36 localhost root update + +The regular expressions that partition_innodb is using are intended to extract +the lock structs and row locks numbers from another part of the output: + + ------------ + TRANSACTIONS + ------------ + Trx id counter 31D + Purge done for trx's n:o < 0 undo n:o < 0 + History list length 4 + LIST OF TRANSACTIONS FOR EACH SESSION: + ---TRANSACTION 0, not started, OS thread id 13645056 + 0 lock struct(s), heap size 488, 0 row lock(s) + MySQL thread id 8, query id 81 localhost root + +In the InnoDB Plugin a transaction id is not printed as 2 consecutive +decimal integers (as it is in InnoDB 5.1) but rather as a single +hexadecimal integer. Thus the regular expressions somehow pick the wrong +part of the SHOW ENGINE INNODB STATUS output. + +So after the regular expressions are adjusted to the InnoDB Plugin's variant +of trx_id prinout, then they pick the expected part of the output. + +This patch cannot be proposed to MySQL because the failures occur only +in this tree and do not occur in the standard InnoDB 5.1. + +--- mysql-test/t/partition_innodb.test 2008-11-14 22:51:17 +0000 ++++ mysql-test/t/partition_innodb.test 2009-02-13 07:36:07 +0000 +@@ -27,14 +27,14 @@ + + # grouping/referencing in replace_regex is very slow on long strings, + # removing all before/after the interesting row before grouping/referencing +---replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ ++--replace_regex /.*---TRANSACTION [0-9A-F]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ + SHOW ENGINE InnoDB STATUS; + + UPDATE t1 SET data = data*2 WHERE data = 2; + + # grouping/referencing in replace_regex is very slow on long strings, + # removing all before/after the interesting row before grouping/referencing +---replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ ++--replace_regex /.*---TRANSACTION [0-9A-F]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ + SHOW ENGINE InnoDB STATUS; + + SET @@session.tx_isolation = @old_tx_isolation; + diff --git a/storage/xtradb/os/os0file.c b/storage/xtradb/os/os0file.c index b502be1eb00..ef048188353 100644 --- a/storage/xtradb/os/os0file.c +++ b/storage/xtradb/os/os0file.c @@ -3593,13 +3593,12 @@ os_aio_simulated_wake_handler_thread( { os_aio_array_t* array; os_aio_slot_t* slot; - ulint segment __attribute__ ((unused)); ulint n; ulint i; ut_ad(!os_aio_use_native_aio); - segment = os_aio_get_array_and_local_segment(&array, global_segment); + os_aio_get_array_and_local_segment(&array, global_segment); n = array->n_slots; @@ -4079,7 +4078,6 @@ os_aio_simulated_handle( ulint* space_id) { os_aio_array_t* array; - ulint segment __attribute__ ((unused)); os_aio_slot_t* slot; os_aio_slot_t* slot2; os_aio_slot_t* consecutive_ios[OS_AIO_MERGE_N_CONSECUTIVE]; @@ -4102,7 +4100,7 @@ os_aio_simulated_handle( /* Fix compiler warning */ *consecutive_ios = NULL; - segment = os_aio_get_array_and_local_segment(&array, global_segment); + os_aio_get_array_and_local_segment(&array, global_segment); restart: /* NOTE! We only access constant fields in os_aio_array. Therefore @@ -4111,7 +4109,6 @@ restart: srv_set_io_thread_op_info(global_segment, "looking for i/o requests (a)"); ut_ad(os_aio_validate()); - ut_ad(segment < array->n_segments); n = array->n_slots; diff --git a/storage/xtradb/os/os0proc.c b/storage/xtradb/os/os0proc.c index 48922886f23..a0679e31570 100644 --- a/storage/xtradb/os/os0proc.c +++ b/storage/xtradb/os/os0proc.c @@ -111,9 +111,6 @@ os_mem_alloc_large( os_fast_mutex_lock(&ut_list_mutex); ut_total_allocated_memory += size; os_fast_mutex_unlock(&ut_list_mutex); -# ifdef UNIV_SET_MEM_TO_ZERO - memset(ptr, '\0', size); -# endif UNIV_MEM_ALLOC(ptr, size); return(ptr); } diff --git a/storage/xtradb/page/page0cur.c b/storage/xtradb/page/page0cur.c index b8c492328e8..88ee6bc09a9 100644 --- a/storage/xtradb/page/page0cur.c +++ b/storage/xtradb/page/page0cur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ diff --git a/storage/xtradb/page/page0page.c b/storage/xtradb/page/page0page.c index 6243029019d..7b72a22fd1c 100644 --- a/storage/xtradb/page/page0page.c +++ b/storage/xtradb/page/page0page.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2012, 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 *****************************************************************************/ @@ -215,12 +215,6 @@ page_set_max_trx_id( { page_t* page = buf_block_get_frame(block); #ifndef UNIV_HOTBACKUP - const ibool is_hashed = block->is_hashed; - - if (is_hashed) { - rw_lock_x_lock(&btr_search_latch); - } - ut_ad(!mtr || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); #endif /* !UNIV_HOTBACKUP */ @@ -241,12 +235,6 @@ page_set_max_trx_id( } else { mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id); } - -#ifndef UNIV_HOTBACKUP - if (is_hashed) { - rw_lock_x_unlock(&btr_search_latch); - } -#endif /* !UNIV_HOTBACKUP */ } /************************************************************//** @@ -1632,6 +1620,7 @@ page_rec_print( rec_validate(rec, offsets); } +# ifdef UNIV_BTR_PRINT /***************************************************************//** This is used to print the contents of the directory for debugging purposes. */ @@ -1792,6 +1781,7 @@ page_print( page_dir_print(page, dn); page_print_list(block, index, rn); } +# endif /* UNIV_BTR_PRINT */ #endif /* !UNIV_HOTBACKUP */ /***************************************************************//** diff --git a/storage/xtradb/revert_gen.sh b/storage/xtradb/revert_gen.sh new file mode 100644 index 00000000000..231e05a21e0 --- /dev/null +++ b/storage/xtradb/revert_gen.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# revert changes to all generated files. this is useful in some situations +# when merging changes between branches. + +set -eu + +svn revert include/pars0grm.h pars/pars0grm.h pars/lexyy.c pars/pars0grm.c diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c index 0bcbc14fbf6..d6f486e5c1b 100644 --- a/storage/xtradb/row/row0ins.c +++ b/storage/xtradb/row/row0ins.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -23,6 +23,15 @@ Insert into a table Created 4/20/1996 Heikki Tuuri *******************************************************/ +#ifdef __WIN__ +/* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */ +# define DEBUG_SYNC_C(dummy) ((void) 0) +#else +# include "my_global.h" /* HAVE_* */ +# include "m_string.h" /* for my_sys.h */ +# include "my_sys.h" /* DEBUG_SYNC_C */ +#endif + #include "row0ins.h" #ifdef UNIV_NONINL @@ -1093,6 +1102,9 @@ row_ins_foreign_check_on_constraint( release the latch. */ row_mysql_unfreeze_data_dictionary(thr_get_trx(thr)); + + DEBUG_SYNC_C("innodb_dml_cascade_dict_unfreeze"); + row_mysql_freeze_data_dictionary(thr_get_trx(thr)); mtr_start(mtr); @@ -1676,7 +1688,7 @@ row_ins_scan_sec_index_for_duplicate( ulint n_fields_cmp; btr_pcur_t pcur; ulint err = DB_SUCCESS; - unsigned allow_duplicates; + ulint allow_duplicates; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -1707,7 +1719,7 @@ row_ins_scan_sec_index_for_duplicate( btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); - allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE; + allow_duplicates = thr_get_trx(thr)->duplicates; /* Scan index records and check if there is a duplicate */ @@ -1841,7 +1853,7 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -1885,7 +1897,7 @@ row_ins_duplicate_error_in_clust( offsets = rec_get_offsets(rec, cursor->index, offsets, ULINT_UNDEFINED, &heap); - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -2111,23 +2123,39 @@ row_ins_index_entry_low( 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); + index->lock and block->lock. Allocate + pages for big_rec in the mtr that + modified the B-tree, but be sure to skip + any pages that were freed in mtr. We will + write out the big_rec pages before + committing the B-tree mini-transaction. If + the system crashes so that crash recovery + will not replay the mtr_commit(&mtr), the + big_rec pages will be left orphaned until + the pages are allocated for something else. + + TODO: If the allocation extends the + tablespace, it will not be redo + logged, in either mini-transaction. + Tablespace extension should be + redo-logged in the big_rec + mini-transaction, so that recovery + will not fail when the big_rec was + written to the extended portion of the + file, in case the file was somehow + truncated in the crash. */ rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets( rec, index, NULL, ULINT_UNDEFINED, &heap); + DEBUG_SYNC_C("before_row_ins_upd_extern"); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, &mtr, FALSE, big_rec); + rec, offsets, big_rec, &mtr, + BTR_STORE_INSERT_UPDATE); + DEBUG_SYNC_C("after_row_ins_upd_extern"); /* If writing big_rec fails (for example, because of DB_OUT_OF_FILE_SPACE), the record will be corrupted. Even if @@ -2138,7 +2166,13 @@ row_ins_index_entry_low( external storage. This non-update would not have been written to the undo log, and thus the record cannot - be rolled back. */ + be rolled back. + + However, because we have not executed + mtr_commit(mtr) yet, the update will + not be replayed in crash recovery, and + the following assertion failure will + effectively "roll back" the operation. */ ut_a(err == DB_SUCCESS); goto stored_big_rec; } @@ -2170,6 +2204,8 @@ function_exit: mtr_commit(&mtr); if (UNIV_LIKELY_NULL(big_rec)) { + rec_t* rec; + ulint* offsets; if (thr_get_trx(thr)->fake_changes) { /* skip store extern */ @@ -2186,8 +2222,13 @@ function_exit: return(err); } + DBUG_EXECUTE_IF( + "row_ins_extern_checkpoint", + log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);); + mtr_start(&mtr); + DEBUG_SYNC_C("before_row_ins_extern_latch"); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, BTR_MODIFY_TREE, &cursor, 0, __FILE__, __LINE__, &mtr); @@ -2195,9 +2236,11 @@ function_exit: offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); + DEBUG_SYNC_C("before_row_ins_extern"); err = btr_store_big_rec_extern_fields( index, btr_cur_get_block(&cursor), - rec, offsets, &mtr, FALSE, big_rec); + rec, offsets, big_rec, &mtr, BTR_STORE_INSERT); + DEBUG_SYNC_C("after_row_ins_extern"); stored_big_rec: if (modify) { diff --git a/storage/xtradb/row/row0merge.c b/storage/xtradb/row/row0merge.c index 782c029fbcc..efff92aa361 100644 --- a/storage/xtradb/row/row0merge.c +++ b/storage/xtradb/row/row0merge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2012, 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 @@ -576,7 +576,7 @@ row_merge_buf_write( REC_STATUS_ORDINARY, entry, n_fields, &extra_size); - ut_ad(size > extra_size); + ut_ad(size >= extra_size); ut_ad(extra_size >= REC_N_NEW_EXTRA_BYTES); extra_size -= REC_N_NEW_EXTRA_BYTES; size -= REC_N_NEW_EXTRA_BYTES; @@ -2019,7 +2019,7 @@ row_merge_drop_index( tables in Innobase. Deleting a row from SYS_INDEXES table also frees the file segments of the B-tree associated with the index. */ - static const char str1[] = + static const char sql[] = "PROCEDURE DROP_INDEX_PROC () IS\n" "BEGIN\n" /* Rename the index, so that it will be dropped by @@ -2045,9 +2045,19 @@ row_merge_drop_index( ut_a(trx->dict_operation_lock_mode == RW_X_LATCH); - err = que_eval_sql(info, str1, FALSE, trx); + err = que_eval_sql(info, sql, FALSE, trx); - ut_a(err == DB_SUCCESS); + + if (err != DB_SUCCESS) { + /* Even though we ensure that DDL transactions are WAIT + and DEADLOCK free, we could encounter other errors e.g., + DB_TOO_MANY_TRANSACTIONS. */ + trx->error_state = DB_SUCCESS; + + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error: row_merge_drop_index failed " + "with error code: %lu.\n", (ulint) err); + } /* Replace this index with another equivalent index for all foreign key constraints on this table where this index is used */ @@ -2299,7 +2309,7 @@ row_merge_rename_indexes( /* We use the private SQL parser of Innobase to generate the query graphs needed in renaming indexes. */ - static const char rename_indexes[] = + static const char sql[] = "PROCEDURE RENAME_INDEXES_PROC () IS\n" "BEGIN\n" "UPDATE SYS_INDEXES SET NAME=SUBSTR(NAME,1,LENGTH(NAME)-1)\n" @@ -2315,7 +2325,7 @@ row_merge_rename_indexes( pars_info_add_dulint_literal(info, "tableid", table->id); - err = que_eval_sql(info, rename_indexes, FALSE, trx); + err = que_eval_sql(info, sql, FALSE, trx); if (err == DB_SUCCESS) { dict_index_t* index = dict_table_get_first_index(table); @@ -2325,6 +2335,15 @@ row_merge_rename_indexes( } index = dict_table_get_next_index(index); } while (index); + } else { + /* Even though we ensure that DDL transactions are WAIT + and DEADLOCK free, we could encounter other errors e.g., + DB_TOO_MANY_TRANSACTIONS. */ + trx->error_state = DB_SUCCESS; + + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error: row_merge_rename_indexes " + "failed with error code: %lu.\n", (ulint) err); } trx->op_info = ""; @@ -2363,7 +2382,7 @@ row_merge_rename_tables( memcpy(old_name, old_table->name, strlen(old_table->name) + 1); } else { ut_print_timestamp(stderr); - fprintf(stderr, "InnoDB: too long table name: '%s', " + fprintf(stderr, " InnoDB: too long table name: '%s', " "max length is %d\n", old_table->name, MAX_FULL_NAME_LEN); ut_error; diff --git a/storage/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c index cb003ad62e0..07cb1578024 100644 --- a/storage/xtradb/row/row0mysql.c +++ b/storage/xtradb/row/row0mysql.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2012, 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 *****************************************************************************/ @@ -54,6 +54,14 @@ Created 9/17/2000 Heikki Tuuri #include "ibuf0ibuf.h" #include "ha_prototypes.h" +#ifdef __WIN__ +/* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */ +# define DEBUG_SYNC_C(dummy) ((void) 0) +#else +# include "m_string.h" /* for my_sys.h */ +# include "my_sys.h" /* DEBUG_SYNC_C */ +#endif + /** Provide optional 4.x backwards compatibility for 5.0 and above */ UNIV_INTERN ibool row_rollback_on_timeout = FALSE; @@ -1363,6 +1371,8 @@ row_update_for_mysql( return(DB_ERROR); } + DEBUG_SYNC_C("innodb_row_update_for_mysql_begin"); + trx->op_info = "updating or deleting"; row_mysql_delay_if_needed(); @@ -1915,6 +1925,20 @@ err_exit: } break; + case DB_TOO_MANY_CONCURRENT_TRXS: + /* We already have .ibd file here. it should be deleted. */ + + if (table->space && !fil_delete_tablespace(table->space)) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: not able to" + " delete tablespace %lu of table ", + (ulong) table->space); + ut_print_name(stderr, trx, TRUE, table->name); + fputs("!\n", stderr); + } + /* fall through */ + case DB_DUPLICATE_KEY: default: /* We may also get err == DB_ERROR if the .ibd file for the @@ -2709,7 +2733,7 @@ row_import_tablespace_for_mysql( success = fil_open_single_table_tablespace( TRUE, table->space, table->flags == DICT_TF_COMPACT ? 0 : table->flags, - table->name); + table->name, trx); if (success) { table->ibd_file_missing = FALSE; table->tablespace_discarded = FALSE; @@ -3121,6 +3145,7 @@ row_drop_table_for_mysql( { dict_foreign_t* foreign; dict_table_t* table; + dict_index_t* index; ulint space_id; ulint err; const char* table_name; @@ -3327,6 +3352,18 @@ check_next_foreign: trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); trx->table_id = table->id; + /* Mark all indexes unavailable in the data dictionary cache + before starting to drop the table. */ + + for (index = dict_table_get_first_index(table); + index != NULL; + index = dict_table_get_next_index(index)) { + rw_lock_x_lock(dict_index_get_lock(index)); + ut_ad(!index->to_be_dropped); + index->to_be_dropped = TRUE; + rw_lock_x_unlock(dict_index_get_lock(index)); + } + /* We use the private SQL parser of Innobase to generate the query graphs needed in deleting the dictionary data from system tables in Innobase. Deleting a row from SYS_INDEXES table also @@ -3343,6 +3380,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" @@ -3365,13 +3415,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" @@ -3381,12 +3427,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" @@ -3399,6 +3444,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" @@ -3485,6 +3531,17 @@ check_next_foreign: the undo log. We can directly exit here and return the DB_TOO_MANY_CONCURRENT_TRXS error. */ + + /* Mark all indexes available in the data dictionary + cache again. */ + + for (index = dict_table_get_first_index(table); + index != NULL; + index = dict_table_get_next_index(index)) { + rw_lock_x_lock(dict_index_get_lock(index)); + index->to_be_dropped = FALSE; + rw_lock_x_unlock(dict_index_get_lock(index)); + } break; case DB_OUT_OF_FILE_SPACE: @@ -3842,6 +3899,7 @@ row_rename_table_for_mysql( ulint n_constraints_to_drop = 0; ibool old_is_tmp, new_is_tmp; pars_info_t* info = NULL; + ulint retry = 0; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_a(old_name != NULL); @@ -3925,6 +3983,25 @@ row_rename_table_for_mysql( } } + /* Is a foreign key check running on this table? */ + for (retry = 0; retry < 100 + && table->n_foreign_key_checks_running > 0; ++retry) { + row_mysql_unlock_data_dictionary(trx); + os_thread_yield(); + row_mysql_lock_data_dictionary(trx); + } + + if (table->n_foreign_key_checks_running > 0) { + ut_print_timestamp(stderr); + fputs(" InnoDB: Error: in ALTER TABLE ", stderr); + ut_print_name(stderr, trx, TRUE, old_name); + fprintf(stderr, "\n" + "InnoDB: a FOREIGN KEY check is running.\n" + "InnoDB: Cannot rename table.\n"); + err = DB_TABLE_IN_FK_CHECK; + goto funct_exit; + } + /* We use the private SQL parser of Innobase to generate the query graphs needed in updating the dictionary data from system tables. */ @@ -4086,6 +4163,7 @@ end: trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; + err = DB_ERROR; goto funct_exit; } diff --git a/storage/xtradb/row/row0purge.c b/storage/xtradb/row/row0purge.c index 752a2ec9e83..4d4c1afc458 100644 --- a/storage/xtradb/row/row0purge.c +++ b/storage/xtradb/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 *****************************************************************************/ @@ -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; } @@ -530,14 +531,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 +551,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 +602,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, diff --git a/storage/xtradb/row/row0row.c b/storage/xtradb/row/row0row.c index cea70e98dee..380d438c59a 100644 --- a/storage/xtradb/row/row0row.c +++ b/storage/xtradb/row/row0row.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -243,19 +243,16 @@ 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. - - 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))); + if (rec_offs_any_null_extern(rec, offsets)) { + /* This condition can occur during crash recovery + before trx_rollback_active() has completed execution, + or when a concurrently executing + row_ins_index_entry_low() has committed the B-tree + mini-transaction but has not yet managed to restore + the cursor position for writing the big_rec. */ + 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/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c index edfccfc495d..ba3db5bc022 100644 --- a/storage/xtradb/row/row0sel.c +++ b/storage/xtradb/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 @@ -101,12 +101,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, @@ -118,7 +123,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); @@ -132,7 +137,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)); } @@ -219,11 +224,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; @@ -494,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; } } @@ -519,6 +533,8 @@ sel_col_prefetch_buf_free( mem_free(sel_buf->data); } } + + mem_free(prefetch_buf); } /*********************************************************************//** diff --git a/storage/xtradb/row/row0upd.c b/storage/xtradb/row/row0upd.c index 5765d3b76d2..56e55e89c82 100644 --- a/storage/xtradb/row/row0upd.c +++ b/storage/xtradb/row/row0upd.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -23,6 +23,15 @@ Update of a row Created 12/27/1996 Heikki Tuuri *******************************************************/ +#ifdef __WIN__ +/* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */ +# define DEBUG_SYNC_C(dummy) ((void) 0) +#else +# include "my_global.h" /* HAVE_* */ +# include "m_string.h" /* for my_sys.h */ +# include "my_sys.h" /* DEBUG_SYNC_C */ +#endif + #include "row0upd.h" #ifdef UNIV_NONINL @@ -1995,27 +2004,42 @@ row_upd_clust_rec( BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur, &heap, &big_rec, node->update, node->cmpl_info, thr, mtr); /* skip store extern for fake_changes */ - if (big_rec && !(thr_get_trx(thr)->fake_changes)) { - ulint offsets_[REC_OFFS_NORMAL_SIZE]; - rec_t* rec; + if (err == DB_SUCCESS && big_rec && !(thr_get_trx(thr)->fake_changes)) { + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + rec_t* 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 while still x-latching + index->lock and block->lock. Allocate + pages for big_rec in the mtr that + modified the B-tree, but be sure to skip + any pages that were freed in mtr. We will + write out the big_rec pages before + committing the B-tree mini-transaction. If + the system crashes so that crash recovery + will not replay the mtr_commit(&mtr), the + big_rec pages will be left orphaned until + the pages are allocated for something else. + + TODO: If the allocation extends the tablespace, it + will not be redo logged, in either mini-transaction. + Tablespace extension should be redo-logged in the + big_rec mini-transaction, so that recovery will not + fail when the big_rec was written to the extended + portion of the file, in case the file was somehow + truncated in the crash. */ rec = btr_cur_get_rec(btr_cur); + DEBUG_SYNC_C("before_row_upd_extern"); 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, BTR_STORE_UPDATE); + DEBUG_SYNC_C("after_row_upd_extern"); /* 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 @@ -2023,7 +2047,12 @@ row_upd_clust_rec( that a non-updated column was selected for external storage. This non-update would not have been written to the undo log, and thus the record cannot be rolled - back. */ + back. + + However, because we have not executed mtr_commit(mtr) + yet, the update will not be replayed in crash + recovery, and the following assertion failure will + effectively "roll back" the operation. */ ut_a(err == DB_SUCCESS); } diff --git a/storage/xtradb/scripts/export.sh b/storage/xtradb/scripts/export.sh new file mode 100644 index 00000000000..2a4355c1e43 --- /dev/null +++ b/storage/xtradb/scripts/export.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# export current working directory in a format suitable for sending to MySQL +# as a snapshot. also generates the actual snapshot and sends it to MySQL. + +set -eu + +die () { + echo $* + exit 1 +} + +if [ $# -ne 2 ] ; then + die "Usage: export.sh revision-number-of-last-snapshot current-revision-number" +fi + +# If we are run from within the scripts/ directory then change directory to +# one level up so that the relative paths work. +DIR=`basename $PWD` + +if [ "${DIR}" = "scripts" ]; then + cd .. +fi + +START_REV=$(($1 + 1)) +END_REV=$2 + +set +u +if test -z $EDITOR; then + die "\$EDITOR is not set" +fi +set -u + +rm -rf to-mysql +mkdir to-mysql{,/storage,/patches,/mysql-test{,/t,/r,/include}} +svn log -v -r "$START_REV:BASE" > to-mysql/log +svn export -q . to-mysql/storage/innobase + +REV=$START_REV +while [ $REV -le $END_REV ] +do + PATCH=to-mysql/patches/r$REV.patch + svn log -v -r$REV > $PATCH + if [ $(wc -c < $PATCH) -gt 73 ] + then + svn diff -r$(($REV-1)):$REV >> $PATCH + else + rm $PATCH + fi + REV=$(($REV + 1)) +done + +cd to-mysql/storage/innobase + +mv mysql-test/*.test mysql-test/*.opt ../../mysql-test/t +mv mysql-test/*.result ../../mysql-test/r +mv mysql-test/*.inc ../../mysql-test/include +rmdir mysql-test + +rm setup.sh export.sh revert_gen.sh compile-innodb-debug compile-innodb + +cd ../.. +$EDITOR log +cd .. + +fname="innodb-5.1-ss$2.tar.gz" + +rm -f $fname +tar czf $fname to-mysql +scp $fname mysql:snapshots +rm $fname +rm -rf to-mysql + +echo "Sent $fname to MySQL" diff --git a/storage/xtradb/scripts/install_innodb_plugins.sql b/storage/xtradb/scripts/install_innodb_plugins.sql index 5a555a652f7..3fdb8f11e22 100644 --- a/storage/xtradb/scripts/install_innodb_plugins.sql +++ b/storage/xtradb/scripts/install_innodb_plugins.sql @@ -7,11 +7,3 @@ INSTALL PLUGIN innodb_cmp SONAME 'ha_innodb.so'; INSTALL PLUGIN innodb_cmp_reset SONAME 'ha_innodb.so'; INSTALL PLUGIN innodb_cmpmem SONAME 'ha_innodb.so'; INSTALL PLUGIN innodb_cmpmem_reset SONAME 'ha_innodb.so'; -INSTALL PLUGIN XTRADB_ENHANCEMENTS SONAME 'ha_innodb.so'; -INSTALL PLUGIN INNODB_BUFFER_POOL_PAGES SONAME 'ha_innodb.so'; -INSTALL PLUGIN INNODB_BUFFER_POOL_PAGES_BLOB SONAME 'ha_innodb.so'; -INSTALL PLUGIN INNODB_BUFFER_POOL_PAGES_INDEX SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_rseg SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_table_stats SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_index_stats SONAME 'ha_innodb.so'; -INSTALL PLUGIN xtradb_admin_command SONAME 'ha_innodb.so'; diff --git a/storage/xtradb/scripts/install_innodb_plugins_win.sql b/storage/xtradb/scripts/install_innodb_plugins_win.sql index 7cda3335694..8c94b4e240d 100644 --- a/storage/xtradb/scripts/install_innodb_plugins_win.sql +++ b/storage/xtradb/scripts/install_innodb_plugins_win.sql @@ -7,11 +7,3 @@ INSTALL PLUGIN innodb_cmp SONAME 'ha_innodb.dll'; INSTALL PLUGIN innodb_cmp_reset SONAME 'ha_innodb.dll'; INSTALL PLUGIN innodb_cmpmem SONAME 'ha_innodb.dll'; INSTALL PLUGIN innodb_cmpmem_reset SONAME 'ha_innodb.dll'; -INSTALL PLUGIN XTRADB_ENHANCEMENTS SONAME 'ha_innodb.dll'; -INSTALL PLUGIN INNODB_BUFFER_POOL_PAGES SONAME 'ha_innodb.dll'; -INSTALL PLUGIN INNODB_BUFFER_POOL_PAGES_BLOB SONAME 'ha_innodb.dll'; -INSTALL PLUGIN INNODB_BUFFER_POOL_PAGES_INDEX SONAME 'ha_innodb.dll'; -INSTALL PLUGIN innodb_rseg SONAME 'ha_innodb.dll'; -INSTALL PLUGIN innodb_table_stats SONAME 'ha_innodb.dll'; -INSTALL PLUGIN innodb_index_stats SONAME 'ha_innodb.dll'; -INSTALL PLUGIN xtradb_admin_command SONAME 'ha_innodb.dll'; diff --git a/storage/xtradb/setup.sh b/storage/xtradb/setup.sh new file mode 100644 index 00000000000..b5d8299d411 --- /dev/null +++ b/storage/xtradb/setup.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# +# Copyright (c) 1995, 2009, Innobase Oy. 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 +# Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# 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 +# +# Prepare the MySQL source code tree for building +# with checked-out InnoDB Subversion directory. + +# This script assumes that the current directory is storage/innobase. + +set -eu + +TARGETDIR=../storage/innodb_plugin + +# link the build scripts +BUILDSCRIPTS="compile-innodb compile-innodb-debug" +for script in $BUILDSCRIPTS ; do + ln -sf $TARGETDIR/$script ../../BUILD/ +done + +cd ../../mysql-test/t +ln -sf ../$TARGETDIR/mysql-test/*.test ../$TARGETDIR/mysql-test/*.opt . +cd ../r +ln -sf ../$TARGETDIR/mysql-test/*.result . +cd ../include +ln -sf ../$TARGETDIR/mysql-test/*.inc . + +# Apply any patches that are needed to make the mysql-test suite successful. +# These patches are usually needed because of deviations of behavior between +# the stock InnoDB and the InnoDB Plugin. +cd ../.. +for patch in storage/innobase/mysql-test/patches/*.diff ; do + if [ "${patch}" != "storage/innobase/mysql-test/patches/*.diff" ] ; then + patch -p0 < ${patch} + fi +done diff --git a/storage/xtradb/sync/sync0rw.c b/storage/xtradb/sync/sync0rw.c index fe000e7d008..054423f9116 100644 --- a/storage/xtradb/sync/sync0rw.c +++ b/storage/xtradb/sync/sync0rw.c @@ -611,6 +611,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; @@ -927,11 +930,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)); @@ -975,11 +980,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/xtradb/sync/sync0sync.c b/storage/xtradb/sync/sync0sync.c index 277a53e4fb2..18a961ac18b 100644 --- a/storage/xtradb/sync/sync0sync.c +++ b/storage/xtradb/sync/sync0sync.c @@ -1178,7 +1178,6 @@ sync_thread_add_level( case SYNC_BUF_ZIP_HASH: case SYNC_BUF_POOL: case SYNC_SEARCH_SYS: - case SYNC_SEARCH_SYS_CONF: case SYNC_TRX_LOCK_HEAP: case SYNC_KERNEL: case SYNC_IBUF_BITMAP_MUTEX: @@ -1191,6 +1190,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)" @@ -1254,21 +1254,32 @@ 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: + /* 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)) { + ut_a(sync_thread_levels_g(array, level - 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)); diff --git a/storage/xtradb/trx/trx0purge.c b/storage/xtradb/trx/trx0purge.c index 5a8b42af3af..6c49c5d7ff8 100644 --- a/storage/xtradb/trx/trx0purge.c +++ b/storage/xtradb/trx/trx0purge.c @@ -1111,7 +1111,7 @@ trx_purge(void) { que_thr_t* thr; /* que_thr_t* thr2; */ - ulint old_pages_handled; + ulonglong old_pages_handled; mutex_enter(&(purge_sys->mutex)); @@ -1210,7 +1210,7 @@ trx_purge(void) (ulong) purge_sys->n_pages_handled); } - return(purge_sys->n_pages_handled - old_pages_handled); + return((ulint) (purge_sys->n_pages_handled - old_pages_handled)); } /********************************************************************** diff --git a/storage/xtradb/trx/trx0rec.c b/storage/xtradb/trx/trx0rec.c index a7a393d31c8..124d22eec63 100644 --- a/storage/xtradb/trx/trx0rec.c +++ b/storage/xtradb/trx/trx0rec.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -1110,13 +1110,14 @@ 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)) +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; @@ -1126,6 +1127,7 @@ trx_undo_erase_page_end( (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free); mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr); + return(first_free != TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); } /***********************************************************//** @@ -1187,12 +1189,16 @@ trx_undo_report_row_operation( trx_t* trx; trx_undo_t* undo; ulint page_no; + buf_block_t* undo_block; trx_rseg_t* rseg; mtr_t mtr; ulint err = DB_SUCCESS; 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)); @@ -1226,10 +1232,13 @@ trx_undo_report_row_operation( if (UNIV_UNLIKELY(!undo)) { /* Did not succeed */ + ut_ad(err != DB_SUCCESS); mutex_exit(&(trx->undo_mutex)); return(err); } + + ut_ad(err == DB_SUCCESS); } else { ut_ad(op_type == TRX_UNDO_MODIFY_OP); @@ -1243,30 +1252,30 @@ trx_undo_report_row_operation( if (UNIV_UNLIKELY(!undo)) { /* Did not succeed */ + ut_ad(err != DB_SUCCESS); mutex_exit(&(trx->undo_mutex)); return(err); } + ut_ad(err == DB_SUCCESS); offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); } - page_no = undo->last_page_no; - mtr_start(&mtr); - for (;;) { - buf_block_t* undo_block; + page_no = undo->last_page_no; + undo_block = buf_page_get_gen( + undo->space, undo->zip_size, page_no, RW_X_LATCH, + undo->guess_block, BUF_GET, __FILE__, __LINE__, &mtr); + buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE); + + do { page_t* undo_page; ulint offset; - undo_block = buf_page_get_gen(undo->space, undo->zip_size, - page_no, RW_X_LATCH, - undo->guess_block, BUF_GET, - __FILE__, __LINE__, &mtr); - buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE); - undo_page = buf_block_get_frame(undo_block); + ut_ad(page_no == buf_block_get_page_no(undo_block)); if (op_type == TRX_UNDO_INSERT_OP) { offset = trx_undo_page_report_insert( @@ -1284,7 +1293,31 @@ 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. */ + + /* 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); + + err = DB_TOO_BIG_RECORD; + goto err_exit; + } + mtr_commit(&mtr); } else { /* Success */ @@ -1304,39 +1337,39 @@ 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 a pessimistic insert in a B-tree, and we must reserve the counterpart of the tree latch, which is the rseg mutex. */ - mutex_enter(&(rseg->mutex)); + mutex_enter(&rseg->mutex); + undo_block = trx_undo_add_page(trx, undo, &mtr); + mutex_exit(&rseg->mutex); - page_no = trx_undo_add_page(trx, undo, &mtr); + page_no = undo->last_page_no; + } while (undo_block != NULL); - mutex_exit(&(rseg->mutex)); + /* Did not succeed: out of space */ + err = DB_OUT_OF_FILE_SPACE; - if (UNIV_UNLIKELY(page_no == FIL_NULL)) { - /* Did not succeed: out of 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/xtradb/trx/trx0sys.c b/storage/xtradb/trx/trx0sys.c index 6a15d4261eb..1f7e314a953 100644 --- a/storage/xtradb/trx/trx0sys.c +++ b/storage/xtradb/trx/trx0sys.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -131,6 +131,11 @@ static const char* file_format_name_map[] = { static const ulint FILE_FORMAT_NAME_N = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]); +#ifdef UNIV_DEBUG +/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ +uint trx_rseg_n_slots_debug = 0; +#endif + #ifndef UNIV_HOTBACKUP /** This is used to track the maximum file format id known to InnoDB. It's updated via SET GLOBAL innodb_file_format_check = 'x' or when we open @@ -246,9 +251,7 @@ trx_sys_create_doublewrite_buf(void) { buf_block_t* block; buf_block_t* block2; -#ifdef UNIV_SYNC_DEBUG buf_block_t* new_block; -#endif /* UNIV_SYNC_DEBUG */ byte* doublewrite; byte* fseg_header; ulint page_no; @@ -327,10 +330,9 @@ start_again: for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE + FSP_EXTENT_SIZE / 2; i++) { - page_no = fseg_alloc_free_page(fseg_header, - prev_page_no + 1, - FSP_UP, &mtr); - if (page_no == FIL_NULL) { + new_block = fseg_alloc_free_page( + fseg_header, prev_page_no + 1, FSP_UP, &mtr); + if (new_block == NULL) { fprintf(stderr, "InnoDB: Cannot create doublewrite" " buffer: you must\n" @@ -351,13 +353,8 @@ start_again: the page position in the tablespace, then the page has not been written to in doublewrite. */ -#ifdef UNIV_SYNC_DEBUG - new_block = -#endif /* UNIV_SYNC_DEBUG */ - buf_page_get(TRX_SYS_SPACE, 0, page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level(new_block, - SYNC_NO_ORDER_CHECK); + ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1); + page_no = buf_block_get_page_no(new_block); if (i == FSP_EXTENT_SIZE / 2) { ut_a(page_no == FSP_EXTENT_SIZE); @@ -474,10 +471,10 @@ start_again: for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE + FSP_EXTENT_SIZE / 2; i++) { - page_no = fseg_alloc_free_page(fseg_header, + new_block = fseg_alloc_free_page(fseg_header, prev_page_no + 1, FSP_UP, &mtr); - if (page_no == FIL_NULL) { + if (new_block == NULL) { fprintf(stderr, "InnoDB: Cannot create doublewrite" " buffer: you must\n" @@ -498,13 +495,8 @@ start_again: the page position in the tablespace, then the page has not been written to in doublewrite. */ -#ifdef UNIV_SYNC_DEBUG - new_block = -#endif /* UNIV_SYNC_DEBUG */ - buf_page_get(TRX_DOUBLEWRITE_SPACE, 0, page_no, - RW_X_LATCH, &mtr); - buf_block_dbg_add_level(new_block, - SYNC_NO_ORDER_CHECK); + ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1); + page_no = buf_block_get_page_no(new_block); if (i == FSP_EXTENT_SIZE / 2) { ut_a(page_no == FSP_EXTENT_SIZE); diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c index bf042db4972..0cecbf2eea9 100644 --- a/storage/xtradb/trx/trx0trx.c +++ b/storage/xtradb/trx/trx0trx.c @@ -1078,6 +1078,8 @@ trx_commit_off_kernel( ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0); UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx); + + trx->error_state = DB_SUCCESS; } /****************************************************************//** diff --git a/storage/xtradb/trx/trx0undo.c b/storage/xtradb/trx/trx0undo.c index ec1cd2d2c43..fd89936fd33 100644 --- a/storage/xtradb/trx/trx0undo.c +++ b/storage/xtradb/trx/trx0undo.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2012, 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 *****************************************************************************/ @@ -870,9 +870,9 @@ trx_undo_discard_latest_update_undo( #ifndef UNIV_HOTBACKUP /********************************************************************//** Tries to add a page to the undo log segment where the undo log is placed. -@return page number if success, else FIL_NULL */ +@return X-latched block if success, else NULL */ UNIV_INTERN -ulint +buf_block_t* trx_undo_add_page( /*==============*/ trx_t* trx, /*!< in: transaction */ @@ -882,11 +882,10 @@ trx_undo_add_page( the rollback segment mutex */ { page_t* header_page; + buf_block_t* new_block; page_t* new_page; trx_rseg_t* rseg; - ulint page_no; ulint n_reserved; - ibool success; ut_ad(mutex_own(&(trx->undo_mutex))); ut_ad(!mutex_own(&kernel_mutex)); @@ -896,37 +895,37 @@ trx_undo_add_page( if (rseg->curr_size == rseg->max_size) { - return(FIL_NULL); + return(NULL); } header_page = trx_undo_page_get(undo->space, undo->zip_size, undo->hdr_page_no, mtr); - success = fsp_reserve_free_extents(&n_reserved, undo->space, 1, - FSP_UNDO, mtr); - if (!success) { + if (!fsp_reserve_free_extents(&n_reserved, undo->space, 1, + FSP_UNDO, mtr)) { - return(FIL_NULL); + return(NULL); } - 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); + new_block = fseg_alloc_free_page_general( + TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + + header_page, + undo->top_page_no + 1, FSP_UP, TRUE, mtr, mtr); fil_space_release_free_extents(undo->space, n_reserved); - if (page_no == FIL_NULL) { + if (new_block == NULL) { /* No space left */ - return(FIL_NULL); + return(NULL); } - undo->last_page_no = page_no; + ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1); + buf_block_dbg_add_level(new_block, SYNC_TRX_UNDO_PAGE); + undo->last_page_no = buf_block_get_page_no(new_block); - new_page = trx_undo_page_get(undo->space, undo->zip_size, - page_no, mtr); + new_page = buf_block_get_frame(new_block); trx_undo_page_init(new_page, undo->type, mtr); @@ -935,7 +934,7 @@ trx_undo_add_page( undo->size++; rseg->curr_size++; - return(page_no); + return(new_block); } /********************************************************************//** @@ -998,29 +997,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 +1054,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 +1084,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 +1099,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); } diff --git a/storage/xtradb/ut/ut0auxconf_atomic_pthread_t_gcc.c b/storage/xtradb/ut/ut0auxconf_atomic_pthread_t_gcc.c new file mode 100644 index 00000000000..30de5aa6f17 --- /dev/null +++ b/storage/xtradb/ut/ut0auxconf_atomic_pthread_t_gcc.c @@ -0,0 +1,43 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +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 + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles, then pthread_t objects can be used as arguments +to GCC atomic builtin functions. + +Created March 5, 2009 Vasil Dimov +*****************************************************************************/ + +#include +#include + +int +main(int argc, char** argv) +{ + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + __sync_bool_compare_and_swap(&x1, x2, x3); + + return(0); +} diff --git a/storage/xtradb/ut/ut0auxconf_atomic_pthread_t_solaris.c b/storage/xtradb/ut/ut0auxconf_atomic_pthread_t_solaris.c new file mode 100644 index 00000000000..310603c7503 --- /dev/null +++ b/storage/xtradb/ut/ut0auxconf_atomic_pthread_t_solaris.c @@ -0,0 +1,54 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +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 + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and returns 0, then pthread_t objects can be used as +arguments to Solaris libc atomic functions. + +Created April 18, 2009 Vasil Dimov +*****************************************************************************/ + +#include +#include + +int +main(int argc, char** argv) +{ + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + if (sizeof(pthread_t) == 4) { + + atomic_cas_32(&x1, x2, x3); + + } else if (sizeof(pthread_t) == 8) { + + atomic_cas_64(&x1, x2, x3); + + } else { + + return(1); + } + + return(0); +} diff --git a/storage/xtradb/ut/ut0auxconf_have_gcc_atomics.c b/storage/xtradb/ut/ut0auxconf_have_gcc_atomics.c new file mode 100644 index 00000000000..da5c13d7d79 --- /dev/null +++ b/storage/xtradb/ut/ut0auxconf_have_gcc_atomics.c @@ -0,0 +1,61 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +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 + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and returns 0, then GCC atomic funcions are available. + +Created September 12, 2009 Vasil Dimov +*****************************************************************************/ + +int +main(int argc, char** argv) +{ + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); +} diff --git a/storage/xtradb/ut/ut0auxconf_have_solaris_atomics.c b/storage/xtradb/ut/ut0auxconf_have_solaris_atomics.c new file mode 100644 index 00000000000..7eb704edd4b --- /dev/null +++ b/storage/xtradb/ut/ut0auxconf_have_solaris_atomics.c @@ -0,0 +1,39 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +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 + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles, then Solaris libc atomic funcions are available. + +Created April 18, 2009 Vasil Dimov +*****************************************************************************/ +#include + +int +main(int argc, char** argv) +{ + ulong_t ulong = 0; + uint32_t uint32 = 0; + uint64_t uint64 = 0; + + atomic_cas_ulong(&ulong, 0, 1); + atomic_cas_32(&uint32, 0, 1); + atomic_cas_64(&uint64, 0, 1); + atomic_add_long(&ulong, 0); + + return(0); +} diff --git a/storage/xtradb/ut/ut0auxconf_pause.c b/storage/xtradb/ut/ut0auxconf_pause.c new file mode 100644 index 00000000000..54d63bdd9bc --- /dev/null +++ b/storage/xtradb/ut/ut0auxconf_pause.c @@ -0,0 +1,32 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +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 + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and can be run and returns 0, then the pause +instruction is available. + +Created Jul 21, 2009 Vasil Dimov +*****************************************************************************/ + +int +main(int argc, char** argv) +{ + __asm__ __volatile__ ("pause"); + + return(0); +} diff --git a/storage/xtradb/ut/ut0auxconf_sizeof_pthread_t.c b/storage/xtradb/ut/ut0auxconf_sizeof_pthread_t.c new file mode 100644 index 00000000000..96add4526ef --- /dev/null +++ b/storage/xtradb/ut/ut0auxconf_sizeof_pthread_t.c @@ -0,0 +1,35 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +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 should compile and when run, print a single line like: +#define SIZEOF_PTHREAD_T %d + +Created April 18, 2009 Vasil Dimov +*****************************************************************************/ + +#include +#include + +int +main(int argc, char** argv) +{ + printf("#define SIZEOF_PTHREAD_T %d\n", (int) sizeof(pthread_t)); + + return(0); +} diff --git a/storage/xtradb/ut/ut0mem.c b/storage/xtradb/ut/ut0mem.c index 95fb2187b79..9f9eb1c4d49 100644 --- a/storage/xtradb/ut/ut0mem.c +++ b/storage/xtradb/ut/ut0mem.c @@ -84,17 +84,13 @@ ut_mem_init(void) #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined and set_to_zero is TRUE. +Allocates memory. @return own: allocated memory */ UNIV_INTERN void* ut_malloc_low( /*==========*/ ulint n, /*!< in: number of bytes to allocate */ - ibool set_to_zero, /*!< in: TRUE if allocated memory should be - set to zero if UNIV_SET_MEM_TO_ZERO is - defined */ ibool assert_on_error)/*!< in: if TRUE, we crash mysqld if the memory cannot be allocated */ { @@ -106,12 +102,6 @@ ut_malloc_low( ret = malloc(n); ut_a(ret || !assert_on_error); -#ifdef UNIV_SET_MEM_TO_ZERO - if (set_to_zero) { - memset(ret, '\0', n); - UNIV_MEM_ALLOC(ret, n); - } -#endif return(ret); } @@ -199,12 +189,6 @@ retry: #endif } - if (set_to_zero) { -#ifdef UNIV_SET_MEM_TO_ZERO - memset(ret, '\0', n + sizeof(ut_mem_block_t)); -#endif - } - UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t)); ((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t); @@ -221,74 +205,10 @@ retry: void* ret = malloc(n); ut_a(ret || !assert_on_error); -# ifdef UNIV_SET_MEM_TO_ZERO - if (set_to_zero) { - memset(ret, '\0', n); - } -# endif return(ret); #endif /* !UNIV_HOTBACKUP */ } -/**********************************************************************//** -Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is -defined. -@return own: allocated memory */ -UNIV_INTERN -void* -ut_malloc( -/*======*/ - ulint n) /*!< in: number of bytes to allocate */ -{ -#ifndef UNIV_HOTBACKUP - return(ut_malloc_low(n, TRUE, TRUE)); -#else /* !UNIV_HOTBACKUP */ - return(malloc(n)); -#endif /* !UNIV_HOTBACKUP */ -} - -#ifndef UNIV_HOTBACKUP -/**********************************************************************//** -Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs -out. It cannot be used if we want to return an error message. Prints to -stderr a message if fails. -@return TRUE if succeeded */ -UNIV_INTERN -ibool -ut_test_malloc( -/*===========*/ - ulint n) /*!< in: try to allocate this many bytes */ -{ - void* ret; - - ret = malloc(n); - - if (ret == NULL) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: cannot allocate" - " %lu bytes of memory for\n" - "InnoDB: a BLOB with malloc! Total allocated memory\n" - "InnoDB: by InnoDB %lu bytes." - " Operating system errno: %d\n" - "InnoDB: Check if you should increase" - " the swap file or\n" - "InnoDB: ulimits of your operating system.\n" - "InnoDB: On FreeBSD check you have" - " compiled the OS with\n" - "InnoDB: a big enough maximum process size.\n", - (ulong) n, - (ulong) ut_total_allocated_memory, - (int) errno); - return(FALSE); - } - - free(ret); - - return(TRUE); -} -#endif /* !UNIV_HOTBACKUP */ - /**********************************************************************//** Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is a nop. */ From 8d69a0feaaf61a547e156c60a6c17e0e8282378f Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 22 Aug 2012 18:40:27 +0200 Subject: [PATCH 05/11] MDEV-472 mysql-test-run --valgrind main.ps_2myisam gives warning about not initialized memory Item::get_date() should return 1 unless the value is a valid date. --- sql/item_subselect.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 16f754575f5..bd55d196704 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1218,7 +1218,7 @@ bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,uint fuzzydate) else { reset(); - return 0; + return 1; } } From 4201939d575e3530d3c5e0fd9668d11062f70d79 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 23 Aug 2012 13:52:36 +0200 Subject: [PATCH 06/11] remove mysql-5.1 assert that is already absent in mysql-5.5 --- storage/innobase/handler/ha_innodb.cc | 1 - storage/innodb_plugin/handler/ha_innodb.cc | 1 - storage/xtradb/handler/ha_innodb.cc | 1 - 3 files changed, 3 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 42f942bbef4..66f90dcebaa 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6376,7 +6376,6 @@ ha_innobase::records_in_range( void* heap2; DBUG_ENTER("records_in_range"); - DBUG_ASSERT(min_key || max_key); ut_a(prebuilt->trx == thd_to_trx(ha_thd())); diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 1deb2feaa25..4f6c2a40f2c 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -7458,7 +7458,6 @@ ha_innobase::records_in_range( mem_heap_t* heap; DBUG_ENTER("records_in_range"); - DBUG_ASSERT(min_key || max_key); ut_a(prebuilt->trx == thd_to_trx(ha_thd())); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 522ac5842d5..066c393fb4d 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -8196,7 +8196,6 @@ ha_innobase::records_in_range( mem_heap_t* heap; DBUG_ENTER("records_in_range"); - DBUG_ASSERT(min_key || max_key); ut_a(prebuilt->trx == thd_to_trx(ha_thd())); From f024e0d5e9232426a96434efe374a879c0df783f Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 24 Aug 2012 15:30:05 +0200 Subject: [PATCH 07/11] MDEV-484 : allow compilation/packaging on Windows with newly released VS2012 --- win/packaging/ca/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/packaging/ca/CMakeLists.txt b/win/packaging/ca/CMakeLists.txt index 940e9e3a7d1..0da1e5d67b1 100644 --- a/win/packaging/ca/CMakeLists.txt +++ b/win/packaging/ca/CMakeLists.txt @@ -33,7 +33,7 @@ IF(MSVC_VERSION EQUAL 1400) ELSEIF(MSVC_VERSION EQUAL 1500) SET(WIX35_MSVC_SUFFIX "_2008") SET(WIX36_MSVC_SUFFIX "VS2008") -ELSEIF(MSVC_VERSION EQUAL 1600) +ELSEIF(MSVC_VERSION EQUAL 1600 OR MSVC_VERSION EQUAL 1700 ) SET(WIX35_MSVC_SUFFIX "_2010") SET(WIX36_MSVC_SUFFIX "VS2010") ELSE() From 077e453f9f61a123c9fabc66e62ced35922b09b8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 24 Aug 2012 15:32:44 +0200 Subject: [PATCH 08/11] Fix compiler warnings --- include/m_string.h | 3 +-- mysys/mf_iocache2.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/m_string.h b/include/m_string.h index be9af2ad558..71d8100e53f 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -249,8 +249,7 @@ extern ulonglong strtoull(const char *str, char **ptr, int base); extern size_t my_vsnprintf(char *str, size_t n, const char *format, va_list ap); -extern size_t my_snprintf(char *to, size_t n, const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 3, 4); +extern size_t my_snprintf(char *to, size_t n, const char *fmt, ...); #if defined(__cplusplus) } diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 7c967cf1bf2..5836314b742 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -437,7 +437,7 @@ process_flags: /* TODO: implement precision */ if (backtick_quoting) { - size_t total= my_b_write_backtick_quote(info, (uchar *) par, length2); + size_t total= my_b_write_backtick_quote(info, par, length2); if (total == (size_t)-1) goto err; out_length+= total; From f37610ecb4c7917f1dd3015eb897b4ff41cd2b57 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 24 Aug 2012 19:11:54 +0200 Subject: [PATCH 09/11] Fix compiler warning --- sql/mysql_priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f7a5f05ae9a..337825fa857 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -845,7 +845,7 @@ Item *negate_expression(THD *thd, Item *expr); /* log.cc */ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args); -void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); +void sql_print_error(const char *format, ...); void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); void sql_print_information(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); From 4d2b05b7d795bfa980065b4f4465444549401c9f Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 25 Aug 2012 09:15:57 +0300 Subject: [PATCH 10/11] fix for MDEV-367 The problem was that was_null and null_value variables was reset in each reexecution of IN subquery, but engine rerun only for non-constant subqueries. Fixed checking constant in Item_equal sort. Fix constant reporting in Item_subselect. --- mysql-test/r/subselect.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_mat.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_opts.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_scache.result | 26 +++++++++++++++++++++++ mysql-test/r/subselect_no_semijoin.result | 26 +++++++++++++++++++++++ mysql-test/t/subselect.test | 21 ++++++++++++++++++ sql/item_subselect.cc | 26 ++++++++++++++++++++++- sql/sql_select.cc | 4 ++-- sql/sql_union.cc | 2 ++ 9 files changed, 180 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 024dca5d1bb..5126e6b8d5b 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -6137,5 +6137,31 @@ NULL UNION RESULT ALL NULL NULL NULL NULL NULL SELECT MIN(a) AS min_a, a FROM t1 WHERE 1=2 HAVING a NOT IN ( SELECT a from t1 UNION select a+1 from t1 ) OR min_a != 1; min_a a drop table t1; +# +# MDEV-367: Different results with and without subquery_cache on +# a query with a constant NOT IN condition +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2),(3); +set @mdev367_optimizer_switch = @@optimizer_switch; +set optimizer_switch = 'subquery_cache=on'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +set optimizer_switch = 'subquery_cache=off'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +DROP TABLE t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index e8c084f9700..ad56c1c2f49 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -6136,6 +6136,32 @@ NULL UNION RESULT ALL NULL NULL NULL NULL NULL SELECT MIN(a) AS min_a, a FROM t1 WHERE 1=2 HAVING a NOT IN ( SELECT a from t1 UNION select a+1 from t1 ) OR min_a != 1; min_a a drop table t1; +# +# MDEV-367: Different results with and without subquery_cache on +# a query with a constant NOT IN condition +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2),(3); +set @mdev367_optimizer_switch = @@optimizer_switch; +set optimizer_switch = 'subquery_cache=on'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +set optimizer_switch = 'subquery_cache=off'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +DROP TABLE t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set optimizer_switch=default; diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index ace1f198853..92bd97593b3 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -6132,6 +6132,32 @@ NULL UNION RESULT ALL NULL NULL NULL NULL NULL SELECT MIN(a) AS min_a, a FROM t1 WHERE 1=2 HAVING a NOT IN ( SELECT a from t1 UNION select a+1 from t1 ) OR min_a != 1; min_a a drop table t1; +# +# MDEV-367: Different results with and without subquery_cache on +# a query with a constant NOT IN condition +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2),(3); +set @mdev367_optimizer_switch = @@optimizer_switch; +set optimizer_switch = 'subquery_cache=on'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +set optimizer_switch = 'subquery_cache=off'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +DROP TABLE t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 32f24f9cf14..7e2ae9606ef 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -6143,6 +6143,32 @@ NULL UNION RESULT ALL NULL NULL NULL NULL NULL SELECT MIN(a) AS min_a, a FROM t1 WHERE 1=2 HAVING a NOT IN ( SELECT a from t1 UNION select a+1 from t1 ) OR min_a != 1; min_a a drop table t1; +# +# MDEV-367: Different results with and without subquery_cache on +# a query with a constant NOT IN condition +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2),(3); +set @mdev367_optimizer_switch = @@optimizer_switch; +set optimizer_switch = 'subquery_cache=on'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +set optimizer_switch = 'subquery_cache=off'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +DROP TABLE t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set optimizer_switch=default; diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 3860bb9fb18..53b914a5af0 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -6132,6 +6132,32 @@ NULL UNION RESULT ALL NULL NULL NULL NULL NULL SELECT MIN(a) AS min_a, a FROM t1 WHERE 1=2 HAVING a NOT IN ( SELECT a from t1 UNION select a+1 from t1 ) OR min_a != 1; min_a a drop table t1; +# +# MDEV-367: Different results with and without subquery_cache on +# a query with a constant NOT IN condition +# +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2),(3); +set @mdev367_optimizer_switch = @@optimizer_switch; +set optimizer_switch = 'subquery_cache=on'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +set optimizer_switch = 'subquery_cache=off'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +a +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +a ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) +1 NULL +2 NULL +3 NULL +set optimizer_switch=@mdev367_optimizer_switch; +DROP TABLE t1; # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; set @optimizer_switch_for_subselect_test=null; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index a476551ff08..70682842ee1 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -5208,5 +5208,26 @@ SELECT MIN(a) AS min_a, a FROM t1 WHERE 1=2 HAVING a NOT IN ( SELECT a from t1 U drop table t1; +--echo # +--echo # MDEV-367: Different results with and without subquery_cache on +--echo # a query with a constant NOT IN condition +--echo # +CREATE TABLE t1 (a INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1),(2),(3); + +set @mdev367_optimizer_switch = @@optimizer_switch; + +set optimizer_switch = 'subquery_cache=on'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +set optimizer_switch=@mdev367_optimizer_switch; + +set optimizer_switch = 'subquery_cache=off'; +SELECT * FROM t1 WHERE ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) OR a > 100; +SELECT *, ( 3, 3 ) NOT IN ( SELECT NULL, NULL ) FROM t1; +set optimizer_switch=@mdev367_optimizer_switch; + +DROP TABLE t1; + --echo # return optimizer switch changed in the beginning of this test set optimizer_switch=@subselect_tmp; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index bd55d196704..7063f87c676 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -765,7 +765,9 @@ table_map Item_subselect::used_tables() const bool Item_subselect::const_item() const { - return thd->lex->context_analysis_only ? FALSE : const_item_cache; + return (thd->lex->context_analysis_only ? + FALSE : + forced_const || const_item_cache); } Item *Item_subselect::get_tmp_table_item(THD *thd_arg) @@ -1484,6 +1486,10 @@ double Item_in_subselect::val_real() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + if (forced_const) + return value; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1504,6 +1510,10 @@ longlong Item_in_subselect::val_int() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + if (forced_const) + return value; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1524,6 +1534,10 @@ String *Item_in_subselect::val_str(String *str) */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + if (forced_const) + goto value_is_ready; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1535,6 +1549,7 @@ String *Item_in_subselect::val_str(String *str) null_value= TRUE; return 0; } +value_is_ready: str->set((ulonglong)value, &my_charset_bin); return str; } @@ -1545,6 +1560,8 @@ bool Item_in_subselect::val_bool() DBUG_ASSERT(fixed == 1); if (forced_const) return value; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; if (exec()) { @@ -1563,6 +1580,10 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) method should not be used */ DBUG_ASSERT(0); + if (forced_const) + goto value_is_ready; + DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) || + ! engine->is_executed()); null_value= was_null= FALSE; DBUG_ASSERT(fixed == 1); if (exec()) @@ -1572,6 +1593,7 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) } if (was_null && !value) null_value= TRUE; +value_is_ready: int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); return decimal_value; } @@ -3117,6 +3139,8 @@ int subselect_single_select_engine::exec() tab->read_record.read_record= tab->save_read_record; } executed= 1; + if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN)) + item->make_const(); thd->where= save_where; thd->lex->current_select= save_select; DBUG_RETURN(join->error || thd->is_fatal_error || thd->is_error()); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 14641ee6b04..5f2e97d57c1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11621,9 +11621,9 @@ static int compare_fields_by_table_order(Item *field1, bool outer_ref= 0; Item_field *f1= (Item_field *) (field1->real_item()); Item_field *f2= (Item_field *) (field2->real_item()); - if (f1->const_item()) + if (field1->const_item() || f1->const_item()) return 1; - if (f2->const_item()) + if (field2->const_item() || f2->const_item()) return -1; if (f2->used_tables() & OUTER_REF_TABLE_BIT) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 5c235fd1778..942392c4c98 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -616,6 +616,8 @@ bool st_select_lex_unit::exec() if (executed && !uncacheable && !describe) DBUG_RETURN(FALSE); executed= 1; + if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item) + item->make_const(); saved_error= optimize(); From e988c4dde6c1b88523b1d4e748cbd4f5025b128d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 24 Aug 2012 23:43:18 +0200 Subject: [PATCH 11/11] MDEV-336 oqgraph 5.5 crashes in buildbot force -fno-strict-aliasing for oqgraph --- storage/oqgraph/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/oqgraph/Makefile.am b/storage/oqgraph/Makefile.am index e99e134db02..052c0e9a773 100644 --- a/storage/oqgraph/Makefile.am +++ b/storage/oqgraph/Makefile.am @@ -38,7 +38,7 @@ BOOST_CXXFLAGS = -frtti -fexceptions -fimplicit-templates # it also makes an extra register available in many functions. # It also makes debugging impossible on some machines. # (automatically gets enabled anyway by -O* on some architectures) -BOOST_CXXFLAGS+= -O3 -fstrict-aliasing +BOOST_CXXFLAGS+= -O3 -fno-strict-aliasing BOOST_CXXFLAGS+= -falign-loops if HAVE_FVISIBILITY_INLINES_HIDDEN BOOST_CXXFLAGS+= -fvisibility-inlines-hidden