Pastry Class Reference

#include <Pastry.h>

Inheritance diagram for Pastry:

BasePastry BaseOverlay BaseRpc TopologyVis RpcListener

List of all members.


Detailed Description

Pastry overlay module.

Author:
Felix Palmen
See also:
BaseOverlay

Public Member Functions

virtual ~Pastry ()
virtual void initializeOverlay (int stage)
 Initializes derived-class-attributes.
virtual void handleTimerEvent (cMessage *msg)
 Processes "timer" self-messages.
virtual void handleUDPMessage (BaseOverlayMessage *msg)
 Processes messages from underlay.
void handleStateMessage (PastryStateMessage *msg)
 processes state messages, merging with own state tables

Protected Member Functions

virtual void changeState (int toState)
 changes node state

Private Member Functions

void doSecondStage (void)
 do the second stage of initialization as described in the paper
bool handleFailedNode (const TransportAddress &failed)
 notifies leafset and routingtable of a failed node and sends out a repair request if possible
void checkProxCache (void)
 checks whether proxCache is complete, takes appropriate actions depending on the protocol state
void doJoinUpdate (void)
 send updated state to all nodes when entering ready state
virtual void joinOverlay ()
 Join the overlay with a given nodeID in thisNode.key.

Private Attributes

double secondStageWaitAmount
double ringCheckInterval
double discoveryTimeoutAmount
int depth
bool useSecondStage
bool sendStateAtLeafsetRepair
bool overrideOldPastry
bool overrideNewPastry
cMessage * secondStageWait
cMessage * ringCheck
cMessage * discoveryTimeout

Constructor & Destructor Documentation

Pastry::~Pastry (  )  [virtual]

00041 {
00042     // destroy self timer messages
00043     cancelAndDelete(joinTimeout);
00044     cancelAndDelete(readyWait);
00045     cancelAndDelete(joinUpdateWait);
00046     cancelAndDelete(secondStageWait);
00047     cancelAndDelete(ringCheck);
00048     if (useDiscovery) cancelAndDelete(discoveryTimeout);
00049     if (periodicMaintenance) cancelAndDelete(repairTaskTimeout);
00050 
00051     purgeVectors();
00052 }


Member Function Documentation

void Pastry::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.

00055 {
00056     if ( stage != MIN_STAGE_OVERLAY )
00057         return;
00058 
00059     // Pastry provides KBR services
00060     kbr = true;
00061 
00062     baseInit();
00063 
00064     useSecondStage = par("useSecondStage");
00065     useDiscovery = par("useDiscovery");
00066     periodicMaintenance = par("periodicMaintenance");
00067     secondStageWaitAmount = par("secondStageWait");
00068     discoveryTimeoutAmount = par("discoveryTimeoutAmount");
00069     repairTaskTimeoutAmount = par("repairTaskTimeoutAmount");
00070     sendStateAtLeafsetRepair = par("sendStateAtLeafsetRepair");
00071     ringCheckInterval = par("ringCheckInterval");
00072 
00073     overrideOldPastry = par("overrideOldPastry");
00074     overrideNewPastry = par("overrideNewPastry");
00075 
00076     if (overrideOldPastry) {
00077         useSecondStage = true;
00078         useDiscovery = false;
00079         periodicMaintenance = false;
00080         sendStateAtLeafsetRepair = true;
00081     }
00082 
00083     if (overrideNewPastry) {
00084         useSecondStage = false;
00085         useDiscovery = true;
00086         periodicMaintenance = true;
00087         discoveryTimeoutAmount = 0.4;
00088         repairTaskTimeoutAmount = 60;
00089         sendStateAtLeafsetRepair = false;
00090     }
00091 
00092     joinTimeout = new cMessage("joinTimeout");
00093     readyWait = new cMessage("readyWait");
00094     secondStageWait = new cMessage("secondStageWait");
00095     joinUpdateWait = new cMessage("joinUpdateWait");
00096     ringCheck = new cMessage("ringCheck");
00097 
00098     if (useDiscovery) discoveryTimeout = new cMessage("discoveryTimeout");
00099     if (periodicMaintenance) repairTaskTimeout = new cMessage("repairTaskTimeout");
00100 
00101     sendPullFlag = false;
00102 
00103 }

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

Processes "timer" self-messages.

Parameters:
msg A self-message

Reimplemented from BaseOverlay.

