📄 distgaplib.c
字号:
distPktGapTry.tryHdr.pktType = DIST_PKT_TYPE_GAP; distPktGapTry.tryHdr.pktSubType = DIST_PKT_TYPE_GAP_TRY; distPktGapTry.tryId = htons (pDistGrpDbNode->grpDbId); /* uint16 */ strcpy ((char *) &distPktGapTry.tryName, (char *) &pDistGrpDbNode->grpDbName);#ifdef DIST_GAP_REPORT printf ("distGapTry: send a TRY for `%s'/%d to node %ld\n", (char *) &pDistGrpDbNode->grpDbName, pDistGrpDbNode->grpDbId, distNodeId);#endif status = distNetSend (distNodeId, (DIST_PKT *) &distPktGapTry, sizeof (distPktGapTry), WAIT_FOREVER, DIST_GAP_PRIO); return (status); }/********************************************************************************* distGapInput - GAP incoming message dispatcher** NOMANUAL*/LOCAL DIST_STATUS distGapInput ( DIST_NODE_ID distNodeIdSrc, DIST_TBUF_HDR *pTBufHdr ) { char distPktGap[DIST_PKT_GAP_MAX_LEN]; distTBufCopy (DIST_TBUF_GET_NEXT (pTBufHdr), 0, (char *) &distPktGap, DIST_PKT_GAP_MAX_LEN); switch (((DIST_PKT *) &distPktGap)->pktSubType) { /* * We have received a TRY. Look if there are conflicts. If not, * respond with OK, else compare the node ids (buddy algorithm) * and send either OK or REJECT. */ case DIST_PKT_TYPE_GAP_TRY: { DIST_PKT_GAP_TRY *pDistPktGapTry = (DIST_PKT_GAP_TRY *) &distPktGap; DIST_GRP_DB_NODE *pGrpFoundById; DIST_GRP_DB_NODE *pGrpFoundByName; DIST_GRP_STATE grpState; /* Convert tryId (uint16) to host order */ pDistPktGapTry->tryId = ntohs (pDistPktGapTry->tryId); /* * What can we read out form the TRY-id? * * If we receive a TRY for an id that is greater the one * we would try, we have missed a TRY. * This can happen, if some node sent a TRY, which is correctly * received by some other node, but not by us--retransmission * is enforced, but takes some time. The other node immediately * starts sendind a TRY of its own, which in turn is received by us * correctly. As you can see, it seams for us that we have * missed a TRY--in fact the missing TRY is just delayed. * * If we receive a TRY for an id that is lower the one * we would try, it is *NOT* for sure, that the remote * node has missed a TRY. This can happen if an outgoing * TRY is delayed at the remote node. */#ifdef DIST_GAP_REPORT printf ("distGapInput: received TRY for `%s'/%d from node %ld\n", pDistPktGapTry->tryName, pDistPktGapTry->tryId, distNodeIdSrc);#endif msgQDistGrpDbLock(); /* * Test for conflicts. Try to find id and name in local database. * If found, ask for GLOBAL state. */ pGrpFoundById = msgQDistGrpLclFindById (pDistPktGapTry->tryId); if (pGrpFoundById) { grpState = msgQDistGrpLclGetState (pGrpFoundById);#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: group id %d already in %s use\n", pDistPktGapTry->tryId, (grpState == DIST_GRP_STATE_GLOBAL) ? "global" : "local");#endif if (grpState == DIST_GRP_STATE_GLOBAL) { /* * Someone sends a TRY for an id, already confirmed * by GAP. Give him a reject. */ DIST_PKT_GAP_REJECT *pDistPktGapReject; msgQDistGrpDbUnlock();#ifdef DIST_GAP_REPORT printf ("distGapInput:TRY: group id already in use; reject\n");#endif pDistPktGapReject = (DIST_PKT_GAP_REJECT *) &distPktGap; pDistPktGapReject->rejectHdr.pktSubType = DIST_PKT_TYPE_GAP_REJECT; pDistPktGapReject->rejectId = htons (pDistPktGapReject->rejectId); distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapReject, sizeof (*pDistPktGapReject), WAIT_FOREVER, DIST_GAP_PRIO); break; } } pGrpFoundByName = msgQDistGrpLclFindByName (pDistPktGapTry->tryName); if (pGrpFoundByName) { grpState = msgQDistGrpLclGetState (pGrpFoundByName);#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: group name `%s' already in %s use\n", pDistPktGapTry->tryName, (grpState == DIST_GRP_STATE_GLOBAL) ? "global" : "local");#endif if (grpState == DIST_GRP_STATE_GLOBAL) { DIST_PKT_GAP_SET *pDistPktGapSet; /* * Someone sends a TRY for a group that is in GLOBAL * state here. * This can happen, if * 1) someone did a TRY before receiving our * SET (remote TRYs do not force creation of a * database entry). * 2) a WAIT timed out and the state shifts to * WAIT_TRY. In this case the remote node has * missed the SET. Directly respond with SET. */ /* * Respond with SET. */ pDistPktGapSet = (DIST_PKT_GAP_SET *) &distPktGap; pDistPktGapSet->setHdr.pktSubType = DIST_PKT_TYPE_GAP_SET; pDistPktGapSet->setId = msgQDistGrpLclGetId (pGrpFoundByName); msgQDistGrpDbUnlock();#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: respond with SET `%s'/%d\n", pDistPktGapSet->setName, pDistPktGapSet->setId);#endif /* Convert setId (uint16) to network byte order */ pDistPktGapSet->setId = htons (pDistPktGapSet->setId); distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapSet, sizeof (*pDistPktGapSet), WAIT_FOREVER, DIST_GAP_PRIO); break; } } else { DIST_GRP_DB_NODE *pDistGrp; /* * Create DB entry for new group. */ pDistGrp = msgQDistGrpLclCreate (pDistPktGapTry->tryName, pDistPktGapTry->tryId, DIST_GRP_STATE_REMOTE_TRY); if (pDistGrp == NULL) { /* * We cannot create a new node in the group database. * This is a fatal error. */ distPanic ("distGapInput:TRY: creation of new node failed\n"); } /* only temporary, creator may change */ msgQDistGrpLclSetCreator (pDistGrp, distNodeIdSrc); pDistGrp->pGrpDbGapNode = NULL; } /* * If there is a local group with the same name as currently * tried, it is not in GLOBAL state. We have checked this * before. */ if (pGrpFoundById == NULL && pGrpFoundByName == NULL) { DIST_PKT_GAP_OK *pDistPktGapOk; /* * No conflicts. Neither group id nor group name * are used in the local database. */ distGrpIdNext++; msgQDistGrpDbUnlock(); /* * Respond with OK. */#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: neither id nor name used; respond OK\n");#endif pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap; pDistPktGapOk->okHdr.pktSubType = DIST_PKT_TYPE_GAP_OK; /* Convert okId (uint16) to network byte order */ pDistPktGapOk->okId = htons (pDistPktGapOk->okId); distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapOk, sizeof (*pDistPktGapOk), WAIT_FOREVER, DIST_GAP_PRIO); break; } if (pGrpFoundById == pGrpFoundByName) { /* * No conflict. There is already an object that * exactly matches the remote one. */ DIST_PKT_GAP_OK *pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap; msgQDistGrpDbUnlock(); /* * Respond with OK. */#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: id and name match; respond OK\n");#endif pDistPktGapOk->okHdr.pktSubType = DIST_PKT_TYPE_GAP_OK; /* Convert okId (uint16) to network byte order */ pDistPktGapOk->okId = htons (pDistPktGapOk->okId); distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapOk, sizeof (*pDistPktGapOk), WAIT_FOREVER, DIST_GAP_PRIO); break; } /* * There is a conflict. Compare node ids to solve the conflict. * This is kind of a game: the one with the higher node id wins. */ if (distNodeLocalGetId() < distNodeIdSrc) { DIST_PKT_GAP_OK *pDistPktGapOk; /* * We have lost. Do a local cleanup and send OK. */ distGrpIdNext++;#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: we have lost, trying %d\n", pDistPktGapTry->tryId);#endif if (pGrpFoundByName) { /* * Someone else is trying to create the same group, but has * a different group id. We have lost, so let us wait until * we receive a SET. */ /* * Remove linked list of outstanding responses. */ distGapOutstandUnlink (pGrpFoundByName->pGrpDbGapNode); /* * Set WAIT state. */ msgQDistGrpLclSetState (pGrpFoundByName, DIST_GRP_STATE_WAIT); pGrpFoundByName->pGrpDbGapNode->gapTimeout = DIST_GAP_WAIT_TIMO; msgQDistGrpDbUnlock (); } else { /* * Someone else is trying to create a group with an * id, that was also proposed by us. We have lost, * so forget about the id and try another one. */ /* * Cleanup and reinitialize the GAP structure. */ distGapOutstandUnlink (pGrpFoundById->pGrpDbGapNode); distGapOutstandLink (pGrpFoundById->pGrpDbGapNode); pGrpFoundById->pGrpDbGapNode->gapTimeout = DIST_GAP_TRY_TIMO; pGrpFoundById->pGrpDbGapNode->gapRetries = 1; /* * Get a new id and reset state. */ msgQDistGrpLclSetId (pGrpFoundByName, distGrpIdNext++); msgQDistGrpLclSetState (pGrpFoundByName, DIST_GRP_STATE_LOCAL_TRY); msgQDistGrpDbUnlock(); /* * Have a different TRY. */ distGapTry (DIST_IF_BROADCAST_ADDR, pGrpFoundByName); }#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: respond with OK\n");#endif pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap; pDistPktGapOk->okHdr.pktSubType = DIST_PKT_TYPE_GAP_OK; /* Convert okId (uint16) to network byte order */ pDistPktGapOk->okId = htons (pDistPktGapOk->okId); distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapOk, sizeof (*pDistPktGapOk), WAIT_FOREVER, DIST_GAP_PRIO); } else { /* * We won. */#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: we have won, trying %d\n", pDistPktGapTry->tryId);#endif msgQDistGrpDbUnlock(); if (pGrpFoundByName) { /* * Someone is trying to create the same group, we * are trying, with a different group id. We won * the game, ask him to wait (ASK_WAIT). */ DIST_PKT_GAP_ASK_WAIT *pDistPktGapAskWait;#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: respond with ASK_WAIT\n");#endif pDistPktGapAskWait = (DIST_PKT_GAP_ASK_WAIT *) &distPktGap; pDistPktGapAskWait->askWaitHdr.pktSubType = DIST_PKT_TYPE_GAP_ASK_WAIT; /* Convert askWaitId (uint16) to network byte order */ pDistPktGapAskWait->askWaitId = htons (pDistPktGapAskWait->askWaitId); distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapAskWait, sizeof (*pDistPktGapAskWait), WAIT_FOREVER, DIST_GAP_PRIO); } else { /* * Someone is trying to create a group with an * id, already in use by us. We won the game, so * give him a REJECT. */ DIST_PKT_GAP_REJECT *pDistPktGapReject;#ifdef DIST_GAP_REPORT printf ("distGapInput/TRY: respond with REJECT\n");#endif pDistPktGapReject = (DIST_PKT_GAP_REJECT *) &distPktGap; pDistPktGapReject->rejectHdr.pktSubType = DIST_PKT_TYPE_GAP_REJECT; /* Convert rejectId (uint16) to network byte order */ pDistPktGapReject->rejectId = htons (pDistPktGapReject->rejectId); distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapReject, sizeof (*pDistPktGapReject), WAIT_FOREVER, DIST_GAP_PRIO); } } break; } /* * We have received an OK in response to an earlier TRY. */ case DIST_PKT_TYPE_GAP_OK: { DIST_PKT_GAP_OK *pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap; DIST_GRP_DB_NODE *pDistGrp; BOOL more; /* Convert okId (uint16) to host order */ pDistPktGapOk->okId = ntohs (pDistPktGapOk->okId); #ifdef DIST_GAP_REPORT printf ("distGapInput: received OK for `%s'/%d from node %ld\n", pDistPktGapOk->okName, pDistPktGapOk->okId, distNodeIdSrc);#endif msgQDistGrpDbLock(); /* * Try to find the confirmed id. */ pDistGrp = msgQDistGrpLclFindById (pDistPktGapOk->okId); if (pDistGrp == NULL || msgQDistGrpLclGetState (pDistGrp) == DIST_GRP_STATE_GLOBAL) { /* * This is an OK for an id, that * 1) does not exist anymore (due to earlier REJECTs): * This means, someone sent us a REJECT. As a * consequence of this, we destoyed the local entry * for this group and tried again with a new id. * 2) was confirmed by GAP earlier (group is in GLOBAL state). * * All responses to the old group id go here and will be ignored. */ msgQDistGrpDbUnlock(); break; } distGapLock(); /* * Update list of outstanding responses. */ more = distGapOutstandOk(pDistGrp->pGrpDbGapNode, distNodeIdSrc); distGapUnlock(); if (more == FALSE) { msgQDistGrpLclSetState (pDistGrp, DIST_GRP_STATE_GLOBAL); msgQDistGrpLclSetCreator (pDistGrp, distNodeLocalGetId()); msgQDistGrpDbUnlock(); distGapPh1Done (pDistGrp); break; } msgQDistGrpDbUnlock(); break; } /* * We have received a REJECT. * Someone else is trying to create another group with an * id, that was also proposed by us. It seams, we have
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -