Skip to content

Commit c0b4d74

Browse files
author
Nisha Gopalakrishnan
committed
BUG#27216817: INNODB: FAILING ASSERTION:
PREBUILT->TABLE->N_MYSQL_HANDLES_OPENED == 1 ANALYSIS: ========= Adding unique index to a InnoDB table which is locked as mutliple instances may trigger an InnoDB assert. When we add a primary key or an unique index, we need to drop the original table and rebuild all indexes. InnoDB expects that only the instance of the table that is being rebuilt, is open during the process. In the current scenario we have opened multiple instances of the table. This triggers an assert during table rebuild. 'Locked_tables_list' encapsulates a list of all instances of tables locked by LOCK TABLES statement. FIX: === We are now temporarily closing all the instances of the table except the one which is being altered and later reopen them via Locked_tables_list::reopen_tables().
1 parent 873f8c2 commit c0b4d74

File tree

7 files changed

+43
-20
lines changed

7 files changed

+43
-20
lines changed

sql/sql_admin.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights
1+
/* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights
22
reserved.
33
44
This program is free software; you can redistribute it and/or modify
@@ -168,7 +168,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
168168
*/
169169
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
170170
goto end;
171-
close_all_tables_for_name(thd, table_list->table->s, FALSE);
171+
close_all_tables_for_name(thd, table_list->table->s, FALSE, NULL);
172172
table_list->table= 0;
173173
}
174174
/*

sql/sql_base.cc

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -1096,7 +1096,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
10961096
result= TRUE;
10971097
goto err_with_reopen;
10981098
}
1099-
close_all_tables_for_name(thd, table->s, FALSE);
1099+
close_all_tables_for_name(thd, table->s, FALSE, NULL);
11001100
}
11011101
}
11021102

@@ -1367,13 +1367,16 @@ static void close_open_tables(THD *thd)
13671367
In that case the documented behaviour is to
13681368
implicitly remove the table from LOCK TABLES
13691369
list.
1370+
@param[in] skip_table
1371+
TABLE instance that should be kept open.
13701372
13711373
@pre Must be called with an X MDL lock on the table.
13721374
*/
13731375

13741376
void
13751377
close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
1376-
bool remove_from_locked_tables)
1378+
bool remove_from_locked_tables,
1379+
TABLE *skip_table)
13771380
{
13781381
char key[MAX_DBKEY_LENGTH];
13791382
uint key_length= share->table_cache_key.length;
@@ -1388,7 +1391,8 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
13881391
TABLE *table= *prev;
13891392

13901393
if (table->s->table_cache_key.length == key_length &&
1391-
!memcmp(table->s->table_cache_key.str, key, key_length))
1394+
!memcmp(table->s->table_cache_key.str, key, key_length) &&
1395+
table != skip_table)
13921396
{
13931397
thd->locked_tables_list.unlink_from_list(thd,
13941398
table->pos_in_locked_tables,
@@ -1401,7 +1405,8 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
14011405
mysql_lock_remove(thd, thd->lock, table);
14021406

14031407
/* Inform handler that table will be dropped after close */
1404-
if (table->db_stat) /* Not true for partitioned tables. */
1408+
if (table->db_stat && /* Not true for partitioned tables. */
1409+
skip_table == NULL)
14051410
table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
14061411
close_thread_table(thd, prev);
14071412
}
@@ -1411,9 +1416,12 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
14111416
prev= &table->next;
14121417
}
14131418
}
1419+
1420+
if (skip_table == NULL) {
14141421
/* Remove the table share from the cache. */
14151422
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name,
14161423
FALSE);
1424+
}
14171425
}
14181426

14191427

sql/sql_base.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -306,7 +306,8 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
306306
bool wait_for_refresh, ulong timeout);
307307
bool close_cached_connection_tables(THD *thd, LEX_STRING *connect_string);
308308
void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
309-
bool remove_from_locked_tables);
309+
bool remove_from_locked_tables,
310+
TABLE *skip_table);
310311
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
311312
void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
312313
const char *db, const char *table_name,

sql/sql_partition.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -6512,7 +6512,7 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
65126512
THD *thd= lpt->thd;
65136513

65146514
if (lpt->old_table)
6515-
close_all_tables_for_name(thd, lpt->old_table->s, FALSE);
6515+
close_all_tables_for_name(thd, lpt->old_table->s, FALSE, NULL);
65166516
if (lpt->table)
65176517
{
65186518
/*
@@ -6549,7 +6549,7 @@ static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt, bool close_old)
65496549
}
65506550
if (close_old && lpt->old_table)
65516551
{
6552-
close_all_tables_for_name(lpt->thd, lpt->old_table->s, FALSE);
6552+
close_all_tables_for_name(lpt->thd, lpt->old_table->s, FALSE, NULL);
65536553
lpt->old_table= 0;
65546554
}
65556555
DBUG_RETURN(0);

sql/sql_table.cc

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -2165,7 +2165,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
21652165
error= -1;
21662166
goto err;
21672167
}
2168-
close_all_tables_for_name(thd, table->table->s, TRUE);
2168+
close_all_tables_for_name(thd, table->table->s, TRUE, NULL);
21692169
table->table= 0;
21702170
}
21712171

@@ -6168,7 +6168,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
61686168
*/
61696169
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
61706170
goto err;
6171-
close_all_tables_for_name(thd, table->s, TRUE);
6171+
close_all_tables_for_name(thd, table->s, TRUE, NULL);
61726172
/*
61736173
Then, we want check once again that target table does not exist.
61746174
Actually the order of these two steps does not matter since
@@ -6305,6 +6305,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
63056305
changes only" means also that the handler for the table does not
63066306
change. The table is open and locked. The handler can be accessed.
63076307
*/
6308+
63086309
if (need_copy_table == ALTER_TABLE_INDEX_CHANGED)
63096310
{
63106311
int pk_changed= 0;
@@ -6606,6 +6607,19 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
66066607
thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
66076608
thd->cuted_fields=0L;
66086609
copied=deleted=0;
6610+
6611+
if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
6612+
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
6613+
{
6614+
/*
6615+
Temporarily close the TABLE instances belonging to this
6616+
thread except the one to be used for ALTER TABLE.
6617+
6618+
This is mostly needed to satisfy InnoDB assumptions/asserts.
6619+
*/
6620+
close_all_tables_for_name(thd, table->s, false, table);
6621+
}
6622+
66096623
/*
66106624
We do not copy data for MERGE tables. Only the children have data.
66116625
MERGE tables have HA_NO_COPY_ON_ALTER set.
@@ -6877,7 +6891,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
68776891
}
68786892

68796893
close_all_tables_for_name(thd, table->s,
6880-
new_name != table_name || new_db != db);
6894+
new_name != table_name || new_db != db, NULL);
68816895

68826896
error=0;
68836897
table_list->table= table= 0; /* Safety */

sql/sql_trigger.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
2+
Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License as published by
@@ -568,7 +568,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
568568
if (result)
569569
goto end;
570570

571-
close_all_tables_for_name(thd, table->s, FALSE);
571+
close_all_tables_for_name(thd, table->s, FALSE, NULL);
572572
/*
573573
Reopen the table if we were under LOCK TABLES.
574574
Ignore the return value for now. It's better to

sql/sql_truncate.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -394,7 +394,7 @@ bool Truncate_statement::lock_table(THD *thd, TABLE_LIST *table_ref,
394394
m_ticket_downgrade= table->mdl_ticket;
395395
/* Close if table is going to be recreated. */
396396
if (*hton_can_recreate)
397-
close_all_tables_for_name(thd, table->s, FALSE);
397+
close_all_tables_for_name(thd, table->s, FALSE, NULL);
398398
}
399399
else
400400
{

0 commit comments

Comments
 (0)