Commit f4b56000 authored by unknown's avatar unknown

WL#2347 - Load independent heartbeats

Reset missed heartbeat count on receipt of signal from node.

This fixes a bug where that under high network load, the heartbeat packets could be
delayed, causing the appearance of node failure (due to lost heartbeats).


ndb/include/kernel/NodeInfo.hpp:
  Add m_heartbeat_cnt to track missed heartbeats
ndb/include/transporter/TransporterCallback.hpp:
  add prototype for transporter_recv_from()
  
  Called on receipt from a node.
ndb/src/common/transporter/TransporterRegistry.cpp:
  Add calls to transporter_receive_from when data is received (before unpack)
ndb/src/kernel/blocks/qmgr/Qmgr.hpp:
  remove NodeRec::alarmCount. missed heartbeat count now kept in NodeInfo
ndb/src/kernel/blocks/qmgr/QmgrMain.cpp:
  Use NodeInfo::m_heartbeat_cnt for missed heartbeat count
ndb/src/kernel/vm/TransporterCallback.cpp:
  add transporter_recv_from(), which is called on receipt of signals.
  It resets missed heartbeat count for that node.
ndb/src/ndbapi/ClusterMgr.cpp:
  Use NodeInfo::m_heartbeat_cnt for missed heartbeat count
ndb/src/ndbapi/ClusterMgr.hpp:
  Use NodeInfo::m_heartbeat_cnt instead of ClusterMgr::Node::hbSent for missed
  heartbeat count.
  
  We now use the same storage for API and Kernel heartbeats.
  
  Add ClusterMgr::hb_received(nodeId) to reset hbSent (as if we received a heartbeat,
  but callable from elsewhere - e.g. when signal received)
ndb/src/ndbapi/TransporterFacade.cpp:
  Implement transporter_recv_from for ndbapi - which resets hbSent
ndb/src/ndbapi/TransporterFacade.hpp:
  Add hb_received(nodeId)
