#include <Pastry.h>
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 |
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 }
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.
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.
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.
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
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
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
failed | the failed node |
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 }
double Pastry::secondStageWaitAmount [private] |
Referenced by changeState(), and initializeOverlay().
double Pastry::ringCheckInterval [private] |
Referenced by changeState(), handleTimerEvent(), and initializeOverlay().
double Pastry::discoveryTimeoutAmount [private] |
Referenced by handleUDPMessage(), and initializeOverlay().
int Pastry::depth [private] |
Referenced by changeState(), handleTimerEvent(), and handleUDPMessage().
bool Pastry::useSecondStage [private] |
Referenced by changeState(), and initializeOverlay().
bool Pastry::sendStateAtLeafsetRepair [private] |
Referenced by handleFailedNode(), and initializeOverlay().
bool Pastry::overrideOldPastry [private] |
Referenced by initializeOverlay().
bool Pastry::overrideNewPastry [private] |
Referenced by initializeOverlay().
cMessage* Pastry::secondStageWait [private] |
Referenced by changeState(), initializeOverlay(), and ~Pastry().
cMessage* Pastry::ringCheck [private] |
Referenced by changeState(), handleTimerEvent(), initializeOverlay(), and ~Pastry().
cMessage* Pastry::discoveryTimeout [private] |
Referenced by handleUDPMessage(), initializeOverlay(), and ~Pastry().