Chord Class Reference

#include <Chord.h>

Inheritance diagram for Chord:

BaseOverlay RpcListener Koorde List of all members.

Detailed Description

Chord overlay module.

Implementation of the Chord KBR overlay as described in "Chord: A Scalable Peer-to-Peer Lookup Protocol for Inetnet Applications" by I. Stoica et al. published in Transactions on Networking.

Author:
Markus Mauch, Ingmar Baumgart
See also:
BaseOverlay, ChordFingerTable, ChordSuccessorList


Public Member Functions

virtual ~Chord ()
virtual void initializeOverlay (int stage)
 Initializes derived-class-attributes.
virtual void receiveChangeNotification (int category, cPolymorphic *details)
 callback-method for events at the NotificationBoard
virtual bool isResponsible (const OverlayKey &key)
 Query if the node is responsible for a key.
virtual void handleTimerEvent (cMessage *msg)
 handles self-messages
virtual void handleUDPMessage (BaseOverlayMessage *msg)
 processes messages from underlay
virtual void recordOverlaySentStats (BaseOverlayMessage *msg)
 Collect overlay specific sent messages statistics.
virtual void finishOverlay ()
 collects statisticts
virtual void updateTooltip ()
 updates information shown in tk-environment

Protected Member Functions

virtual void changeState (int toState)
 changes node state
virtual void handleJoinTimerExpired (cMessage *msg)
 handle a expired join timer
virtual void handleStabilizeTimerExpired (cMessage *msg)
 handle a expired stabilize timer
virtual void handleFixFingersTimerExpired (cMessage *msg)
 handle a expired fix_fingers timer
virtual void handleNewSuccessorHint (ChordMessage *chordMsg)
 handle a received NEWSUCCESSORHINT message
virtual const NodeHandleclosestPreceedingNode (const OverlayKey &key)
 looks up the finger table and returns the closest preceeding node.
virtual void findFriendModules ()
 Assigns the finger table and succesesor list module to our reference.
virtual void initializeFriendModules ()
 initializes finger table and successor list
virtual void handleRpc (BaseCallMessage *msg)
 Processes Remote-Procedure-Call invokation messages.
NodeVectorfindNode (const OverlayKey &key, BaseOverlayMessage *msg)
 Implements the find node call.
void rpcFixfingers (FixfingersCall *call)
 Fixfingers Remote-Procedure-Call.
void rpcJoin (JoinCall *call)
 Join Remote-Procedure-Call.
void rpcNotify (NotifyCall *call)
 NOTIFY Remote-Procedure-Call.
void rpcStabilize (StabilizeCall *call)
 STABILIZE Remote-Procedure-Call.
virtual void handleRpcResponse (BaseResponseMessage *msg, int rpcId, simtime_t rtt)
 This method is called if an RPC response has been received.
virtual void handleRpcTimeout (BaseCallMessage *msg, const NodeHandle &dest, int rpcId)
 This method is called if an RPC timeout has been reached.
virtual void handleRpcJoinResponse (JoinResponse *joinResponse)
virtual void handleRpcNotifyResponse (NotifyResponse *notifyResponse)
virtual void handleRpcStabilizeResponse (StabilizeResponse *stabilizeResponse)
virtual void handleRpcFixfingersResponse (FixfingersResponse *fixfingersResponse)
virtual void predecessorIsDead ()
virtual void successorIsDead ()

Protected Attributes

int joinRetry
int stabilizeRetry
 // retries before neighbor considered failed
double joinDelay
double stabilizeDelay
 stabilize interval (secs)
double fixfingersDelay
int successorListSize
bool aggressiveJoinMode
 use modified (faster) JOIN protocol
cMessage * join_timer
cMessage * stabilize_timer
cMessage * fixfingers_timer
int joinCount
int stabilizeCount
int fixfingersCount
int notifyCount
int newsuccessorhintCount
int joinBytesSent
int stabilizeBytesSent
int notifyBytesSent
int fixfingersBytesSent
int newsuccessorhintBytesSent
int state
 current node state
int keyLength
 length of an overlay key in bits
int missingPredecessorStabRequests
 missing StabilizeCall msgs
int missingSuccessorStabResponses
 missing StabilizeResponse msgs
NodeHandle predecessorNode
 predecessor of this node
NodeHandle bootstrapNode
 node used to bootrap
ChordFingerTablefingerTable
 pointer to this node's finger table
ChordSuccessorListsuccessorList
 pointer to this node's successor list


Constructor & Destructor Documentation

Chord::~Chord (  )  [virtual]

00093 {
00094     // destroy self timer messages
00095     cancelEvent(join_timer);
00096     cancelEvent(stabilize_timer);
00097     cancelEvent(fixfingers_timer);
00098 
00099     delete join_timer;
00100     delete stabilize_timer;
00101     delete fixfingers_timer;
00102 }


Member Function Documentation

void Chord::changeState ( int  toState  )  [protected, virtual]

changes node state

Parameters:
toState state to change to

Reimplemented in Koorde.