00195 {
00196 
00197     if (msg->isName("joinTimeout")) {
00198         EV << "Pastry: join timeout expired, restarting..." << endl;
00199         //std::cout << simTime() << " " << thisNode.ip << " " << stReceived.size() <<" Pastry: join timeout expired, restarting..." << std::endl;
00200         joinOverlay();
00201     } else if (msg->isName("readyWait")) {
00202         if (partialJoinPath) {
00203             RECORD_STATS(joinPartial++);
00204             sort(stReceived.begin(), stReceived.end(), stateMsgIsSmaller);
00205 
00206             // start pinging the nodes found in the first state message:
00207             stReceivedPos = stReceived.begin();
00208             stateCache = *stReceivedPos;
00209             EV << "Pastry: joining despite some missing STATE messages."
00210                << endl;
00211             pingNodes();
00212         } else {
00213             EV << "Pastry: timeout waiting for missing state messages in JOIN "
00214                 "state, restarting..." << endl;
00215             //std::cout << thisNode.ip << "Pastry: timeout waiting for missing state messages in JOIN "
00216             //                "state, restarting..." << std::endl;
00217             joinOverlay();
00218         }
00219     } else if (msg->isName("joinUpdateWait")) {
00220         EV << "Pastry: sending state updates to all nodes." << endl;
00221         doJoinUpdate();
00222     } else if (msg->isName("secondStageWait")) {
00223         EV << "Pastry: sending STATE requests to all nodes in second stage "
00224             "of initialization." << endl;
00225         doSecondStage();
00226     } else if (msg->isName("ringCheck")) {
00227         if (state == READY) {
00228             // ping direct neighbors on the ring:
00229             const NodeHandle& pred = leafSet->getPredecessor();
00230             const NodeHandle& succ = leafSet->getSuccessor();
00231             if (! pred.isUnspecified()) {
00232                 pingNode(pred, timeoutPing, pingRetries,
00233                          NULL, "PING ring check");
00234             }
00235             if (! succ.isUnspecified()) {
00236                 pingNode(succ, timeoutPing, pingRetries,
00237                          NULL, "PING ring check");
00238             }
00239         }
00240         scheduleAt(simTime()+ringCheckInterval, ringCheck);
00241     } else if (msg->isName("sendStateWait")) {
00242         PastrySendState* sendStateMsg = check_and_cast<PastrySendState*>(msg);
00243 
00244         std::vector<PastrySendState*>::iterator pos =
00245             std::find(sendStateWait.begin(), sendStateWait.end(),
00246                       sendStateMsg);
00247         if (pos != sendStateWait.end()) sendStateWait.erase(pos);
00248 
00249         sendStateTables(sendStateMsg->getDest());
00250         delete sendStateMsg;
00251     }
00252 
00253     else if (msg->isName("discoveryTimeout")) {
00254 
00255         if ((depth == 0) && (nearNodeImproved)) depth++; //repeat last step if closer node was found
00256         if ((depth == 0) || (pingedNodes < 1)) changeState(JOINING_2);
00257         else {
00258             PastryRoutingRowRequestMessage* msg = new PastryRoutingRowRequestMessage("ROWREQ");
00259             msg->setPastryMsgType(PASTRY_MSG_ROWREQ);
00260             msg->setStatType(MAINTENANCE_STAT);
00261             msg->setSendStateTo(thisNode);
00262             msg->setRow(depth);
00263             msg->setLength(PASTRYRTREQ_L(msg));
00264             RECORD_STATS(routingTableReqSent++; routingTableReqBytesSent += msg->byteLength());
00265             sendMessageToUDP(nearNode, msg);
00266         }
00267     }
00268 
00269     else if (msg->isName("repairTaskTimeout")) {
00270         EV << "Pastry: starting routing table maintenance" << endl;
00271         doRoutingTableMaintenance();
00272         scheduleAt(simTime()+repairTaskTimeoutAmount, repairTaskTimeout);
00273     }
00274 
00275 }

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

Processes messages from underlay.

Parameters:
msg Message from UDP

Reimplemented from BaseOverlay.

00278 {
00279     PastryMessage* pastryMsg = check_and_cast<PastryMessage*>(msg);
00280     uint type = pastryMsg->getPastryMsgType();
00281 
00282     if (debugOutput) {
00283         EV << "Pastry: incoming message of type ";
00284         switch(type) {
00285         case PASTRY_MSG_STD:
00286             EV << "PASTRY_MSG_STD";
00287             break;
00288         case PASTRY_MSG_JOIN:
00289             EV << "PASTRY_MSG_JOIN";
00290             break;
00291         case PASTRY_MSG_STATE:
00292             EV << "PASTRY_MSG_STATE";
00293             break;
00294         case PASTRY_MSG_LEAFSET:
00295             EV << "PASTRY_MSG_LEAFSET";
00296             break;
00297         case PASTRY_MSG_ROWREQ:
00298             EV << "PASTRY_MSG_ROWREQ";
00299             break;
00300         case PASTRY_MSG_RROW:
00301             EV << "PASTRY_MSG_RROW";
00302             break;
00303         case PASTRY_MSG_REQ:
00304             EV << "PASTRY_MSG_REQ";
00305             break;
00306         default:
00307             EV << "UNKNOWN (" << type <<")";
00308             break;
00309         }
00310         EV << endl;
00311     }
00312 
00313     switch (type) {
00314     case PASTRY_MSG_STD:
00315         opp_error("Pastry received PastryMessage of unknown type!");
00316         break;
00317 
00318     case PASTRY_MSG_JOIN: {
00319         PastryJoinMessage* jmsg =
00320             check_and_cast<PastryJoinMessage*>(pastryMsg);
00321         RECORD_STATS(joinReceived++; joinBytesReceived +=
00322                      jmsg->byteLength());
00323         if (state != READY) {
00324             if (jmsg->getSendStateTo() == thisNode) {
00325                 EV << "[Pastry::handleUDPMessage() @ " << thisNode.ip
00326                    << " (" << thisNode.key.toString(16) << ")]\n"
00327                    << "    PastryJoinMessage received by originator!";
00328             } else {
00329                 EV << "Pastry: received join message before reaching "
00330                    << "READY state, dropping message!" << endl;
00331             }
00332         }
00333         else if (jmsg->getSendStateTo() == thisNode) {
00334             EV << "[Pastry::handleUDPMessage() @ " << thisNode.ip
00335                << " (" << thisNode.key.toString(16) << ")]\n"
00336                << "    PastryJoinMessage gets dropped because it is "
00337                << "outdated and has been received by originator!"
00338                << endl;
00339         } else {
00340             OverlayCtrlInfo* overlayCtrlInfo
00341                 = check_and_cast<OverlayCtrlInfo*>(jmsg->controlInfo());
00342 
00343             uint joinHopCount =  overlayCtrlInfo->getHopCount();
00344             //std::cout << "-> " << jmsg->getSendStateTo().ip << " "
00345             //          << joinHopCount << " ";
00346             if ((joinHopCount > 1) &&
00347                 ((defaultRoutingType == ITERATIVE_ROUTING) ||
00348                  (defaultRoutingType == EXHAUSTIVE_ITERATIVE_ROUTING)))
00349                  joinHopCount--;
00350             //std::cout << joinHopCount << std::endl;
00351 
00352             sendStateTables(jmsg->getSendStateTo(),
00353                             PASTRY_STATE_JOIN, joinHopCount, true);
00354         }
00355 
00356         delete jmsg;
00357     }
00358         break;
00359 
00360     case PASTRY_MSG_LEAFSET: {
00361         PastryLeafsetMessage* lmsg =
00362             check_and_cast<PastryLeafsetMessage*>(pastryMsg);
00363         RECORD_STATS(leafsetReceived++; leafsetBytesReceived +=
00364             lmsg->byteLength());
00365 
00366         if (state == DISCOVERY) {
00367             uint lsSize = lmsg->getLeafSetArraySize();
00368             const NodeHandle* node;
00369             pingedNodes = 0;
00370 
00371             for (uint i = 0; i < lsSize; i++) {
00372                 node = &(lmsg->getLeafSet(i));
00373                 // unspecified nodes not considered
00374                 if ( !(node->isUnspecified()) ) {
00375                     pingNode(*node, discoveryTimeoutAmount, 0,
00376                              NULL, "PING received leafs for nearest node");
00377                     pingedNodes++;
00378                }
00379             }
00380 
00381             EV << "Pastry: received leafset, waiting for pings" << endl;
00382             scheduleAt(simTime()+discoveryTimeoutAmount, discoveryTimeout);
00383             delete lmsg;
00384         }
00385 
00386         else if (state == READY) {
00387             handleLeafsetMessage(lmsg, false);
00388 
00389         } else {
00390             delete lmsg;
00391         }
00392     }
00393         break;
00394 
00395     case PASTRY_MSG_ROWREQ: {
00396         PastryRoutingRowRequestMessage* rtrmsg =
00397             check_and_cast<PastryRoutingRowRequestMessage*>(pastryMsg);
00398         RECORD_STATS(routingTableReqReceived++; routingTableReqBytesReceived +=
00399             rtrmsg->byteLength());
00400         if (state == READY)
00401             if (rtrmsg->getRow() == -1)
00402                 sendRoutingRow(rtrmsg->getSendStateTo(), routingTable->getLastRow());
00403                 else if (rtrmsg->getRow() > routingTable->getLastRow())
00404                     EV << "Pastry: received request for nonexistent routing"
00405                        << "table row, dropping message!" << endl;
00406                 else sendRoutingRow(rtrmsg->getSendStateTo(), rtrmsg->getRow());
00407         else
00408             EV << "Pastry: received routing table request before reaching "
00409                << "READY state, dropping message!" << endl;
00410         delete rtrmsg;
00411     }
00412         break;
00413 
00414     case PASTRY_MSG_RROW: {
00415         PastryRoutingRowMessage* rtmsg =
00416             check_and_cast<PastryRoutingRowMessage*>(pastryMsg);
00417         RECORD_STATS(routingTableReceived++; routingTableBytesReceived +=
00418             rtmsg->byteLength());
00419 
00420         if (state == DISCOVERY) {
00421             //int rtSize = rtmsg->getRoutingTableArraySize();
00422             uint nodesPerRow = routingTable->nodesPerRow;
00423             const NodeHandle* node;
00424             if (depth == -1) depth = rtmsg->getRow();
00425             pingedNodes = 0;
00426             nearNodeImproved = false;
00427 
00428             if (depth > 0) {
00429                 for (uint i = 0; i < nodesPerRow; i++) {
00430                     node = &(rtmsg->getRoutingTable(i));
00431                     // unspecified nodes not considered
00432                     if ( !(node->isUnspecified()) ) {
00433                         // we look for best connection here, so Timeout is short and there are no retries
00434                         pingNode(*node, discoveryTimeoutAmount, 0,
00435                                  NULL, "PING received routing table for nearest node");
00436                         pingedNodes++;
00437                     }
00438                 }
00439                 depth--;
00440             }
00441             EV << "Pastry: received routing table, waiting for pings" << endl;
00442             scheduleAt(simTime()+discoveryTimeoutAmount, discoveryTimeout);
00443 
00444         }
00445 
00446         else if (state == READY) {
00447 
00448             uint nodesPerRow = routingTable->nodesPerRow;
00449             PastryStateMessage* stateMsg;
00450 
00451 
00452             stateMsg = new PastryStateMessage("STATE");
00453             stateMsg->setTimestamp(rtmsg->getTimestamp());
00454             stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
00455             stateMsg->setStatType(MAINTENANCE_STAT);
00456             stateMsg->setSender(rtmsg->getSender());
00457             stateMsg->setLeafSetArraySize(0);
00458             stateMsg->setNeighborhoodSetArraySize(0);
00459             stateMsg->setRoutingTableArraySize(nodesPerRow);
00460 
00461             for (uint i = 0; i < nodesPerRow; i++) {
00462                 stateMsg->setRoutingTable(i, rtmsg->getRoutingTable(i));
00463             }
00464 
00465             handleStateMessage(stateMsg);
00466         }
00467 
00468         delete rtmsg;
00469     }
00470         break;
00471 
00472     case PASTRY_MSG_REQ: {
00473         PastryRequestMessage* lrmsg =
00474             check_and_cast<PastryRequestMessage*>(pastryMsg);
00475         handleRequestMessage(lrmsg);
00476     }
00477         break;
00478 
00479     case PASTRY_MSG_STATE: {
00480         PastryStateMessage* stateMsg =
00481             check_and_cast<PastryStateMessage*>(msg);
00482         RECORD_STATS(stateReceived++; stateBytesReceived +=
00483                      stateMsg->byteLength());
00484         handleStateMessage(stateMsg);
00485     }
00486         break;
00487     }
00488 }

