Chord Class Reference

#include <Chord.h>

Inheritance diagram for Chord:

BaseOverlay RpcListener 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, FingerTable, SuccessorList


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
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.
void handleRpcResponse (BaseResponseMessage *msg, int rpcId, simtime_t rtt)
 This method is called if an RPC response has been received.
void handleRpcTimeout (BaseCallMessage *msg, const NodeHandle &dest, int rpcId)
 This method is called if an RPC timeout has been reached.
void handleRpcJoinResponse (JoinResponse *joinResponse)
void handleRpcNotifyResponse (NotifyResponse *notifyResponse)
void handleRpcStabilizeResponse (StabilizeResponse *stabilizeResponse)
void handleRpcFixfingersResponse (FixfingersResponse *fixfingersResponse)

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
FingerTablefingerTable
 pointer to this node's finger table
SuccessorListsuccessorList
 pointer to this node's successor list


Constructor & Destructor Documentation

Chord::~Chord (  )  [virtual]

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


Member Function Documentation

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

changes node state

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

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

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

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

00874 {
00875     fingerTable = check_and_cast<FingerTable*>
00876                   (parentModule()->submodule("fingerTable"));
00877 
00878     successorList = check_and_cast<SuccessorList*>
00879                     (parentModule()->submodule("successorList"));
00880 }

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.

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

void Chord::finishOverlay (  )  [virtual]

collects statisticts

Reimplemented from BaseOverlay.

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

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

handle a expired fix_fingers timer

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

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

handle a expired join timer

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

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

handle a received NEWSUCCESSORHINT message

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

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

Processes Remote-Procedure-Call invokation messages.

Reimplemented from BaseOverlay.

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

void Chord::handleRpcFixfingersResponse ( FixfingersResponse *  fixfingersResponse  )  [protected]

00865 {
00866     // set new finger pointer
00867     NodeHandle successor = fixfingersResponse->getSucNode();
00868     fingerTable->setFinger(fixfingersResponse->getFinger(), successor);
00869 }

void Chord::handleRpcJoinResponse ( JoinResponse *  joinResponse  )  [protected]

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

void Chord::handleRpcNotifyResponse ( NotifyResponse *  notifyResponse  )  [protected]

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

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.

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

void Chord::handleRpcStabilizeResponse ( StabilizeResponse *  stabilizeResponse  )  [protected]

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

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 from RpcListener.

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

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

handle a expired stabilize timer

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

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

handles self-messages

Parameters:
msg the self-message

Reimplemented from BaseOverlay.

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

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

processes messages from underlay

Parameters:
msg message from UDP

Implements BaseOverlay.

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

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

initializes finger table and successor list

00885 {
00886     // initialize finger table
00887     fingerTable->initializeTable(thisNode.key.getLength(), thisNode);
00888 
00889     // initialize successor list
00890     successorList->initializeList(par("successorListSize"), thisNode);
00891 }

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.

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     successorListSize = par("successorListSize");
00045     joinRetry = par("joinRetry");
00046     stabilizeRetry = par("stabilizeRetry");
00047     joinDelay = par("joinDelay");
00048     stabilizeDelay = par("stabilizeDelay");
00049     fixfingersDelay = par("fixfingersDelay");
00050     aggressiveJoinMode = par("aggressiveJoinMode");
00051 
00052     keyLength = OverlayKey::getLength();
00053     missingPredecessorStabRequests = 0;
00054     missingSuccessorStabResponses = 0;
00055 
00056     // statistics
00057     joinCount = 0;
00058     stabilizeCount = 0;
00059     fixfingersCount = 0;
00060     notifyCount = 0;
00061     newsuccessorhintCount = 0;
00062     joinBytesSent = 0;
00063     stabilizeBytesSent = 0;
00064     notifyBytesSent = 0;
00065     fixfingersBytesSent = 0;
00066     newsuccessorhintBytesSent = 0;
00067 
00068 
00069     // find friend modules
00070     findFriendModules();
00071 
00072     // add some watches
00073     WATCH(predecessorNode);
00074     WATCH(thisNode);
00075     WATCH(bootstrapNode);
00076     WATCH(joinRetry);
00077     WATCH(missingPredecessorStabRequests);
00078     WATCH(missingSuccessorStabResponses);
00079 
00080     // self-messages
00081     join_timer = new cMessage("join_timer");
00082     stabilize_timer = new cMessage("stabilize_timer");
00083     fixfingers_timer = new cMessage("fixfingers_timer");
00084 
00085     // initialize chord protocol
00086     changeState(INIT);
00087     changeState(BOOTSTRAP);
00088 }

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.

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

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

callback-method for events at the NotificationBoard

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

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.

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

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

Fixfingers Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00852 {
00853     FixfingersResponse* fixfingersResponse =
00854         new FixfingersResponse("FixfingersResponse");
00855 
00856     fixfingersResponse->setSucNode(thisNode);
00857     fixfingersResponse->setFinger(call->getFinger());
00858     fixfingersResponse->setLength(FIXFINGERSRESPONSE_L(fixfingersResponse));
00859 
00860     sendRpcResponse(call, fixfingersResponse);
00861 }

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

Join Remote-Procedure-Call.

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

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

NOTIFY Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00790 {
00791     // our predecessor seems to be alive
00792     missingPredecessorStabRequests = 0;
00793 
00794     NodeHandle predecessor = call->getSrcNode();
00795 
00796     // is the new predecessor closer than the current one?
00797     if (predecessorNode.isUnspecified() ||
00798             predecessor.key.isBetween(predecessorNode.key, thisNode.key)) {
00799         // set up new predecessor
00800         predecessorNode = predecessor;
00801         updateTooltip();
00802     }
00803 
00804     // compile NOTIFY response
00805     NotifyResponse* notifyResponse = new NotifyResponse("NotifyResponse");
00806 
00807     int sucNum = successorList->getSize();
00808     notifyResponse->setSucNum(sucNum);
00809     notifyResponse->setSucNodeArraySize(sucNum);
00810 
00811     for (int k = 0; k < sucNum; k++) {
00812         notifyResponse->setSucNode(k, successorList->getSuccessor(k));
00813     }
00814 
00815     notifyResponse->setLength(NOTIFYRESPONSE_L(notifyResponse));
00816 
00817     sendRpcResponse(call, notifyResponse);
00818 }

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

STABILIZE Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00751 {
00752     // our predecessor seems to be alive
00753     missingPredecessorStabRequests = 0;
00754 
00755     // reply with StabilizeResponse message
00756     StabilizeResponse* stabilizeResponse =
00757         new StabilizeResponse("StabilizeResponse");
00758     stabilizeResponse->setPreNode(predecessorNode);
00759     stabilizeResponse->setLength(STABILIZERESPONSE_L(stabilizeResponse));
00760 
00761     sendRpcResponse(call, stabilizeResponse);
00762 }

void Chord::updateTooltip (  )  [virtual]

updates information shown in tk-environment

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


Member Data Documentation

bool Chord::aggressiveJoinMode [protected]

use modified (faster) JOIN protocol

NodeHandle Chord::bootstrapNode [protected]

node used to bootrap

FingerTable* 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

SuccessorList* 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 Wed Apr 4 13:37:06 2007 for ITM OverSim by  doxygen 1.4.7