00118 {
00119     //
00120     // Defines tasks to be executed when a state change occurs.
00121     //
00122 
00123     switch (toState) {
00124     case INIT:
00125         state = INIT;
00126 
00127         // remove current node handle from the bootstrap list
00128         if(!thisNode.key.isUnspecified()) {
00129             bootstrapOracle->removePeer(thisNode);
00130         }
00131 
00132         // Calculate node's id by hashing its IP address
00133         //  thisNode.key = OverlayKey::sha1(const_cast<char*>(
00134         //                      thisNode.ip.str().c_str()));
00135         // better use random numbers (our ip address might not be random)
00136         // keep old id if INIT gets called twice
00137         if (thisNode.key.isUnspecified()) {
00138             thisNode.key = OverlayKey::random();
00139             callUpdate(thisNode, true);
00140         }
00141 
00142 
00143         // initialize predecessor pointer
00144         predecessorNode = NodeHandle::UNSPECIFIED_NODE;
00145 
00146         // initialize finger table and successor list
00147         initializeFriendModules();
00148 
00149         updateTooltip();
00150 
00151         // debug message
00152         if (debugOutput) {
00153             EV << "CHORD: Node " << thisNode.ip
00154             << " entered INIT stage." << endl;
00155         }
00156         // FIXME: bubble() sometimes doesn't work
00157         parentModule()->parentModule()->bubble("Enter INIT state.");
00158         break;
00159 
00160     case BOOTSTRAP:
00161         state = BOOTSTRAP;
00162 
00163         // initiate bootstrap process
00164         cancelEvent(join_timer);
00165         // workaround: prevent notificationBoard from taking
00166         // ownership of join_timer message
00167         take(join_timer);
00168         scheduleAt(simulation.simTime(), join_timer);
00169 
00170         // debug message
00171         if (debugOutput) {
00172             EV << "CHORD: Node " << thisNode.ip
00173             << " entered BOOTSTRAP stage." << endl;
00174         }
00175         parentModule()->parentModule()->bubble("Enter BOOTSTRAP state.");
00176 
00177         // find a new bootstrap node and enroll to the bootstrap list
00178         bootstrapNode = bootstrapOracle->getBootstrapNode();
00179 
00180         // is this the first node?
00181         if (bootstrapNode.isUnspecified()) {
00182             // create new cord ring
00183             bootstrapNode = thisNode;
00184             changeState(READY);
00185             updateTooltip();
00186         }
00187         break;
00188 
00189     case READY:
00190         state = READY;
00191 
00192         bootstrapOracle->registerPeer(thisNode);
00193 
00194         // initiate stabilization protocol
00195         cancelEvent(stabilize_timer);
00196         scheduleAt(simulation.simTime() + stabilizeDelay, stabilize_timer);
00197 
00198         // initiate finger repair protocol
00199         cancelEvent(fixfingers_timer);
00200         scheduleAt(simulation.simTime() + fixfingersDelay,
00201                    fixfingers_timer);
00202 
00203         // debug message
00204         if (debugOutput) {
00205             EV << "CHORD: Node " << thisNode.ip << " entered READY stage."
00206             << endl;
00207         }
00208         parentModule()->parentModule()->bubble("Enter READY state.");
00209         break;
00210     }
00211 
00212     setReadyIcon(state == READY);
00213 }

const NodeHandle & Chord::closestPreceedingNode ( const OverlayKey key  )  [protected, virtual]

looks up the finger table and returns the closest preceeding node.

Parameters:
key key to find the closest preceeding node for
Returns:
node handle of the closest preceeding node to key
00415 {
00416     for (int i = fingerTable->getSize() - 1; i >= 0; i--) {
00417         if (fingerTable->getFinger(i).key.isBetween(thisNode.key, key)) {
00418             // is there a closer preceeding node in the successor list?
00419             for (int j = successorList->getSize() - 1; j >= 0; j--) {
00420                 if (successorList->getSuccessor(j).key.
00421                         isBetween(fingerTable->getFinger(i).key, key)) {
00422                     return successorList->getSuccessor(j);
00423                 }
00424             }
00425 
00426             // if no, settle with the node already found
00427             return fingerTable->getFinger(i);
00428         }
00429     }
00430 
00431     // if no finger is found lookup the rest of the successor list
00432     for (int i = successorList->getSize()-1; i >= 0; i--) {
00433         if(successorList->getSuccessor(i).key.isBetween(thisNode.key, key)) {
00434             return successorList->getSuccessor(i);
00435         }
00436     }
00437 
00438     // if this is the first and only node on the ring, it is responsible
00439     if ((predecessorNode.isUnspecified()) &&
00440             (successorList->getSuccessor() == thisNode)) {
00441         return thisNode;
00442     }
00443 
00444     // if there is still no node found return NodeHandle::UNSPECIFIED_NODE
00445     return NodeHandle::UNSPECIFIED_NODE;
00446 }

void Chord::findFriendModules (  )  [protected, virtual]

Assigns the finger table and succesesor list module to our reference.

Reimplemented in Koorde.

00882 {
00883     fingerTable = check_and_cast<ChordFingerTable*>
00884                   (parentModule()->submodule("fingerTable"));
00885 
00886     successorList = check_and_cast<ChordSuccessorList*>
00887                     (parentModule()->submodule("successorList"));
00888 }

NodeVector * Chord::findNode ( const OverlayKey key,
BaseOverlayMessage msg 
) [protected, virtual]

Implements the find node call.

This method simply returns the closest nodes known in the corresponding routing topology.

Parameters:
key The lookup key.
msg A pointer to the BaseRouteMessage or FindNodeCall message of this lookup.
Returns:
NodeVector with closest nodes.

Reimplemented from BaseOverlay.

Reimplemented in Koorde.

