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 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 joinBytesSent
int stabilizeBytesSent
int notifyBytesSent
int fixfingersBytesSent
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]

00089 {
00090     // destroy self timer messages
00091     cancelEvent(join_timer);
00092     cancelEvent(stabilize_timer);
00093     cancelEvent(fixfingers_timer);
00094 
00095     delete join_timer;
00096     delete stabilize_timer;
00097     delete fixfingers_timer;
00098 }


Member Function Documentation

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

changes node state

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

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
00398 {
00399     for (int i = fingerTable->getSize() - 1; i >= 0; i--) {
00400         if (fingerTable->getFinger(i).key.isBetween(thisNode.key, key)) {
00401             // is there a closer preceeding node in the successor list?
00402             for (int j = successorList->getSize() - 1; j >= 0; j--) {
00403                 if (successorList->getSuccessor(j).key.
00404                         isBetween(fingerTable->getFinger(i).key, key)) {
00405                     return successorList->getSuccessor(j);
00406                 }
00407             }
00408 
00409             // if no, settle with the node already found
00410             return fingerTable->getFinger(i);
00411         }
00412     }
00413 
00414     // if no finger is found lookup the rest of the successor list
00415     for (int i = successorList->getSize()-1; i >= 0; i--) {
00416         if(successorList->getSuccessor(i).key.isBetween(thisNode.key, key)) {
00417             return successorList->getSuccessor(i);
00418         }
00419     }
00420 
00421     // if this is the first and only node on the ring, it is responsible
00422     if ((predecessorNode.isUnspecified()) &&
00423             (successorList->getSuccessor() == thisNode)) {
00424         return thisNode;
00425     }
00426 
00427     // if there is still no node found return NodeHandle::UNSPECIFIED_NODE
00428     return NodeHandle::UNSPECIFIED_NODE;
00429 }

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

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

00837 {
00838     fingerTable = check_and_cast<FingerTable*>
00839                   (parentModule()->submodule("fingerTable"));
00840 
00841     successorList = check_and_cast<SuccessorList*>
00842                     (parentModule()->submodule("successorList"));
00843 }

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.

00353 {
00354     NodeVector* nextHop = new NodeVector(1);
00355 
00356     if (state != READY)
00357         return nextHop;
00358 
00359     //     // example code for findNodeExt
00360 
00361     //     if (msg != NULL) {
00362     //  if (!msg->hasObject("findNodeExt")) {
00363     //      ChordFindNodeExtMessage *extMsg =
00364     //          new ChordFindNodeExtMessage("findNodeExt");
00365     //      msg->addObject( extMsg );
00366     //  }
00367 
00368     //  ChordFindNodeExtMessage *extMsg =
00369     //      (ChordFindNodeExtMessage*) msg->getObject("findNodeExt");
00370 
00371     //  cout << "ChordCount: " << extMsg->getChordCount() + 1 << endl;
00372 
00373     //  extMsg->setChordCount(extMsg->getChordCount() + 1);
00374     //     }
00375 
00376     // if key is unspecified, the message is for this node
00377     if (key.isUnspecified()) {
00378         nextHop->add(thisNode);
00379     } else if (isResponsible(key)) {
00380         // the message is destined for this node
00381         nextHop->add(thisNode);
00382     } else if (key.isBetweenR(thisNode.key,
00383                               successorList->getSuccessor().key)) {
00384         // the message destined for our successor
00385         nextHop->add(successorList->getSuccessor());
00386     } else {
00387         // find next hop with finger table
00388         NodeHandle tmpNode = closestPreceedingNode(key);
00389         if (!tmpNode.isUnspecified())
00390             nextHop->add(tmpNode);
00391     }
00392 
00393     return nextHop;
00394 }

void Chord::finishOverlay (  )  [virtual]

collects statisticts

Reimplemented from BaseOverlay.

00434 {
00435     recordScalar("Chord: Sent JOIN Messages (w/o forwarding)", joinCount);
00436     recordScalar("Chord: Sent STABILIZE Messages", stabilizeCount);
00437     recordScalar("Chord: Sent NOTIFY Messages", notifyCount);
00438     recordScalar("Chord: Sent FIX_FINGERS Messages (w/o forwarding)",
00439                  fixfingersCount);
00440 
00441     recordScalar("Chord: Sent JOIN Bytes (w/o forwarding)", joinBytesSent);
00442     recordScalar("Chord: Sent STABILIZE Bytes", stabilizeBytesSent);
00443     recordScalar("Chord: Sent NOTIFY Bytes", notifyBytesSent);
00444     recordScalar("Chord: Sent FIX_FINGERS Bytes (w/o forwarding)",
00445                  fixfingersBytesSent);
00446 
00447     // remove this node from the bootstrap list
00448     bootstrapOracle->removePeer(thisNode);
00449 }

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