void Pastry::handleStateMessage ( PastryStateMessage *  msg  )  [virtual]

processes state messages, merging with own state tables

Parameters:
msg the pastry state message

Implements BasePastry.

Referenced by handleUDPMessage().

00774 {
00775     if (debugOutput) {
00776         EV << "Pastry::handleStateMessage() new STATE message to process "
00777            << static_cast<void*>(msg) << " in state " <<
00778             ((state == READY)?"READY":((state == JOINING_2)?"JOIN":"INIT"))
00779            << endl;
00780         if (state == JOINING_2) {
00781             EV << " ***   own joinHopCount:  " << joinHopCount << endl;
00782             EV << " ***   already received:  " << stReceived.size() << endl;
00783             EV << " ***   last-hop flag:     " << msg->getLastHop() << endl;
00784             EV << " ***   msg joinHopCount:  "
00785                << msg->getJoinHopCount() << endl;
00786         }
00787     }
00788     if (state == INIT) {
00789         EV << "Pastry: can't handle state messages until at least reaching "
00790             "JOIN state." << endl;
00791         delete msg;
00792         return;
00793     }
00794 
00795     PastryStateMsgHandle handle(msg);
00796 
00797     // in JOIN state, store all received state Messages, need them later:
00798     if (state == JOINING_2) {
00799         //std::cout << simTime() << " " << thisNode.ip << " "
00800         //          << msg->getJoinHopCount()
00801         //          << (msg->getLastHop() ? " *" : "") << std::endl;
00802 
00803         if (joinHopCount && stReceived.size() == joinHopCount) {
00804             EV << "Pastry: Warning: dropping state message received after "
00805                 "all needed state messages were collected in JOIN state."
00806                << endl;
00807             delete msg;
00808             return;
00809         }
00810 
00811         stReceived.push_back(handle);
00812         prePing(msg);
00813 
00814         if (msg->getLastHop()) {
00815             if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00816             if (msg->getSender().key == thisNode.key) {
00817                 EV << "Pastry: Error: OverlayKey already in use, restarting!"
00818                    << endl;
00819                 std::cout << "Pastry: Error: OverlayKey already in use, restarting!"
00820                                    << std::endl;
00821                 joinOverlay();
00822                 return;
00823             }
00824 
00825             if (joinHopCount) {
00826                 EV << "Pastry: Error: received a second `last' state message! "
00827                     "Restarting ..." << endl;
00828                 std::cout << thisNode.ip << "Pastry: Error: received a second `last' state message! "
00829                                     "Restarting ..." << std::endl;
00830                 joinOverlay();
00831                 return;
00832             }
00833 
00834             joinHopCount = msg->getJoinHopCount();
00835 
00836             if (stReceived.size() < joinHopCount) {
00837                 // some states still missing:
00838                 cancelEvent(readyWait);
00839                 scheduleAt(simTime()+readyWaitAmount, readyWait);
00840             }
00841         }
00842 
00843         if (joinHopCount) {
00844             if (stReceived.size() > joinHopCount) {
00845                 EV << "Pastry: Error: too many state messages received in "
00846                       "JOIN state! (" << stReceived.size()
00847                    << " > " << joinHopCount << ") Restarting ..." << endl;
00848                 //std::cout << " failed!" << std::endl;
00849                 joinOverlay();
00850                 return;
00851             }
00852             if (stReceived.size() == joinHopCount) {
00853                 // all state messages are here, sort by hopcount:
00854                 sort(stReceived.begin(), stReceived.end(),
00855                      stateMsgIsSmaller);
00856 
00857                 // start pinging the nodes found in the first state message:
00858                 stReceivedPos = stReceived.begin();
00859                 stateCache = *stReceivedPos;
00860                 EV << "Pastry: have all STATE messages, now pinging nodes."
00861                    << endl;
00862                 pingNodes();
00863 
00864                 // cancel timeout:
00865                 if (readyWait->isScheduled()) cancelEvent(readyWait);
00866             } else {
00867                 //TODO occasionally, here we got a wrong hop count in
00868                 // iterative mode due to more than one it. lookup during join
00869                 // procedure
00870                 EV << "[Pastry::handleStateMessage() @ " << thisNode.ip
00871                    << " (" << thisNode.key.toString(16) << ")]\n"
00872                    << "    Still need some STATE messages."
00873                    << endl;
00874             }
00875 
00876         }
00877         return;
00878     }
00879 
00880     if (debugOutput) {
00881         EV << "Pastry: handling STATE message" << endl;
00882         EV << "        type: " << ((msg->getPastryStateMsgType()
00883                                     == PASTRY_STATE_UPDATE) ? "update"
00884                                                             :"standard")
00885            << endl;
00886         if (msg->getPastryStateMsgType() == PASTRY_STATE_UPDATE) {
00887             EV << "        msg timestamp:      " <<
00888                 msg->getTimestamp() << endl;
00889             EV << "        last state change:  " <<
00890                 lastStateChange << endl;
00891         }
00892     }
00893 
00894     if (((msg->getPastryStateMsgType() == PASTRY_STATE_UPDATE))
00895             && (msg->getTimestamp() <= lastStateChange)) {
00896         // if we received an update based on our outdated state,
00897         // mark handle for retrying later:
00898         EV << "Pastry: outdated state from " << msg->getSender() << endl;
00899         handle.outdatedUpdate = true;
00900     }
00901 
00902     // determine aliveTable to prevent leafSet from merging nodes that are
00903     // known to be dead:
00904     determineAliveTable(msg);
00905 
00906     if (msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR) {
00907         // try to repair leafset based on repair message right now
00908         const TransportAddress& askLs = leafSet->repair(msg, aliveTable);
00909         if (! askLs.isUnspecified()) {
00910             sendRequest(askLs, PASTRY_REQ_REPAIR);
00911         }
00912 
00913         // while not really known, it's safe to assume that a repair
00914         // message changed our state:
00915         lastStateChange = simTime();
00916         newLeafs();
00917     } else if (leafSet->mergeState(msg, aliveTable)) {
00918         // merged state into leafset right now
00919         lastStateChange = simTime();
00920         newLeafs();
00921         updateTooltip();
00922     }
00923     // in READY state, only ping nodes to get proximity metric:
00924     if (!stateCache.msg) {
00925         // no state message is processed right now, start immediately:
00926         stateCache = handle;
00927         pingNodes();
00928     } else {
00929         // enqueue message for later processing:
00930         stateCacheQueue.push(handle);
00931         prePing(msg);
00932     }
00933 }

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

changes node state

Parameters:
toState state to change to

Reimplemented from BasePastry.

Referenced by checkProxCache(), handleTimerEvent(), and joinOverlay().

00121 {
00122     if (ringCheck->isScheduled()) cancelEvent(ringCheck);
00123     baseChangeState(toState);
00124 
00125     switch (toState) {
00126     case INIT:
00127         purgeVectors();
00128         break;
00129 
00130     case DISCOVERY:
00131         state = DISCOVERY;
00132         //nearNode = bootstrapNode;
00133         nearNodeRtt = strToSimtime("10s");
00134         sendRequest(bootstrapNode, PASTRY_REQ_LEAFSET);
00135         depth = -1;
00136 
00137         break;
00138 
00139     case JOINING_2:
00140 
00141         joinHopCount = 0;
00142 
00143         {
00144             PastryJoinMessage* msg = new PastryJoinMessage("JOIN-Request");
00145             msg->setPastryMsgType(PASTRY_MSG_JOIN);
00146             msg->setStatType(MAINTENANCE_STAT);
00147             //msg->setJoinHopCount(1);
00148             msg->setSendStateTo(thisNode);
00149             msg->setLength(PASTRYJOIN_L(msg));
00150             RECORD_STATS(joinSent++; joinBytesSent += msg->byteLength());
00151             std::vector<TransportAddress> sourceRoute;
00152             sourceRoute.push_back(nearNode);
00153             sendToKey(thisNode.key, msg, 0/*1*/, sourceRoute);
00154 
00155         }
00156 
00157 
00158         break;
00159 
00160     case READY:
00161         if (ringCheckInterval > 0) {
00162             scheduleAt(simTime()+ringCheckInterval, ringCheck);
00163         }
00164 
00165         // determine list of all known nodes as notifyList
00166         notifyList.clear();
00167         leafSet->dumpToVector(notifyList);
00168         routingTable->dumpToVector(notifyList);
00169         sort(notifyList.begin(), notifyList.end());
00170         notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00171                          notifyList.end());
00172 
00173         // schedule update
00174         cancelEvent(joinUpdateWait);
00175         scheduleAt(simTime() + sendStateWaitAmount, joinUpdateWait);
00176 
00177         // schedule second stage
00178         if (useSecondStage) {
00179             cancelEvent(secondStageWait);
00180             scheduleAt(simTime() + secondStageWaitAmount, secondStageWait);
00181         }
00182 
00183         // schedule routing table maintenance task
00184         if (periodicMaintenance) {
00185             cancelEvent(repairTaskTimeout);
00186             scheduleAt(simTime() + repairTaskTimeoutAmount, repairTaskTimeout);
00187             //leaf2ask = NULL;
00188         }
00189 
00190         break;
00191     }
00192 }

void Pastry::doSecondStage ( void   )  [private]

do the second stage of initialization as described in the paper

Referenced by handleTimerEvent().

00523 {
00524     parentModule()->parentModule()->bubble("entering SECOND STAGE");
00525     // "second stage" for locality:
00526     notifyList.clear();
00527     routingTable->dumpToVector(notifyList);
00528     neighborhoodSet->dumpToVector(notifyList);
00529     sort(notifyList.begin(), notifyList.end());
00530     notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00531                      notifyList.end());
00532     for (std::vector<TransportAddress>::iterator it = notifyList.begin();
00533          it != notifyList.end(); it++) {
00534         if (*it == thisNode) continue;
00535         EV << "second stage: requesting state from " << *it << endl;
00536         sendRequest(*it, PASTRY_REQ_STATE);
00537     }
00538     notifyList.clear();
00539 }

bool Pastry::handleFailedNode ( const TransportAddress failed  )  [private, virtual]

notifies leafset and routingtable of a failed node and sends out a repair request if possible

Parameters:
failed the failed node
Returns:
true as long as local state is READY (signals lookup to try again)

Reimplemented from BaseOverlay.

00542 {
00543     if (state != READY) {
00544         return false;
00545     }
00546     //std::cout << thisNode.ip << " is handling failed node: " << failed.ip << std::endl;
00547     if (failed.isUnspecified())
00548         opp_error("Pastry::handleFailedNode(): failed is unspecified!");
00549 
00550     const TransportAddress& lsAsk = leafSet->failedNode(failed);
00551     const TransportAddress& rtAsk = routingTable->failedNode(failed);
00552     neighborhoodSet->failedNode(failed);
00553 
00554     if (! lsAsk.isUnspecified()) {
00555         if (sendStateAtLeafsetRepair) sendRequest(lsAsk, PASTRY_REQ_REPAIR);
00556         else sendRequest(lsAsk, PASTRY_REQ_LEAFSET);
00557     }
00558     if (! rtAsk.isUnspecified() &&
00559         (lsAsk.isUnspecified() ||
00560          lsAsk != rtAsk)) sendRequest(rtAsk, PASTRY_REQ_REPAIR);
00561 
00562     newLeafs();
00563 
00564     if (lsAsk.isUnspecified() && (! leafSet->isValid())) {
00565         EV << "Pastry: lost connection to the network, trying to re-join."
00566            << endl;
00567         std::cout << "Pastry: lost connection to the network, trying to re-join."
00568                   << std::endl;
00569         joinOverlay();
00570         return false;
00571     }
00572 
00573     return true;
00574 }

void Pastry::checkProxCache ( void   )  [private, virtual]

checks whether proxCache is complete, takes appropriate actions depending on the protocol state

Implements BasePastry.