00364 {
00365     NodeVector* nextHop = new NodeVector(1);
00366 
00367     if (state != READY)
00368         return nextHop;
00369 
00370 //     // example code for findNodeExt
00371 
00372 //      if (msg != NULL) {
00373 //              if (!msg->hasObject("findNodeExt")) {
00374 //                  ChordFindNodeExtMessage *extMsg =
00375 //                      new ChordFindNodeExtMessage("findNodeExt");
00376 //                      extMsg->setLength(8*10);
00377 //                  msg->addObject( extMsg );
00378 //               }
00379 //
00380 //              ChordFindNodeExtMessage *extMsg =
00381 //                  (ChordFindNodeExtMessage*) msg->getObject("findNodeExt");
00382 //
00383 //          cout << "ChordCount: " << extMsg->getChordCount() + 1 << endl;
00384 //
00385 //          extMsg->setChordCount(extMsg->getChordCount() + 1);
00386 //      }
00387 
00388     // if key is unspecified, the message is for this node
00389     if (key.isUnspecified()) {
00390 //        nextHop->push_back(thisNode);
00391         nextHop->push_back(thisNode);
00392     } else if (isResponsible(key)) {
00393         // the message is destined for this node
00394 //        nextHop->push_back(thisNode);
00395         nextHop->push_back(thisNode);
00396     } else if (key.isBetweenR(thisNode.key,
00397                               successorList->getSuccessor().key)) {
00398         // the message destined for our successor
00399 //        nextHop->push_back(successorList->getSuccessor());
00400         nextHop->push_back(successorList->getSuccessor());
00401     } else {
00402         // find next hop with finger table
00403         NodeHandle tmpNode = closestPreceedingNode(key);
00404         if (!tmpNode.isUnspecified()) {
00405 //            nextHop->push_back(tmpNode);
00406             nextHop->push_back(tmpNode);
00407         }
00408     }
00409 
00410     return nextHop;
00411 }

void Chord::finishOverlay (  )  [virtual]

collects statisticts

Reimplemented from BaseOverlay.

Reimplemented in Koorde.

00494 {
00495     recordScalar("Chord: Sent JOIN Messages", joinCount);
00496     recordScalar("Chord: Sent NEWSUCCESSORHINT Messages",
00497                  newsuccessorhintCount);
00498     recordScalar("Chord: Sent STABILIZE Messages", stabilizeCount);
00499     recordScalar("Chord: Sent NOTIFY Messages", notifyCount);
00500     recordScalar("Chord: Sent FIX_FINGERS Messages", fixfingersCount);
00501     recordScalar("Chord: Sent JOIN Bytes", joinBytesSent);
00502     recordScalar("Chord: Sent NEWSUCCESSORHINT Bytes",
00503                  newsuccessorhintBytesSent);
00504     recordScalar("Chord: Sent STABILIZE Bytes", stabilizeBytesSent);
00505     recordScalar("Chord: Sent NOTIFY Bytes", notifyBytesSent);
00506     recordScalar("Chord: Sent FIX_FINGERS Bytes", fixfingersBytesSent);
00507 
00508     // remove this node from the bootstrap list
00509     bootstrapOracle->removePeer(thisNode);
00510 }

void Chord::handleFixFingersTimerExpired ( cMessage *  msg  )  [protected, virtual]

handle a expired fix_fingers timer

Parameters:
msg the timer self-message

Reimplemented in Koorde.

00603 {
00604     if ((state != READY) || successorList->isEmpty())
00605         return;
00606 
00607     for (uint nextFinger = 0; nextFinger < thisNode.key.getLength();
00608             nextFinger++) {
00609         // calculate "n + 2^(i - 1)"
00610         OverlayKey offset = OverlayKey::pow2(nextFinger);
00611         OverlayKey lookupKey = thisNode.key + offset;
00612 
00613         // send message only for non-trivial fingers
00614         if (offset > successorList->getSuccessor().key - thisNode.key) {
00615             // call FIXFINGER RPC
00616             FixfingersCall* call = new FixfingersCall("FixfingersCall");
00617             call->setFinger(nextFinger);
00618             call->setLength(FIXFINGERSCALL_L(call));
00619 
00620             sendRpcMessage(NodeHandle::UNSPECIFIED_NODE, call, NULL,
00621                            lookupKey, -1, fixfingersDelay);
00622 
00623         } else {
00624             // let trivial fingers point to the successor node
00625             fingerTable->setFinger(nextFinger,
00626                                    successorList->getSuccessor());
00627         }
00628     }
00629 
00630     // schedule next finger repair process
00631     cancelEvent(fixfingers_timer);
00632     scheduleAt(simulation.simTime() + fixfingersDelay, msg);
00633 }

void Chord::handleJoinTimerExpired ( cMessage *  msg  )  [protected, virtual]

handle a expired join timer

Parameters:
msg the timer self-message
00515 {
00516     // only process timer, if node is not bootstrapped yet
00517     if (state == READY)
00518         return;
00519 
00520     // enter state BOOTSTRAP
00521     if (state != BOOTSTRAP)
00522         changeState(BOOTSTRAP);
00523 
00524     // change bootstrap node from time to time
00525     joinRetry--;
00526     if (joinRetry == 0) {
00527         joinRetry = par("joinRetry");
00528         changeState(BOOTSTRAP);
00529         return;
00530     }
00531 
00532     // call JOIN RPC
00533     JoinCall* call = new JoinCall("JoinCall");
00534     call->setLength(JOINCALL_L(call));
00535 
00536     sendRpcMessage(bootstrapNode, call, NULL, thisNode.key, -1, joinDelay);
00537 
00538     // schedule next bootstrap process in the case this one fails
00539     cancelEvent(join_timer);
00540     scheduleAt(simulation.simTime() + joinDelay, msg);
00541 }

void Chord::handleNewSuccessorHint ( ChordMessage chordMsg  )  [protected, virtual]

handle a received NEWSUCCESSORHINT message

Parameters:
chordMsg the message to process
00637 {
00638     NewSuccessorHintMessage* newSuccessorHintMsg =
00639         check_and_cast<NewSuccessorHintMessage*>(chordMsg);
00640 
00641     // fetch the successor's predecessor
00642     NodeHandle predecessor = newSuccessorHintMsg->getPreNode();
00643 
00644     // is the successor's predecessor a new successor for this node?
00645     if (predecessor.key.isBetween(thisNode.key,
00646                                   successorList->getSuccessor().key)
00647             || (thisNode.key == successorList->getSuccessor().key)) {
00648         // add the successor's predecessor to the successor list
00649         successorList->addSuccessor(predecessor);
00650         updateTooltip();
00651     }
00652 }

void Chord::handleRpc ( BaseCallMessage msg  )  [protected, virtual]

Processes Remote-Procedure-Call invokation messages.

Reimplemented from BaseOverlay.

Reimplemented in Koorde.

00255 {
00256     if (state != READY) {
00257         delete msg;
00258         EV << "Chord::handleRpc(): Received RPC call "
00259         << "and state != READY!" << endl;
00260         return;
00261     }
00262 
00263     // delegate messages
00264     RPC_SWITCH_START( msg )
00265     // RPC_DELEGATE( <messageName>[Call|Response], <methodToCall> )
00266     RPC_DELEGATE( Join, rpcJoin );
00267     RPC_DELEGATE( Notify, rpcNotify );
00268     RPC_DELEGATE( Stabilize, rpcStabilize );
00269     RPC_DELEGATE( Fixfingers, rpcFixfingers );
00270     RPC_SWITCH_END( )
00271 }

void Chord::handleRpcFixfingersResponse ( FixfingersResponse fixfingersResponse  )  [protected, virtual]

00873 {
00874     // set new finger pointer
00875     NodeHandle successor = fixfingersResponse->getSucNode();
00876     fingerTable->setFinger(fixfingersResponse->getFinger(), successor);
00877 }

void Chord::handleRpcJoinResponse ( JoinResponse joinResponse  )  [protected, virtual]

Todo:
check commented out addSuccessor (Schenk)

Reimplemented in Koorde.

00717 {
00718     // determine the numer of successor nodes to add
00719     int sucNum = successorListSize - 1;
00720 
00721     if (joinResponse->getSucNum() < successorListSize - 1) {
00722         sucNum = joinResponse->getSucNum();
00723     }
00724 
00725     // add successor node(s)
00726     for (int k = 0; k < sucNum; k++) {
00727         NodeHandle successor = joinResponse->getSucNode(k);
00728         successorList->addSuccessor(successor);
00729     }
00730 
00731 // \todo {check commented out addSuccessor (Schenk)}
00732 //successorList->addSuccessor(joinResponse->getSrcNode());
00733 
00734 
00735     // the sender of this message is our new successor
00736     successorList->addSuccessor(joinResponse->getSrcNode());
00737 
00738     // in aggressiveJoinMode: use hint in JoinResponse
00739     // to set our new predecessor
00740     if (aggressiveJoinMode) {
00741         predecessorNode = joinResponse->getPreNode();
00742     }
00743 
00744     updateTooltip();
00745 
00746     changeState(READY);
00747 
00748     // immediate stabilization protocol
00749     cancelEvent(stabilize_timer);
00750     scheduleAt(simulation.simTime(), stabilize_timer);
00751 
00752     // immediate finger repair protocol
00753     cancelEvent(fixfingers_timer);
00754     scheduleAt(simulation.simTime(), fixfingers_timer);
00755 }

void Chord::handleRpcNotifyResponse ( NotifyResponse notifyResponse  )  [protected, virtual]

Reimplemented in Koorde.

00830 {
00831     if (successorList->getSuccessor() != notifyResponse->getSrcNode()) {
00832         EV << "Chord::handleRpcNotifyResponse: The srcNode of the received "
00833         << "NotifyResponse is not our current successor!" << endl;
00834         return;
00835     }
00836 
00837     // determine number of successor nodes to add
00838     int sucNum = successorListSize - 1;
00839     if (notifyResponse->getSucNum() < successorListSize - 1) {
00840         sucNum = notifyResponse->getSucNum();
00841     }
00842 
00843     // replace our successor list by our successor's successor list
00844     // and add our current successor to the list
00845     successorList->clear();
00846     successorList->addSuccessor(notifyResponse->getSrcNode());
00847     for (int k = 0; k < sucNum; k++) {
00848         NodeHandle successor = notifyResponse->getSucNode(k);
00849         // don't add nodes, if this would change our successor
00850         if (!successor.key.isBetweenLR(thisNode.key,
00851                                        notifyResponse->getSrcNode().key)) {
00852             successorList->addSuccessor(successor);
00853         }
00854     }
00855     updateTooltip();
00856 }

void Chord::handleRpcResponse ( BaseResponseMessage msg,
int  rpcId,
simtime_t  rtt 
) [protected, virtual]

This method is called if an RPC response has been received.

Parameters:
msg The response message.
rpcId The RPC id.
rtt The Round-Trip-Time of this RPC

Reimplemented from RpcListener.

Reimplemented in Koorde.

