mirror of
https://github.com/MariaDB/server.git
synced 2025-08-30 11:22:14 +03:00
Bug#12861864 RACE CONDITION IN BTR_GET_SIZE() AND DROP INDEX/TABLE/DATABASE
also filed as Bug#13146269, Bug#13713178 btr_get_size(): Add mtr_t parameter. Require that the caller S-latches index->lock. If index->page==FIL_NULL or the index is to be dropped, return ULINT_UNDEFINED to indicate that the statistics are unavailable. dict_update_statistics(): If btr_get_size() returns ULINT_UNDEFINED, fake the index cardinality statistics. dict_index_set_page(): Unused function, remove. row_drop_table_for_mysql(): Before starting to drop the table, mark the indexes unavailable in the data dictionary cache while holding index->lock X-latch. ha_innobase::prepare_drop_index(), ha_innobase::final_drop_index(): When setting index->to_be_dropped, acquire the index->lock X-latch. rb:960 approved by Jimmy Yang
This commit is contained in:
@@ -1,3 +1,11 @@
|
|||||||
|
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
|
2012-02-15 The InnoDB Team
|
||||||
|
|
||||||
* btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, ibuf/ibuf0ibuf.c,
|
* btr/btr0btr.c, btr/btr0cur.c, fsp/fsp0fsp.c, ibuf/ibuf0ibuf.c,
|
||||||
|
@@ -991,45 +991,49 @@ btr_page_alloc(
|
|||||||
|
|
||||||
/**************************************************************//**
|
/**************************************************************//**
|
||||||
Gets the number of pages in a B-tree.
|
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
|
UNIV_INTERN
|
||||||
ulint
|
ulint
|
||||||
btr_get_size(
|
btr_get_size(
|
||||||
/*=========*/
|
/*=========*/
|
||||||
dict_index_t* index, /*!< in: index */
|
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;
|
fseg_header_t* seg_header;
|
||||||
page_t* root;
|
page_t* root;
|
||||||
ulint n;
|
ulint n;
|
||||||
ulint dummy;
|
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 (flag == BTR_N_LEAF_PAGES) {
|
if (flag == BTR_N_LEAF_PAGES) {
|
||||||
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
|
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) {
|
} else if (flag == BTR_TOTAL_SIZE) {
|
||||||
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
|
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;
|
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 {
|
} else {
|
||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtr_commit(&mtr);
|
|
||||||
|
|
||||||
return(n);
|
return(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4267,16 +4267,27 @@ dict_update_statistics(
|
|||||||
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
|
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
|
||||||
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
|
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
|
||||||
&& dict_index_is_clust(index)))) {
|
&& dict_index_is_clust(index)))) {
|
||||||
|
mtr_t mtr;
|
||||||
ulint size;
|
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);
|
||||||
|
|
||||||
|
size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
|
||||||
|
|
||||||
|
if (size != ULINT_UNDEFINED) {
|
||||||
sum_of_index_sizes += size;
|
sum_of_index_sizes += size;
|
||||||
|
index->stat_index_size = size;
|
||||||
|
size = btr_get_size(
|
||||||
|
index, BTR_N_LEAF_PAGES, &mtr);
|
||||||
|
}
|
||||||
|
|
||||||
size = btr_get_size(index, BTR_N_LEAF_PAGES);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
if (size == 0) {
|
switch (size) {
|
||||||
|
case ULINT_UNDEFINED:
|
||||||
|
goto fake_statistics;
|
||||||
|
case 0:
|
||||||
/* The root node of the tree is a leaf */
|
/* The root node of the tree is a leaf */
|
||||||
size = 1;
|
size = 1;
|
||||||
}
|
}
|
||||||
@@ -4293,6 +4304,7 @@ dict_update_statistics(
|
|||||||
various means, also via secondary indexes. */
|
various means, also via secondary indexes. */
|
||||||
ulint i;
|
ulint i;
|
||||||
|
|
||||||
|
fake_statistics:
|
||||||
sum_of_index_sizes++;
|
sum_of_index_sizes++;
|
||||||
index->stat_index_size = index->stat_n_leaf_pages = 1;
|
index->stat_index_size = index->stat_n_leaf_pages = 1;
|
||||||
|
|
||||||
|
@@ -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
|
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
|
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.
|
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
|
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
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
@@ -1010,7 +1010,9 @@ ha_innobase::prepare_drop_index(
|
|||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rw_lock_x_lock(dict_index_get_lock(index));
|
||||||
index->to_be_dropped = TRUE;
|
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
|
/* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
|
||||||
@@ -1129,7 +1131,9 @@ func_exit:
|
|||||||
= dict_table_get_first_index(prebuilt->table);
|
= dict_table_get_first_index(prebuilt->table);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
rw_lock_x_lock(dict_index_get_lock(index));
|
||||||
index->to_be_dropped = FALSE;
|
index->to_be_dropped = FALSE;
|
||||||
|
rw_lock_x_unlock(dict_index_get_lock(index));
|
||||||
index = dict_table_get_next_index(index);
|
index = dict_table_get_next_index(index);
|
||||||
} while (index);
|
} while (index);
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1193,9 @@ ha_innobase::final_drop_index(
|
|||||||
for (index = dict_table_get_first_index(prebuilt->table);
|
for (index = dict_table_get_first_index(prebuilt->table);
|
||||||
index; index = dict_table_get_next_index(index)) {
|
index; index = dict_table_get_next_index(index)) {
|
||||||
|
|
||||||
|
rw_lock_x_lock(dict_index_get_lock(index));
|
||||||
index->to_be_dropped = FALSE;
|
index->to_be_dropped = FALSE;
|
||||||
|
rw_lock_x_unlock(dict_index_get_lock(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
|
@@ -536,13 +536,16 @@ btr_parse_page_reorganize(
|
|||||||
#ifndef UNIV_HOTBACKUP
|
#ifndef UNIV_HOTBACKUP
|
||||||
/**************************************************************//**
|
/**************************************************************//**
|
||||||
Gets the number of pages in a B-tree.
|
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
|
UNIV_INTERN
|
||||||
ulint
|
ulint
|
||||||
btr_get_size(
|
btr_get_size(
|
||||||
/*=========*/
|
/*=========*/
|
||||||
dict_index_t* index, /*!< in: index */
|
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
|
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!
|
that the caller has made the reservation for free extents!
|
||||||
|
@@ -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
|
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
|
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.
|
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
|
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
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
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 */
|
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.
|
Gets the read-write lock of the index tree.
|
||||||
@return read-write lock */
|
@return read-write lock */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
|
@@ -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
|
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
|
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.
|
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
|
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
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
@@ -722,21 +722,6 @@ dict_index_get_page(
|
|||||||
return(index->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.
|
Gets the read-write lock of the index tree.
|
||||||
@return read-write lock */
|
@return read-write lock */
|
||||||
|
@@ -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
|
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
|
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.
|
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
|
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
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
@@ -305,7 +305,9 @@ struct dict_index_struct{
|
|||||||
unsigned to_be_dropped:1;
|
unsigned to_be_dropped:1;
|
||||||
/*!< TRUE if this index is marked to be
|
/*!< TRUE if this index is marked to be
|
||||||
dropped in ha_innobase::prepare_drop_index(),
|
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 */
|
dict_field_t* fields; /*!< array of field descriptions */
|
||||||
#ifndef UNIV_HOTBACKUP
|
#ifndef UNIV_HOTBACKUP
|
||||||
UT_LIST_NODE_T(dict_index_t)
|
UT_LIST_NODE_T(dict_index_t)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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
|
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
|
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.
|
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
|
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
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
@@ -3013,6 +3013,7 @@ row_drop_table_for_mysql(
|
|||||||
{
|
{
|
||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign;
|
||||||
dict_table_t* table;
|
dict_table_t* table;
|
||||||
|
dict_index_t* index;
|
||||||
ulint space_id;
|
ulint space_id;
|
||||||
ulint err;
|
ulint err;
|
||||||
const char* table_name;
|
const char* table_name;
|
||||||
@@ -3305,6 +3306,18 @@ check_next_foreign:
|
|||||||
"END;\n"
|
"END;\n"
|
||||||
, FALSE, trx);
|
, FALSE, trx);
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
}
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
ibool is_temp;
|
ibool is_temp;
|
||||||
const char* name_or_path;
|
const char* name_or_path;
|
||||||
@@ -3384,6 +3397,17 @@ check_next_foreign:
|
|||||||
the undo log. We can directly exit here
|
the undo log. We can directly exit here
|
||||||
and return the DB_TOO_MANY_CONCURRENT_TRXS
|
and return the DB_TOO_MANY_CONCURRENT_TRXS
|
||||||
error. */
|
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;
|
break;
|
||||||
|
|
||||||
case DB_OUT_OF_FILE_SPACE:
|
case DB_OUT_OF_FILE_SPACE:
|
||||||
|
Reference in New Issue
Block a user