00577 {
00578     // no cached STATE message?
00579     if (!(stateCache.msg && stateCache.prox)) return;
00580 
00581     // no entries in stateCache.prox?
00582     if (stateCache.prox->pr_rt.empty()) return;
00583     if (stateCache.prox->pr_ls.empty()) return;
00584     if (stateCache.prox->pr_ns.empty()) return;
00585 
00586     //debug
00587     /*for (uint i = 0; i < stateCache.prox->pr_rt.size(); ++i) {
00588         if (stateCache.prox->pr_rt[i] == -3)
00589             EV << stateCache.msg->getRoutingTable(i).ip << " ";
00590     }
00591     for (uint i = 0; i < stateCache.prox->pr_ls.size(); ++i) {
00592         if (stateCache.prox->pr_ls[i] == -3)
00593             EV << stateCache.msg->getLeafSet(i).ip << " ";
00594     }
00595     for (uint i = 0; i < stateCache.prox->pr_ns.size(); ++i) {
00596         if (stateCache.prox->pr_ns[i] == -3)
00597             EV << stateCache.msg->getNeighborhoodSet(i).ip << " ";
00598     }
00599     EV << endl;*/
00600 
00601     // some entries not yet determined?
00602     if (find(stateCache.prox->pr_rt.begin(), stateCache.prox->pr_rt.end(),
00603              PASTRY_PROX_PENDING) != stateCache.prox->pr_rt.end()) return;
00604     if (find(stateCache.prox->pr_ls.begin(), stateCache.prox->pr_ls.end(),
00605              PASTRY_PROX_PENDING) != stateCache.prox->pr_ls.end()) return;
00606     if (find(stateCache.prox->pr_ns.begin(), stateCache.prox->pr_ns.end(),
00607              PASTRY_PROX_PENDING) != stateCache.prox->pr_ns.end()) return;
00608 
00609     EV << "[Pastry::checkProxCache() @ " << thisNode.ip
00610        << " (" << thisNode.key.toString(16) << ")]\n"
00611        << "    all proximities for current STATE message from "
00612        << stateCache.msg->getSender().ip
00613        << " collected!"
00614        << endl;
00615 /*
00616     //debug
00617     if (stateCache.prox != NULL) {
00618         std::vector<PastryStateMsgHandle>::iterator it;
00619         for (it = stReceived.begin(); it != stReceived.end(); ++it) {
00620             if (it->prox == NULL) {
00621                 EV << ". " << endl;
00622                 continue;
00623             }
00624             for (uint i = 0; i < it->prox->pr_rt.size(); ++i) {
00625                 EV << it->prox->pr_rt[i] << " ";
00626             }
00627             for (uint i = 0; i < it->prox->pr_ls.size(); ++i) {
00628                 EV << it->prox->pr_ls[i] << " ";
00629             }
00630             for (uint i = 0; i < it->prox->pr_ns.size(); ++i) {
00631                 EV << it->prox->pr_ns[i] << " ";
00632             }
00633             EV << endl;
00634         }
00635         EV << endl;
00636     } else EV << "NULL" << endl;
00637 */
00638 
00639     simtime_t now = simTime();
00640 
00641     if (state == JOINING_2) {
00642         // save pointer to proximity vectors:
00643         stReceivedPos->prox = stateCache.prox;
00644 
00645         // collected proximities for all STATE messages?
00646         if (++stReceivedPos == stReceived.end()) {
00647             EV << "[Pastry::checkProxCache() @ " << thisNode.ip
00648                << " (" << thisNode.key.toString(16) << ")]\n"
00649                << "    proximities for all STATE messages collected!"
00650                << endl;
00651             stateCache.msg = NULL;
00652             stateCache.prox = NULL;
00653             if (debugOutput) {
00654                 EV << "Pastry: [JOIN] starting to build own state from "
00655                    << stReceived.size() << " received state messages..."
00656                    << endl;
00657                 EV << "Pastry: [JOIN] initializing NeighborhoodSet from "
00658                 << stReceived.front().msg->getJoinHopCount() << ". hop"
00659                 << endl;
00660             }
00661             if (!neighborhoodSet->mergeState( stReceived.front().msg,
00662                                              *stReceived.front().prox )) {
00663                 EV << "Pastry: Error initializing own neighborhoodSet while "
00664                     "joining! Restarting ..." << endl;
00665                 std::cout << "Pastry: Error initializing own neighborhoodSet while "
00666                              "joining! Restarting ..." << std::endl;
00667                 joinOverlay();
00668                 return;
00669             }
00670             if (debugOutput) {
00671                 EV << "Pastry: [JOIN] initializing LeafSet from "
00672                 << stReceived.back().msg->getJoinHopCount() << ". hop" << endl;
00673             }
00674             if (!leafSet->mergeState( stReceived.back().msg,
00675                                      *stReceived.back().prox )) {
00676                 EV << "Pastry: Error initializing own leafSet while "
00677                     "joining! Restarting ..." << endl;
00678                 std::cout << "Pastry: Error initializing own leafSet while "
00679                                     "joining! Restarting ..." << std::endl;
00680                 joinOverlay();
00681                 return;
00682             }
00683             if (debugOutput) {
00684                 EV << "Pastry: [JOIN] initializing RoutingTable from all hops"
00685                    << endl;
00686             }
00687             if (!routingTable->initStateFromHandleVector(stReceived)) {
00688                 EV << "Pastry: Error initializing own routingTable "
00689                     "while joining! Restarting ..." << endl;
00690                 std::cout << "Pastry: Error initializing own routingTable "
00691                              "while joining! Restarting ..." << std::endl;
00692                 joinOverlay();
00693                 return;
00694             }
00695             lastStateChange = now;
00696             newLeafs();
00697             changeState(READY);
00698             EV << "changeState(READY) called" << endl;
00699 
00700         } else {
00701             EV << "[Pastry::checkProxCache() @ " << thisNode.ip
00702                << " (" << thisNode.key.toString(16) << ")]\n"
00703                << "    NOT all proximities for all STATE messages collected!"
00704                << endl;
00705             for (uint i = 0; i < stReceived.size(); ++i) {
00706                 if (stReceived[i].msg == stReceivedPos->msg) EV << " *";
00707                 EV << stReceived[i].msg;
00708             }
00709             EV << endl;
00710 
00711             // process next state message in vector:
00712             if (stReceivedPos->msg == NULL)
00713                 throw new cRuntimeError("stReceivedPos->msg = NULL");
00714             stateCache = *stReceivedPos;
00715             if (stateCache.msg == NULL)
00716                 throw new cRuntimeError("msg = NULL");
00717             pingNodes();
00718         }
00719     } else {
00720         // state == READY
00721         if (stateCache.msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR) {
00722             // try to repair routingtable based on repair message:
00723             const TransportAddress& askRt =
00724                 routingTable->repair(stateCache.msg, *stateCache.prox);
00725             if (! askRt.isUnspecified()) {
00726                 sendRequest(askRt, PASTRY_REQ_REPAIR);
00727             }
00728 
00729             // while not really known, it's safe to assume that a repair
00730             // message changed our state:
00731             lastStateChange = now;
00732         } else {
00733             if (stateCache.outdatedUpdate) {
00734                 // send another STATE message on outdated state update:
00735                 sendStateDelayed(stateCache.msg->getSender());
00736 
00737             } else {//hack
00738 
00739                 // merge info in own state tables
00740                 // except leafset (was already handled in handleStateMessage)
00741                 if (neighborhoodSet->mergeState(stateCache.msg, *stateCache.prox))
00742                     lastStateChange = now;
00743                 EV << "Merging nodes into routing table" << endl;
00744                 if (routingTable->mergeState(stateCache.msg, *stateCache.prox)) {
00745                     lastStateChange = now;
00746                     EV << "merged nodes into routing table" << endl;
00747                 }
00748             }
00749         }
00750         updateTooltip();
00751 
00752         // if state message was not an update, send one back:
00753         if (stateCache.msg->getPastryStateMsgType() != PASTRY_STATE_UPDATE &&
00754             (alwaysSendUpdate || lastStateChange == now)) {//hack
00755             sendStateTables(stateCache.msg->getSender(), PASTRY_STATE_UPDATE,
00756                             stateCache.msg->getTimestamp());
00757         }
00758 
00759         delete stateCache.msg;
00760         stateCache.msg = NULL;
00761         delete stateCache.prox;
00762         stateCache.prox = NULL;
00763 
00764         // process next queued message:
00765         if (! stateCacheQueue.empty()) {
00766             stateCache = stateCacheQueue.front();
00767             stateCacheQueue.pop();
00768             pingNodes();
00769         }
00770     }
00771 }