00275 {
00276     RPC_SWITCH_START(msg)
00277     RPC_ON_RESPONSE( Join ) {
00278         handleRpcJoinResponse(_JoinResponse);
00279         EV << "Join RPC Response received: id=" << rpcId
00280         << " msg=" << *_JoinResponse << " rtt=" << rtt << endl;
00281         break;
00282     }
00283     RPC_ON_RESPONSE( Notify ) {
00284         handleRpcNotifyResponse(_NotifyResponse);
00285         EV << "Notify RPC Response received: id=" << rpcId
00286         << " msg=" << *_NotifyResponse << " rtt=" << rtt << endl;
00287         break;
00288     }
00289     RPC_ON_RESPONSE( Stabilize ) {
00290         handleRpcStabilizeResponse(_StabilizeResponse);
00291         EV << "Stabilize RPC Response received: id=" << rpcId
00292         << " msg=" << *_StabilizeResponse << " rtt=" << rtt << endl;
00293         break;
00294     }
00295     RPC_ON_RESPONSE( Fixfingers ) {
00296         handleRpcFixfingersResponse(_FixfingersResponse);
00297         EV << "Fixfingers RPC Response received: id=" << rpcId
00298         << " msg=" << *_FixfingersResponse << " rtt=" << rtt << endl;
00299         break;
00300     }
00301     RPC_SWITCH_END( )
00302 }

void Chord::handleRpcStabilizeResponse ( StabilizeResponse stabilizeResponse  )  [protected, virtual]

Reimplemented in Koorde.

00773 {
00774     // our successor seems to be alive
00775     missingSuccessorStabResponses = 0;
00776 
00777     // fetch the successor's predecessor
00778     NodeHandle predecessor = stabilizeResponse->getPreNode();
00779 
00780     // is the successor's predecessor a new successor for this node?
00781     if (successorList->isEmpty() ||
00782             predecessor.key.isBetween(thisNode.key,
00783                                       successorList->getSuccessor().key)) {
00784         // add the successor's predecessor to the successor list
00785         successorList->addSuccessor(predecessor);
00786         updateTooltip();
00787     }
00788 
00789     // compile NOTIFY RPC
00790     NotifyCall* notifyCall = new NotifyCall("NotifyCall");
00791     notifyCall->setLength(NOTIFYCALL_L(notifyCall));
00792 
00793     sendRpcMessage(successorList->getSuccessor(), notifyCall);
00794 }

void Chord::handleRpcTimeout ( BaseCallMessage msg,
const NodeHandle dest,
int  rpcId 
) [protected, virtual]

This method is called if an RPC timeout has been reached.

Parameters:
msg The original RPC message.
dest The destination of the RPC
rpcId The RPC id.

Reimplemented in Koorde.

00306 {
00307     RPC_SWITCH_START(msg)
00308     RPC_ON_CALL( FindNode ) {
00309         EV << "FindNode RPC Call timed out: id=" << rpcId
00310         << " msg=" << *_FindNodeCall << endl;
00311         break;
00312     }
00313     RPC_ON_CALL( Join ) {
00314         EV << "Join RPC Call timed out: id=" << rpcId
00315         << " msg=" << *_JoinCall << endl;
00316         break;
00317     }
00318     RPC_ON_CALL( Notify ) {
00319         EV << "Notify RPC Call timed out: id=" << rpcId
00320         << " msg=" << *_NotifyCall << endl;
00321         break;
00322     }
00323     RPC_ON_CALL( Stabilize ) {
00324         EV << "Stabilize RPC Call timed out: id=" << rpcId
00325         << " msg=" << *_StabilizeCall << endl;
00326         break;
00327     }
00328     RPC_ON_CALL( Fixfingers ) {
00329         EV << "Fixfingers RPC Call timed out: id=" << rpcId
00330         << " msg=" << *_FixfingersCall << endl;
00331         break;
00332     }
00333     RPC_SWITCH_END( )
00334 }

void Chord::handleStabilizeTimerExpired ( cMessage *  msg  )  [protected, virtual]

handle a expired stabilize timer

Parameters:
msg the timer self-message
00545 {
00546     if (state != READY)
00547         return;
00548 
00549     if (missingPredecessorStabRequests >= stabilizeRetry) {
00550         // predecessor node seems to be dead
00551         // remove it from the predecessor / successor lists
00552         successorList->removeSuccessor(predecessorNode);
00553         predecessorIsDead();
00554         predecessorNode = NodeHandle::UNSPECIFIED_NODE;
00555 
00556         missingPredecessorStabRequests = 0;
00557         updateTooltip();
00558     }
00559 
00560     if (missingSuccessorStabResponses >= stabilizeRetry) {
00561         // successor node seems to be dead
00562         // remove it from the predecessor / successor list
00563         successorIsDead();
00564         NodeHandle successor = successorList->popSuccessor();
00565 
00566         // if we had a ring consisting of 2 nodes and our successor seems
00567         // to be dead. Remove also predecessor because the successor
00568         // and predecessor are the same node
00569         if ((!predecessorNode.isUnspecified()) &&
00570                 predecessorNode == successor) {
00571             predecessorIsDead();
00572             predecessorNode = NodeHandle::UNSPECIFIED_NODE;
00573         }
00574 
00575         missingSuccessorStabResponses = 0;
00576         updateTooltip();
00577 
00578         if (successorList->isEmpty()) {
00579             changeState(INIT);
00580             changeState(BOOTSTRAP);
00581             return;
00582         }
00583     }
00584 
00585     if (!successorList->isEmpty()) {
00586         // call STABILIZE RPC
00587         StabilizeCall* call = new StabilizeCall("StabilizeCall");
00588         call->setLength(STABILIZECALL_L(call));
00589 
00590         sendRpcMessage(successorList->getSuccessor(), call);
00591 
00592         missingPredecessorStabRequests++;
00593         missingSuccessorStabResponses++;
00594     }
00595 
00596     // schedule next stabilization process
00597     cancelEvent(stabilize_timer);
00598     scheduleAt(simulation.simTime() + stabilizeDelay, msg);
00599 }

