From: magnus.blaudd Date: June 21 2011 2:02pm Subject: bzr push into mysql-5.1-telco-7.1 branch (magnus.blaudd:4250 to 4251) List-Archive: http://lists.mysql.com/commits/139567 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4251 magnus.blaudd@stripped 2011-06-21 [merge] Merge 7.0 -> 7.1 added: mysql-test/suite/ndb/r/ndb_select_count.result mysql-test/suite/ndb/t/ndb_select_count.test modified: sql/ha_ndbcluster.cc storage/ndb/include/mgmapi/mgmapi.h storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp storage/ndb/src/mgmapi/mgmapi.cpp storage/ndb/src/mgmsrv/MgmtSrvr.cpp storage/ndb/src/mgmsrv/MgmtSrvr.hpp storage/ndb/src/ndbapi/ClusterMgr.cpp storage/ndb/src/ndbapi/NdbQueryBuilder.hpp storage/ndb/src/ndbapi/NdbQueryOperation.cpp storage/ndb/src/ndbapi/NdbQueryOperation.hpp storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp storage/ndb/test/ndbapi/testMgmd.cpp 4250 Craig L Russell 2011-06-20 Modify some error conditions to print mismatches instead of failing immediately Allow data comparison failures to continue or throw an exception Normalize operation names (remove "_" from names except at end) Clean rows only at the beginning (operations already delete rows during tests) modified: storage/ndb/test/crund/src/com/mysql/cluster/crund/CrundDriver.java storage/ndb/test/crund/src/com/mysql/cluster/crund/Driver.java storage/ndb/test/crund/src/com/mysql/cluster/crund/JdbcLoad.java === added file 'mysql-test/suite/ndb/r/ndb_select_count.result' --- a/mysql-test/suite/ndb/r/ndb_select_count.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/ndb/r/ndb_select_count.result 2011-06-20 12:34:27 +0000 @@ -0,0 +1,19 @@ +create table t1( +k int not null auto_increment primary key, +i int, +j int +) engine=ndbcluster; +insert into t1(i,j) values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +select count(*) from t1; +count(*) +7 +begin; +delete from t1 where k = 10000; +select count(*) from t1; +count(*) +7 +commit; +select count(*) from t1; +count(*) +7 +drop table t1; === added file 'mysql-test/suite/ndb/t/ndb_select_count.test' --- a/mysql-test/suite/ndb/t/ndb_select_count.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/ndb/t/ndb_select_count.test 2011-06-20 12:34:27 +0000 @@ -0,0 +1,18 @@ +-- source include/have_ndb.inc + +create table t1( + k int not null auto_increment primary key, + i int, + j int +) engine=ndbcluster; + +insert into t1(i,j) values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); + +select count(*) from t1; +begin; +delete from t1 where k = 10000; # none existant, rbwr +select count(*) from t1; +commit; +select count(*) from t1; + +drop table t1; === modified file 'sql/ha_ndbcluster.cc' --- a/sql/ha_ndbcluster.cc 2011-06-20 16:22:38 +0000 +++ b/sql/ha_ndbcluster.cc 2011-06-21 13:50:33 +0000 @@ -5057,6 +5057,7 @@ int ha_ndbcluster::end_bulk_delete() assert(m_rows_deleted >= ignore_count); m_rows_deleted-= ignore_count; + no_uncommitted_rows_update(ignore_count); DBUG_RETURN(0); } @@ -5249,6 +5250,7 @@ int ha_ndbcluster::ndb_delete_row(const { assert(m_rows_deleted >= ignore_count); m_rows_deleted-= ignore_count; + no_uncommitted_rows_update(ignore_count); } DBUG_RETURN(0); } === modified file 'storage/ndb/include/mgmapi/mgmapi.h' --- a/storage/ndb/include/mgmapi/mgmapi.h 2011-02-01 23:27:25 +0000 +++ b/storage/ndb/include/mgmapi/mgmapi.h 2011-06-21 13:10:37 +0000 @@ -206,11 +206,13 @@ extern "C" { NDB_MGM_NODE_STATUS_SINGLEUSER = 7, /** Resume mode*/ NDB_MGM_NODE_STATUS_RESUME = 8, + /** Node is connected */ + NDB_MGM_NODE_STATUS_CONNECTED = 9, #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL /** Min valid value*/ NDB_MGM_NODE_STATUS_MIN = 0, /** Max valid value*/ - NDB_MGM_NODE_STATUS_MAX = 8 + NDB_MGM_NODE_STATUS_MAX = 9 #endif }; === modified file 'storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp' --- a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp 2011-06-13 06:14:32 +0000 +++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp 2011-06-21 13:10:37 +0000 @@ -3728,6 +3728,7 @@ Qmgr::execAPI_VERSION_REQ(Signal * signa else { conf->version = 0; + conf->mysql_version = 0; conf->inet_addr= 0; } conf->nodeId = nodeId; === modified file 'storage/ndb/src/mgmapi/mgmapi.cpp' --- a/storage/ndb/src/mgmapi/mgmapi.cpp 2011-03-28 09:01:03 +0000 +++ b/storage/ndb/src/mgmapi/mgmapi.cpp 2011-06-21 13:10:37 +0000 @@ -934,7 +934,10 @@ static struct ndb_mgm_status_atoi status { "STARTED", NDB_MGM_NODE_STATUS_STARTED }, { "SHUTTING_DOWN", NDB_MGM_NODE_STATUS_SHUTTING_DOWN }, { "RESTARTING", NDB_MGM_NODE_STATUS_RESTARTING }, - { "SINGLE USER MODE", NDB_MGM_NODE_STATUS_SINGLEUSER } + { "SINGLE USER MODE", NDB_MGM_NODE_STATUS_SINGLEUSER }, + { "SINGLE USER MODE", NDB_MGM_NODE_STATUS_SINGLEUSER }, + { "RESUME", NDB_MGM_NODE_STATUS_RESUME }, + { "CONNECTED", NDB_MGM_NODE_STATUS_CONNECTED } }; const int no_of_status_values = (sizeof(status_values) / === modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp' --- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp 2011-06-01 07:51:41 +0000 +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp 2011-06-21 13:50:33 +0000 @@ -835,59 +835,34 @@ MgmtSrvr::start(int nodeId) * Version handling *****************************************************************************/ -int -MgmtSrvr::versionNode(int nodeId, Uint32 &version, Uint32& mysql_version, - const char **address) -{ - version= 0; - mysql_version = 0; - if (getOwnNodeId() == nodeId) - { - /** - * If we're inquiring about our own node id, - * We know what version we are (version implies connected for mgm) - * but would like to find out from elsewhere what address they're using - * to connect to us. This means that secondary mgm servers - * can list ip addresses for mgm servers. - * - * If we don't get an address (i.e. no db nodes), - * we get the address from the configuration. - */ - sendVersionReq(nodeId, version, mysql_version, address); - version= NDB_VERSION; - mysql_version = NDB_MYSQL_VERSION_D; - if(!*address) - { - Guard g(m_local_config_mutex); - ConfigIter iter(m_local_config, CFG_SECTION_NODE); - unsigned tmp= 0; - for(iter.first();iter.valid();iter.next()) - { - if(iter.get(CFG_NODE_ID, &tmp)) require(false); - if((unsigned)nodeId!=tmp) - continue; - if(iter.get(CFG_NODE_HOST, address)) require(false); - break; - } - } +void +MgmtSrvr::status_api(int nodeId, + ndb_mgm_node_status& node_status, + Uint32& version, Uint32& mysql_version, + const char **address) +{ + assert(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API); + assert(version == 0 && mysql_version == 0); + + if (sendVersionReq(nodeId, version, mysql_version, address) != 0) + { + // Couldn't get version from any NDB node. + assert(version == 0); + node_status = NDB_MGM_NODE_STATUS_UNKNOWN; + return; } - else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB) + + if (version) { - trp_node node = getNodeInfo(nodeId); - if(node.is_connected()) - { - version= node.m_info.m_version; - mysql_version = node.m_info.m_mysql_version; - } - *address= get_connect_address(nodeId); + assert(mysql_version); + node_status = NDB_MGM_NODE_STATUS_CONNECTED; } - else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API || - getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM) + else { - return sendVersionReq(nodeId, version, mysql_version, address); + assert(mysql_version == 0); + node_status = NDB_MGM_NODE_STATUS_NO_CONTACT; } - - return 0; + return; } @@ -1898,6 +1873,75 @@ MgmtSrvr::updateStatus() theFacade->ext_forceHB(); } + +void +MgmtSrvr::status_mgmd(NodeId node_id, + ndb_mgm_node_status& node_status, + Uint32& version, Uint32& mysql_version, + const char **address) +{ + assert(getNodeType(node_id) == NDB_MGM_NODE_TYPE_MGM); + + if (node_id == getOwnNodeId()) + { + /* + Special case to get version of own node + - version and mysql_version is hardcoded + - address should be the address seen from ndbd(if it's connected) + else use HostName from config + */ + Uint32 tmp_version = 0, tmp_mysql_version = 0; + sendVersionReq(node_id, tmp_version, tmp_mysql_version, address); + // Check that the version returned is equal to compiled in version + assert(tmp_version == 0 || + (tmp_version == NDB_VERSION && + tmp_mysql_version == NDB_MYSQL_VERSION_D)); + + version = NDB_VERSION; + mysql_version = NDB_MYSQL_VERSION_D; + if(!*address) + { + // No address returned from ndbd -> get HostName from config + Guard g(m_local_config_mutex); + ConfigIter iter(m_local_config, CFG_SECTION_NODE); + require(iter.find(CFG_NODE_ID, node_id) == 0); + require(iter.get(CFG_NODE_HOST, address) == 0); + + /* + Try to convert HostName to numerical ip address + (to get same output as if ndbd had replied) + */ + struct in_addr addr; + if (Ndb_getInAddr(&addr, *address) == 0) + *address = inet_ntoa(addr); + } + + node_status = NDB_MGM_NODE_STATUS_CONNECTED; + return; + } + + /* + MGM nodes are connected directly to all other MGM + node(s), return status as seen by ClusterMgr + */ + const trp_node node = getNodeInfo(node_id); + if(node.is_connected()) + { + version = node.m_info.m_version; + mysql_version = node.m_info.m_mysql_version; + node_status = NDB_MGM_NODE_STATUS_CONNECTED; + *address= get_connect_address(node_id); + } + else + { + version = 0; + mysql_version = 0; + node_status = NDB_MGM_NODE_STATUS_NO_CONTACT; + } + + return; +} + int MgmtSrvr::status(int nodeId, ndb_mgm_node_status * _status, @@ -1910,24 +1954,38 @@ MgmtSrvr::status(int nodeId, Uint32 * connectCount, const char **address) { - if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API || - getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM) { - versionNode(nodeId, *version, *mysql_version, address); - } else { - *address= get_connect_address(nodeId); + switch(getNodeType(nodeId)){ + case NDB_MGM_NODE_TYPE_API: + status_api(nodeId, *_status, *version, *mysql_version, address); + return 0; + break; + + case NDB_MGM_NODE_TYPE_MGM: + status_mgmd(nodeId, *_status, *version, *mysql_version, address); + return 0; + break; + + case NDB_MGM_NODE_TYPE_NDB: + break; + + default: + abort(); + break; } const trp_node node = getNodeInfo(nodeId); + assert(getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB && + node.m_info.getType() == NodeInfo::DB); if(!node.is_connected()){ * _status = NDB_MGM_NODE_STATUS_NO_CONTACT; return 0; } - - if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB) { - * version = node.m_info.m_version; - * mysql_version = node.m_info.m_mysql_version; - } + + * version = node.m_info.m_version; + * mysql_version = node.m_info.m_mysql_version; + + *address= get_connect_address(nodeId); * dynamic = node.m_state.dynamicId; * nodegroup = node.m_state.nodeGroup; @@ -2792,9 +2850,10 @@ MgmtSrvr::getNodeType(NodeId nodeId) con const char *MgmtSrvr::get_connect_address(Uint32 node_id) { - if (m_connect_address[node_id].s_addr == 0 && - theFacade && - getNodeType(node_id) == NDB_MGM_NODE_TYPE_NDB) + if (theFacade && + m_connect_address[node_id].s_addr == 0 && + (getNodeType(node_id) == NDB_MGM_NODE_TYPE_MGM || + getNodeType(node_id) == NDB_MGM_NODE_TYPE_NDB)) { const trp_node &node= getNodeInfo(node_id); if (node.is_connected()) === modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.hpp' --- a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp 2011-06-01 07:40:49 +0000 +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp 2011-06-21 13:10:37 +0000 @@ -364,8 +364,14 @@ public: private: int guess_master_node(SignalSender&); - int versionNode(int nodeId, Uint32 &version, - Uint32 &mysql_version, const char **address); + void status_api(int nodeId, + ndb_mgm_node_status& node_status, + Uint32& version, Uint32& mysql_version, + const char **address); + void status_mgmd(NodeId node_id, + ndb_mgm_node_status& node_status, + Uint32& version, Uint32& mysql_version, + const char **address); int sendVersionReq(int processId, Uint32 &version, Uint32& mysql_version, const char **address); === modified file 'storage/ndb/src/ndbapi/ClusterMgr.cpp' --- a/storage/ndb/src/ndbapi/ClusterMgr.cpp 2011-02-03 14:45:49 +0000 +++ b/storage/ndb/src/ndbapi/ClusterMgr.cpp 2011-06-21 13:50:33 +0000 @@ -651,6 +651,9 @@ ClusterMgr::execAPI_REGREQ(const Uint32 if(node.m_info.m_version != apiRegReq->version){ node.m_info.m_version = apiRegReq->version; + node.m_info.m_mysql_version = apiRegReq->mysql_version; + if (node.m_info.m_version < NDBD_SPLIT_VERSION) + node.m_info.m_mysql_version = 0; if (getMajor(node.m_info.m_version) < getMajor(NDB_VERSION) || getMinor(node.m_info.m_version) < getMinor(NDB_VERSION)) { === modified file 'storage/ndb/src/ndbapi/NdbQueryBuilder.hpp' --- a/storage/ndb/src/ndbapi/NdbQueryBuilder.hpp 2011-06-16 09:32:43 +0000 +++ b/storage/ndb/src/ndbapi/NdbQueryBuilder.hpp 2011-06-20 13:25:48 +0000 @@ -479,13 +479,8 @@ private: * times. It is valid until it is explicitely released(). * * The NdbQueryDef *must* be keept alive until the last thread - * which executing a query based on this NdbQueryDef has completed execution - * *and* result handling. Used from multiple threads this implies either: - * - * - Keep the NdbQueryDef until all threads terminates. - * - Implement reference counting on the NdbQueryDef. - * - Use the supplied copy constructor to give each thread its own copy - * of the NdbQueryDef. + * which executing a query based on this NdbQueryDef has called + * NdbQuery::close(). * * A NdbQueryDef is scheduled for execution by appending it to an open * transaction - optionally together with a set of parameters specifying === modified file 'storage/ndb/src/ndbapi/NdbQueryOperation.cpp' --- a/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2011-06-16 09:32:43 +0000 +++ b/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2011-06-20 13:25:48 +0000 @@ -1389,7 +1389,7 @@ NdbQueryImpl::NdbQueryImpl(NdbTransactio m_state(Initial), m_tcState(Inactive), m_next(NULL), - m_queryDef(queryDef), + m_queryDef(&queryDef), m_error(), m_transaction(trans), m_scanTransaction(NULL), @@ -1452,9 +1452,13 @@ NdbQueryImpl::NdbQueryImpl(NdbTransactio NdbQueryImpl::~NdbQueryImpl() { - - // Do this to check that m_queryDef still exists. - assert(getNoOfOperations() == m_queryDef.getNoOfOperations()); + /** BEWARE: + * Don't refer NdbQueryDef or NdbQueryOperationDefs after + * NdbQuery::close() as at this stage the appliaction is + * allowed to destruct the Def's. + */ + assert(m_state==Closed); + assert(m_rootFrags==NULL); // NOTE: m_operations[] was allocated as a single memory chunk with // placement new construction of each operation. @@ -1465,8 +1469,6 @@ NdbQueryImpl::~NdbQueryImpl() } m_operations = NULL; } - delete[] m_rootFrags; - m_rootFrags = NULL; m_state = Destructed; } @@ -1478,6 +1480,9 @@ NdbQueryImpl::postFetchRelease() { m_operations[i].postFetchRelease(); } } + delete[] m_rootFrags; + m_rootFrags = NULL; + m_rowBufferAlloc.reset(); m_tupleSetAlloc.reset(); m_resultStreamAlloc.reset(); @@ -1957,7 +1962,7 @@ NdbQueryImpl::awaitMoreResults(bool forc assert(m_applFrags.getCurrent() == NULL); /* Check if there are any more completed fragments available.*/ - if (m_queryDef.isScanQuery()) + if (getQueryDef().isScanQuery()) { assert (m_scanTransaction); assert (m_state==Executing); @@ -2052,7 +2057,7 @@ NdbQueryImpl::awaitMoreResults(bool forc assert(m_pendingFrags == 0); assert(m_finalBatchFrags == getRootFragCount()); return FetchResult_noMoreData; - } // if(m_queryDef.isScanQuery()) + } // if(getQueryDef().isScanQuery()) } //NdbQueryImpl::awaitMoreResults @@ -2131,32 +2136,41 @@ NdbQueryImpl::close(bool forceSend) int res = 0; assert (m_state >= Initial && m_state < Destructed); - Ndb* const ndb = m_transaction.getNdb(); - - if (m_tcState != Inactive) + if (m_state != Closed) { - /* We have started a scan, but we have not yet received the last batch - * for all root fragments. We must therefore close the scan to release - * the scan context at TC.*/ - res = closeTcCursor(forceSend); - } + if (m_tcState != Inactive) + { + /* We have started a scan, but we have not yet received the last batch + * for all root fragments. We must therefore close the scan to release + * the scan context at TC.*/ + res = closeTcCursor(forceSend); + } - // Throw any pending results - m_fullFrags.clear(); - m_applFrags.clear(); + // Throw any pending results + m_fullFrags.clear(); + m_applFrags.clear(); - if (m_scanTransaction != NULL) - { - assert (m_state != Closed); - assert (m_scanTransaction->m_scanningQuery == this); - m_scanTransaction->m_scanningQuery = NULL; - ndb->closeTransaction(m_scanTransaction); - ndb->theRemainingStartTransactions--; // Compensate; m_scanTransaction was not a real Txn - m_scanTransaction = NULL; + Ndb* const ndb = m_transaction.getNdb(); + if (m_scanTransaction != NULL) + { + assert (m_state != Closed); + assert (m_scanTransaction->m_scanningQuery == this); + m_scanTransaction->m_scanningQuery = NULL; + ndb->closeTransaction(m_scanTransaction); + ndb->theRemainingStartTransactions--; // Compensate; m_scanTransaction was not a real Txn + m_scanTransaction = NULL; + } + + postFetchRelease(); + m_state = Closed; // Even if it was previously 'Failed' it is closed now! } - postFetchRelease(); - m_state = Closed; // Even if it was previously 'Failed' it is closed now! + /** BEWARE: + * Don't refer NdbQueryDef or its NdbQueryOperationDefs after ::close() + * as the application is allowed to destruct the Def's after this point. + */ + m_queryDef= NULL; + return res; } //NdbQueryImpl::close @@ -2819,7 +2833,7 @@ NdbQueryImpl::sendFetchMore(NdbRootFragm { assert(getRoot().m_resultStreams!=NULL); assert(!emptyFrag.finalBatchReceived()); - assert(m_queryDef.isScanQuery()); + assert(getQueryDef().isScanQuery()); const Uint32 fragNo = emptyFrag.getFragNo(); emptyFrag.reset(); @@ -2892,7 +2906,7 @@ NdbQueryImpl::sendFetchMore(NdbRootFragm int NdbQueryImpl::closeTcCursor(bool forceSend) { - assert (m_queryDef.isScanQuery()); + assert (getQueryDef().isScanQuery()); NdbImpl* const ndb = m_transaction.getNdb()->theImpl; const Uint32 timeout = ndb->get_waitfor_timeout(); === modified file 'storage/ndb/src/ndbapi/NdbQueryOperation.hpp' --- a/storage/ndb/src/ndbapi/NdbQueryOperation.hpp 2011-04-06 14:16:13 +0000 +++ b/storage/ndb/src/ndbapi/NdbQueryOperation.hpp 2011-06-20 13:25:48 +0000 @@ -180,7 +180,15 @@ public: NdbTransaction* getNdbTransaction() const; /** - * Close query + * Close query. + * + * Will release most of the internally allocated objects owned + * by this NdbQuery and detach itself from the NdbQueryDef + * used to instantiate it. + * + * The application may destruct the NdbQueryDef after + * ::close() has been called on *all* NdbQuery objects + * instantiated from it. */ void close(bool forceSend = false); === modified file 'storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp' --- a/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2011-04-06 14:16:13 +0000 +++ b/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2011-06-20 13:25:48 +0000 @@ -142,7 +142,8 @@ public: /** Close query: * - Release datanode resources, * - Discard pending result sets, - * - optionaly dealloc NdbQuery structures + * - Delete internal buffer and structures for receiving results. + * - Disconnect with NdbQueryDef - it might now be destructed . */ int close(bool forceSend); @@ -191,7 +192,10 @@ public: /** Get the (transaction independent) definition of this query. */ const NdbQueryDefImpl& getQueryDef() const - { return m_queryDef; } + { + assert(m_queryDef); + return *m_queryDef; + } /** Process TCKEYCONF message. Return true if query is complete. */ bool execTCKEYCONF(); @@ -213,7 +217,7 @@ public: */ void setStartIndicator() { - assert(!m_queryDef.isScanQuery()); + assert(!getQueryDef().isScanQuery()); m_startIndicator = true; } @@ -224,7 +228,7 @@ public: */ void setCommitIndicator() { - assert(!m_queryDef.isScanQuery()); + assert(!getQueryDef().isScanQuery()); m_commitIndicator = true; } @@ -415,7 +419,7 @@ private: /** Next query in same transaction.*/ NdbQueryImpl* m_next; /** Definition of this query.*/ - const NdbQueryDefImpl& m_queryDef; + const NdbQueryDefImpl* m_queryDef; /** Possible error status of this query.*/ NdbError m_error; === modified file 'storage/ndb/test/ndbapi/testMgmd.cpp' --- a/storage/ndb/test/ndbapi/testMgmd.cpp 2011-02-03 14:45:49 +0000 +++ b/storage/ndb/test/ndbapi/testMgmd.cpp 2011-06-21 13:50:33 +0000 @@ -934,6 +934,171 @@ runBug56844(NDBT_Context* ctx, NDBT_Step return NDBT_OK; } +static bool +get_status(const char* connectstring, + Properties& status) +{ + NdbMgmd ndbmgmd; + if (!ndbmgmd.connect(connectstring)) + return false; + + Properties args; + if (!ndbmgmd.call("get status", args, + "node status", status, NULL, true)) + { + g_err << "fetch_mgmd_status: mgmd.call failed" << endl; + return false; + } + return true; +} + +static bool +value_equal(Properties& status, + int nodeid, const char* name, + const char* expected_value) +{ + const char* value; + BaseString key; + key.assfmt("node.%d.%s", nodeid, name); + if (!status.get(key.c_str(), &value)) + { + g_err << "value_equal: no value found for '" << name + << "." << nodeid << "'" << endl; + return false; + } + + if (strcmp(value, expected_value)) + { + g_err << "value_equal: found unexpected value: '" << value + << "', expected: '" << expected_value << "'" < + +int runTestBug12352191(NDBT_Context* ctx, NDBT_Step* step) +{ + BaseString version; + version.assfmt("%u", NDB_VERSION_D); + BaseString mysql_version; + mysql_version.assfmt("%u", NDB_MYSQL_VERSION_D); + BaseString address("127.0.0.1"); + + NDBT_Workingdir wd("test_mgmd"); // temporary working directory + + g_err << "** Create config.ini" << endl; + Properties config = ConfigFactory::create(2); + CHECK(ConfigFactory::write_config_ini(config, + path(wd.path(), + "config.ini", + NULL).c_str())); + + MgmdProcessList mgmds; + const int nodeid1 = 1; + Mgmd* mgmd1 = new Mgmd(nodeid1); + mgmds.push_back(mgmd1); + + const int nodeid2 = 2; + Mgmd* mgmd2 = new Mgmd(nodeid2); + mgmds.push_back(mgmd2); + + // Start first mgmd + CHECK(mgmd1->start_from_config_ini(wd.path())); + CHECK(mgmd1->connect(config)); + + Properties status1; + CHECK(get_status(mgmd1->connectstring(config).c_str(), status1)); + //status1.print(); + // Check status for own mgm node, always CONNECTED + CHECK(value_equal(status1, nodeid1, "type", "MGM")); + CHECK(value_equal(status1, nodeid1, "status", "CONNECTED")); + CHECK(value_equal(status1, nodeid1, "version", version.c_str())); + CHECK(value_equal(status1, nodeid1, "mysql_version", mysql_version.c_str())); + CHECK(value_equal(status1, nodeid1, "address", address.c_str())); + CHECK(value_equal(status1, nodeid1, "startphase", "0")); + CHECK(value_equal(status1, nodeid1, "dynamic_id", "0")); + CHECK(value_equal(status1, nodeid1, "node_group", "0")); + CHECK(value_equal(status1, nodeid1, "connect_count", "0")); + + // Check status for other mgm node + // not started yet -> NO_CONTACT, no address, no versions + CHECK(value_equal(status1, nodeid2, "type", "MGM")); + CHECK(value_equal(status1, nodeid2, "status", "NO_CONTACT")); + CHECK(value_equal(status1, nodeid2, "version", "0")); + CHECK(value_equal(status1, nodeid2, "mysql_version", "0")); + CHECK(value_equal(status1, nodeid2, "address", "")); + CHECK(value_equal(status1, nodeid2, "startphase", "0")); + CHECK(value_equal(status1, nodeid2, "dynamic_id", "0")); + CHECK(value_equal(status1, nodeid2, "node_group", "0")); + CHECK(value_equal(status1, nodeid2, "connect_count", "0")); + + // Start second mgmd + CHECK(mgmd2->start_from_config_ini(wd.path())); + CHECK(mgmd2->connect(config)); + + // wait for confirmed config + for (unsigned i = 0; i < mgmds.size(); i++) + CHECK(mgmds[i]->wait_confirmed_config()); + + Properties status2; + CHECK(get_status(mgmd2->connectstring(config).c_str(), status2)); + //status2.print(); + // Check status for own mgm node, always CONNECTED + CHECK(value_equal(status2, nodeid2, "type", "MGM")); + CHECK(value_equal(status2, nodeid2, "status", "CONNECTED")); + CHECK(value_equal(status2, nodeid2, "version", version.c_str())); + CHECK(value_equal(status2, nodeid2, "mysql_version", mysql_version.c_str())); + CHECK(value_equal(status2, nodeid2, "address", address.c_str())); + CHECK(value_equal(status2, nodeid2, "startphase", "0")); + CHECK(value_equal(status2, nodeid2, "dynamic_id", "0")); + CHECK(value_equal(status2, nodeid2, "node_group", "0")); + CHECK(value_equal(status2, nodeid2, "connect_count", "0")); + + // Check status for other mgm node + // both started now -> CONNECTED, address and versions filled in + CHECK(value_equal(status2, nodeid1, "type", "MGM")); + CHECK(value_equal(status2, nodeid1, "status", "CONNECTED")); + CHECK(value_equal(status2, nodeid1, "version", version.c_str())); + CHECK(value_equal(status2, nodeid1, "mysql_version", mysql_version.c_str())); + CHECK(value_equal(status2, nodeid1, "address", address.c_str())); + CHECK(value_equal(status2, nodeid1, "startphase", "0")); + CHECK(value_equal(status2, nodeid1, "dynamic_id", "0")); + CHECK(value_equal(status2, nodeid1, "node_group", "0")); + CHECK(value_equal(status2, nodeid1, "connect_count", "0")); + + Properties status3; + CHECK(get_status(mgmd1->connectstring(config).c_str(), status3)); + //status3.print(); + // Check status for own mgm node, always CONNECTED + CHECK(value_equal(status3, nodeid1, "type", "MGM")); + CHECK(value_equal(status3, nodeid1, "status", "CONNECTED")); + CHECK(value_equal(status3, nodeid1, "version", version.c_str())); + CHECK(value_equal(status3, nodeid1, "mysql_version", mysql_version.c_str())); + CHECK(value_equal(status3, nodeid1, "address", address.c_str())); + CHECK(value_equal(status3, nodeid1, "startphase", "0")); + CHECK(value_equal(status3, nodeid1, "dynamic_id", "0")); + CHECK(value_equal(status3, nodeid1, "node_group", "0")); + CHECK(value_equal(status3, nodeid1, "connect_count", "0")); + + // Check status for other mgm node + // both started now -> CONNECTED, address and versions filled in + CHECK(value_equal(status3, nodeid2, "type", "MGM")); + CHECK(value_equal(status3, nodeid2, "status", "CONNECTED")); + CHECK(value_equal(status3, nodeid2, "version", version.c_str())); + CHECK(value_equal(status3, nodeid2, "mysql_version", mysql_version.c_str())); + CHECK(value_equal(status3, nodeid2, "address", address.c_str())); + CHECK(value_equal(status3, nodeid2, "startphase", "0")); + CHECK(value_equal(status3, nodeid2, "dynamic_id", "0")); + CHECK(value_equal(status3, nodeid2, "node_group", "0")); + CHECK(value_equal(status3, nodeid2, "connect_count", "0")); + + return NDBT_OK; + +} + NDBT_TESTSUITE(testMgmd); DRIVER(DummyDriver); /* turn off use of NdbApi */ @@ -981,6 +1146,11 @@ TESTCASE("Bug56844", { INITIALIZER(runBug56844); } +TESTCASE("Bug12352191", + "Test mgmd status for other mgmd") +{ + INITIALIZER(runTestBug12352191); +} NDBT_TESTSUITE_END(testMgmd); No bundle (reason: useless for push emails).