Loading mysql-test/r/ndb_multi.result +21 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,26 @@ a show status like 'handler_discover%'; Variable_name Value Handler_discover 0 select * from t1; a 2 drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); select * from t1; a 2 show status like 'handler_discover%'; Variable_name Value Handler_discover 0 drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); select * from t1; ERROR HY000: Got error 241 'Invalid schema object version' from ndbcluster select * from t1; a 2 flush status; select * from t1; a Loading @@ -20,7 +40,7 @@ a update t1 set a=3 where a=2; show status like 'handler_discover%'; Variable_name Value Handler_discover 1 Handler_discover 0 create table t3 (a int not null primary key, b varchar(22), c int, last_col text) engine=ndb; insert into t3 values(1, 'Hi!', 89, 'Longtext column'); Loading mysql-test/t/ndb_multi.test +24 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,30 @@ select * from t1; select * from t2; show status like 'handler_discover%'; # Check dropping and recreating table on same server connect (con1,localhost,,,test); connect (con2,localhost,,,test); connection con1; select * from t1; connection con2; drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); connection con1; select * from t1; # Check dropping and recreating table on different server connection server2; show status like 'handler_discover%'; drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); connection server1; # Currently a retry is required remotely --error 1296 select * from t1; select * from t1; # Connect to server2 and use the tables from there connection server2; flush status; Loading ndb/include/ndbapi/NdbDictionary.hpp +4 −1 Original line number Diff line number Diff line Loading @@ -75,8 +75,11 @@ public: Changed, ///< The object has been modified in memory ///< and has to be commited in NDB Kernel for ///< changes to take effect Retrieved ///< The object exist and has been read Retrieved, ///< The object exist and has been read ///< into main memory from NDB Kernel Invalid ///< The object has been invalidated ///< and should not be used }; /** Loading ndb/src/ndbapi/NdbDictionaryImpl.cpp +7 −4 Original line number Diff line number Diff line Loading @@ -1448,6 +1448,7 @@ int NdbDictionaryImpl::alterTable(NdbTableImpl &impl) // If in local cache it must be in global if (!cachedImpl) abort(); cachedImpl->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(cachedImpl); m_globalHash->unlock(); } Loading Loading @@ -1747,8 +1748,8 @@ NdbDictionaryImpl::dropTable(const char * name) DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName)); m_localHash.drop(internalTableName); m_globalHash->lock(); tab->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(tab); m_globalHash->unlock(); DBUG_RETURN(dropTable(name)); Loading Loading @@ -1793,9 +1794,10 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl) if(ret == 0 || m_error.code == 709){ const char * internalTableName = impl.m_internalName.c_str(); m_localHash.drop(internalTableName); m_localHash.drop(internalTableName); m_globalHash->lock(); impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); Loading Loading @@ -1889,6 +1891,7 @@ NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl) m_localHash.drop(internalTableName); m_globalHash->lock(); impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); return 0; Loading Loading @@ -2152,8 +2155,8 @@ NdbDictionaryImpl::dropIndex(const char * indexName, m_ndb.internalizeTableName(indexName); // Index is also a table m_localHash.drop(internalIndexName); m_globalHash->lock(); idx->m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(idx->m_table); m_globalHash->unlock(); return dropIndex(indexName, tableName); Loading Loading @@ -2187,8 +2190,8 @@ NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName) int ret = m_receiver.dropIndex(impl, *timpl); if(ret == 0){ m_localHash.drop(internalIndexName); m_globalHash->lock(); impl.m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(impl.m_table); m_globalHash->unlock(); } Loading sql/ha_ndbcluster.cc +77 −20 Original line number Diff line number Diff line Loading @@ -331,11 +331,28 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd) # The mapped error code */ void ha_ndbcluster::invalidateDictionaryCache() void ha_ndbcluster::invalidate_dictionary_cache(bool global) { NDBDICT *dict= get_ndb()->getDictionary(); DBUG_ENTER("invalidate_dictionary_cache"); DBUG_PRINT("info", ("invalidating %s", m_tabname)); if (global) { const NDBTAB *tab= dict->getTable(m_tabname); if (!tab) DBUG_VOID_RETURN; if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { // Global cache has already been invalidated dict->removeCachedTable(m_tabname); global= FALSE; } else dict->invalidateTable(m_tabname); } else dict->removeCachedTable(m_tabname); table->version=0L; /* Free when thread is ready */ /* Invalidate indexes */ for (uint i= 0; i < table->keys; i++) Loading @@ -347,18 +364,28 @@ void ha_ndbcluster::invalidateDictionaryCache() switch(idx_type) { case(PRIMARY_KEY_ORDERED_INDEX): case(ORDERED_INDEX): if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); break; case(UNIQUE_ORDERED_INDEX): if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); case(UNIQUE_INDEX): if (global) dict->invalidateIndex(unique_index->getName(), m_tabname); else dict->removeCachedIndex(unique_index->getName(), m_tabname); break; case(PRIMARY_KEY_INDEX): case(UNDEFINED_INDEX): break; } } DBUG_VOID_RETURN; } int ha_ndbcluster::ndb_err(NdbConnection *trans) Loading @@ -371,7 +398,7 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans) switch (err.classification) { case NdbError::SchemaError: { invalidateDictionaryCache(); invalidate_dictionary_cache(TRUE); if (err.code==284) { Loading Loading @@ -765,9 +792,16 @@ int ha_ndbcluster::get_metadata(const char *path) const void *data, *pack_data; uint length, pack_length; if (!(tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); // Check if thread has stale local cache if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { invalidate_dictionary_cache(FALSE); if (!(tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); } /* Compare FrmData in NDB with frm file from disk. */ Loading @@ -786,7 +820,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (!invalidating_ndb_table) { DBUG_PRINT("info", ("Invalidating table")); invalidateDictionaryCache(); invalidate_dictionary_cache(TRUE); invalidating_ndb_table= TRUE; } else Loading @@ -812,7 +846,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (error) DBUG_RETURN(error); m_tableVersion= tab->getObjectVersion(); m_table_version= tab->getObjectVersion(); m_table= (void *)tab; m_table_info= NULL; // Set in external lock Loading Loading @@ -3226,15 +3260,25 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) void *tab_info; if (!(tab= dict->getTable(m_tabname, &tab_info))) ERR_RETURN(dict->getNdbError()); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); if (m_table != (void *)tab || m_tableVersion != tab->getObjectVersion()) DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); // Check if thread has stale local cache if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { invalidate_dictionary_cache(FALSE); if (!(tab= dict->getTable(m_tabname, &tab_info))) ERR_RETURN(dict->getNdbError()); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); } if (m_table != (void *)tab || m_table_version < tab->getObjectVersion()) { /* The table has been altered, refresh the index list */ build_index_list(ndb, table, ILBP_OPEN); m_table= (void *)tab; m_tableVersion = tab->getObjectVersion(); m_table_version = tab->getObjectVersion(); } m_table_info= tab_info; } Loading @@ -3260,7 +3304,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) thd->transaction.stmt.ndb_tid= 0; } } m_table= NULL; m_table_info= NULL; /* This is the place to make sure this handler instance Loading Loading @@ -3882,7 +3925,13 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) dict= ndb->getDictionary(); if (!(orig_tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); // Check if thread has stale local cache if (orig_tab->getObjectStatus() == NdbDictionary::Object::Invalid) { dict->removeCachedTable(m_tabname); if (!(orig_tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); } m_table= (void *)orig_tab; // Change current database to that of target table set_dbname(to); Loading Loading @@ -4006,7 +4055,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_active_trans(NULL), m_active_cursor(NULL), m_table(NULL), m_tableVersion(-1), m_table_version(-1), m_table_info(NULL), m_table_flags(HA_REC_NOT_IN_SEQ | HA_NULL_IN_KEY | Loading Loading @@ -4250,7 +4299,6 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, DBUG_RETURN(1); ERR_RETURN(err); } DBUG_PRINT("info", ("Found table %s", tab->getName())); len= tab->getFrmLength(); Loading Loading @@ -4327,6 +4375,7 @@ int ndbcluster_drop_database(const char *path) uint i; char *tabname; List<char> drop_list; int ret= 0; ha_ndbcluster::set_dbname(path, (char *)&dbname); DBUG_PRINT("enter", ("db: %s", dbname)); Loading @@ -4353,10 +4402,18 @@ int ndbcluster_drop_database(const char *path) ndb->setDatabaseName(dbname); List_iterator_fast<char> it(drop_list); while ((tabname=it++)) { if (dict->dropTable(tabname)) ERR_RETURN(dict->getNdbError()); DBUG_RETURN(0); { const NdbError err= dict->getNdbError(); if (err.code != 709) { ERR_PRINT(err); ret= ndb_to_mysql_error(&err); } } } DBUG_RETURN(ret); } Loading Loading
mysql-test/r/ndb_multi.result +21 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,26 @@ a show status like 'handler_discover%'; Variable_name Value Handler_discover 0 select * from t1; a 2 drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); select * from t1; a 2 show status like 'handler_discover%'; Variable_name Value Handler_discover 0 drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); select * from t1; ERROR HY000: Got error 241 'Invalid schema object version' from ndbcluster select * from t1; a 2 flush status; select * from t1; a Loading @@ -20,7 +40,7 @@ a update t1 set a=3 where a=2; show status like 'handler_discover%'; Variable_name Value Handler_discover 1 Handler_discover 0 create table t3 (a int not null primary key, b varchar(22), c int, last_col text) engine=ndb; insert into t3 values(1, 'Hi!', 89, 'Longtext column'); Loading
mysql-test/t/ndb_multi.test +24 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,30 @@ select * from t1; select * from t2; show status like 'handler_discover%'; # Check dropping and recreating table on same server connect (con1,localhost,,,test); connect (con2,localhost,,,test); connection con1; select * from t1; connection con2; drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); connection con1; select * from t1; # Check dropping and recreating table on different server connection server2; show status like 'handler_discover%'; drop table t1; create table t1 (a int) engine=ndbcluster; insert into t1 value (2); connection server1; # Currently a retry is required remotely --error 1296 select * from t1; select * from t1; # Connect to server2 and use the tables from there connection server2; flush status; Loading
ndb/include/ndbapi/NdbDictionary.hpp +4 −1 Original line number Diff line number Diff line Loading @@ -75,8 +75,11 @@ public: Changed, ///< The object has been modified in memory ///< and has to be commited in NDB Kernel for ///< changes to take effect Retrieved ///< The object exist and has been read Retrieved, ///< The object exist and has been read ///< into main memory from NDB Kernel Invalid ///< The object has been invalidated ///< and should not be used }; /** Loading
ndb/src/ndbapi/NdbDictionaryImpl.cpp +7 −4 Original line number Diff line number Diff line Loading @@ -1448,6 +1448,7 @@ int NdbDictionaryImpl::alterTable(NdbTableImpl &impl) // If in local cache it must be in global if (!cachedImpl) abort(); cachedImpl->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(cachedImpl); m_globalHash->unlock(); } Loading Loading @@ -1747,8 +1748,8 @@ NdbDictionaryImpl::dropTable(const char * name) DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName)); m_localHash.drop(internalTableName); m_globalHash->lock(); tab->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(tab); m_globalHash->unlock(); DBUG_RETURN(dropTable(name)); Loading Loading @@ -1793,9 +1794,10 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl) if(ret == 0 || m_error.code == 709){ const char * internalTableName = impl.m_internalName.c_str(); m_localHash.drop(internalTableName); m_localHash.drop(internalTableName); m_globalHash->lock(); impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); Loading Loading @@ -1889,6 +1891,7 @@ NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl) m_localHash.drop(internalTableName); m_globalHash->lock(); impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); return 0; Loading Loading @@ -2152,8 +2155,8 @@ NdbDictionaryImpl::dropIndex(const char * indexName, m_ndb.internalizeTableName(indexName); // Index is also a table m_localHash.drop(internalIndexName); m_globalHash->lock(); idx->m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(idx->m_table); m_globalHash->unlock(); return dropIndex(indexName, tableName); Loading Loading @@ -2187,8 +2190,8 @@ NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName) int ret = m_receiver.dropIndex(impl, *timpl); if(ret == 0){ m_localHash.drop(internalIndexName); m_globalHash->lock(); impl.m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(impl.m_table); m_globalHash->unlock(); } Loading
sql/ha_ndbcluster.cc +77 −20 Original line number Diff line number Diff line Loading @@ -331,11 +331,28 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd) # The mapped error code */ void ha_ndbcluster::invalidateDictionaryCache() void ha_ndbcluster::invalidate_dictionary_cache(bool global) { NDBDICT *dict= get_ndb()->getDictionary(); DBUG_ENTER("invalidate_dictionary_cache"); DBUG_PRINT("info", ("invalidating %s", m_tabname)); if (global) { const NDBTAB *tab= dict->getTable(m_tabname); if (!tab) DBUG_VOID_RETURN; if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { // Global cache has already been invalidated dict->removeCachedTable(m_tabname); global= FALSE; } else dict->invalidateTable(m_tabname); } else dict->removeCachedTable(m_tabname); table->version=0L; /* Free when thread is ready */ /* Invalidate indexes */ for (uint i= 0; i < table->keys; i++) Loading @@ -347,18 +364,28 @@ void ha_ndbcluster::invalidateDictionaryCache() switch(idx_type) { case(PRIMARY_KEY_ORDERED_INDEX): case(ORDERED_INDEX): if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); break; case(UNIQUE_ORDERED_INDEX): if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); case(UNIQUE_INDEX): if (global) dict->invalidateIndex(unique_index->getName(), m_tabname); else dict->removeCachedIndex(unique_index->getName(), m_tabname); break; case(PRIMARY_KEY_INDEX): case(UNDEFINED_INDEX): break; } } DBUG_VOID_RETURN; } int ha_ndbcluster::ndb_err(NdbConnection *trans) Loading @@ -371,7 +398,7 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans) switch (err.classification) { case NdbError::SchemaError: { invalidateDictionaryCache(); invalidate_dictionary_cache(TRUE); if (err.code==284) { Loading Loading @@ -765,9 +792,16 @@ int ha_ndbcluster::get_metadata(const char *path) const void *data, *pack_data; uint length, pack_length; if (!(tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); // Check if thread has stale local cache if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { invalidate_dictionary_cache(FALSE); if (!(tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); } /* Compare FrmData in NDB with frm file from disk. */ Loading @@ -786,7 +820,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (!invalidating_ndb_table) { DBUG_PRINT("info", ("Invalidating table")); invalidateDictionaryCache(); invalidate_dictionary_cache(TRUE); invalidating_ndb_table= TRUE; } else Loading @@ -812,7 +846,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (error) DBUG_RETURN(error); m_tableVersion= tab->getObjectVersion(); m_table_version= tab->getObjectVersion(); m_table= (void *)tab; m_table_info= NULL; // Set in external lock Loading Loading @@ -3226,15 +3260,25 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) void *tab_info; if (!(tab= dict->getTable(m_tabname, &tab_info))) ERR_RETURN(dict->getNdbError()); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); if (m_table != (void *)tab || m_tableVersion != tab->getObjectVersion()) DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); // Check if thread has stale local cache if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { invalidate_dictionary_cache(FALSE); if (!(tab= dict->getTable(m_tabname, &tab_info))) ERR_RETURN(dict->getNdbError()); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); } if (m_table != (void *)tab || m_table_version < tab->getObjectVersion()) { /* The table has been altered, refresh the index list */ build_index_list(ndb, table, ILBP_OPEN); m_table= (void *)tab; m_tableVersion = tab->getObjectVersion(); m_table_version = tab->getObjectVersion(); } m_table_info= tab_info; } Loading @@ -3260,7 +3304,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) thd->transaction.stmt.ndb_tid= 0; } } m_table= NULL; m_table_info= NULL; /* This is the place to make sure this handler instance Loading Loading @@ -3882,7 +3925,13 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) dict= ndb->getDictionary(); if (!(orig_tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); // Check if thread has stale local cache if (orig_tab->getObjectStatus() == NdbDictionary::Object::Invalid) { dict->removeCachedTable(m_tabname); if (!(orig_tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); } m_table= (void *)orig_tab; // Change current database to that of target table set_dbname(to); Loading Loading @@ -4006,7 +4055,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_active_trans(NULL), m_active_cursor(NULL), m_table(NULL), m_tableVersion(-1), m_table_version(-1), m_table_info(NULL), m_table_flags(HA_REC_NOT_IN_SEQ | HA_NULL_IN_KEY | Loading Loading @@ -4250,7 +4299,6 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, DBUG_RETURN(1); ERR_RETURN(err); } DBUG_PRINT("info", ("Found table %s", tab->getName())); len= tab->getFrmLength(); Loading Loading @@ -4327,6 +4375,7 @@ int ndbcluster_drop_database(const char *path) uint i; char *tabname; List<char> drop_list; int ret= 0; ha_ndbcluster::set_dbname(path, (char *)&dbname); DBUG_PRINT("enter", ("db: %s", dbname)); Loading @@ -4353,10 +4402,18 @@ int ndbcluster_drop_database(const char *path) ndb->setDatabaseName(dbname); List_iterator_fast<char> it(drop_list); while ((tabname=it++)) { if (dict->dropTable(tabname)) ERR_RETURN(dict->getNdbError()); DBUG_RETURN(0); { const NdbError err= dict->getNdbError(); if (err.code != 709) { ERR_PRINT(err); ret= ndb_to_mysql_error(&err); } } } DBUG_RETURN(ret); } Loading