void Chord::handleTimerEvent ( cMessage *  msg  )  [virtual]

handles self-messages

Parameters:
msg the self-message

Reimplemented from BaseOverlay.

Reimplemented in Koorde.

00217 {
00218     // catch JOIN timer
00219     if (msg->isName("join_timer")) {
00220         handleJoinTimerExpired(msg);
00221     }
00222     // catch STABILIZE timer
00223     else if (msg->isName("stabilize_timer")) {
00224         handleStabilizeTimerExpired(msg);
00225     }
00226     // catch FIX_FINGERS timer
00227     else if (msg->isName("fixfingers_timer")) {
00228         handleFixFingersTimerExpired(msg);
00229     }
00230     // unknown self message
00231     else {
00232         error("Chord::handleTimerEvent(): received self message of "
00233               "unknown type!");
00234     }
00235 }

void Chord::handleUDPMessage ( BaseOverlayMessage msg  )  [virtual]

processes messages from underlay

Parameters:
msg message from UDP

Implements BaseOverlay.

Reimplemented in Koorde.

00239 {
00240     ChordMessage* chordMsg = check_and_cast<ChordMessage*>(msg);
00241     switch(chordMsg->getCommand()) {
00242     case NEWSUCCESSORHINT:
00243         handleNewSuccessorHint(chordMsg);
00244         break;
00245     default:
00246         error("handleUDPMessage(): Unknown message type!");
00247         break;
00248     }
00249 
00250     delete chordMsg;
00251 }

void Chord::initializeFriendModules (  )  [protected, virtual]

initializes finger table and successor list

Reimplemented in Koorde.

00893 {
00894     // initialize finger table
00895     fingerTable->initializeTable(thisNode.key.getLength(), thisNode);
00896 
00897     // initialize successor list
00898     successorList->initializeList(par("successorListSize"), thisNode);
00899 }

void Chord::initializeOverlay ( int  stage  )  [virtual]

Initializes derived-class-attributes.


Initializes derived-class-attributes, called by BaseOverlay::initialize(). By default this method is called once. If more stages are needed one can overload numInitStages() and add more stages.

Parameters:
stage the init stage

Reimplemented from BaseOverlay.

Reimplemented in Koorde.

00037 {
00038     // because of IPAddressResolver, we need to wait until interfaces
00039     // are registered, address auto-assignment takes place etc.
00040     if(stage != MIN_STAGE_OVERLAY)
00041         return;
00042 
00043     // fetch some parameters
00044     useCommonAPIforward = par("useCommonAPIforward");
00045     successorListSize = par("successorListSize");
00046     joinRetry = par("joinRetry");
00047     stabilizeRetry = par("stabilizeRetry");
00048     joinDelay = par("joinDelay");
00049     stabilizeDelay = par("stabilizeDelay");
00050     fixfingersDelay = par("fixfingersDelay");
00051     aggressiveJoinMode = par("aggressiveJoinMode");
00052 
00053     keyLength = OverlayKey::getLength();
00054     missingPredecessorStabRequests = 0;
00055     missingSuccessorStabResponses = 0;
00056 
00057     // statistics
00058     joinCount = 0;
00059     stabilizeCount = 0;
00060     fixfingersCount = 0;
00061     notifyCount = 0;
00062     newsuccessorhintCount = 0;
00063     joinBytesSent = 0;
00064     stabilizeBytesSent = 0;
00065     notifyBytesSent = 0;
00066     fixfingersBytesSent = 0;
00067     newsuccessorhintBytesSent = 0;
00068 
00069 
00070     // find friend modules
00071     findFriendModules();
00072 
00073     // add some watches
00074     WATCH(predecessorNode);
00075     WATCH(thisNode);
00076     WATCH(bootstrapNode);
00077     WATCH(joinRetry);
00078     WATCH(missingPredecessorStabRequests);
00079     WATCH(missingSuccessorStabResponses);
00080 
00081     // self-messages
00082     join_timer = new cMessage("join_timer");
00083     stabilize_timer = new cMessage("stabilize_timer");
00084     fixfingers_timer = new cMessage("fixfingers_timer");
00085 
00086     // initialize chord protocol
00087     changeState(INIT);
00088     changeState(BOOTSTRAP);
00089 }

bool Chord::isResponsible ( const OverlayKey key  )  [virtual]

Query if the node is responsible for a key.

Query if the node currently is responsible for the given key. Usually this means, that the nodeId of this node is close to the key.

Parameters:
key destination key
Returns:
bool true, if the node is responsible for the key.

Reimplemented from BaseOverlay.

00338 {
00339     if (key.isUnspecified())
00340         error("Chord::isResponsible(): key is unspecified!");
00341 
00342     if (state != READY)
00343         return false;
00344 
00345     // if this is the first and only node on the ring, it is responsible
00346     if (predecessorNode.isUnspecified()) {
00347         if(successorList->isEmpty()) {
00348             return true;
00349         } else {
00350             return false;
00351         }
00352     }
00353 
00354     // is the message destined for this node?
00355     if (key.isBetweenR(predecessorNode.key, thisNode.key)) {
00356         return true;
00357     }
00358 
00359     return false;
00360 }