void Pastry::doJoinUpdate ( void   )  [private]

send updated state to all nodes when entering ready state

Referenced by handleTimerEvent().

00491 {
00492     // send "update" state message to all nodes who sent us their state
00493     // during INIT, remove these from notifyList so they don't get our
00494     // state twice
00495     std::vector<TransportAddress>::iterator nListPos;
00496     if (!stReceived.empty()) {
00497         for (std::vector<PastryStateMsgHandle>::iterator it =
00498                  stReceived.begin(); it != stReceived.end(); ++it) {
00499             sendStateTables(it->msg->getSender(), PASTRY_STATE_UPDATE,
00500                             it->msg->getTimestamp());
00501             nListPos = find(notifyList.begin(), notifyList.end(),
00502                             it->msg->getSender());
00503             if (nListPos != notifyList.end()) {
00504                 notifyList.erase(nListPos);
00505             }
00506             delete it->msg;
00507             delete it->prox;
00508         }
00509         stReceived.clear();
00510     }
00511 
00512     // send a normal STATE message to all remaining known nodes
00513     for (std::vector<TransportAddress>::iterator it =
00514              notifyList.begin(); it != notifyList.end(); it++) {
00515         if (*it != thisNode) sendStateTables(*it);
00516     }
00517     notifyList.clear();
00518 
00519     updateTooltip();
00520 }

void Pastry::joinOverlay (  )  [private, virtual]

Join the overlay with a given nodeID in thisNode.key.

Join the overlay with a given nodeID in thisNode.key. This method may be called by an application to join the overlay with a specific nodeID. It is also called if the node's IP address changes.

Reimplemented from BaseOverlay.

Referenced by checkProxCache(), handleFailedNode(), handleStateMessage(), and handleTimerEvent().

00106 {
00107     changeState(INIT);
00108 
00109     if (bootstrapNode.isUnspecified()) {
00110         // no existing pastry network -> first node of a new one
00111         changeState(READY);
00112     } else {
00113         // join existing pastry network
00114         nearNode = bootstrapNode;
00115         if (useDiscovery) changeState(DISCOVERY);
00116         else changeState(JOINING_2);
00117     }
00118 }


Member Data Documentation

Referenced by changeState(), and initializeOverlay().

double Pastry::ringCheckInterval [private]

int Pastry::depth [private]

bool Pastry::useSecondStage [private]

Referenced by changeState(), and initializeOverlay().

bool Pastry::overrideOldPastry [private]

Referenced by initializeOverlay().

bool Pastry::overrideNewPastry [private]

Referenced by initializeOverlay().

cMessage* Pastry::secondStageWait [private]

cMessage* Pastry::ringCheck [private]

cMessage* Pastry::discoveryTimeout [private]


The documentation for this class was generated from the following files:

Generated on Fri Sep 19 13:05:07 2008 for ITM OverSim by  doxygen 1.5.5