Commit c961fefd authored by unknown's avatar unknown

ndb - bug#18612 (detection of partitioned cluster)

  this also impl. gcp safe multi node shutdown
  1) block gcp
  2) wait for ongoing gcp
  3) inform all stopping QMGR's (so that they don't start with error handler)
  4) wait for all QMGR's to reply
  5) broadcast failrep for stopping nodes
  6) (if !master died) unblock gcp

  


ndb/include/kernel/signaldata/DumpStateOrd.hpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/include/kernel/signaldata/FailRep.hpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/include/kernel/signaldata/StopReq.hpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/src/kernel/blocks/qmgr/Qmgr.hpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/src/kernel/blocks/qmgr/QmgrInit.cpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/src/kernel/blocks/qmgr/QmgrMain.cpp:
  Impl. GCP safe multi node shutdown in order to test bug#18612
ndb/test/ndbapi/testNodeRestart.cpp:
  test program for bug#18612
parent 7efbf0af
...@@ -64,6 +64,7 @@ public: ...@@ -64,6 +64,7 @@ public:
// 19 NDBFS Fipple with O_SYNC, O_CREATE etc. // 19 NDBFS Fipple with O_SYNC, O_CREATE etc.
// 20-24 BACKUP // 20-24 BACKUP
NdbcntrTestStopOnError = 25, NdbcntrTestStopOnError = 25,
NdbcntrStopNodes = 70,
// 100-105 TUP and ACC // 100-105 TUP and ACC
// 200-240 UTIL // 200-240 UTIL
// 300-305 TRIX // 300-305 TRIX
......
...@@ -27,6 +27,7 @@ class FailRep { ...@@ -27,6 +27,7 @@ class FailRep {
* Sender(s) & Reciver(s) * Sender(s) & Reciver(s)
*/ */
friend class Qmgr; friend class Qmgr;
friend class Ndbcntr;
/** /**
* For printing * For printing
...@@ -43,7 +44,8 @@ public: ...@@ -43,7 +44,8 @@ public:
ZSTART_IN_REGREQ=3, ZSTART_IN_REGREQ=3,
ZHEARTBEAT_FAILURE=4, ZHEARTBEAT_FAILURE=4,
ZLINK_FAILURE=5, ZLINK_FAILURE=5,
ZOTHERNODE_FAILED_DURING_START=6 ZOTHERNODE_FAILED_DURING_START=6,
ZMULTI_NODE_SHUTDOWN = 7
}; };
private: private:
......
...@@ -32,7 +32,7 @@ class StopReq ...@@ -32,7 +32,7 @@ class StopReq
friend class MgmtSrvr; friend class MgmtSrvr;
public: public:
STATIC_CONST( SignalLength = 9 ); STATIC_CONST( SignalLength = 9 + NdbNodeBitmask::Size);
public: public:
Uint32 senderRef; Uint32 senderRef;
...@@ -49,29 +49,34 @@ public: ...@@ -49,29 +49,34 @@ public:
Int32 readOperationTimeout; // Timeout before read operations are aborted Int32 readOperationTimeout; // Timeout before read operations are aborted
Int32 operationTimeout; // Timeout before all operations are aborted Int32 operationTimeout; // Timeout before all operations are aborted
Uint32 nodes[NdbNodeBitmask::Size];
static void setSystemStop(Uint32 & requestInfo, bool value); static void setSystemStop(Uint32 & requestInfo, bool value);
static void setPerformRestart(Uint32 & requestInfo, bool value); static void setPerformRestart(Uint32 & requestInfo, bool value);
static void setNoStart(Uint32 & requestInfo, bool value); static void setNoStart(Uint32 & requestInfo, bool value);
static void setInitialStart(Uint32 & requestInfo, bool value); static void setInitialStart(Uint32 & requestInfo, bool value);
static void setEscalateOnNodeFail(Uint32 & requestInfo, bool value);
/** /**
* Don't perform "graceful" shutdown/restart... * Don't perform "graceful" shutdown/restart...
*/ */
static void setStopAbort(Uint32 & requestInfo, bool value); static void setStopAbort(Uint32 & requestInfo, bool value);
static void setStopNodes(Uint32 & requestInfo, bool value);
static bool getSystemStop(const Uint32 & requestInfo); static bool getSystemStop(const Uint32 & requestInfo);
static bool getPerformRestart(const Uint32 & requestInfo); static bool getPerformRestart(const Uint32 & requestInfo);
static bool getNoStart(const Uint32 & requestInfo); static bool getNoStart(const Uint32 & requestInfo);
static bool getInitialStart(const Uint32 & requestInfo); static bool getInitialStart(const Uint32 & requestInfo);
static bool getEscalateOnNodeFail(const Uint32 & requestInfo);
static bool getStopAbort(const Uint32 & requestInfo); static bool getStopAbort(const Uint32 & requestInfo);
static bool getStopNodes(const Uint32 & requestInfo);
}; };
struct StopConf struct StopConf
{ {
STATIC_CONST( SignalLength = 2 ); STATIC_CONST( SignalLength = 2 );
Uint32 senderData; Uint32 senderData;
union {
Uint32 nodeState; Uint32 nodeState;
Uint32 nodeId;
};
}; };
class StopRef class StopRef
...@@ -94,7 +99,9 @@ public: ...@@ -94,7 +99,9 @@ public:
NodeShutdownInProgress = 1, NodeShutdownInProgress = 1,
SystemShutdownInProgress = 2, SystemShutdownInProgress = 2,
NodeShutdownWouldCauseSystemCrash = 3, NodeShutdownWouldCauseSystemCrash = 3,
TransactionAbortFailed = 4 TransactionAbortFailed = 4,
UnsupportedNodeShutdown = 5,
MultiNodeShutdownNotMaster = 6
}; };
public: public:
...@@ -132,16 +139,16 @@ StopReq::getInitialStart(const Uint32 & requestInfo) ...@@ -132,16 +139,16 @@ StopReq::getInitialStart(const Uint32 & requestInfo)
inline inline
bool bool
StopReq::getEscalateOnNodeFail(const Uint32 & requestInfo) StopReq::getStopAbort(const Uint32 & requestInfo)
{ {
return requestInfo & 16; return requestInfo & 32;
} }
inline inline
bool bool
StopReq::getStopAbort(const Uint32 & requestInfo) StopReq::getStopNodes(const Uint32 & requestInfo)
{ {
return requestInfo & 32; return requestInfo & 64;
} }
...@@ -187,24 +194,23 @@ StopReq::setInitialStart(Uint32 & requestInfo, bool value) ...@@ -187,24 +194,23 @@ StopReq::setInitialStart(Uint32 & requestInfo, bool value)
inline inline
void void
StopReq::setEscalateOnNodeFail(Uint32 & requestInfo, bool value) StopReq::setStopAbort(Uint32 & requestInfo, bool value)
{ {
if(value) if(value)
requestInfo |= 16; requestInfo |= 32;
else else
requestInfo &= ~16; requestInfo &= ~32;
} }
inline inline
void void
StopReq::setStopAbort(Uint32 & requestInfo, bool value) StopReq::setStopNodes(Uint32 & requestInfo, bool value)
{ {
if(value) if(value)
requestInfo |= 32; requestInfo |= 64;
else else
requestInfo &= ~32; requestInfo &= ~64;
} }
#endif #endif
...@@ -202,6 +202,7 @@ private: ...@@ -202,6 +202,7 @@ private:
void execWAIT_GCP_CONF(Signal* signal); void execWAIT_GCP_CONF(Signal* signal);
void execSTOP_REQ(Signal* signal); void execSTOP_REQ(Signal* signal);
void execSTOP_CONF(Signal* signal);
void execRESUME_REQ(Signal* signal); void execRESUME_REQ(Signal* signal);
void execCHANGE_NODE_STATE_CONF(Signal* signal); void execCHANGE_NODE_STATE_CONF(Signal* signal);
...@@ -337,6 +338,16 @@ public: ...@@ -337,6 +338,16 @@ public:
void progError(int line, int cause, const char * extra) { void progError(int line, int cause, const char * extra) {
cntr.progError(line, cause, extra); cntr.progError(line, cause, extra);
} }
enum StopNodesStep {
SR_BLOCK_GCP_START_GCP = 0,
SR_WAIT_COMPLETE_GCP = 1,
SR_UNBLOCK_GCP_START_GCP = 2,
SR_QMGR_STOP_REQ = 3,
SR_WAIT_NODE_FAILURES = 4,
SR_CLUSTER_SHUTDOWN = 12
} m_state;
SignalCounter m_stop_req_counter;
}; };
private: private:
StopRecord c_stopRec; StopRecord c_stopRec;
......
...@@ -86,6 +86,7 @@ Ndbcntr::Ndbcntr(const class Configuration & conf): ...@@ -86,6 +86,7 @@ Ndbcntr::Ndbcntr(const class Configuration & conf):
addRecSignal(GSN_STOP_ME_CONF, &Ndbcntr::execSTOP_ME_CONF); addRecSignal(GSN_STOP_ME_CONF, &Ndbcntr::execSTOP_ME_CONF);
addRecSignal(GSN_STOP_REQ, &Ndbcntr::execSTOP_REQ); addRecSignal(GSN_STOP_REQ, &Ndbcntr::execSTOP_REQ);
addRecSignal(GSN_STOP_CONF, &Ndbcntr::execSTOP_CONF);
addRecSignal(GSN_RESUME_REQ, &Ndbcntr::execRESUME_REQ); addRecSignal(GSN_RESUME_REQ, &Ndbcntr::execRESUME_REQ);
addRecSignal(GSN_WAIT_GCP_REF, &Ndbcntr::execWAIT_GCP_REF); addRecSignal(GSN_WAIT_GCP_REF, &Ndbcntr::execWAIT_GCP_REF);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <signaldata/CmRegSignalData.hpp> #include <signaldata/CmRegSignalData.hpp>
#include <signaldata/ApiRegSignalData.hpp> #include <signaldata/ApiRegSignalData.hpp>
#include <signaldata/FailRep.hpp> #include <signaldata/FailRep.hpp>
#include <signaldata/StopReq.hpp>
#include "timer.hpp" #include "timer.hpp"
...@@ -218,6 +219,7 @@ private: ...@@ -218,6 +219,7 @@ private:
void execPRES_TOCONF(Signal* signal); void execPRES_TOCONF(Signal* signal);
void execDISCONNECT_REP(Signal* signal); void execDISCONNECT_REP(Signal* signal);
void execSYSTEM_ERROR(Signal* signal); void execSYSTEM_ERROR(Signal* signal);
void execSTOP_REQ(Signal* signal);
// Received signals // Received signals
void execDUMP_STATE_ORD(Signal* signal); void execDUMP_STATE_ORD(Signal* signal);
...@@ -403,6 +405,8 @@ private: ...@@ -403,6 +405,8 @@ private:
Uint16 cprepFailedNodes[MAX_NDB_NODES]; Uint16 cprepFailedNodes[MAX_NDB_NODES];
Uint16 ccommitFailedNodes[MAX_NDB_NODES]; Uint16 ccommitFailedNodes[MAX_NDB_NODES];
StopReq c_stopReq;
void check_multi_node_shutdown(Signal* signal);
}; };
#endif #endif
...@@ -35,6 +35,7 @@ void Qmgr::initData() ...@@ -35,6 +35,7 @@ void Qmgr::initData()
Uint32 hbDBAPI = 500; Uint32 hbDBAPI = 500;
setHbApiDelay(hbDBAPI); setHbApiDelay(hbDBAPI);
c_stopReq.senderRef = 0;
}//Qmgr::initData() }//Qmgr::initData()
void Qmgr::initRecords() void Qmgr::initRecords()
...@@ -49,6 +50,7 @@ Qmgr::Qmgr(const class Configuration & conf) ...@@ -49,6 +50,7 @@ Qmgr::Qmgr(const class Configuration & conf)
// Transit signals // Transit signals
addRecSignal(GSN_DUMP_STATE_ORD, &Qmgr::execDUMP_STATE_ORD); addRecSignal(GSN_DUMP_STATE_ORD, &Qmgr::execDUMP_STATE_ORD);
addRecSignal(GSN_STOP_REQ, &Qmgr::execSTOP_REQ);
addRecSignal(GSN_DEBUG_SIG, &Qmgr::execDEBUG_SIG); addRecSignal(GSN_DEBUG_SIG, &Qmgr::execDEBUG_SIG);
addRecSignal(GSN_CONTINUEB, &Qmgr::execCONTINUEB); addRecSignal(GSN_CONTINUEB, &Qmgr::execCONTINUEB);
addRecSignal(GSN_CM_HEARTBEAT, &Qmgr::execCM_HEARTBEAT); addRecSignal(GSN_CM_HEARTBEAT, &Qmgr::execCM_HEARTBEAT);
......
...@@ -2342,6 +2342,9 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode, ...@@ -2342,6 +2342,9 @@ void Qmgr::failReportLab(Signal* signal, Uint16 aFailedNode,
failedNodePtr.i = aFailedNode; failedNodePtr.i = aFailedNode;
ptrCheckGuard(failedNodePtr, MAX_NODES, nodeRec); ptrCheckGuard(failedNodePtr, MAX_NODES, nodeRec);
check_multi_node_shutdown(signal);
if (failedNodePtr.i == getOwnNodeId()) { if (failedNodePtr.i == getOwnNodeId()) {
jam(); jam();
...@@ -2434,6 +2437,8 @@ void Qmgr::execPREP_FAILREQ(Signal* signal) ...@@ -2434,6 +2437,8 @@ void Qmgr::execPREP_FAILREQ(Signal* signal)
NodeRecPtr myNodePtr; NodeRecPtr myNodePtr;
jamEntry(); jamEntry();
check_multi_node_shutdown(signal);
PrepFailReqRef * const prepFail = (PrepFailReqRef *)&signal->theData[0]; PrepFailReqRef * const prepFail = (PrepFailReqRef *)&signal->theData[0];
BlockReference Tblockref = prepFail->xxxBlockRef; BlockReference Tblockref = prepFail->xxxBlockRef;
...@@ -4085,6 +4090,8 @@ Qmgr::stateArbitCrash(Signal* signal) ...@@ -4085,6 +4090,8 @@ Qmgr::stateArbitCrash(Signal* signal)
if (! (arbitRec.getTimediff() > getArbitTimeout())) if (! (arbitRec.getTimediff() > getArbitTimeout()))
return; return;
#endif #endif
CRASH_INSERTION(932);
progError(__LINE__, ERR_ARBIT_SHUTDOWN, "Arbitrator decided to shutdown this node"); progError(__LINE__, ERR_ARBIT_SHUTDOWN, "Arbitrator decided to shutdown this node");
} }
...@@ -4245,3 +4252,40 @@ Qmgr::execAPI_BROADCAST_REP(Signal* signal) ...@@ -4245,3 +4252,40 @@ Qmgr::execAPI_BROADCAST_REP(Signal* signal)
NodeReceiverGroup rg(API_CLUSTERMGR, mask); NodeReceiverGroup rg(API_CLUSTERMGR, mask);
sendSignal(rg, api.gsn, signal, len, JBB); // forward sections sendSignal(rg, api.gsn, signal, len, JBB); // forward sections
} }
void
Qmgr::execSTOP_REQ(Signal* signal)
{
jamEntry();
c_stopReq = * (StopReq*)signal->getDataPtr();
if (c_stopReq.senderRef)
{
ndbrequire(NdbNodeBitmask::get(c_stopReq.nodes, getOwnNodeId()));
StopConf *conf = (StopConf*)signal->getDataPtrSend();
conf->senderData = c_stopReq.senderData;
conf->nodeState = getOwnNodeId();
sendSignal(c_stopReq.senderRef,
GSN_STOP_CONF, signal, StopConf::SignalLength, JBA);
}
}
void
Qmgr::check_multi_node_shutdown(Signal* signal)
{
if (c_stopReq.senderRef &&
NdbNodeBitmask::get(c_stopReq.nodes, getOwnNodeId()))
{
jam();
if(StopReq::getPerformRestart(c_stopReq.requestInfo))
{
jam();
StartOrd * startOrd = (StartOrd *)&signal->theData[0];
startOrd->restartInfo = c_stopReq.requestInfo;
EXECUTE_DIRECT(CMVMI, GSN_START_ORD, signal, 2);
} else {
EXECUTE_DIRECT(CMVMI, GSN_STOP_ORD, signal, 1);
}
}
}
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <NdbRestarts.hpp> #include <NdbRestarts.hpp>
#include <Vector.hpp> #include <Vector.hpp>
#include <signaldata/DumpStateOrd.hpp> #include <signaldata/DumpStateOrd.hpp>
#include <Bitmask.hpp>
int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){ int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
...@@ -669,6 +669,110 @@ runBug18414(NDBT_Context* ctx, NDBT_Step* step){ ...@@ -669,6 +669,110 @@ runBug18414(NDBT_Context* ctx, NDBT_Step* step){
return NDBT_FAILED; return NDBT_FAILED;
} }
int
runBug18612(NDBT_Context* ctx, NDBT_Step* step){
// Assume two replicas
NdbRestarter restarter;
if (restarter.getNumDbNodes() < 2)
{
ctx->stopTest();
return NDBT_OK;
}
Uint32 cnt = restarter.getNumDbNodes();
for(int loop = 0; loop < ctx->getNumLoops(); loop++)
{
int partition0[256];
int partition1[256];
bzero(partition0, sizeof(partition0));
bzero(partition1, sizeof(partition1));
Bitmask<4> nodesmask;
Uint32 node1 = restarter.getDbNodeId(rand()%cnt);
for (Uint32 i = 0; i<cnt/2; i++)
{
do {
node1 = restarter.getRandomNodeOtherNodeGroup(node1, rand());
} while(nodesmask.get(node1));
partition0[i] = node1;
partition1[i] = restarter.getRandomNodeSameNodeGroup(node1, rand());
ndbout_c("nodes %d %d", node1, partition1[i]);
assert(!nodesmask.get(node1));
assert(!nodesmask.get(partition1[i]));
nodesmask.set(node1);
nodesmask.set(partition1[i]);
}
ndbout_c("done");
int dump[255];
dump[0] = DumpStateOrd::NdbcntrStopNodes;
memcpy(dump + 1, partition0, sizeof(int)*cnt/2);
Uint32 master = restarter.getMasterNodeId();
if (restarter.dumpStateOneNode(master, dump, 1+cnt/2))
return NDBT_FAILED;
if (restarter.waitNodesNoStart(partition0, cnt/2))
return NDBT_FAILED;
int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
if (restarter.dumpStateAllNodes(val2, 2))
return NDBT_FAILED;
if (restarter.insertErrorInAllNodes(932))
return NDBT_FAILED;
dump[0] = 9000;
memcpy(dump + 1, partition0, sizeof(int)*cnt/2);
for (Uint32 i = 0; i<cnt/2; i++)
if (restarter.dumpStateOneNode(partition1[i], dump, 1+cnt/2))
return NDBT_FAILED;
dump[0] = 9000;
memcpy(dump + 1, partition1, sizeof(int)*cnt/2);
for (Uint32 i = 0; i<cnt/2; i++)
if (restarter.dumpStateOneNode(partition0[i], dump, 1+cnt/2))
return NDBT_FAILED;
if (restarter.startNodes(partition0, cnt/2))
return NDBT_FAILED;
if (restarter.waitNodesStartPhase(partition0, cnt/2, 2))
return NDBT_FAILED;
dump[0] = 9001;
for (Uint32 i = 0; i<cnt/2; i++)
if (restarter.dumpStateAllNodes(dump, 2))
return NDBT_FAILED;
if (restarter.waitClusterNoStart())
return NDBT_FAILED;
for (Uint32 i = 0; i<cnt/2; i++)
if (restarter.restartOneDbNode(partition0[i], true, true, true))
return NDBT_FAILED;
if (restarter.waitNodesNoStart(partition0, cnt/2))
return NDBT_FAILED;
if (restarter.startAll())
return NDBT_FAILED;
if (restarter.waitClusterStarted())
return NDBT_FAILED;
}
return NDBT_OK;
}
NDBT_TESTSUITE(testNodeRestart); NDBT_TESTSUITE(testNodeRestart);
TESTCASE("NoLoad", TESTCASE("NoLoad",
"Test that one node at a time can be stopped and then restarted "\ "Test that one node at a time can be stopped and then restarted "\
...@@ -963,6 +1067,12 @@ TESTCASE("Bug18414", ...@@ -963,6 +1067,12 @@ TESTCASE("Bug18414",
STEP(runBug18414); STEP(runBug18414);
FINALIZER(runClearTable); FINALIZER(runClearTable);
} }
TESTCASE("Bug18612",
"Test bug with partitioned clusters"){
INITIALIZER(runLoadTable);
STEP(runBug18612);
FINALIZER(runClearTable);
}
NDBT_TESTSUITE_END(testNodeRestart); NDBT_TESTSUITE_END(testNodeRestart);
int main(int argc, const char** argv){ int main(int argc, const char** argv){
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment