From: magnus.blaudd Date: June 21 2011 1:28pm Subject: bzr push into mysql-5.1-telco-7.0 branch (magnus.blaudd:4468 to 4469) Bug#48301 Bug#12352191 List-Archive: http://lists.mysql.com/commits/139565 X-Bug: 48301,12352191 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4469 magnus.blaudd@stripped 2011-06-21 Bug#12352191 NDB_MGMD NODES DON'T SEE EACH OTHER AS CONNECTED UNTIL END OF SYSTEM RESTART. - Add specialized function status_mgmd() and status_api() used to retrive version and status for API and MGM nodes. - Make status_mgmd() aware that other MGM nodes are connected directly to own node with transporter - Fix missing assignment of mysql_version in Qmgr - Return the connected adress from transporter also for MGM nodes - Also fix bug#48301 by adding a new status CONNECTED to be used when we know the node is connected(this stats was previously only indicated by version != 0) modified: 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/test/ndbapi/testMgmd.cpp 4468 Ole John Aske 2011-06-20 SPJ API change: Relax lifetime dependencies between 'NdbQueryDef' and its instantiated NdbQuery objects. The application is now allowed to destruct the NdbQueryDef after all its instantiated NdbQuery objects has been '::close()'ed. modified: storage/ndb/src/ndbapi/NdbQueryBuilder.hpp storage/ndb/src/ndbapi/NdbQueryOperation.cpp storage/ndb/src/ndbapi/NdbQueryOperation.hpp storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp === 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:40:49 +0000 +++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp 2011-06-21 13:10:37 +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:20:36 +0000 +++ b/storage/ndb/src/ndbapi/ClusterMgr.cpp 2011-06-21 13:10:37 +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/test/ndbapi/testMgmd.cpp' --- a/storage/ndb/test/ndbapi/testMgmd.cpp 2011-02-03 14:20:36 +0000 +++ b/storage/ndb/test/ndbapi/testMgmd.cpp 2011-06-21 13:10:37 +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).