From: Date: October 4 2007 8:38pm Subject: bk commit into 5.1 tree (istruewing:1.2610) BUG#26379 List-Archive: http://lists.mysql.com/commits/34923 X-Bug: 26379 Message-Id: Below is the list of changes that have just been committed into a local 5.1 repository of istruewing. When istruewing does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2007-10-04 20:38:09+02:00, istruewing@stripped +3 -0 Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Not to be pushed. For intermediate review only. This is a technology preview for removing wait_for_tables() from mysql_lock_tables(). Done during my Heidelberg stay. All calls to mysql_lock_tables() do now use the flag MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN. This means that wait_for_tables() is not called any more. The next step would be to remove the flag and the call to wait_for_tables() and the function itself alltogether. It is not used elsewhere. Added MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN flag to mysql_lock_tables() and added restart code where necessary. sql/sql_base.cc@stripped, 2007-10-04 20:38:07+02:00, istruewing@stripped +29 -5 Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN flag to mysql_lock_tables() and added restart code where necessary. sql/sql_handler.cc@stripped, 2007-10-04 20:38:07+02:00, istruewing@stripped +14 -3 Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN flag to mysql_lock_tables() and added restart code where necessary. sql/sql_insert.cc@stripped, 2007-10-04 20:38:07+02:00, istruewing@stripped +12 -4 Bug#26379 - Combination of FLUSH TABLE and REPAIR TABLE corrupts a MERGE table Added MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN flag to mysql_lock_tables() and added restart code where necessary. diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc --- a/sql/sql_base.cc 2007-09-12 22:11:44 +02:00 +++ b/sql/sql_base.cc 2007-10-04 20:38:07 +02:00 @@ -3194,7 +3194,8 @@ bool reopen_tables(THD *thd,bool get_loc /* We should always get these locks */ thd->some_tables_deleted=0; if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables), - 0, ¬_used))) + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, + ¬_used))) { thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock); } @@ -4214,6 +4215,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST thd->current_tablenr= 0; /* open_ltable can be used only for BASIC TABLEs */ table_list->required_type= FRMTYPE_TABLE; + restart: while (!(table= open_table(thd, table_list, thd->mem_root, &refresh, 0)) && refresh) ; @@ -4223,10 +4225,12 @@ TABLE *open_ltable(THD *thd, TABLE_LIST if (table->child_l) { /* A MERGE table must not come here. */ + /* purecov: begin tested */ my_error(ER_WRONG_OBJECT, MYF(0), table->s->db.str, table->s->table_name.str, "BASE TABLE"); table= 0; goto end; + /* purecov: end */ } table_list->lock_type= lock_type; @@ -4242,8 +4246,20 @@ TABLE *open_ltable(THD *thd, TABLE_LIST DBUG_ASSERT(thd->lock == 0); // You must lock everything at once if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK) if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, - lock_flags, &refresh))) - table= 0; + lock_flags | + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, + &refresh))) + { + if (refresh) + { + /* This thread should have opened this table only. */ + DBUG_ASSERT(thd->open_tables == table); + close_thread_table(thd, &thd->open_tables); + goto restart; + } + else + table= 0; + } } } @@ -8070,6 +8086,7 @@ open_system_tables_for_read(THD *thd, TA uint count= 0; bool not_used; + restart: for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global) { TABLE *table= open_table(thd, tables, thd->mem_root, ¬_used, @@ -8088,11 +8105,18 @@ open_system_tables_for_read(THD *thd, TA { TABLE **list= (TABLE**) thd->alloc(sizeof(TABLE*) * count); TABLE **ptr= list; + bool refresh; + for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global) *(ptr++)= tables->table; - thd->lock= mysql_lock_tables(thd, list, count, - MYSQL_LOCK_IGNORE_FLUSH, ¬_used); + thd->lock= mysql_lock_tables(thd, list, count, MYSQL_LOCK_IGNORE_FLUSH | + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &refresh); + if (!thd->lock && refresh) + { + close_system_tables(thd, backup); + goto restart; + } } if (thd->lock) DBUG_RETURN(FALSE); diff -Nrup a/sql/sql_handler.cc b/sql/sql_handler.cc --- a/sql/sql_handler.cc 2007-08-30 21:23:53 +02:00 +++ b/sql/sql_handler.cc 2007-10-04 20:38:07 +02:00 @@ -361,7 +361,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST uint num_rows; uchar *key; uint key_len; - bool not_used; + bool refresh; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", tables->db, tables->table_name, tables->alias)); @@ -375,6 +375,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST List_iterator it(list); it++; + restart: if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, (uchar*) tables->alias, strlen(tables->alias) + 1))) @@ -429,11 +430,21 @@ bool mysql_ha_read(THD *thd, TABLE_LIST tables->table=table; HANDLER_TABLES_HACK(thd); - lock= mysql_lock_tables(thd, &tables->table, 1, 0, ¬_used); + lock= mysql_lock_tables(thd, &tables->table, 1, + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &refresh); HANDLER_TABLES_HACK(thd); if (!lock) - goto err0; // mysql_lock_tables() printed error message already + { + if (refresh) + { + mysql_ha_close_table(thd, hash_tables); + hash_tables->table= NULL; + goto restart; + } + else + goto err0; // mysql_lock_tables() printed error message already + } // Always read all columns tables->table->read_set= &tables->table->s->all_set; diff -Nrup a/sql/sql_insert.cc b/sql/sql_insert.cc --- a/sql/sql_insert.cc 2007-09-12 22:11:45 +02:00 +++ b/sql/sql_insert.cc 2007-10-04 20:38:07 +02:00 @@ -1676,6 +1676,7 @@ public: pthread_cond_t cond,cond_client; volatile uint tables_in_use,stacked_inserts; volatile bool status,dead; + bool refresh; COPY_INFO info; I_List rows; ulong group_count; @@ -1844,6 +1845,7 @@ bool delayed_get_table(THD *thd, TABLE_L /* Must be set in the parser */ DBUG_ASSERT(table_list->db); + restart: /* Find the thread which handles this table. */ if (!(di= find_handler(thd, table_list))) { @@ -1945,6 +1947,9 @@ bool delayed_get_table(THD *thd, TABLE_L } /* Unlock the delayed insert object after its last access. */ di->unlock(); + /* If mysql_lock_tables() failed, table needs refresh. */ + if (!table_list->table && di->refresh) + goto restart; DBUG_RETURN((table_list->table == NULL)); end_create: @@ -2368,7 +2373,6 @@ pthread_handler_t handle_delayed_insert( if (di->tables_in_use && ! thd->lock) { - bool not_used; /* Request for new delayed insert. Lock the table, but avoid to be blocked by a global read lock. @@ -2380,8 +2384,9 @@ pthread_handler_t handle_delayed_insert( inserts are done. */ if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, - MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK, - ¬_used))) + MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK | + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, + &di->refresh))) { /* Fatal error */ di->dead= 1; @@ -3446,8 +3451,11 @@ static TABLE *create_table_from_items(TH { table->reginfo.lock_type= TL_WRITE; hooks->prelock(&table, 1); // Call prelock hooks + /* Locking should not fail with "need reopen". Name lock exists. */ if (! ((*lock)= mysql_lock_tables(thd, &table, 1, - MYSQL_LOCK_IGNORE_FLUSH, ¬_used)) || + MYSQL_LOCK_IGNORE_FLUSH | + MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, + ¬_used)) || hooks->postlock(&table, 1)) { if (*lock)