258 lines
7.4 KiB
C
258 lines
7.4 KiB
C
#include <app/App.h>
|
|
#include <common/nodes/Node.h>
|
|
#include <common/toolkit/SocketTk.h>
|
|
#include <common/net/msghelpers/MsgHelperAck.h>
|
|
#include <common/toolkit/ListTk.h>
|
|
#include <nodes/NodeStoreEx.h>
|
|
#include <app/config/Config.h>
|
|
#include "HeartbeatMsgEx.h"
|
|
|
|
const struct NetMessageOps HeartbeatMsgEx_Ops = {
|
|
.serializePayload = HeartbeatMsgEx_serializePayload,
|
|
.deserializePayload = HeartbeatMsgEx_deserializePayload,
|
|
.processIncoming = __HeartbeatMsgEx_processIncoming,
|
|
.getSupportedHeaderFeatureFlagsMask = NetMessage_getSupportedHeaderFeatureFlagsMask,
|
|
};
|
|
|
|
void HeartbeatMsgEx_serializePayload(NetMessage* this, SerializeCtx* ctx)
|
|
{
|
|
HeartbeatMsgEx* thisCast = (HeartbeatMsgEx*)this;
|
|
|
|
// instanceVersion
|
|
Serialization_serializeUInt64(ctx, thisCast->instanceVersion);
|
|
|
|
// nicListVersion
|
|
Serialization_serializeUInt64(ctx, thisCast->nicListVersion);
|
|
|
|
// nodeType
|
|
Serialization_serializeInt(ctx, thisCast->nodeType);
|
|
|
|
// nodeID
|
|
Serialization_serializeStr(ctx, thisCast->nodeIDLen, thisCast->nodeID);
|
|
|
|
// ackID
|
|
Serialization_serializeStrAlign4(ctx, thisCast->ackIDLen, thisCast->ackID);
|
|
|
|
// nodeNumID
|
|
NumNodeID_serialize(ctx, &thisCast->nodeNumID);
|
|
|
|
// rootNumID
|
|
NumNodeID_serialize(ctx, &thisCast->rootNumID);
|
|
|
|
// rootIsBuddyMirrored
|
|
Serialization_serializeBool(ctx, thisCast->rootIsBuddyMirrored);
|
|
|
|
// portUDP
|
|
Serialization_serializeUShort(ctx, thisCast->portUDP);
|
|
|
|
// portTCP
|
|
Serialization_serializeUShort(ctx, thisCast->portTCP);
|
|
|
|
// nicList
|
|
Serialization_serializeNicList(ctx, thisCast->nicList);
|
|
|
|
// machineUUID
|
|
Serialization_serializeStr(ctx, thisCast->machineUUIDLen, thisCast->machineUUID);
|
|
}
|
|
|
|
bool HeartbeatMsgEx_deserializePayload(NetMessage* this, DeserializeCtx* ctx)
|
|
{
|
|
HeartbeatMsgEx* thisCast = (HeartbeatMsgEx*)this;
|
|
|
|
// instanceVersion
|
|
if(!Serialization_deserializeUInt64(ctx, &thisCast->instanceVersion) )
|
|
return false;
|
|
|
|
// nicListVersion
|
|
if(!Serialization_deserializeUInt64(ctx, &thisCast->nicListVersion) )
|
|
return false;
|
|
|
|
// nodeType
|
|
if(!Serialization_deserializeInt(ctx, &thisCast->nodeType) )
|
|
return false;
|
|
|
|
// nodeID
|
|
if(!Serialization_deserializeStr(ctx, &thisCast->nodeIDLen, &thisCast->nodeID) )
|
|
return false;
|
|
|
|
// ackID
|
|
if(!Serialization_deserializeStrAlign4(ctx, &thisCast->ackIDLen, &thisCast->ackID) )
|
|
return false;
|
|
|
|
// nodeNumID
|
|
if(!NumNodeID_deserialize(ctx, &thisCast->nodeNumID) )
|
|
return false;
|
|
|
|
// rootNumID
|
|
if(!NumNodeID_deserialize(ctx, &thisCast->rootNumID) )
|
|
return false;
|
|
|
|
// rootIsBuddyMirrored
|
|
if(!Serialization_deserializeBool(ctx, &thisCast->rootIsBuddyMirrored) )
|
|
return false;
|
|
|
|
// portUDP
|
|
if(!Serialization_deserializeUShort(ctx, &thisCast->portUDP) )
|
|
return false;
|
|
|
|
// portTCP
|
|
if(!Serialization_deserializeUShort(ctx, &thisCast->portTCP) )
|
|
return false;
|
|
|
|
// nicList
|
|
if(!Serialization_deserializeNicListPreprocess(ctx, &thisCast->rawNicList) )
|
|
return false;
|
|
|
|
// machineUUID
|
|
if(!Serialization_deserializeStr(ctx, &thisCast->machineUUIDLen, &thisCast->machineUUID) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool __HeartbeatMsgEx_processIncoming(NetMessage* this, struct App* app,
|
|
fhgfs_sockaddr_in* fromAddr, struct Socket* sock, char* respBuf, size_t bufLen)
|
|
{
|
|
Logger* log = App_getLogger(app);
|
|
const char* logContext = "Heartbeat incoming";
|
|
|
|
HeartbeatMsgEx* thisCast = (HeartbeatMsgEx*)this;
|
|
|
|
NicAddressList nicList;
|
|
Node* node;
|
|
NodeConnPool* connPool;
|
|
Node* localNode;
|
|
NicAddressList localNicList;
|
|
NicListCapabilities localNicCaps;
|
|
NodeStoreEx* nodes = NULL;
|
|
bool isNodeNew;
|
|
NumNodeID nodeNumID;
|
|
int nodeType;
|
|
|
|
// check if nodeNumID is set
|
|
nodeNumID = HeartbeatMsgEx_getNodeNumID(thisCast);
|
|
if(NumNodeID_isZero(&nodeNumID))
|
|
{ // shouldn't happen: this node would need to register first to get a nodeNumID assigned
|
|
Logger_logFormatted(log, Log_WARNING, logContext,
|
|
"Rejecting heartbeat of node without numeric ID: %s (Type: %s)",
|
|
HeartbeatMsgEx_getNodeID(thisCast),
|
|
Node_nodeTypeToStr(HeartbeatMsgEx_getNodeType(thisCast) ) );
|
|
|
|
goto ack_resp;
|
|
}
|
|
|
|
// find the corresponding node store for this node type
|
|
|
|
nodeType = HeartbeatMsgEx_getNodeType(thisCast);
|
|
switch(nodeType)
|
|
{
|
|
case NODETYPE_Meta:
|
|
nodes = App_getMetaNodes(app); break;
|
|
|
|
case NODETYPE_Storage:
|
|
nodes = App_getStorageNodes(app); break;
|
|
|
|
case NODETYPE_Mgmt:
|
|
nodes = App_getMgmtNodes(app); break;
|
|
|
|
default:
|
|
{
|
|
const char* nodeID = HeartbeatMsgEx_getNodeID(thisCast);
|
|
|
|
Logger_logErrFormatted(log, logContext, "Invalid node type: %d (%s); ID: %s",
|
|
nodeType, Node_nodeTypeToStr(nodeType), nodeID);
|
|
|
|
goto ack_resp;
|
|
} break;
|
|
}
|
|
|
|
// construct node
|
|
|
|
NicAddressList_init(&nicList);
|
|
|
|
HeartbeatMsgEx_parseNicList(thisCast, &nicList);
|
|
|
|
App_lockNicList(app);
|
|
node = Node_construct(app,
|
|
HeartbeatMsgEx_getNodeID(thisCast), HeartbeatMsgEx_getNodeNumID(thisCast),
|
|
HeartbeatMsgEx_getPortUDP(thisCast), HeartbeatMsgEx_getPortTCP(thisCast), &nicList,
|
|
nodeType == NODETYPE_Meta || nodeType == NODETYPE_Storage? App_getLocalRDMANicListLocked(app) : NULL);
|
|
// (will belong to the NodeStore => no destruct() required)
|
|
App_unlockNicList(app);
|
|
|
|
Node_setNodeAliasAndType(node, NULL, nodeType);
|
|
|
|
// set local nic capabilities
|
|
|
|
localNode = App_getLocalNode(app);
|
|
Node_cloneNicList(localNode, &localNicList);
|
|
connPool = Node_getConnPool(node);
|
|
|
|
NIC_supportedCapabilities(&localNicList, &localNicCaps);
|
|
NodeConnPool_setLocalNicCaps(connPool, &localNicCaps);
|
|
|
|
// add node to store (or update it)
|
|
|
|
isNodeNew = NodeStoreEx_addOrUpdateNode(nodes, &node);
|
|
if(isNodeNew)
|
|
{
|
|
bool supportsRDMA = NIC_supportsRDMA(&nicList);
|
|
|
|
Logger_logFormatted(log, Log_WARNING, logContext,
|
|
"New node: %s %s [ID: %hu]; %s",
|
|
Node_nodeTypeToStr(nodeType),
|
|
HeartbeatMsgEx_getNodeID(thisCast),
|
|
HeartbeatMsgEx_getNodeNumID(thisCast).value,
|
|
(supportsRDMA ? "RDMA; " : "") );
|
|
}
|
|
|
|
__HeartbeatMsgEx_processIncomingRoot(thisCast, app);
|
|
|
|
ack_resp:
|
|
// send ack
|
|
MsgHelperAck_respondToAckRequest(app, HeartbeatMsgEx_getAckID(thisCast), fromAddr, sock,
|
|
respBuf, bufLen);
|
|
|
|
// clean-up
|
|
ListTk_kfreeNicAddressListElems(&nicList);
|
|
NicAddressList_uninit(&nicList);
|
|
ListTk_kfreeNicAddressListElems(&localNicList);
|
|
NicAddressList_uninit(&localNicList);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Handles the contained root information.
|
|
*/
|
|
void __HeartbeatMsgEx_processIncomingRoot(HeartbeatMsgEx* this, App* app)
|
|
{
|
|
Logger* log = App_getLogger(app);
|
|
const char* logContext = "Heartbeat incoming (root)";
|
|
|
|
NodeStoreEx* metaNodes;
|
|
bool setRootRes;
|
|
NodeOrGroup rootOwner = this->rootIsBuddyMirrored
|
|
? NodeOrGroup_fromGroup(this->rootNumID.value)
|
|
: NodeOrGroup_fromNode(this->rootNumID);
|
|
NumNodeID rootNumID = HeartbeatMsgEx_getRootNumID(this);
|
|
|
|
// check whether root info is defined
|
|
if( (HeartbeatMsgEx_getNodeType(this) != NODETYPE_Meta) || (NumNodeID_isZero(&rootNumID)))
|
|
return;
|
|
|
|
// try to apply the contained root info
|
|
|
|
metaNodes = App_getMetaNodes(app);
|
|
|
|
setRootRes = NodeStoreEx_setRootOwner(metaNodes, rootOwner, false);
|
|
|
|
if(setRootRes)
|
|
{ // found the very first root
|
|
Logger_logFormatted(log, Log_CRITICAL, logContext, "Root (by Heartbeat): %hu",
|
|
HeartbeatMsgEx_getRootNumID(this).value );
|
|
}
|
|
|
|
}
|
|
|