From: Date: October 7 2008 10:19am Subject: bzr commit into mysql-5.1 branch (tomas.ulin:2688) Bug#39885 List-Archive: http://lists.mysql.com/commits/55536 X-Bug: 39885 Message-Id: <20081007081944.66509440D4@linux.local> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit #At file:///home/tomas/mysql_src/cge-6.2-global-schema-lock/ 2688 Tomas Ulin 2008-10-07 Bug#39885 Heavy DDL opertaions causes hand due to error 266 in ndb_global_schema_lock modified: sql/ha_ndbcluster_binlog.cc sql/ha_ndbcluster_binlog.h sql/ha_ndbcluster_lock_ext.h sql/handler.cc sql/handler.h sql/sql_table.cc === modified file 'sql/ha_ndbcluster_binlog.cc' --- a/sql/ha_ndbcluster_binlog.cc 2008-10-02 15:52:29 +0000 +++ b/sql/ha_ndbcluster_binlog.cc 2008-10-07 08:19:31 +0000 @@ -762,32 +762,40 @@ int ndbcluster_no_global_schema_lock_abo #include "ha_ndbcluster_lock_ext.h" +/* + lock/unlock calls are reference counted, so calls to lock + must be matched to a call to unlock even if the lock call fails +*/ static int ndbcluster_global_schema_lock(THD *thd, int report_cluster_disconnected) { Ndb *ndb= check_ndb_in_thd(thd); Thd_ndb *thd_ndb= get_thd_ndb(thd); NdbError ndb_error; - thd_ndb->global_schema_lock_error= 0; if (thd_ndb->options & TNO_NO_LOCK_SCHEMA_OP) return 0; DBUG_ENTER("ndbcluster_global_schema_lock"); DBUG_PRINT("enter", ("query: %s", thd->query)); - if (thd_ndb->global_schema_lock_trans) + if (thd_ndb->global_schema_lock_count) { - thd_ndb->global_schema_lock_trans->refresh(); + if (thd_ndb->global_schema_lock_trans) + thd_ndb->global_schema_lock_trans->refresh(); + else + DBUG_ASSERT(thd_ndb->global_schema_lock_error != 0); thd_ndb->global_schema_lock_count++; DBUG_PRINT("exit", ("global_schema_lock_count: %d", thd_ndb->global_schema_lock_count)); DBUG_RETURN(0); } DBUG_ASSERT(thd_ndb->global_schema_lock_count == 0); - thd_ndb->global_schema_lock_count= 0; + thd_ndb->global_schema_lock_count= 1; + thd_ndb->global_schema_lock_error= 0; + DBUG_PRINT("exit", ("global_schema_lock_count: %d", + thd_ndb->global_schema_lock_count)); if ((thd_ndb->global_schema_lock_trans= - ndbcluster_global_schema_lock_ext(ndb, ndb_error)) != NULL) + ndbcluster_global_schema_lock_ext(thd, ndb, ndb_error, -1)) != NULL) { - thd_ndb->global_schema_lock_count= 1; DBUG_RETURN(0); } @@ -805,32 +813,32 @@ static int ndbcluster_global_schema_lock ndb_error.code, ndb_error.message, "NDB. Could not acquire global schema lock"); } - thd_ndb->global_schema_lock_error= ndb_error.code; + thd_ndb->global_schema_lock_error= ndb_error.code ? ndb_error.code : -1; DBUG_RETURN(-1); } static int ndbcluster_global_schema_unlock(THD *thd) { Thd_ndb *thd_ndb= get_thd_ndb(thd); DBUG_ASSERT(thd_ndb != 0); - if (thd_ndb) - thd_ndb->global_schema_lock_error= 0; if (thd_ndb == 0 || (thd_ndb->options & TNO_NO_LOCK_SCHEMA_OP)) return 0; Ndb *ndb= thd_ndb->ndb; + DBUG_ENTER("ndbcluster_global_schema_unlock"); + NdbTransaction *trans= thd_ndb->global_schema_lock_trans; + thd_ndb->global_schema_lock_count--; + DBUG_PRINT("exit", ("global_schema_lock_count: %d", + thd_ndb->global_schema_lock_count)); DBUG_ASSERT(ndb != NULL); if (ndb == NULL) return 0; - DBUG_ENTER("ndbcluster_global_schema_unlock"); - NdbTransaction *trans= thd_ndb->global_schema_lock_trans; + DBUG_ASSERT(trans != NULL || thd_ndb->global_schema_lock_error != 0); + if (thd_ndb->global_schema_lock_count != 0) + { + DBUG_RETURN(0); + } + thd_ndb->global_schema_lock_error= 0; if (trans) { - thd_ndb->global_schema_lock_count--; - if (thd_ndb->global_schema_lock_count != 0) - { - DBUG_PRINT("exit", ("global_schema_lock_count: %d", - thd_ndb->global_schema_lock_count)); - DBUG_RETURN(0); - } thd_ndb->global_schema_lock_trans= NULL; NdbError ndb_error; if (ndbcluster_global_schema_unlock_ext(ndb, trans, ndb_error)) @@ -845,8 +853,6 @@ static int ndbcluster_global_schema_unlo DBUG_RETURN(-1); } } - DBUG_PRINT("exit", ("global_schema_lock_count: %d", - thd_ndb->global_schema_lock_count)); DBUG_RETURN(0); } @@ -872,7 +878,7 @@ static int ndbcluster_binlog_func(handle ndbcluster_binlog_index_purge_file(thd, (const char *)arg); break; case BFN_GLOBAL_SCHEMA_LOCK: - ndbcluster_global_schema_lock(thd, 1); + DBUG_RETURN(ndbcluster_global_schema_lock(thd, 1)); break; case BFN_GLOBAL_SCHEMA_UNLOCK: ndbcluster_global_schema_unlock(thd); @@ -891,14 +897,15 @@ Ndbcluster_global_schema_lock_guard::~Nd } int Ndbcluster_global_schema_lock_guard::lock() { - m_lock= !ndbcluster_global_schema_lock(m_thd, 0); - return !m_lock; -} -void Ndbcluster_global_schema_lock_guard::unlock() -{ - if (m_lock) - ndbcluster_global_schema_unlock(m_thd); - m_lock= 0; + /* only one lock call allowed */ + DBUG_ASSERT(m_lock == 0); + /* + Always se m_lock, even if lock fails. Since the + lock/unlock calls are reference counted, the number + of calls to lock and unlock need to match up. + */ + m_lock= 1; + return ndbcluster_global_schema_lock(m_thd, 0); } void ndbcluster_binlog_init_handlerton() === modified file 'sql/ha_ndbcluster_binlog.h' --- a/sql/ha_ndbcluster_binlog.h 2008-10-02 15:52:29 +0000 +++ b/sql/ha_ndbcluster_binlog.h 2008-10-07 08:19:31 +0000 @@ -275,7 +275,6 @@ public: Ndbcluster_global_schema_lock_guard(THD *thd); ~Ndbcluster_global_schema_lock_guard(); int lock(); - void unlock(); private: THD *m_thd; int m_lock; === modified file 'sql/ha_ndbcluster_lock_ext.h' --- a/sql/ha_ndbcluster_lock_ext.h 2008-09-30 09:14:44 +0000 +++ b/sql/ha_ndbcluster_lock_ext.h 2008-10-07 08:19:31 +0000 @@ -19,26 +19,43 @@ tables through ndb_restore is syncronized correctly with the mysqld's The lock/unlock functions use the BACKUP_SEQUENCE row in SYSTAB_0 + + retry_time == 0 means no retry + retry_time < 0 means infinite retries + retry_time > 0 means retries for max 'retry_time' seconds */ static NdbTransaction * -ndbcluster_global_schema_lock_ext(Ndb *ndb, NdbError &ndb_error) +ndbcluster_global_schema_lock_ext(THD *thd, Ndb *ndb, NdbError &ndb_error, + int retry_time= 10) { ndb->setDatabaseName("sys"); ndb->setDatabaseSchemaName("def"); NdbDictionary::Dictionary *dict= ndb->getDictionary(); Ndb_table_guard ndbtab_g(dict, "SYSTAB_0"); - const NdbDictionary::Table *ndbtab; + const NdbDictionary::Table *ndbtab= NULL; NdbOperation *op; NdbTransaction *trans= NULL; - int retries= 100; int retry_sleep= 50; /* 50 milliseconds, transaction */ - if (!(ndbtab= ndbtab_g.get_table())) + struct timeval time_end; + + if (retry_time > 0) { - ndb_error= dict->getNdbError(); - goto error_handler; + gettimeofday(&time_end, 0); + time_end.tv_sec+= retry_time; } while (1) { + if (!ndbtab) + { + if (!(ndbtab= ndbtab_g.get_table())) + { + if (dict->getNdbError().status == NdbError::TemporaryError) + goto retry; + ndb_error= dict->getNdbError(); + goto error_handler; + } + } + trans= ndb->startTransaction(); if (trans == NULL) { @@ -53,24 +70,34 @@ ndbcluster_global_schema_lock_ext(Ndb *n if (trans->execute(NdbTransaction::NoCommit) == 0) break; - if (trans->getNdbError().status == NdbError::TemporaryError) + if (trans->getNdbError().status != NdbError::TemporaryError) + goto error_handler; + else if (thd->killed) + goto error_handler; + retry: + if (retry_time == 0) + goto error_handler; + if (retry_time > 0) { - if (retries--) - { - ndb->closeTransaction(trans); - trans= NULL; - do_retry_sleep(retry_sleep); - continue; // retry - } + struct timeval time_now; + gettimeofday(&time_now, 0); + if ((time_end.tv_sec < time_now.tv_sec) || + (time_end.tv_sec == time_now.tv_sec && time_end.tv_usec < time_now.tv_usec)) + break; // terminate } - ndb_error= trans->getNdbError(); - goto error_handler; + if (trans) + { + ndb->closeTransaction(trans); + trans= NULL; + } + do_retry_sleep(retry_sleep); } return trans; error_handler: if (trans) { + ndb_error= trans->getNdbError(); ndb->closeTransaction(trans); } return NULL; === modified file 'sql/handler.cc' --- a/sql/handler.cc 2008-09-30 09:14:44 +0000 +++ b/sql/handler.cc 2008-10-07 08:19:31 +0000 @@ -3850,7 +3850,7 @@ int ha_binlog_index_purge_file(THD *thd, return 0; } -int ha_global_schema_lock(THD *thd) +static int ha_global_schema_lock(THD *thd) { binlog_func_st bfn= {BFN_GLOBAL_SCHEMA_LOCK, 0}; binlog_func_foreach(thd, &bfn); @@ -3859,13 +3859,31 @@ int ha_global_schema_lock(THD *thd) return 0; } -int ha_global_schema_unlock(THD *thd) +static int ha_global_schema_unlock(THD *thd) { binlog_func_st bfn= {BFN_GLOBAL_SCHEMA_UNLOCK, 0}; binlog_func_foreach(thd, &bfn); if (thd->main_da.is_error()) return 1; return 0; +} + +Ha_global_schema_lock_guard::Ha_global_schema_lock_guard(THD *thd) + : m_thd(thd), m_lock(0) +{ +} + +Ha_global_schema_lock_guard::~Ha_global_schema_lock_guard() +{ + if (m_lock) + ha_global_schema_unlock(m_thd); +} + +int Ha_global_schema_lock_guard::lock() +{ + DBUG_ASSERT(m_lock == 0); + m_lock= 1; + return ha_global_schema_lock(m_thd); } struct binlog_log_query_st === modified file 'sql/handler.h' --- a/sql/handler.h 2008-09-30 09:14:44 +0000 +++ b/sql/handler.h 2008-10-07 08:19:31 +0000 @@ -2183,25 +2183,12 @@ void ha_binlog_log_query(THD *thd, handl const char *db, const char *table_name); void ha_binlog_wait(THD *thd); int ha_binlog_end(THD *thd); -int ha_global_schema_lock(THD *thd); -int ha_global_schema_unlock(THD *thd); class Ha_global_schema_lock_guard { public: - Ha_global_schema_lock_guard(THD *thd) - : m_thd(thd), m_lock(0) - { - } - ~Ha_global_schema_lock_guard() - { - if (m_lock) - ha_global_schema_unlock(m_thd); - } - int lock() - { - m_lock= !ha_global_schema_lock(m_thd); - return !m_lock; - } + Ha_global_schema_lock_guard(THD *thd); + ~Ha_global_schema_lock_guard(); + int lock(); private: THD *m_thd; int m_lock; @@ -2214,8 +2201,6 @@ inline int ha_int_dummy() { return 0; } #define ha_binlog_log_query(a,b,c,d,e,f,g) do {} while (0) #define ha_binlog_wait(a) do {} while (0) #define ha_binlog_end(a) do {} while (0) -#define ha_global_schema_lock(a) ha_int_dummy() -#define ha_global_schema_unlock(a) ha_int_dummy() class Ha_global_schema_lock_guard { public: === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2008-10-02 08:56:22 +0000 +++ b/sql/sql_table.cc 2008-10-07 08:19:31 +0000 @@ -3620,7 +3620,9 @@ bool mysql_create_table(THD *thd, const Ha_global_schema_lock_guard global_schema_lock_guard(thd); DBUG_ENTER("mysql_create_table"); - if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) + if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) && + !create_info->frm_only && + !internal_tmp_table) global_schema_lock_guard.lock(); /* Wait for any database locks */