void Chord::predecessorIsDead (  )  [protected, virtual]

Reimplemented in Koorde.

00925 { };

void Chord::receiveChangeNotification ( int  category,
cPolymorphic *  details 
) [virtual]

callback-method for events at the NotificationBoard

Parameters:
category 
details 
Todo:
parameter description, implementation
00106 {
00107     Enter_Method_Silent();
00108     // get new ip address
00109     thisNode.ip = IPAddressResolver().addressOf(
00110                       parentModule()->parentModule()).get4();
00111 
00112     changeState(INIT);
00113     changeState(BOOTSTRAP);
00114 }

void Chord::recordOverlaySentStats ( BaseOverlayMessage msg  )  [virtual]

Collect overlay specific sent messages statistics.

This method is called from BaseOverlay::sendMessageToUDP() for every overlay message that is sent by a node. Use this to collect statistical data for overlay protocol specific message types.

Parameters:
msg The overlay message to be sent to the UDP layer

Reimplemented from BaseOverlay.

Reimplemented in Koorde.

00449 {
00450     BaseOverlayMessage* innerMsg;
00451 
00452     if (msg->getType() == OVERLAYROUTE)
00453         innerMsg = dynamic_cast<BaseOverlayMessage*>(msg->encapsulatedMsg());
00454     else
00455         innerMsg = msg;
00456 
00457     switch (innerMsg->getType()) {
00458 
00459     case OVERLAYSIGNALING: {
00460             ChordMessage* chordMsg = dynamic_cast<ChordMessage*>(innerMsg);
00461             switch(chordMsg->getCommand()) {
00462             case NEWSUCCESSORHINT:
00463                 RECORD_STATS(newsuccessorhintCount++; newsuccessorhintBytesSent +=
00464                                  msg->byteLength());
00465                 break;
00466             }
00467             break;
00468         }
00469 
00470     case RPC: {
00471             if ((dynamic_cast<StabilizeCall*>(innerMsg) != NULL) ||
00472                     (dynamic_cast<StabilizeResponse*>(innerMsg) != NULL)) {
00473                 RECORD_STATS(stabilizeCount++; stabilizeBytesSent +=
00474                                  msg->byteLength());
00475             } else if ((dynamic_cast<NotifyCall*>(innerMsg) != NULL) ||
00476                        (dynamic_cast<NotifyResponse*>(innerMsg) != NULL)) {
00477                 RECORD_STATS(notifyCount++; notifyBytesSent +=
00478                                  msg->byteLength());
00479             } else if ((dynamic_cast<FixfingersCall*>(innerMsg) != NULL) ||
00480                        (dynamic_cast<FixfingersResponse*>(innerMsg) != NULL)) {
00481                 RECORD_STATS(fixfingersCount++; fixfingersBytesSent +=
00482                                  msg->byteLength());
00483             } else if ((dynamic_cast<JoinCall*>(innerMsg) != NULL) ||
00484                        (dynamic_cast<JoinResponse*>(innerMsg) != NULL)) {
00485                 RECORD_STATS(joinCount++; joinBytesSent += msg->byteLength());
00486             }
00487             break;
00488         }
00489     }
00490 }

void Chord::rpcFixfingers ( FixfingersCall call  )  [protected]

Fixfingers Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00860 {
00861     FixfingersResponse* fixfingersResponse =
00862         new FixfingersResponse("FixfingersResponse");
00863 
00864     fixfingersResponse->setSucNode(thisNode);
00865     fixfingersResponse->setFinger(call->getFinger());
00866     fixfingersResponse->setLength(FIXFINGERSRESPONSE_L(fixfingersResponse));
00867 
00868     sendRpcResponse(call, fixfingersResponse);
00869 }

void Chord::rpcJoin ( JoinCall call  )  [protected]

Join Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00656 {
00657     NodeHandle requestor = joinCall->getSrcNode();
00658 
00659     // compile successor list
00660     JoinResponse* joinResponse =
00661         new JoinResponse("JoinResponse");
00662 
00663     int sucNum = successorList->getSize();
00664     joinResponse->setSucNum(sucNum);
00665     joinResponse->setSucNodeArraySize(sucNum);
00666 
00667     for (int k = 0; k < sucNum; k++) {
00668         joinResponse->setSucNode(k, successorList->getSuccessor(k));
00669     }
00670 
00671     // sent our predecessor as hint to the joining node
00672     if (predecessorNode.isUnspecified() && successorList->isEmpty()) {
00673         // we are the only node in the ring
00674         joinResponse->setPreNode(thisNode);
00675     } else {
00676         joinResponse->setPreNode(predecessorNode);
00677     }
00678 
00679     joinResponse->setLength(JOINRESPONSE_L(joinResponse));
00680 
00681     sendRpcResponse(joinCall, joinResponse);
00682 
00683     if (aggressiveJoinMode) {
00684         // aggressiveJoinMode differs from standard join operations:
00685         // 1. set our predecessor pointer to the joining node
00686         // 2. send our old predecessor as hint in JoinResponse msgs
00687         // 3. send a NEWSUCCESSORHINT to our old predecessor to update
00688         //    its successor pointer
00689 
00690         // send NEWSUCCESSORHINT to our old predecessor
00691 
00692         if (!predecessorNode.isUnspecified()) {
00693             NewSuccessorHintMessage* newSuccessorHintMsg =
00694                 new NewSuccessorHintMessage("NEWSUCCESSORHINT");
00695             newSuccessorHintMsg->setCommand(NEWSUCCESSORHINT);
00696 
00697             newSuccessorHintMsg->setSrcNode(thisNode);
00698             newSuccessorHintMsg->setPreNode(requestor);
00699             newSuccessorHintMsg->setLength(
00700                 NEWSUCCESSORHINT_L(newSuccessorHintMsg));
00701 
00702             sendMessageToUDP(predecessorNode, newSuccessorHintMsg);
00703         }
00704 
00705         // the requestor is our new predecessor
00706         predecessorNode = requestor;
00707     }
00708 
00709     // if we don't have a successor, the requestor is also our new successor
00710     if (successorList->isEmpty())
00711         successorList->addSuccessor(requestor);
00712 
00713     updateTooltip();
00714 }

