mirror of
https://github.com/MariaDB/server.git
synced 2025-09-02 09:41:40 +03:00
MDEV-13818 CREATE INDEX leaks memory if running out of undo log space
row_merge_create_index_graph(): Relay the internal state
from dict_create_index_step(). Our caller should free the index
only if it was not copied, added to the cache, and freed.
row_merge_create_index(): Free the index template if it was
not added to the cache. This is a safer variant of the logic
that was introduced in 65070beffd
in 10.2.
prepare_inplace_alter_table_dict(): Add additional fault injection
to exercise a code path where we have already added an index
to the cache.
This commit is contained in:
@@ -3,6 +3,9 @@
|
|||||||
#
|
#
|
||||||
CREATE TABLE t1(c1 INT PRIMARY KEY, c2 CHAR(1), c3 INT UNSIGNED) ENGINE=InnoDB;
|
CREATE TABLE t1(c1 INT PRIMARY KEY, c2 CHAR(1), c3 INT UNSIGNED) ENGINE=InnoDB;
|
||||||
SET @saved_debug_dbug = @@SESSION.debug_dbug;
|
SET @saved_debug_dbug = @@SESSION.debug_dbug;
|
||||||
|
SET DEBUG_DBUG='+d,create_index_metadata_fail';
|
||||||
|
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
|
||||||
|
ERROR HY000: The table 't1' is full
|
||||||
SET DEBUG_DBUG='+d,ib_create_table_fail_too_many_trx';
|
SET DEBUG_DBUG='+d,ib_create_table_fail_too_many_trx';
|
||||||
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
|
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
|
||||||
ERROR HY000: Too many active concurrent transactions
|
ERROR HY000: Too many active concurrent transactions
|
||||||
@@ -11,21 +14,21 @@ ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
|
|||||||
SET DEBUG_DBUG='+d,dict_set_index_corrupted';
|
SET DEBUG_DBUG='+d,dict_set_index_corrupted';
|
||||||
CHECK TABLE t1;
|
CHECK TABLE t1;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t1 check Warning InnoDB: Index c2 is marked as corrupted
|
test.t1 check Warning InnoDB: Index "c2" is marked as corrupted
|
||||||
test.t1 check Warning InnoDB: Index c3 is marked as corrupted
|
test.t1 check Warning InnoDB: Index "c3" is marked as corrupted
|
||||||
test.t1 check error Corrupt
|
test.t1 check error Corrupt
|
||||||
CHECK TABLE t1;
|
CHECK TABLE t1;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t1 check Warning InnoDB: Index c2 is marked as corrupted
|
test.t1 check Warning InnoDB: Index "c2" is marked as corrupted
|
||||||
test.t1 check Warning InnoDB: Index c3 is marked as corrupted
|
test.t1 check Warning InnoDB: Index "c3" is marked as corrupted
|
||||||
test.t1 check error Corrupt
|
test.t1 check error Corrupt
|
||||||
ALTER TABLE t1 DROP INDEX c2;
|
ALTER TABLE t1 DROP INDEX c2;
|
||||||
CHECK TABLE t1;
|
CHECK TABLE t1;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t1 check Warning InnoDB: Index c3 is marked as corrupted
|
test.t1 check Warning InnoDB: Index "c3" is marked as corrupted
|
||||||
test.t1 check error Corrupt
|
test.t1 check error Corrupt
|
||||||
ALTER TABLE t1 ADD INDEX (c2,c3);
|
ALTER TABLE t1 ADD INDEX (c2,c3);
|
||||||
ERROR HY000: Index c3 is corrupted
|
ERROR HY000: Index "c3" is corrupted
|
||||||
ALTER TABLE t1 CHANGE c3 c3 INT NOT NULL;
|
ALTER TABLE t1 CHANGE c3 c3 INT NOT NULL;
|
||||||
CHECK TABLE t1;
|
CHECK TABLE t1;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
|
@@ -7,10 +7,7 @@
|
|||||||
--source include/not_crashrep.inc
|
--source include/not_crashrep.inc
|
||||||
|
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
call mtr.add_suppression('InnoDB: cannot find a free slot for an undo log');
|
call mtr.add_suppression('InnoDB: Flagged corruption of c[23]');
|
||||||
call mtr.add_suppression('InnoDB: row_merge_rename_index_to_add failed with error 47');
|
|
||||||
call mtr.add_suppression('InnoDB: Flagged corruption of `c[23]`');
|
|
||||||
call mtr.add_suppression('InnoDB: Index `c[23]` .*is corrupted');
|
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
@@ -19,6 +16,10 @@ call mtr.add_suppression('InnoDB: Index `c[23]` .*is corrupted');
|
|||||||
|
|
||||||
CREATE TABLE t1(c1 INT PRIMARY KEY, c2 CHAR(1), c3 INT UNSIGNED) ENGINE=InnoDB;
|
CREATE TABLE t1(c1 INT PRIMARY KEY, c2 CHAR(1), c3 INT UNSIGNED) ENGINE=InnoDB;
|
||||||
SET @saved_debug_dbug = @@SESSION.debug_dbug;
|
SET @saved_debug_dbug = @@SESSION.debug_dbug;
|
||||||
|
SET DEBUG_DBUG='+d,create_index_metadata_fail';
|
||||||
|
--error ER_RECORD_FILE_FULL
|
||||||
|
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
|
||||||
|
|
||||||
SET DEBUG_DBUG='+d,ib_create_table_fail_too_many_trx';
|
SET DEBUG_DBUG='+d,ib_create_table_fail_too_many_trx';
|
||||||
--error ER_TOO_MANY_CONCURRENT_TRXS
|
--error ER_TOO_MANY_CONCURRENT_TRXS
|
||||||
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
|
ALTER TABLE t1 ADD INDEX (c2), ADD INDEX (c3);
|
||||||
|
@@ -3090,10 +3090,18 @@ prepare_inplace_alter_table_dict(
|
|||||||
/* Create the indexes in SYS_INDEXES and load into dictionary. */
|
/* Create the indexes in SYS_INDEXES and load into dictionary. */
|
||||||
|
|
||||||
for (ulint a = 0; a < ctx->num_to_add_index; a++) {
|
for (ulint a = 0; a < ctx->num_to_add_index; a++) {
|
||||||
|
DBUG_EXECUTE_IF(
|
||||||
|
"create_index_metadata_fail",
|
||||||
|
if (a + 1 == ctx->num_to_add_index) {
|
||||||
|
ctx->trx->error_state = DB_OUT_OF_FILE_SPACE;
|
||||||
|
ctx->add_index[a] = NULL;
|
||||||
|
goto index_created;
|
||||||
|
});
|
||||||
ctx->add_index[a] = row_merge_create_index(
|
ctx->add_index[a] = row_merge_create_index(
|
||||||
ctx->trx, ctx->new_table, &index_defs[a]);
|
ctx->trx, ctx->new_table, &index_defs[a]);
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
index_created:
|
||||||
|
#endif
|
||||||
add_key_nums[a] = index_defs[a].key_number;
|
add_key_nums[a] = index_defs[a].key_number;
|
||||||
|
|
||||||
if (!ctx->add_index[a]) {
|
if (!ctx->add_index[a]) {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
|
Copyright (c) 2017, MariaDB Corporation.
|
||||||
|
|
||||||
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
|
||||||
@@ -84,7 +85,7 @@ ut_dbg_assertion_failed(
|
|||||||
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
||||||
#define ut_ad(EXPR) ut_a(EXPR)
|
#define ut_ad(EXPR) ut_a(EXPR)
|
||||||
/** Debug statement. Does nothing unless UNIV_DEBUG is defined. */
|
/** Debug statement. Does nothing unless UNIV_DEBUG is defined. */
|
||||||
#define ut_d(EXPR) do {EXPR;} while (0)
|
#define ut_d(EXPR) EXPR
|
||||||
#else
|
#else
|
||||||
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
||||||
#define ut_ad(EXPR)
|
#define ut_ad(EXPR)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2014, 2018, MariaDB Corporation.
|
Copyright (c) 2014, 2019, MariaDB Corporation.
|
||||||
|
|
||||||
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
|
||||||
@@ -3702,7 +3702,7 @@ row_merge_create_index_graph(
|
|||||||
/*=========================*/
|
/*=========================*/
|
||||||
trx_t* trx, /*!< in: trx */
|
trx_t* trx, /*!< in: trx */
|
||||||
dict_table_t* table, /*!< in: table */
|
dict_table_t* table, /*!< in: table */
|
||||||
dict_index_t* index) /*!< in: index */
|
dict_index_t*& index) /*!< in,out: index */
|
||||||
{
|
{
|
||||||
ind_node_t* node; /*!< Index creation node */
|
ind_node_t* node; /*!< Index creation node */
|
||||||
mem_heap_t* heap; /*!< Memory heap */
|
mem_heap_t* heap; /*!< Memory heap */
|
||||||
@@ -3726,6 +3726,8 @@ row_merge_create_index_graph(
|
|||||||
|
|
||||||
err = trx->error_state;
|
err = trx->error_state;
|
||||||
|
|
||||||
|
index = node->index;
|
||||||
|
|
||||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||||
|
|
||||||
return(err);
|
return(err);
|
||||||
@@ -3767,20 +3769,21 @@ row_merge_create_index(
|
|||||||
ifield->prefix_len);
|
ifield->prefix_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ut_d(const dict_index_t* const index_template = index);
|
||||||
/* Add the index to SYS_INDEXES, using the index prototype. */
|
/* Add the index to SYS_INDEXES, using the index prototype. */
|
||||||
err = row_merge_create_index_graph(trx, table, index);
|
err = row_merge_create_index_graph(trx, table, index);
|
||||||
|
|
||||||
if (err == DB_SUCCESS) {
|
if (err == DB_SUCCESS) {
|
||||||
|
ut_ad(index != index_template);
|
||||||
index = dict_table_get_index_on_name(table, index_def->name);
|
|
||||||
|
|
||||||
ut_a(index);
|
|
||||||
|
|
||||||
/* Note the id of the transaction that created this
|
/* Note the id of the transaction that created this
|
||||||
index, we use it to restrict readers from accessing
|
index, we use it to restrict readers from accessing
|
||||||
this index, to ensure read consistency. */
|
this index, to ensure read consistency. */
|
||||||
ut_ad(index->trx_id == trx->id);
|
ut_ad(index->trx_id == trx->id);
|
||||||
} else {
|
} else {
|
||||||
|
ut_ad(!index || index == index_template);
|
||||||
|
if (index) {
|
||||||
|
dict_mem_index_free(index);
|
||||||
|
}
|
||||||
index = NULL;
|
index = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3097,10 +3097,18 @@ prepare_inplace_alter_table_dict(
|
|||||||
/* Create the indexes in SYS_INDEXES and load into dictionary. */
|
/* Create the indexes in SYS_INDEXES and load into dictionary. */
|
||||||
|
|
||||||
for (ulint a = 0; a < ctx->num_to_add_index; a++) {
|
for (ulint a = 0; a < ctx->num_to_add_index; a++) {
|
||||||
|
DBUG_EXECUTE_IF(
|
||||||
|
"create_index_metadata_fail",
|
||||||
|
if (a + 1 == ctx->num_to_add_index) {
|
||||||
|
ctx->trx->error_state = DB_OUT_OF_FILE_SPACE;
|
||||||
|
ctx->add_index[a] = NULL;
|
||||||
|
goto index_created;
|
||||||
|
});
|
||||||
ctx->add_index[a] = row_merge_create_index(
|
ctx->add_index[a] = row_merge_create_index(
|
||||||
ctx->trx, ctx->new_table, &index_defs[a]);
|
ctx->trx, ctx->new_table, &index_defs[a]);
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
index_created:
|
||||||
|
#endif
|
||||||
add_key_nums[a] = index_defs[a].key_number;
|
add_key_nums[a] = index_defs[a].key_number;
|
||||||
|
|
||||||
if (!ctx->add_index[a]) {
|
if (!ctx->add_index[a]) {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
|
Copyright (c) 2017, MariaDB Corporation.
|
||||||
|
|
||||||
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
|
||||||
@@ -84,7 +85,7 @@ ut_dbg_assertion_failed(
|
|||||||
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
||||||
#define ut_ad(EXPR) ut_a(EXPR)
|
#define ut_ad(EXPR) ut_a(EXPR)
|
||||||
/** Debug statement. Does nothing unless UNIV_DEBUG is defined. */
|
/** Debug statement. Does nothing unless UNIV_DEBUG is defined. */
|
||||||
#define ut_d(EXPR) do {EXPR;} while (0)
|
#define ut_d(EXPR) EXPR
|
||||||
#else
|
#else
|
||||||
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
/** Debug assertion. Does nothing unless UNIV_DEBUG is defined. */
|
||||||
#define ut_ad(EXPR)
|
#define ut_ad(EXPR)
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2014, 2018, MariaDB Corporation.
|
Copyright (c) 2014, 2019, MariaDB Corporation.
|
||||||
|
|
||||||
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
|
||||||
@@ -3705,7 +3705,7 @@ row_merge_create_index_graph(
|
|||||||
/*=========================*/
|
/*=========================*/
|
||||||
trx_t* trx, /*!< in: trx */
|
trx_t* trx, /*!< in: trx */
|
||||||
dict_table_t* table, /*!< in: table */
|
dict_table_t* table, /*!< in: table */
|
||||||
dict_index_t* index) /*!< in: index */
|
dict_index_t*& index) /*!< in,out: index */
|
||||||
{
|
{
|
||||||
ind_node_t* node; /*!< Index creation node */
|
ind_node_t* node; /*!< Index creation node */
|
||||||
mem_heap_t* heap; /*!< Memory heap */
|
mem_heap_t* heap; /*!< Memory heap */
|
||||||
@@ -3729,6 +3729,8 @@ row_merge_create_index_graph(
|
|||||||
|
|
||||||
err = trx->error_state;
|
err = trx->error_state;
|
||||||
|
|
||||||
|
index = node->index;
|
||||||
|
|
||||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||||
|
|
||||||
return(err);
|
return(err);
|
||||||
@@ -3770,20 +3772,21 @@ row_merge_create_index(
|
|||||||
ifield->prefix_len);
|
ifield->prefix_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ut_d(const dict_index_t* const index_template = index);
|
||||||
/* Add the index to SYS_INDEXES, using the index prototype. */
|
/* Add the index to SYS_INDEXES, using the index prototype. */
|
||||||
err = row_merge_create_index_graph(trx, table, index);
|
err = row_merge_create_index_graph(trx, table, index);
|
||||||
|
|
||||||
if (err == DB_SUCCESS) {
|
if (err == DB_SUCCESS) {
|
||||||
|
ut_ad(index != index_template);
|
||||||
index = dict_table_get_index_on_name(table, index_def->name);
|
|
||||||
|
|
||||||
ut_a(index);
|
|
||||||
|
|
||||||
/* Note the id of the transaction that created this
|
/* Note the id of the transaction that created this
|
||||||
index, we use it to restrict readers from accessing
|
index, we use it to restrict readers from accessing
|
||||||
this index, to ensure read consistency. */
|
this index, to ensure read consistency. */
|
||||||
ut_ad(index->trx_id == trx->id);
|
ut_ad(index->trx_id == trx->id);
|
||||||
} else {
|
} else {
|
||||||
|
ut_ad(!index || index == index_template);
|
||||||
|
if (index) {
|
||||||
|
dict_mem_index_free(index);
|
||||||
|
}
|
||||||
index = NULL;
|
index = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user