parent ef45f4b6
......@@ -41,6 +41,7 @@ public:
Uint32 m_type; ///< Node type
Uint32 m_connectCount; ///< No of times connected
bool m_connected; ///< Node is connected
Uint32 m_heartbeat_cnt; ///< Missed heartbeats
friend NdbOut & operator<<(NdbOut&, const NodeInfo&);
};
......@@ -52,6 +53,7 @@ NodeInfo::NodeInfo(){
m_signalVersion = 0;
m_type = INVALID;
m_connectCount = 0;
m_heartbeat_cnt= 0;
}
inline
......
......@@ -341,5 +341,8 @@ enum TransporterError {
*/
void
reportError(void * callbackObj, NodeId nodeId, TransporterError errorCode);
void
transporter_recv_from(void* callbackObj, NodeId node);
#endif
......@@ -918,6 +918,7 @@ TransporterRegistry::performReceive()
NodeId remoteNodeId;
Uint32 * readPtr;
Uint32 sz = theOSEReceiver->getReceiveData(&remoteNodeId, &readPtr);
transporter_recv_from(callbackObj, remoteNodeId);
Uint32 szUsed = unpack(readPtr,
sz,
remoteNodeId,
......@@ -953,6 +954,7 @@ TransporterRegistry::performReceive()
{
Uint32 * ptr;
Uint32 sz = t->getReceiveData(&ptr);
transporter_recv_from(callbackObj, nodeId);
Uint32 szUsed = unpack(ptr, sz, nodeId, ioStates[nodeId]);
t->updateReceiveDataPtr(szUsed);
}
......@@ -976,6 +978,7 @@ TransporterRegistry::performReceive()
{
Uint32 * readPtr, * eodPtr;
t->getReceivePtr(&readPtr, &eodPtr);
transporter_recv_from(callbackObj, nodeId);
Uint32 *newPtr = unpack(readPtr, eodPtr, nodeId, ioStates[nodeId]);
t->updateReceivePtr(newPtr);
}
......@@ -993,6 +996,7 @@ TransporterRegistry::performReceive()
{
Uint32 * readPtr, * eodPtr;
t->getReceivePtr(&readPtr, &eodPtr);
transporter_recv_from(callbackObj, nodeId);
Uint32 *newPtr = unpack(readPtr, eodPtr, nodeId, ioStates[nodeId]);
t->updateReceivePtr(newPtr);
}
......
......@@ -118,8 +118,7 @@ public:
struct NodeRec {
UintR ndynamicId;
Phase phase;
UintR alarmCount;
QmgrState sendPrepFailReqStatus;
QmgrState sendCommitFailReqStatus;
QmgrState sendPresToStatus;
......
......@@ -66,7 +66,7 @@ void Qmgr::execCM_HEARTBEAT(Signal* signal)
jamEntry();
hbNodePtr.i = signal->theData[0];
ptrCheckGuard(hbNodePtr, MAX_NDB_NODES, nodeRec);
hbNodePtr.p->alarmCount = 0;
setNodeInfo(hbNodePtr.i).m_heartbeat_cnt= 0;
return;
}//Qmgr::execCM_HEARTBEAT()
......@@ -1040,7 +1040,7 @@ void Qmgr::execCM_ADD(Signal* signal)
jam();
ndbrequire(addNodePtr.p->phase == ZSTARTING);
addNodePtr.p->phase = ZRUNNING;
addNodePtr.p->alarmCount = 0;
setNodeInfo(addNodePtr.i).m_heartbeat_cnt= 0;
c_clusterNodes.set(addNodePtr.i);
findNeighbours(signal);
......@@ -1078,7 +1078,7 @@ Qmgr::joinedCluster(Signal* signal, NodeRecPtr nodePtr){
* NODES IN THE CLUSTER.
*/
nodePtr.p->phase = ZRUNNING;
nodePtr.p->alarmCount = 0;
setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0;
findNeighbours(signal);
c_clusterNodes.set(nodePtr.i);
c_start.reset();
......@@ -1299,7 +1299,7 @@ void Qmgr::findNeighbours(Signal* signal)
*---------------------------------------------------------------------*/
fnNodePtr.i = cneighbourl;
ptrCheckGuard(fnNodePtr, MAX_NDB_NODES, nodeRec);
fnNodePtr.p->alarmCount = 0;
setNodeInfo(fnNodePtr.i).m_heartbeat_cnt= 0;
}//if
}//if
......@@ -1347,8 +1347,8 @@ void Qmgr::initData(Signal* signal)
} else {
nodePtr.p->phase = ZAPI_INACTIVE;
}
nodePtr.p->alarmCount = 0;
setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0;
nodePtr.p->sendPrepFailReqStatus = Q_NOT_ACTIVE;
nodePtr.p->sendCommitFailReqStatus = Q_NOT_ACTIVE;
nodePtr.p->sendPresToStatus = Q_NOT_ACTIVE;
......@@ -1550,18 +1550,18 @@ void Qmgr::checkHeartbeat(Signal* signal)
}//if
ptrCheckGuard(nodePtr, MAX_NDB_NODES, nodeRec);
nodePtr.p->alarmCount ++;
setNodeInfo(nodePtr.i).m_heartbeat_cnt++;
ndbrequire(nodePtr.p->phase == ZRUNNING);
ndbrequire(getNodeInfo(nodePtr.i).m_type == NodeInfo::DB);
if(nodePtr.p->alarmCount > 2){
if(getNodeInfo(nodePtr.i).m_heartbeat_cnt > 2){
signal->theData[0] = NDB_LE_MissedHeartbeat;
signal->theData[1] = nodePtr.i;
signal->theData[2] = nodePtr.p->alarmCount - 1;
signal->theData[2] = getNodeInfo(nodePtr.i).m_heartbeat_cnt - 1;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
}
if (nodePtr.p->alarmCount > 4) {
if (getNodeInfo(nodePtr.i).m_heartbeat_cnt > 4) {
jam();
/**----------------------------------------------------------------------
* OUR LEFT NEIGHBOUR HAVE KEPT QUIET FOR THREE CONSECUTIVE HEARTBEAT
......@@ -1593,16 +1593,16 @@ void Qmgr::apiHbHandlingLab(Signal* signal)
if (TnodePtr.p->phase == ZAPI_ACTIVE){
jam();
TnodePtr.p->alarmCount ++;
setNodeInfo(TnodePtr.i).m_heartbeat_cnt++;
if(TnodePtr.p->alarmCount > 2){
if(getNodeInfo(TnodePtr.i).m_heartbeat_cnt > 2){
signal->theData[0] = NDB_LE_MissedHeartbeat;
signal->theData[1] = nodeId;
signal->theData[2] = TnodePtr.p->alarmCount - 1;
signal->theData[2] = getNodeInfo(TnodePtr.i).m_heartbeat_cnt - 1;
sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 3, JBB);
}
if (TnodePtr.p->alarmCount > 4) {
if (getNodeInfo(TnodePtr.i).m_heartbeat_cnt > 4) {
jam();
/*------------------------------------------------------------------*/
/* THE API NODE HAS NOT SENT ANY HEARTBEAT FOR THREE SECONDS.
......@@ -1634,16 +1634,17 @@ void Qmgr::checkStartInterface(Signal* signal)
ptrAss(nodePtr, nodeRec);
if (nodePtr.p->phase == ZFAIL_CLOSING) {
jam();
nodePtr.p->alarmCount = nodePtr.p->alarmCount + 1;
setNodeInfo(nodePtr.i).m_heartbeat_cnt++;
if (c_connectedNodes.get(nodePtr.i)){
jam();
/*-------------------------------------------------------------------*/
// We need to ensure that the connection is not restored until it has
// been disconnected for at least three seconds.
/*-------------------------------------------------------------------*/
nodePtr.p->alarmCount = 0;
setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0;
}//if
if ((nodePtr.p->alarmCount > 3) && (nodePtr.p->failState == NORMAL)) {
if ((getNodeInfo(nodePtr.i).m_heartbeat_cnt > 3)
&& (nodePtr.p->failState == NORMAL)) {
/**------------------------------------------------------------------
* WE HAVE DISCONNECTED THREE SECONDS AGO. WE ARE NOW READY TO
* CONNECT AGAIN AND ACCEPT NEW REGISTRATIONS FROM THIS NODE.
......@@ -1659,18 +1660,18 @@ void Qmgr::checkStartInterface(Signal* signal)
nodePtr.p->phase = ZINIT;
}//if
nodePtr.p->alarmCount = 0;
setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0;
signal->theData[0] = 0;
signal->theData[1] = nodePtr.i;
sendSignal(CMVMI_REF, GSN_OPEN_COMREQ, signal, 2, JBA);
} else {
if(((nodePtr.p->alarmCount + 1) % 60) == 0){
if(((getNodeInfo(nodePtr.i).m_heartbeat_cnt + 1) % 60) == 0){
char buf[100];
BaseString::snprintf(buf, sizeof(buf),
"Failure handling of node %d has not completed in %d min."
" - state = %d",
nodePtr.i,
(nodePtr.p->alarmCount + 1)/60,
(getNodeInfo(nodePtr.i).m_heartbeat_cnt + 1)/60,
nodePtr.p->failState);
warningEvent(buf);
}
......@@ -1718,7 +1719,7 @@ void Qmgr::sendApiFailReq(Signal* signal, Uint16 failedNodeNo)
* WE ONLY NEED TO SET PARAMETERS TO ENABLE A NEW CONNECTION IN A FEW
* SECONDS.
*-------------------------------------------------------------------------*/
failedNodePtr.p->alarmCount = 0;
setNodeInfo(failedNodePtr.i).m_heartbeat_cnt= 0;
CloseComReqConf * const closeCom = (CloseComReqConf *)&signal->theData[0];
......@@ -1871,7 +1872,7 @@ void Qmgr::node_failed(Signal* signal, Uint16 aFailedNode)
/*---------------------------------------------------------------------*/
failedNodePtr.p->failState = NORMAL;
failedNodePtr.p->phase = ZFAIL_CLOSING;
failedNodePtr.p->alarmCount = 0;
setNodeInfo(failedNodePtr.i).m_heartbeat_cnt= 0;
CloseComReqConf * const closeCom =
(CloseComReqConf *)&signal->theData[0];
......@@ -1965,8 +1966,8 @@ void Qmgr::execAPI_REGREQ(Signal* signal)
}
setNodeInfo(apiNodePtr.i).m_version = version;
apiNodePtr.p->alarmCount = 0;
setNodeInfo(apiNodePtr.i).m_heartbeat_cnt= 0;
ApiRegConf * const apiRegConf = (ApiRegConf *)&signal->theData[0];
apiRegConf->qmgrRef = reference();
......@@ -2484,7 +2485,7 @@ void Qmgr::execCOMMIT_FAILREQ(Signal* signal)
ptrCheckGuard(nodePtr, MAX_NDB_NODES, nodeRec);
nodePtr.p->phase = ZFAIL_CLOSING;
nodePtr.p->failState = WAITING_FOR_NDB_FAILCONF;
nodePtr.p->alarmCount = 0;
setNodeInfo(nodePtr.i).m_heartbeat_cnt= 0;
c_clusterNodes.clear(nodePtr.i);
}//for
/*----------------------------------------------------------------------*/
......@@ -2742,7 +2743,7 @@ void Qmgr::failReport(Signal* signal,
failedNodePtr.p->sendPrepFailReqStatus = Q_NOT_ACTIVE;
failedNodePtr.p->sendCommitFailReqStatus = Q_NOT_ACTIVE;
failedNodePtr.p->sendPresToStatus = Q_NOT_ACTIVE;
failedNodePtr.p->alarmCount = 0;
setNodeInfo(failedNodePtr.i).m_heartbeat_cnt= 0;
if (aSendFailRep == ZTRUE) {
jam();
if (failedNodePtr.i != getOwnNodeId()) {
......
......@@ -33,6 +33,7 @@
#include <NdbOut.hpp>
#include "DataBuffer.hpp"
/**
* The instance
*/
......@@ -452,3 +453,8 @@ SignalLoggerManager::printSegmentedSection(FILE * output,
putc('\n', output);
}
void
transporter_recv_from(void * callbackObj, NodeId nodeId){
globalData.m_nodeInfo[nodeId].m_heartbeat_cnt= 0;
return;
}
......@@ -214,7 +214,7 @@ ClusterMgr::threadMain( ){
* It is now time to send a new Heartbeat
*/
if (theNode.hbCounter >= theNode.hbFrequency) {
theNode.hbSent++;
theNode.m_info.m_heartbeat_cnt++;
theNode.hbCounter = 0;
}
......@@ -231,7 +231,7 @@ ClusterMgr::threadMain( ){
theFacade.sendSignalUnCond(&signal, nodeId);
}//if
if (theNode.hbSent == 4 && theNode.hbFrequency > 0){
if (theNode.m_info.m_heartbeat_cnt == 4 && theNode.hbFrequency > 0){
reportNodeFailed(i);
}//if
}
......@@ -337,7 +337,7 @@ ClusterMgr::execAPI_REGCONF(const Uint32 * theData){
node.compatible = ndbCompatible_api_ndb(NDB_VERSION,
node.m_info.m_version);
}
node.m_state = apiRegConf->nodeState;
if (node.compatible && (node.m_state.startLevel == NodeState::SL_STARTED ||
node.m_state.startLevel == NodeState::SL_SINGLEUSER)){
......@@ -345,7 +345,7 @@ ClusterMgr::execAPI_REGCONF(const Uint32 * theData){
} else {
set_node_alive(node, false);
}//if
node.hbSent = 0;
node.m_info.m_heartbeat_cnt = 0;
node.hbCounter = 0;
if (node.m_info.m_type != NodeInfo::REP) {
node.hbFrequency = (apiRegConf->apiHeartbeatFrequency * 10) - 50;
......@@ -414,7 +414,7 @@ ClusterMgr::reportConnected(NodeId nodeId){
Node & theNode = theNodes[nodeId];
theNode.connected = true;
theNode.hbSent = 0;
theNode.m_info.m_heartbeat_cnt = 0;
theNode.hbCounter = 0;
/**
......
......@@ -73,12 +73,12 @@ public:
*/
Uint32 hbFrequency; // Heartbeat frequence
Uint32 hbCounter; // # milliseconds passed since last hb sent
Uint32 hbSent; // # heartbeats sent (without answer)
};
const Node & getNodeInfo(NodeId) const;
Uint32 getNoOfConnectedNodes() const;
void hb_received(NodeId);
private:
Uint32 noOfAliveNodes;
Uint32 noOfConnectedNodes;
......@@ -128,6 +128,12 @@ ClusterMgr::getNoOfConnectedNodes() const {
return noOfConnectedNodes;
}
inline
void
ClusterMgr::hb_received(NodeId nodeId) {
theNodes[nodeId].m_info.m_heartbeat_cnt= 0;
}
/*****************************************************************************/
/**
......
......@@ -126,6 +126,10 @@ reportDisconnect(void * callbackObj, NodeId nodeId, Uint32 error){
//TransporterFacade::instance()->reportDisconnected(nodeId);
}
void
transporter_recv_from(void * callbackObj, NodeId nodeId){
((TransporterFacade*)(callbackObj))->hb_received(nodeId);
}
/****************************************************************************
*
......
......@@ -114,6 +114,9 @@ public:
TransporterRegistry* get_registry() { return theTransporterRegistry;};
// heart beat received from a node (e.g. a signal came)
void hb_received(NodeId n);
private:
/**
* Send a signal unconditional of node status (used by ClusterMgr)
......@@ -295,6 +298,12 @@ TransporterFacade::get_node_alive(NodeId n) const {
return node.m_alive;
}
inline
void
TransporterFacade::hb_received(NodeId n) {
theClusterMgr->hb_received(n);
}
inline
bool
TransporterFacade::get_node_stopping(NodeId n) const {
......
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