handle a expired fix_fingers timer

Parameters:
msg the timer self-message
00546 {
00547     if ((state != READY) || successorList->isEmpty())
00548         return;
00549 
00550     for (uint nextFinger = 0; nextFinger < thisNode.key.getLength();
00551             nextFinger++) {
00552         // calculate "n + 2^(i - 1)"
00553         OverlayKey offset = OverlayKey::pow2(nextFinger);
00554         OverlayKey lookupKey = thisNode.key + offset;
00555 
00556         // send message only for non-trivial fingers
00557         if (offset > successorList->getSuccessor().key - thisNode.key) {
00558             // call FIXFINGER RPC
00559             FixfingersCall* call = new FixfingersCall("FixfingersCall");
00560             call->setFinger(nextFinger);
00561             call->setLength(FIXFINGERSCALL_L(call));
00562             RECORD_STATS(fixfingersCount++; fixfingersBytesSent +=
00563                              call->byteLength());
00564 
00565             sendRpcMessage(NodeHandle::UNSPECIFIED_NODE, call, NULL,
00566                            lookupKey, -1, fixfingersDelay);
00567 
00568         } else {
00569             // let trivial fingers point to the successor node
00570             fingerTable->setFinger(nextFinger,
00571                                    successorList->getSuccessor());
00572         }
00573     }
00574 
00575     // schedule next finger repair process
00576     cancelEvent(fixfingers_timer);
00577     scheduleAt(simulation.simTime() + fixfingersDelay, msg);
00578 }

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

handle a expired join timer

Parameters:
msg the timer self-message
00454 {
00455     // only process timer, if node is not bootstrapped yet
00456     if (state == READY)
00457         return;
00458 
00459     // enter state BOOTSTRAP
00460     if (state != BOOTSTRAP)
00461         changeState(BOOTSTRAP);
00462 
00463     // change bootstrap node from time to time
00464     joinRetry--;
00465     if (joinRetry == 0) {
00466         joinRetry = par("joinRetry");
00467         changeState(BOOTSTRAP);
00468         return;
00469     }
00470 
00471     // call JOIN RPC
00472     JoinCall* call = new JoinCall("JoinCall");
00473     call->setLength(JOINCALL_L(call));
00474 
00475     // statistics
00476     RECORD_STATS(joinCount++; joinBytesSent += call->byteLength());
00477     sendRpcMessage(bootstrapNode, call, NULL, thisNode.key, -1, joinDelay);
00478 
00479 
00480     // schedule next bootstrap process in the case this one fails
00481     cancelEvent(join_timer);
00482     scheduleAt(simulation.simTime() + joinDelay, msg);
00483 }

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

handle a received NEWSUCCESSORHINT message

Parameters:
chordMsg the message to process
00582 {
00583     NewSuccessorHintMessage* newSuccessorHintMsg =
00584         check_and_cast<NewSuccessorHintMessage*>(chordMsg);
00585 
00586     // fetch the successor's predecessor
00587     NodeHandle predecessor = newSuccessorHintMsg->getPreNode();
00588 
00589     // is the successor's predecessor a new successor for this node?
00590     if (predecessor.key.isBetween(thisNode.key,
00591                                   successorList->getSuccessor().key)
00592             || (thisNode.key == successorList->getSuccessor().key)) {
00593         // add the successor's predecessor to the successor list
00594         successorList->addSuccessor(predecessor);
00595         updateTooltip();
00596     }
00597 }

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

Processes Remote-Procedure-Call invokation messages.

Reimplemented from BaseOverlay.

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

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

00828 {
00829     // set new finger pointer
00830     NodeHandle successor = fixfingersResponse->getSucNode();
00831     fingerTable->setFinger(fixfingersResponse->getFinger(), successor);
00832 }

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

00664 {
00665     // determine the numer of successor nodes to add
00666     int sucNum = successorListSize - 1;
00667 
00668     if (joinResponse->getSucNum() < successorListSize - 1) {
00669         sucNum = joinResponse->getSucNum();
00670     }
00671 
00672     successorList->addSuccessor(joinResponse->getSrcNode());
00673 
00674     // add successor node(s)
00675     for (int k = 0; k < sucNum; k++) {
00676         NodeHandle successor = joinResponse->getSucNode(k);
00677         successorList->addSuccessor(successor);
00678     }
00679 
00680     // the sender of this message is our new successor
00681     successorList->addSuccessor(joinResponse->getSrcNode());
00682 
00683     // in aggressiveJoinMode: use hint in JoinResponse
00684     // to set our new predecessor
00685     if (aggressiveJoinMode) {
00686         predecessorNode = joinResponse->getPreNode();
00687     }
00688 
00689     updateTooltip();
00690 
00691     changeState(READY);
00692 
00693     // immediate stabilization protocol
00694     cancelEvent(stabilize_timer);
00695     scheduleAt(simulation.simTime(), stabilize_timer);
00696 
00697     // immediate finger repair protocol
00698     cancelEvent(fixfingers_timer);
00699     scheduleAt(simulation.simTime(), fixfingers_timer);
00700 }

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

00782 {
00783     if (successorList->getSuccessor() != notifyResponse->getSrcNode()) {
00784         EV << "Chord::handleRpcNotifyResponse: The srcNode of the received "
00785         << "NotifyResponse is not our current successor!" << endl;
00786         return;
00787     }
00788 
00789     // determine number of successor nodes to add
00790     int sucNum = successorListSize - 1;
00791     if (notifyResponse->getSucNum() < successorListSize - 1) {
00792         sucNum = notifyResponse->getSucNum();
00793     }
00794 
00795     // replace our successor list by our successor's successor list
00796     // and add our current successor to the list
00797     successorList->clear();
00798     successorList->addSuccessor(notifyResponse->getSrcNode());
00799     for (int k = 0; k < sucNum; k++) {
00800         NodeHandle successor = notifyResponse->getSucNode(k);
00801         // don't add nodes, if this would change our successor
00802         if (!successor.key.isBetweenLR(thisNode.key,
00803                                        notifyResponse->getSrcNode().key)) {
00804             successorList->addSuccessor(successor);
00805         }
00806     }
00807     updateTooltip();
00808 }

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.

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

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

00720 {
00721     // our successor seems to be alive
00722     missingSuccessorStabResponses = 0;
00723 
00724     // fetch the successor's predecessor
00725     NodeHandle predecessor = stabilizeResponse->getPreNode();
00726 
00727     // is the successor's predecessor a new successor for this node?
00728     if (successorList->isEmpty() ||
00729             predecessor.key.isBetween(thisNode.key,
00730                                       successorList->getSuccessor().key)) {
00731         // add the successor's predecessor to the successor list
00732         successorList->addSuccessor(predecessor);
00733         updateTooltip();
00734     }
00735 
00736     // compile NOTIFY RPC
00737     NotifyCall* notifyCall = new NotifyCall("NotifyCall");
00738     notifyCall->setLength(NOTIFYCALL_L(notifyCall));
00739 
00740     // notify the current first successor
00741     RECORD_STATS(notifyCount++; notifyBytesSent += notifyCall->byteLength());
00742     sendRpcMessage(successorList->getSuccessor(), notifyCall);
00743 }

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.

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

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

handle a expired stabilize timer

Parameters:
msg the timer self-message
00487 {
00488     if (state != READY)
00489         return;
00490 
00491     if (missingPredecessorStabRequests >= stabilizeRetry) {
00492         // predecessor node seems to be dead
00493         // remove it from the predecessor / successor lists
00494         successorList->removeSuccessor(predecessorNode);
00495         predecessorNode = NodeHandle::UNSPECIFIED_NODE;
00496 
00497         missingPredecessorStabRequests = 0;
00498         updateTooltip();
00499     }
00500 
00501     if (missingSuccessorStabResponses >= stabilizeRetry) {
00502         // successor node seems to be dead
00503         // remove it from the predecessor / successor list
00504         NodeHandle successor = successorList->popSuccessor();
00505 
00506         // if we had a ring consisting of 2 nodes and our successor seems
00507         // to be dead. Remove also predecessor because the successor
00508         // and predecessor are the same node
00509         if ((!predecessorNode.isUnspecified()) &&
00510             predecessorNode == successor) {
00511             predecessorNode = NodeHandle::UNSPECIFIED_NODE;
00512         }
00513 
00514         missingSuccessorStabResponses = 0;
00515         updateTooltip();
00516 
00517         if (successorList->isEmpty()) {
00518             changeState(INIT);
00519             changeState(BOOTSTRAP);
00520             return;
00521         }
00522     }
00523 
00524     if (!successorList->isEmpty()) {
00525         // call STABILIZE RPC
00526         StabilizeCall* call = new StabilizeCall("StabilizeCall");
00527         call->setLength(STABILIZECALL_L(call));
00528 
00529         // statistics
00530         RECORD_STATS(stabilizeCount++;
00531                      stabilizeBytesSent += call->byteLength());
00532         sendRpcMessage(successorList->getSuccessor(), call);
00533 
00534 
00535         missingPredecessorStabRequests++;
00536         missingSuccessorStabResponses++;
00537     }
00538 
00539     // schedule next stabilization process
00540     cancelEvent(stabilize_timer);
00541     scheduleAt(simulation.simTime() + stabilizeDelay, msg);
00542 }

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

handles self-messages

Parameters:
msg the self-message

Reimplemented from BaseOverlay.

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

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

processes messages from underlay

Parameters:
msg message from UDP

Implements BaseOverlay.

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

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

initializes finger table and successor list

00848 {
00849     // initialize finger table
00850     fingerTable->initializeTable(thisNode.key.getLength(), thisNode);
00851 
00852     // initialize successor list
00853     successorList->initializeList(par("successorListSize"), thisNode);
00854 }

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     joinBytesSent = 0;
00062     stabilizeBytesSent = 0;
00063     notifyBytesSent = 0;
00064     fixfingersBytesSent = 0;
00065 
00066     // find friend modules
00067     findFriendModules();
00068 
00069     // add some watches
00070     WATCH(predecessorNode);
00071     WATCH(thisNode);
00072     WATCH(bootstrapNode);
00073     WATCH(joinRetry);
00074     WATCH(missingPredecessorStabRequests);
00075     WATCH(missingSuccessorStabResponses);
00076 
00077     // self-messages
00078     join_timer = new cMessage("join_timer");
00079     stabilize_timer = new cMessage("stabilize_timer");
00080     fixfingers_timer = new cMessage("fixfingers_timer");
00081 
00082     // initialize chord protocol
00083     changeState(INIT);
00084     changeState(BOOTSTRAP);
00085 }

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.

00327 {
00328     if (key.isUnspecified())
00329         error("Chord::isResponsible(): key is unspecified!");
00330 
00331     if (state != READY)
00332         return false;
00333 
00334     // if this is the first and only node on the ring, it is responsible
00335     if (predecessorNode.isUnspecified()) {
00336         if(successorList->isEmpty()) {
00337             return true;
00338         } else {
00339             return false;
00340         }
00341     }
00342 
00343     // is the message destined for this node?
00344     if (key.isBetweenR(predecessorNode.key, thisNode.key)) {
00345         return true;
00346     }
00347 
00348     return false;
00349 }

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

callback-method for events at the NotificationBoard

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

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

Fixfingers Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00812 {
00813     FixfingersResponse* fixfingersResponse =
00814         new FixfingersResponse("FixfingersResponse");
00815 
00816     fixfingersResponse->setSucNode(successorList->getSuccessor());
00817     fixfingersResponse->setFinger(call->getFinger());
00818     fixfingersResponse->setLength(FIXFINGERSRESPONSE_L(fixfingersResponse));
00819 
00820     RECORD_STATS(fixfingersCount++; fixfingersBytesSent +=
00821                      fixfingersResponse->byteLength());
00822 
00823     sendRpcResponse(call, fixfingersResponse);
00824 }

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

