From: Sergey Vojtovich Date: May 5 2011 11:03am Subject: bzr commit into mysql-5.1 branch (sergey.vojtovich:3682) Bug#11763712 List-Archive: http://lists.mysql.com/commits/136738 X-Bug: 11763712 Message-Id: <201105051109.p45B9CNP030320@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1752063526976536939==" --===============1752063526976536939== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/svoj/mysql/server/mysql-5.1-bug56458/ based on revid:alexander.nozdrin@stripped 3682 Sergey Vojtovich 2011-05-05 BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD CRASHES SERVER Flushing objects of MERGE table, which is locked by flushing thread using LOCK TABLES, may cause deadlocks, assertion failures, invalid memory access. @ mysql-test/r/merge_debug_sync.result A test case for BUG#11763712. @ mysql-test/t/merge_debug_sync.test A test case for BUG#11763712 @ sql/sql_base.cc When flushing tables under LOCK TABLES, all locked and flushed tables are released and then reopened. It may happen that we failed to reopen some tables, in this case we reopen as much tables as possible. If it was not possible to reopen MERGE child, MERGE parent is unusable and must be removed from thread open tables list. If it was not possible to reopen MERGE parent, all MERGE child table objects are unusable as well, at least because their locks are handled by MERGE parent. They must also be removed from thread open tables list. In other words if it was impossible to reopen any object of a MERGE table, all objects of this MERGE table must be considered unusable and closed. When flushing objects of MERGE table, which is locked by flushing thread, flush MERGE objects altogether. Since table locks for MERGE objects released altogether, another thread may acquire a lock for a MERGE child, which is not to be flushed. added: mysql-test/r/merge_debug_sync.result mysql-test/t/merge_debug_sync.test modified: sql/mysql_priv.h sql/sql_base.cc === added file 'mysql-test/r/merge_debug_sync.result' --- a/mysql-test/r/merge_debug_sync.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/r/merge_debug_sync.result 2011-05-05 11:03:29 +0000 @@ -0,0 +1,30 @@ +# +# BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD +# CRASHES SERVER +# +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT); +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); +# Test reopen merge parent failure +LOCK TABLES m1 READ; +SET SESSION debug='d,simulate_reopen_merge_parent_error'; +FLUSH TABLES; +ERROR HY000: Can't reopen table: 'm1' +UNLOCK TABLES; +# Test reopen merge child failure +LOCK TABLES m1 READ; +SET SESSION debug='d,simulate_reopen_merge_child_error'; +FLUSH TABLES; +ERROR HY000: Can't reopen table: 't2' +UNLOCK TABLES; +SET SESSION debug=DEFAULT; +# Test deadlock on LOCK_open +LOCK TABLE m1 WRITE; +SET DEBUG_SYNC='before_lock_tables_takes_lock SIGNAL opened WAIT_FOR flushed'; +LOCK TABLE t1 WRITE; +SET DEBUG_SYNC='now WAIT_FOR opened'; +SET DEBUG_SYNC='after_flush_unlock SIGNAL flushed'; +FLUSH TABLE t2; +UNLOCK TABLES; +SET DEBUG_SYNC='RESET'; +DROP TABLES t1, t2, m1; === added file 'mysql-test/t/merge_debug_sync.test' --- a/mysql-test/t/merge_debug_sync.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/t/merge_debug_sync.test 2011-05-05 11:03:29 +0000 @@ -0,0 +1,50 @@ +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--echo # +--echo # BUG#11763712 - 56458: KILLING A FLUSH TABLE FOR A MERGE/CHILD +--echo # CRASHES SERVER +--echo # +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT); +CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); + +--echo # Test reopen merge parent failure +LOCK TABLES m1 READ; +SET SESSION debug='d,simulate_reopen_merge_parent_error'; +--error ER_CANT_REOPEN_TABLE +FLUSH TABLES; +UNLOCK TABLES; + +--echo # Test reopen merge child failure +LOCK TABLES m1 READ; +SET SESSION debug='d,simulate_reopen_merge_child_error'; +--error ER_CANT_REOPEN_TABLE +FLUSH TABLES; +UNLOCK TABLES; + +SET SESSION debug=DEFAULT; + +--echo # Test deadlock on LOCK_open +let $ID= `select connection_id()`; +LOCK TABLE m1 WRITE; +connect(con1,localhost,root,,); + +connection con1; +SET DEBUG_SYNC='before_lock_tables_takes_lock SIGNAL opened WAIT_FOR flushed'; +send LOCK TABLE t1 WRITE; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR opened'; +SET DEBUG_SYNC='after_flush_unlock SIGNAL flushed'; +FLUSH TABLE t2; +UNLOCK TABLES; + +connection con1; +reap; +disconnect con1; + +connection default; +SET DEBUG_SYNC='RESET'; + +DROP TABLES t1, t2, m1; === modified file 'sql/mysql_priv.h' --- a/sql/mysql_priv.h 2011-03-15 11:36:12 +0000 +++ b/sql/mysql_priv.h 2011-05-05 11:03:29 +0000 @@ -1606,6 +1606,7 @@ uint prep_alter_part_table(THD *thd, TAB #define RTFC_OWNED_BY_THD_FLAG 0x0001 #define RTFC_WAIT_OTHER_THREAD_FLAG 0x0002 #define RTFC_CHECK_KILLED_FLAG 0x0004 +#define RTFC_MERGE_EXPANSION_FLAG 0x0008 bool remove_table_from_cache(THD *thd, const char *db, const char *table, uint flags); === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2011-03-29 08:09:05 +0000 +++ b/sql/sql_base.cc 2011-05-05 11:03:29 +0000 @@ -930,7 +930,8 @@ bool close_cached_tables(THD *thd, TABLE for (TABLE_LIST *table= tables; table; table= table->next_local) { if (remove_table_from_cache(thd, table->db, table->table_name, - RTFC_OWNED_BY_THD_FLAG)) + RTFC_OWNED_BY_THD_FLAG | + RTFC_MERGE_EXPANSION_FLAG)) found=1; } if (!found) @@ -3068,6 +3069,10 @@ bool reopen_table(TABLE *table) table_list.table_name= table->s->table_name.str; table_list.table= table; + DBUG_EXECUTE_IF("simulate_reopen_merge_parent_error", + if (table->child_l) DBUG_RETURN(1);); + DBUG_EXECUTE_IF("simulate_reopen_merge_child_error", + if (table->parent) DBUG_RETURN(1);); if (wait_for_locked_table_names(thd, &table_list)) DBUG_RETURN(1); // Thread was killed @@ -3335,20 +3340,38 @@ bool reopen_tables(THD *thd, bool get_lo (long) table, (long) table->parent, db_stat)); if (table->child_l && !db_stat) merge_table_found= TRUE; - if (!tables || (!db_stat && reopen_table(table))) + if (!tables || table->parent == (TABLE *) 1 || + (!db_stat && reopen_table(table))) { - my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); + TABLE *parent= table->child_l ? table : table->parent; /* If we could not allocate 'tables', we may close open tables - here. If a MERGE table is affected, detach the children first. - It is not necessary to clear the child or parent table reference - of this table because the TABLE is freed. But we need to clear - the child or parent references of the other belonging tables so - that they cannot be moved into the unused_tables chain with - these pointers set. - */ - if (table->child_l || table->parent) - detach_merge_children(table, TRUE); + here. + + If a MERGE table is affected for the first time, mark all + relevant tables invalid. Otherwise handle it as usual. + All in all we must end up with: + - child tables are detached from parent. Child tables were + detached earlier, but child<->parent references kept + valid for reopen. + - parent is not in the to-be-locked tables. + - all child tables and parent are not in the THD::open_tables. + - all child tables and parent are not in the open_cache. + */ + if (parent && table->parent != (TABLE *) 1) + { + TABLE_LIST *child_l; + parent->parent= (TABLE *) 1; + for (child_l= parent->child_l; ; child_l= child_l->next_global) + { + child_l->table->parent= (TABLE *) 1; + if (&child_l->next_global == parent->child_last_l) + break; + } + } + /* Reset parent reference, it may be used while freeing the table. */ + table->parent= NULL; + my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias); VOID(hash_delete(&open_cache,(uchar*) table)); error=1; } @@ -3369,6 +3392,57 @@ bool reopen_tables(THD *thd, bool get_lo } } *prev=0; + + /* + It may happen that we opened a few objects of a MERGE table + before we detected an error. Cleanup these objects now. + */ + if (merge_table_found && error) + { + prev= &thd->open_tables; + for (table= thd->open_tables; table; table= next) + { + next= table->next; + if (table->parent == (TABLE *) 1) + { + /* + MERGE parent must have been handled before and we must + never catch it here. It is expected because MERGE parent + always comes after it's children in THD::open_tables list. + If this assumption is wrong, we must remove parent from + the to-be-locked tables array. + */ + DBUG_ASSERT(!table->child_l); +#if 0 + /* Remove merge parent from to-be-locked tables array. */ + if (get_locks && table->child_l) + { + TABLE **t; + for (t= tables; t < tables_ptr; t++) + { + if (*t == table) + { + tables_ptr--; + memmove(t, t + 1, (tables_ptr - t) * sizeof(TABLE *)); + break; + } + } + } +#endif + /* Reset parent reference, it may be used while freeing the table. */ + table->parent= NULL; + /* Free table. */ + VOID(hash_delete(&open_cache, (uchar *) table)); + } + else + { + *prev= table; + prev= &table->next; + } + } + *prev= 0; + } + /* When all tables are open again, we can re-attach MERGE children to their parents. All TABLE objects are still present. @@ -8524,6 +8598,7 @@ bool remove_table_from_cache(THD *thd, c char key[MAX_DBKEY_LENGTH]; uint key_length; TABLE *table; + TABLE *parent= NULL; TABLE_SHARE *share; bool result= 0, signalled= 0; DBUG_ENTER("remove_table_from_cache"); @@ -8600,6 +8675,7 @@ bool remove_table_from_cache(THD *thd, c } else { + parent= table->child_l ? table : table->parent; DBUG_PRINT("info", ("Table was in use by current thread. db_stat: %u", table->db_stat)); result= result || (flags & RTFC_OWNED_BY_THD_FLAG); @@ -8658,6 +8734,28 @@ bool remove_table_from_cache(THD *thd, c } break; } + if (flags & RTFC_MERGE_EXPANSION_FLAG) + { + /* Flush objects in a MERGE table altogether. */ + if (parent) + { + TABLE_LIST *child_l; + if (parent->s->version) + result|= remove_table_from_cache(thd, parent->s->db.str, + parent->s->table_name.str, + flags & ~RTFC_MERGE_EXPANSION_FLAG); + for (child_l= parent->child_l; ; child_l= child_l->next_global) + { + TABLE *child= child_l->table; + if (child->s->version) + result|= remove_table_from_cache(thd, child->s->db.str, + child->s->table_name.str, + flags & ~RTFC_MERGE_EXPANSION_FLAG); + if (&child_l->next_global == parent->child_last_l) + break; + } + } + } DBUG_RETURN(result); } --===============1752063526976536939== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/sergey.vojtovich@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: sergey.vojtovich@stripped\ # 2ncyowhr0enox1wo # target_branch: file:///home/svoj/mysql/server/mysql-5.1-bug56458/ # testament_sha1: 44b8e6d081661f16262fc1dbeb8f498cace4e2f5 # timestamp: 2011-05-05 15:03:35 +0400 # base_revision_id: alexander.nozdrin@stripped\ # pbwr2k9x04qdgxh8 # # Begin bundle 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 --===============1752063526976536939==--