void Chord::rpcNotify ( NotifyCall call  )  [protected]

NOTIFY Remote-Procedure-Call.

Parameters:
call RPC Parameter Message

Reimplemented in Koorde.

00798 {
00799     // our predecessor seems to be alive
00800     missingPredecessorStabRequests = 0;
00801 
00802     NodeHandle predecessor = call->getSrcNode();
00803 
00804     // is the new predecessor closer than the current one?
00805     if (predecessorNode.isUnspecified() ||
00806             predecessor.key.isBetween(predecessorNode.key, thisNode.key)) {
00807         // set up new predecessor
00808         predecessorNode = predecessor;
00809         updateTooltip();
00810     }
00811 
00812     // compile NOTIFY response
00813     NotifyResponse* notifyResponse = new NotifyResponse("NotifyResponse");
00814 
00815     int sucNum = successorList->getSize();
00816     notifyResponse->setSucNum(sucNum);
00817     notifyResponse->setSucNodeArraySize(sucNum);
00818 
00819     for (int k = 0; k < sucNum; k++) {
00820         notifyResponse->setSucNode(k, successorList->getSuccessor(k));
00821     }
00822 
00823     notifyResponse->setLength(NOTIFYRESPONSE_L(notifyResponse));
00824 
00825     sendRpcResponse(call, notifyResponse);
00826 }

void Chord::rpcStabilize ( StabilizeCall call  )  [protected]

STABILIZE Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00759 {
00760     // our predecessor seems to be alive
00761     missingPredecessorStabRequests = 0;
00762 
00763     // reply with StabilizeResponse message
00764     StabilizeResponse* stabilizeResponse =
00765         new StabilizeResponse("StabilizeResponse");
00766     stabilizeResponse->setPreNode(predecessorNode);
00767     stabilizeResponse->setLength(STABILIZERESPONSE_L(stabilizeResponse));
00768 
00769     sendRpcResponse(call, stabilizeResponse);
00770 }

void Chord::successorIsDead (  )  [protected, virtual]

Reimplemented in Koorde.

00926 { };

void Chord::updateTooltip (  )  [virtual]

updates information shown in tk-environment

Reimplemented in Koorde.

00903 {
00904     if (ev.isGUI()) {
00905         std::stringstream ttString;
00906 
00907         // show our predecessor and successor in tooltip
00908         ttString << predecessorNode << endl << thisNode << endl
00909         << successorList->getSuccessor();
00910 
00911         parentModule()->parentModule()->displayString().
00912         setTagArg("tt", 0, ttString.str().c_str());
00913         parentModule()->displayString().
00914         setTagArg("tt", 0, ttString.str().c_str());
00915         displayString().setTagArg("tt", 0, ttString.str().c_str());
00916 
00917         // draw an arrow to our current successor
00918         showOverlayNeighborArrow(successorList->getSuccessor(), true,
00919                                  "m=m,50,0,50,0;o=red,1");
00920         showOverlayNeighborArrow(predecessorNode, false,
00921                                  "m=m,50,100,50,100;o=green,1");
00922     }
00923 }


Member Data Documentation

bool Chord::aggressiveJoinMode [protected]

use modified (faster) JOIN protocol

NodeHandle Chord::bootstrapNode [protected]

node used to bootrap

ChordFingerTable* Chord::fingerTable [protected]

pointer to this node's finger table

cMessage* Chord::fixfingers_timer [protected]

int Chord::fixfingersBytesSent [protected]

int Chord::fixfingersCount [protected]

double Chord::fixfingersDelay [protected]

cMessage* Chord::join_timer [protected]

int Chord::joinBytesSent [protected]

int Chord::joinCount [protected]

double Chord::joinDelay [protected]

int Chord::joinRetry [protected]

int Chord::keyLength [protected]

length of an overlay key in bits

int Chord::missingPredecessorStabRequests [protected]

missing StabilizeCall msgs

int Chord::missingSuccessorStabResponses [protected]

missing StabilizeResponse msgs

int Chord::newsuccessorhintBytesSent [protected]

int Chord::newsuccessorhintCount [protected]

int Chord::notifyBytesSent [protected]

int Chord::notifyCount [protected]

NodeHandle Chord::predecessorNode [protected]

predecessor of this node

cMessage* Chord::stabilize_timer [protected]

int Chord::stabilizeBytesSent [protected]

int Chord::stabilizeCount [protected]

double Chord::stabilizeDelay [protected]

stabilize interval (secs)

int Chord::stabilizeRetry [protected]

// retries before neighbor considered failed

int Chord::state [protected]

current node state

ChordSuccessorList* Chord::successorList [protected]

pointer to this node's successor list

int Chord::successorListSize [protected]


The documentation for this class was generated from the following files:
Generated on Fri May 11 14:52:39 2007 for ITM OverSim by  doxygen 1.4.7