Join Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00601 {
00602     NodeHandle requestor = joinCall->getSrcNode();
00603 
00604     // compile successor list
00605     JoinResponse* joinResponse =
00606         new JoinResponse("JoinResponse");
00607 
00608     int sucNum = successorList->getSize();
00609     joinResponse->setSucNum(sucNum);
00610     joinResponse->setSucNodeArraySize(sucNum);
00611 
00612     for (int k = 0; k < sucNum; k++) {
00613         joinResponse->setSucNode(k, successorList->getSuccessor(k));
00614     }
00615 
00616     // sent our predecessor as hint to the joining node
00617     if (predecessorNode.isUnspecified() && successorList->isEmpty()) {
00618         // we are the only node in the ring
00619         joinResponse->setPreNode(thisNode);
00620     } else {
00621         joinResponse->setPreNode(predecessorNode);
00622     }
00623 
00624     joinResponse->setLength(JOINRESPONSE_L(joinResponse));
00625 
00626     // join-rsp added to joinCount
00627     RECORD_STATS(joinCount++; joinBytesSent += joinResponse->byteLength());
00628     // send back successor list
00629     sendRpcResponse(joinCall, joinResponse);
00630 
00631     if (aggressiveJoinMode) {
00632         // aggressiveJoinMode differs from standard join operations:
00633         // 1. set our predecessor pointer to the joining node
00634         // 2. send our old predecessor as hint in JoinResponse msgs
00635         // 3. send a NEWSUCCESSORHINT to our old predecessor to update
00636         //    its successor pointer
00637 
00638         // send NEWSUCCESSORHINT to our old predecessor
00639 
00640         if (!predecessorNode.isUnspecified()) {
00641             NewSuccessorHintMessage* newSuccessorHintMsg =
00642                 new NewSuccessorHintMessage("NEWSUCCESSORHINT");
00643             newSuccessorHintMsg->setCommand(NEWSUCCESSORHINT);
00644 
00645             newSuccessorHintMsg->setSrcNode(thisNode);
00646             newSuccessorHintMsg->setPreNode(requestor);
00647             newSuccessorHintMsg->setLength(
00648                 NEWSUCCESSORHINT_L(newSuccessorHintMsg));
00649             sendMessageToUDP(predecessorNode, newSuccessorHintMsg);
00650         }
00651 
00652         // the requestor is our new predecessor
00653         predecessorNode = requestor;
00654     }
00655 
00656     // if we don't have a successor, the requestor is also our new successor
00657     if (successorList->isEmpty())
00658         successorList->addSuccessor(requestor);
00659 
00660     updateTooltip();
00661 }

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

NOTIFY Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00747 {
00748     // our predecessor seems to be alive
00749     missingPredecessorStabRequests = 0;
00750 
00751     NodeHandle predecessor = call->getSrcNode();
00752 
00753     // is the new predecessor closer than the current one?
00754     if (predecessorNode.isUnspecified() ||
00755             predecessor.key.isBetween(predecessorNode.key, thisNode.key)) {
00756         // set up new predecessor
00757         predecessorNode = predecessor;
00758         updateTooltip();
00759     }
00760 
00761     // compile NOTIFY response
00762     NotifyResponse* notifyResponse = new NotifyResponse("NotifyResponse");
00763 
00764     int sucNum = successorList->getSize();
00765     notifyResponse->setSucNum(sucNum);
00766     notifyResponse->setSucNodeArraySize(sucNum);
00767 
00768     for (int k = 0; k < sucNum; k++) {
00769         notifyResponse->setSucNode(k, successorList->getSuccessor(k));
00770     }
00771 
00772     notifyResponse->setLength(NOTIFYRESPONSE_L(notifyResponse));
00773 
00774     // send back successor list
00775     RECORD_STATS(notifyCount++; notifyBytesSent +=
00776                      notifyResponse->byteLength());
00777     sendRpcResponse(call, notifyResponse);
00778 }

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

STABILIZE Remote-Procedure-Call.

Parameters:
call RPC Parameter Message
00704 {
00705     // our predecessor seems to be alive
00706     missingPredecessorStabRequests = 0;
00707 
00708     // reply with StabilizeResponse message
00709     StabilizeResponse* stabilizeResponse =
00710         new StabilizeResponse("StabilizeResponse");
00711     stabilizeResponse->setPreNode(predecessorNode);
00712     stabilizeResponse->setLength(STABILIZERESPONSE_L(stabilizeResponse));
00713 
00714     RECORD_STATS(stabilizeCount++; stabilizeBytesSent +=
00715                      stabilizeResponse->byteLength());
00716     sendRpcResponse(call, stabilizeResponse);
00717 }

void Chord::updateTooltip (  )  [virtual]

updates information shown in tk-environment

00858 {
00859     if (ev.isGUI()) {
00860         std::stringstream ttString;
00861 
00862         // show our predecessor and successor in tooltip
00863         ttString << predecessorNode << endl << thisNode << endl
00864         << successorList->getSuccessor();
00865 
00866         parentModule()->parentModule()->displayString().
00867         setTagArg("tt", 0, ttString.str().c_str());
00868         parentModule()->displayString().
00869         setTagArg("tt", 0, ttString.str().c_str());
00870         displayString().setTagArg("tt", 0, ttString.str().c_str());
00871 
00872         // draw an arrow to our current successor
00873         showOverlayNeighborArrow(successorList->getSuccessor(), true,
00874                                  "m=m,50,0,50,0;o=red,1");
00875         showOverlayNeighborArrow(predecessorNode, false,
00876                                  "m=m,50,100,50,100;o=green,1");
00877     }
00878 }


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::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 Fri Dec 15 17:50:30 2006 for ITM OverSim by  doxygen 1.4.7