#include <Pastry.h>
Inheritance diagram for Pastry:
Public Member Functions | |
virtual void | initializeOverlay (int stage) |
Initializes derived-class-attributes. | |
virtual void | handleTimerEvent (cMessage *msg) |
handles self-messages | |
virtual void | handleUDPMessage (BaseOverlayMessage *msg) |
processes messages from underlay | |
virtual void | handleRpcResponse (BaseResponseMessage *msg, int rpcId, simtime_t rtt) |
process RPC responses | |
virtual void | handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, int rpcID, const OverlayKey &destKey) |
handle RPC timeouts | |
void | handleStateMessage (PastryStateMessage *msg) |
processes state messages, merging with own state tables | |
virtual void | handleAppMessage (BaseOverlayMessage *msg) |
processes messages from application | |
virtual void | finishOverlay () |
collects statisticts | |
virtual void | receiveChangeNotification (int category, cPolymorphic *details) |
callback-method for events at the NotificationBoard | |
virtual void | updateTooltip () |
updates information shown in tk-environment | |
virtual NodeVector * | findNode (const OverlayKey &key, int numRedundantNodes, int numSiblings, BaseOverlayMessage *msg) |
implement the findNode call | |
int | getMaxNumSiblings () |
Query the maximum number of siblings (nodes close to a key) that are maintained by this overlay protocol. | |
int | getMaxNumRedundantNodes () |
Query the maximum number of redundant next hop nodes that are returned by findNode(). | |
Protected Member Functions | |
virtual void | changeState (int toState) |
changes node state | |
void | sendStateTables (const TransportAddress &destination, int type=PASTRY_STATE_STD,...) |
send a PastryStateMessage directly to a node | |
void | sendStateDelayed (const TransportAddress &destination) |
send a standard state message with a small delay | |
virtual bool | isSiblingFor (const NodeHandle &node, const OverlayKey &key, int numSiblings, bool *err) |
see BaseOverlay.cc | |
virtual AbstractLookup * | createLookup (const BaseRouteMessage *msg=NULL) |
Protected Attributes | |
int | joins |
int | joinTries |
int | joinPartial |
int | joinSeen |
int | joinBytesSeen |
int | joinReceived |
int | joinBytesReceived |
int | joinSent |
int | joinBytesSent |
int | stateSent |
int | stateBytesSent |
int | stateReceived |
int | stateBytesReceived |
int | repairReqSent |
int | repairReqBytesSent |
int | repairReqReceived |
int | repairReqBytesReceived |
int | stateReqSent |
int | stateReqBytesSent |
int | stateReqReceived |
int | stateReqBytesReceived |
int | totalLookups |
int | responsibleLookups |
int | routingTableLookups |
int | closerNodeLookups |
int | closerNodeLookupsFromNeighborhood |
Private Member Functions | |
virtual void | forwardMessageRecursive (const TransportAddress &dest, BaseRouteMessage *msg) |
Hook for forwarded message in recursive lookup mode. | |
void | doJoinUpdate (void) |
send updated state to all nodes when entering ready state | |
void | doSecondStage (void) |
do the second stage of initialization as described in the paper | |
void | purgeVectors (void) |
delete all information/messages caching vectors, used for restarting overlay or finish() | |
void | prePing (const PastryStateMessage *stateMsg) |
ping all nodes in a given state message. | |
void | pingNodes (void) |
ping all nodes in the pastry state message pointed to by private member stateCache | |
void | determineAliveTable (const PastryStateMessage *stateMsg) |
change the aliveTable to match the given stateMsg. | |
void | checkProxCache (void) |
checks whether proxCache is complete, takes appropriate actions depending on the protocol state | |
void | sendRepairRequest (const TransportAddress &ask) |
send a repair request to a given node | |
bool | handleFailedNode (const TransportAddress &failed) |
notifies leafset and routingtable of a failed node and sends out a repair request if possible | |
virtual void | joinOverlay () |
| |
void | newLeafs (void) |
Pastry API: send newLeafs() to application if enabled. | |
Private Attributes | |
PastryRoutingTable * | routingTable |
PastryLeafSet * | leafSet |
PastryNeighborhoodSet * | neighborhoodSet |
uint | state |
uint | bitsPerDigit |
uint | numberOfLeaves |
uint | numberOfNeighbors |
uint | pingRetries |
double | pingTimeout |
double | readyWaitAmount |
double | joinTimeoutAmount |
double | secondStageWaitAmount |
double | pingCacheExpireTime |
double | repairTimeout |
double | ringCheckInterval |
double | sendStateWaitAmount |
bool | enableNewLeafs |
bool | optimizeLookup |
bool | optimisticForward |
bool | avoidDuplicates |
bool | partialJoinPath |
NodeHandle | bootstrapNode |
std::vector< PastryStateMessage * > | stReceived |
std::vector< TransportAddress > | notifyList |
PastryStateMessage * | stateCache |
cQueue | stateCacheQueue |
PastryStateMsgProximity | proxCache |
PastryStateMsgProximity | aliveTable |
std::vector< PastryStateMsgProximity > | stateReceivedProximities |
PastryPingCache | pingCache |
std::map< TransportAddress, BaseRouteMessage * > | recFwdQueue |
uint | joinHopCount |
cMessage * | joinTimeout |
cMessage * | readyWait |
cMessage * | secondStageWait |
cMessage * | joinUpdateWait |
cMessage * | ringCheck |
std::vector< PastrySendState * > | sendStateWait |
simtime_t | lastStateChange |
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.
00036 { 00037 if ( stage != MIN_STAGE_OVERLAY ) 00038 return; 00039 00040 bitsPerDigit = par("bitsPerDigit"); 00041 numberOfLeaves = par("numberOfLeaves"); 00042 numberOfNeighbors = par("numberOfNeighbors"); 00043 joinTimeoutAmount = par("joinTimeout"); 00044 readyWaitAmount = par("readyWait"); 00045 secondStageWaitAmount = par("secondStageWait"); 00046 pingCacheExpireTime = par("pingCacheExpireTime"); 00047 repairTimeout = par("repairTimeout"); 00048 enableNewLeafs = par("enableNewLeafs"); 00049 optimizeLookup = par("optimizeLookup"); 00050 optimisticForward = par("optimisticForward"); 00051 avoidDuplicates = par("avoidDuplicates"); 00052 ringCheckInterval = par("ringCheckInterval"); 00053 sendStateWaitAmount = par("sendStateWaitAmount"); 00054 partialJoinPath = par("partialJoinPath"); 00055 pingTimeout = par("pingTimeout"); 00056 pingRetries = par("pingRetries"); 00057 00058 if (numberOfLeaves % 2) 00059 { 00060 EV << "Pastry: Warning: numberOfLeaves must be even - adding 1."; 00061 numberOfLeaves++; 00062 } 00063 00064 routingTable = check_and_cast<PastryRoutingTable*> 00065 (parentModule()->submodule("pastryRoutingTable")); 00066 leafSet = check_and_cast<PastryLeafSet*> 00067 (parentModule()->submodule("pastryLeafSet")); 00068 neighborhoodSet = check_and_cast<PastryNeighborhoodSet*> 00069 (parentModule()->submodule("pastryNeighborhoodSet")); 00070 00071 joinTimeout = new cMessage("joinTimeout"); 00072 readyWait = new cMessage("readyWait"); 00073 secondStageWait = new cMessage("secondStageWait"); 00074 joinUpdateWait = new cMessage("joinUpdateWait"); 00075 ringCheck = new cMessage("ringCheck"); 00076 00077 stateCache = NULL; 00078 00079 // initialize statistics 00080 joins = 0; 00081 joinTries = 0; 00082 joinPartial = 0; 00083 joinSeen = 0; 00084 joinReceived = 0; 00085 joinSent = 0; 00086 stateSent = 0; 00087 stateReceived = 0; 00088 repairReqSent = 0; 00089 repairReqReceived = 0; 00090 stateReqSent = 0; 00091 stateReqReceived = 0; 00092 00093 joinBytesSeen = 0; 00094 joinBytesReceived = 0; 00095 joinBytesSent = 0; 00096 stateBytesSent = 0; 00097 stateBytesReceived = 0; 00098 repairReqBytesSent = 0; 00099 repairReqBytesReceived = 0; 00100 stateReqBytesSent = 0; 00101 stateReqBytesReceived = 0; 00102 00103 totalLookups = 0; 00104 responsibleLookups = 0; 00105 routingTableLookups = 0; 00106 closerNodeLookups = 0; 00107 closerNodeLookupsFromNeighborhood = 0; 00108 00109 WATCH(joins); 00110 WATCH(joinTries); 00111 WATCH(joinSeen); 00112 WATCH(joinBytesSeen); 00113 WATCH(joinReceived); 00114 WATCH(joinBytesReceived); 00115 WATCH(joinSent); 00116 WATCH(joinBytesSent); 00117 WATCH(stateSent); 00118 WATCH(stateBytesSent); 00119 WATCH(stateReceived); 00120 WATCH(stateBytesReceived); 00121 WATCH(repairReqSent); 00122 WATCH(repairReqBytesSent); 00123 WATCH(repairReqReceived); 00124 WATCH(repairReqBytesReceived); 00125 WATCH(stateReqSent); 00126 WATCH(stateReqBytesSent); 00127 WATCH(stateReqReceived); 00128 WATCH(stateReqBytesReceived); 00129 WATCH(lastStateChange); 00130 WATCH(proxCache); 00131 WATCH_VECTOR(stateReceivedProximities); 00132 }
void Pastry::handleTimerEvent | ( | cMessage * | msg | ) | [virtual] |
handles self-messages
msg | the self-message |
Reimplemented from BaseOverlay.
00338 { 00339 00340 if (msg->isName("joinTimeout")) 00341 { 00342 EV << "Pastry: join timeout expired, restarting..." << endl; 00343 joinOverlay(); 00344 } 00345 else if (msg->isName("readyWait")) 00346 { 00347 if (partialJoinPath) 00348 { 00349 RECORD_STATS(joinPartial++); 00350 sort(stReceived.begin(), stReceived.end(), stateMsgIsSmaller); 00351 00352 // start pinging the nodes found in the first state message: 00353 stateReceivedProximities.clear(); 00354 stateCache = stReceived.front(); 00355 EV << "Pastry: joining despite some missing STATE messages." 00356 << endl; 00357 pingNodes(); 00358 } 00359 else 00360 { 00361 EV << "Pastry: timeout waiting for missing state messages in JOIN " 00362 "state, restarting..." << endl; 00363 joinOverlay(); 00364 } 00365 } 00366 else if (msg->isName("joinUpdateWait")) 00367 { 00368 EV << "Pastry: sending state updates to all nodes." << endl; 00369 doJoinUpdate(); 00370 } 00371 else if (msg->isName("secondStageWait")) 00372 { 00373 EV << "Pastry: sending STATE requests to all nodes in second stage " 00374 "of initialization." << endl; 00375 doSecondStage(); 00376 } 00377 else if (msg->isName("ringCheck")) 00378 { 00379 if (state == READY) 00380 { 00381 // ping direct neighbors on the ring: 00382 const NodeHandle& pred = leafSet->getPredecessor(); 00383 const NodeHandle& succ = leafSet->getSuccessor(); 00384 if (! pred.isUnspecified()) 00385 { 00386 pingNode(pred, pingTimeout, pingRetries, "PING ring check"); 00387 } 00388 if (! succ.isUnspecified()) 00389 { 00390 pingNode(succ, pingTimeout, pingRetries, "PING ring check"); 00391 } 00392 } 00393 scheduleAt(simTime()+ringCheckInterval, ringCheck); 00394 } 00395 else if (msg->isName("sendStateWait")) 00396 { 00397 PastrySendState* sendStateMsg = check_and_cast<PastrySendState*>(msg); 00398 00399 std::vector<PastrySendState*>::iterator pos = 00400 std::find(sendStateWait.begin(), sendStateWait.end(), 00401 sendStateMsg); 00402 if (pos != sendStateWait.end()) sendStateWait.erase(pos); 00403 00404 sendStateTables(sendStateMsg->getDest()); 00405 delete sendStateMsg; 00406 } 00407 }
void Pastry::handleUDPMessage | ( | BaseOverlayMessage * | msg | ) | [virtual] |
processes messages from underlay
msg | message from UDP |
Implements BaseOverlay.
00410 { 00411 PastryMessage* pastryMsg = check_and_cast<PastryMessage*>(msg); 00412 uint type = pastryMsg->getPastryMsgType(); 00413 00414 if (debugOutput) 00415 { 00416 EV << "Pastry: incoming message of type "; 00417 switch(type) 00418 { 00419 case PASTRY_MSG_STD: EV << "PASTRY_MSG_STD"; break; 00420 case PASTRY_MSG_JOIN: EV << "PASTRY_MSG_JOIN"; break; 00421 case PASTRY_MSG_STATE: EV << "PASTRY_MSG_STATE"; break; 00422 case PASTRY_MSG_RREQ: EV << "PASTRY_MSG_RREQ"; break; 00423 case PASTRY_MSG_SREQ: EV << "PASTRY_MSG_SREQ"; break; 00424 default: EV << "UNKNOWN (" << type <<")"; break; 00425 } 00426 EV << endl; 00427 } 00428 00429 switch (type) 00430 { 00431 case PASTRY_MSG_STD: 00432 opp_error("Pastry received PastryMessage of unknown type!"); 00433 break; 00434 00435 case PASTRY_MSG_JOIN: 00436 { 00437 PastryJoinMessage* jmsg = 00438 check_and_cast<PastryJoinMessage*>(pastryMsg); 00439 RECORD_STATS(joinReceived++; joinBytesReceived += 00440 jmsg->byteLength()); 00441 if (state == READY) 00442 sendStateTables(jmsg->getSendStateTo(), 00443 PASTRY_STATE_JOIN, jmsg->getJoinHopCount(), 00444 true); 00445 else 00446 EV << "Pastry: received join message before reaching " 00447 << "READY state, dropping message!" << endl; 00448 delete jmsg; 00449 } 00450 break; 00451 00452 case PASTRY_MSG_RREQ: 00453 { 00454 PastryRepairRequestMessage* rrmsg = 00455 check_and_cast<PastryRepairRequestMessage*>(pastryMsg); 00456 RECORD_STATS(repairReqReceived++; repairReqBytesReceived += 00457 rrmsg->byteLength()); 00458 if (state == READY) 00459 sendStateTables(rrmsg->getSendStateTo(), 00460 PASTRY_STATE_REPAIR); 00461 else 00462 EV << "Pastry: received repair request before reaching " 00463 << "READY state, dropping message!" << endl; 00464 delete rrmsg; 00465 } 00466 break; 00467 00468 case PASTRY_MSG_SREQ: 00469 { 00470 PastryStateRequestMessage* srmsg = 00471 check_and_cast<PastryStateRequestMessage*>(pastryMsg); 00472 RECORD_STATS(stateReqReceived++; stateReqBytesReceived += 00473 srmsg->byteLength()); 00474 if (state == READY) 00475 sendStateTables(srmsg->getSendStateTo()); 00476 else 00477 EV << "Pastry: received state request before reaching " 00478 << "READY state, dropping message!" << endl; 00479 delete srmsg; 00480 } 00481 break; 00482 00483 case PASTRY_MSG_STATE: 00484 { 00485 PastryStateMessage* stateMsg = 00486 check_and_cast<PastryStateMessage*>(msg); 00487 RECORD_STATS(stateReceived++; stateBytesReceived += 00488 stateMsg->byteLength()); 00489 handleStateMessage(stateMsg); 00490 } 00491 break; 00492 } 00493 }
void Pastry::handleRpcResponse | ( | BaseResponseMessage * | msg, | |
int | rpcId, | |||
simtime_t | rtt | |||
) | [virtual] |
process RPC responses
msg | the RPC response message | |
rpcId | the RPC identifier | |
rtt | round-trip time |
Reimplemented from RpcListener.
00737 { 00738 const NodeHandle& src = msg->getSrcNode(); 00739 const NodeHandle* node; 00740 int i; 00741 int n; 00742 PastryPingCacheEntry pce; 00743 std::map<TransportAddress, BaseRouteMessage*>::iterator pos; 00744 00745 RPC_SWITCH_START(msg) 00746 RPC_ON_RESPONSE(Ping) 00747 { 00748 // insert into pingCache 00749 pce.inserted = simTime(); 00750 pce.rtt = rtt; 00751 pingCache[src.ip] = pce; 00752 00753 if (stateCache) 00754 { 00755 // look for node in routing table of processed state message: 00756 n = stateCache->getRoutingTableArraySize(); 00757 for (i = 0; i < n; i++) 00758 { 00759 node = &(stateCache->getRoutingTable(i)); 00760 if ((!node->isUnspecified()) && (*node == src)) 00761 *(proxCache.pr_rt.begin()+i) = rtt; 00762 } 00763 00764 // look for node in leaf set of processed state message: 00765 n = stateCache->getLeafSetArraySize(); 00766 for (i = 0; i < n; i++) 00767 { 00768 node = &(stateCache->getLeafSet(i)); 00769 if ((!node->isUnspecified()) && (*node == src)) 00770 *(proxCache.pr_ls.begin()+i) = rtt; 00771 } 00772 00773 // look for node in neighb. set of processed state message: 00774 n = stateCache->getNeighborhoodSetArraySize(); 00775 for (i = 0; i < n; i++) 00776 { 00777 node = &(stateCache->getNeighborhoodSet(i)); 00778 if ((!node->isUnspecified()) && (*node == src)) 00779 *(proxCache.pr_ns.begin()+i) = rtt; 00780 } 00781 00782 checkProxCache(); 00783 } 00784 00785 if ((pos = recFwdQueue.find(src)) != recFwdQueue.end()) 00786 { 00787 // send message 00788 if (!optimisticForward) 00789 { 00790 sendMessageToUDP(pos->first, pos->second); 00791 } 00792 else if (!avoidDuplicates) 00793 { 00794 delete pos->second; 00795 } 00796 recFwdQueue.erase(pos); 00797 } 00798 00799 break; 00800 } 00801 RPC_SWITCH_END() 00802 }
void Pastry::handleRpcTimeout | ( | BaseCallMessage * | msg, | |
const TransportAddress & | dest, | |||
int | rpcID, | |||
const OverlayKey & | destKey | |||
) | [virtual] |
handle RPC timeouts
msg | the RPC call that timed out | |
dest | the destination node of the RPC call | |
rpcID | the RPC identifier |
01175 { 01176 const NodeHandle* node; 01177 int i; 01178 int n; 01179 PastryPingCacheEntry pce; 01180 std::map<TransportAddress, BaseRouteMessage*>::iterator pos; 01181 01182 RPC_SWITCH_START(msg) 01183 RPC_ON_CALL(Ping) 01184 { 01185 EV << "Pastry: Ping timeout occured." << endl; 01186 01187 // update ping cache: 01188 pce.inserted = simTime(); 01189 pce.rtt = PASTRY_PROX_INFINITE; 01190 pingCache[dest.ip] = pce; 01191 01192 // handle failed node 01193 if (state == READY) 01194 { 01195 handleFailedNode(dest); 01196 01197 // this could initiate a re-join, exit the handler in that 01198 // case because all local data was erased: 01199 if (state != READY) break; 01200 } 01201 01202 if (stateCache && msg->isName("PING received state")) 01203 { 01204 // look for node in routing table of processed state message: 01205 n = stateCache->getRoutingTableArraySize(); 01206 for (i = 0; i < n; i++) 01207 { 01208 node = &(stateCache->getRoutingTable(i)); 01209 if ((!node->isUnspecified()) && (node->ip == dest.ip)) 01210 *(proxCache.pr_rt.begin() + i) = PASTRY_PROX_INFINITE; 01211 } 01212 01213 // look for node in leaf set of processed state message: 01214 n = stateCache->getLeafSetArraySize(); 01215 for (i = 0; i < n; i++) 01216 { 01217 node = &(stateCache->getLeafSet(i)); 01218 if ((!node->isUnspecified()) && (node->ip == dest.ip)) 01219 *(proxCache.pr_ls.begin() + i) = PASTRY_PROX_INFINITE; 01220 } 01221 01222 // look for node in neighborhood set of processed state message: 01223 n = stateCache->getNeighborhoodSetArraySize(); 01224 for (i = 0; i < n; i++) 01225 { 01226 node = &(stateCache->getNeighborhoodSet(i)); 01227 if ((!node->isUnspecified()) && (node->ip == dest.ip)) 01228 *(proxCache.pr_ns.begin() + i) = PASTRY_PROX_INFINITE; 01229 } 01230 checkProxCache(); 01231 } 01232 01233 if (msg->isName("PING next hop")) 01234 { 01235 // handle forward queue entry 01236 if ((pos = recFwdQueue.find(dest)) == recFwdQueue.end()) break; 01237 BaseRouteMessage* rmsg = pos->second; 01238 recFwdQueue.erase(pos); 01239 sendToKey(rmsg->getDestKey(), rmsg); 01240 } 01241 01242 break; 01243 } 01244 RPC_SWITCH_END() 01245 }
void Pastry::handleStateMessage | ( | PastryStateMessage * | msg | ) |
processes state messages, merging with own state tables
msg | the pastry state message |
00496 { 00497 if (debugOutput) 00498 { 00499 EV << "Pastry::handleStateMessage() new STATE message to process " 00500 << static_cast<void*>(msg) << " in state " << 00501 ((state == READY)?"READY":((state == JOIN)?"JOIN":"INIT")) 00502 << endl; 00503 if (state == JOIN) 00504 { 00505 EV << " *** own joinHopCount: " << joinHopCount << endl; 00506 EV << " *** already received: " << stReceived.size() << endl; 00507 EV << " *** last-hop flag: " << msg->getLastHop() << endl; 00508 EV << " *** msg joinHopCount: " 00509 << msg->getJoinHopCount() << endl; 00510 } 00511 } 00512 if (state == INIT) 00513 { 00514 EV << "Pastry: can't handle state messages until at least reaching " 00515 "JOIN state." << endl; 00516 delete msg; 00517 return; 00518 } 00519 00520 // in JOIN state, store all received state Messages, need them later: 00521 if (state == JOIN) 00522 { 00523 if (joinHopCount && stReceived.size() == joinHopCount) 00524 { 00525 EV << "Pastry: Warning: dropping state message received after " 00526 "all needed state messages were collected in JOIN state." 00527 << endl; 00528 delete msg; 00529 return; 00530 } 00531 00532 stReceived.push_back(msg); 00533 prePing(msg); 00534 00535 if (msg->getLastHop()) 00536 { 00537 if (joinTimeout->isScheduled()) cancelEvent(joinTimeout); 00538 00539 if (msg->getSender().key == thisNode.key) 00540 { 00541 EV << "Pastry: Error: OverlayKey already in use, restarting!" 00542 << endl; 00543 joinOverlay(); 00544 return; 00545 } 00546 00547 if (joinHopCount) 00548 { 00549 EV << "Pastry: Error: received a second `last' state message! " 00550 "Restarting ..." << endl; 00551 joinOverlay(); 00552 return; 00553 } 00554 00555 joinHopCount = msg->getJoinHopCount(); 00556 if (stReceived.size() < joinHopCount) 00557 { 00558 // some states still missing: 00559 cancelEvent(readyWait); 00560 scheduleAt(simTime()+readyWaitAmount, readyWait); 00561 } 00562 } 00563 00564 if (joinHopCount) 00565 { 00566 if (stReceived.size() > joinHopCount) 00567 { 00568 EV << "Pastry: Error: too many state messages received in " 00569 "JOIN state! Restarting ..." << endl; 00570 joinOverlay(); 00571 return; 00572 } 00573 if (stReceived.size() == joinHopCount) 00574 { 00575 // all state messages are here, sort by hopcount: 00576 sort(stReceived.begin(), stReceived.end(), 00577 stateMsgIsSmaller); 00578 00579 // start pinging the nodes found in the first state message: 00580 stateReceivedProximities.clear(); 00581 stateCache = stReceived.front(); 00582 EV << "Pastry: have all STATE messages, now pinging nodes." 00583 << endl; 00584 pingNodes(); 00585 00586 // cancel timeout: 00587 if (readyWait->isScheduled()) cancelEvent(readyWait); 00588 } 00589 } 00590 return; 00591 } 00592 00593 // determine aliveTable to prevent leafSet from merging nodes that are 00594 // known to be dead: 00595 determineAliveTable(msg); 00596 00597 if (msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR) 00598 { 00599 // try to repair leafset based on repair message right now 00600 const TransportAddress& askLs = leafSet->repair(msg, aliveTable); 00601 if (! askLs.isUnspecified()) sendRepairRequest(askLs); 00602 00603 // while not really known, it's safe to assume that a repair 00604 // message changed our state: 00605 lastStateChange = simTime(); 00606 newLeafs(); 00607 } 00608 else if (leafSet->mergeState(msg, aliveTable)) 00609 { 00610 // merged state into leafset right now 00611 lastStateChange = simTime(); 00612 newLeafs(); 00613 } 00614 00615 // in READY state, only ping nodes to get proximity metric: 00616 if (!stateCache) 00617 { 00618 // no state message is processed right now, start immediately: 00619 stateCache = msg; 00620 pingNodes(); 00621 } 00622 else 00623 { 00624 // enqueue message for later processing: 00625 stateCacheQueue.insert(msg); 00626 prePing(msg); 00627 } 00628 }
void Pastry::handleAppMessage | ( | BaseOverlayMessage * | msg | ) | [virtual] |
void Pastry::finishOverlay | ( | ) | [virtual] |
collects statisticts
Reimplemented from BaseOverlay.
01453 { 01454 // destroy self timer messages 01455 if (joinTimeout->isScheduled()) cancelEvent(joinTimeout); 01456 if (readyWait->isScheduled()) cancelEvent(readyWait); 01457 if (joinUpdateWait->isScheduled()) cancelEvent(joinUpdateWait); 01458 if (secondStageWait->isScheduled()) cancelEvent(secondStageWait); 01459 if (ringCheck->isScheduled()) cancelEvent(ringCheck); 01460 01461 delete joinTimeout; 01462 delete readyWait; 01463 delete joinUpdateWait; 01464 delete secondStageWait; 01465 delete ringCheck; 01466 01467 purgeVectors(); 01468 01469 // remove this node from the bootstrap list 01470 if (!thisNode.key.isUnspecified()) bootstrapOracle->removePeer(thisNode); 01471 01472 // collect statistics 01473 simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime); 01474 if(time == 0) return; 01475 01476 globalStatistics->addStdDev("Pastry: Successful Joins/s", joins / time); 01477 globalStatistics->addStdDev("Pastry: overall join tries/s", joinTries / time); 01478 globalStatistics->addStdDev("Pastry: joins with missing replies from routing path/s", 01479 joinPartial / time); 01480 globalStatistics->addStdDev("Pastry: JOIN Messages seen/s", joinSeen / time); 01481 globalStatistics->addStdDev("Pastry: bytes of JOIN Messages seen/s", joinBytesSeen / time); 01482 globalStatistics->addStdDev("Pastry: JOIN Messages received/s", joinReceived / time); 01483 globalStatistics->addStdDev("Pastry: bytes of JOIN Messages received/s", 01484 joinBytesReceived / time); 01485 globalStatistics->addStdDev("Pastry: JOIN Messages sent/s", joinSent / time); 01486 globalStatistics->addStdDev("Pastry: bytes of JOIN Messages sent/s", joinBytesSent / time); 01487 globalStatistics->addStdDev("Pastry: STATE Messages sent/s", stateSent / time); 01488 globalStatistics->addStdDev("Pastry: bytes of STATE Messages sent/s", stateBytesSent / time); 01489 globalStatistics->addStdDev("Pastry: STATE Messages received/s", stateReceived / time); 01490 globalStatistics->addStdDev("Pastry: bytes of STATE Messages received/s", 01491 stateBytesReceived / time); 01492 globalStatistics->addStdDev("Pastry: REPAIR Requests sent/s", repairReqSent / time); 01493 globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests sent/s", 01494 repairReqBytesSent / time); 01495 globalStatistics->addStdDev("Pastry: REPAIR Requests received/s", repairReqReceived / time); 01496 globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests received/s", 01497 repairReqBytesReceived / time); 01498 globalStatistics->addStdDev("Pastry: STATE Requests sent/s", stateReqSent / time); 01499 globalStatistics->addStdDev("Pastry: bytes of STATE Requests sent/s", stateReqBytesSent / time); 01500 globalStatistics->addStdDev("Pastry: STATE Requests received/s", stateReqReceived / time); 01501 globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s", 01502 stateReqBytesReceived / time); 01503 01504 globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s", 01505 stateReqBytesReceived / time); 01506 01507 globalStatistics->addStdDev("Pastry: total number of lookups", totalLookups); 01508 globalStatistics->addStdDev("Pastry: responsible lookups", responsibleLookups); 01509 globalStatistics->addStdDev("Pastry: lookups in routing table", routingTableLookups); 01510 globalStatistics->addStdDev("Pastry: lookups using closerNode()", closerNodeLookups); 01511 globalStatistics->addStdDev("Pastry: lookups using closerNode() with result from " 01512 "neighborhood set", closerNodeLookupsFromNeighborhood); 01513 }
void Pastry::receiveChangeNotification | ( | int | category, | |
cPolymorphic * | details | |||
) | [virtual] |
callback-method for events at the NotificationBoard
category | ... TODO ... | |
details | ... TODO ... |
01442 { 01443 Enter_Method_Silent(); 01444 if (category == NF_HOSTPOSITION_UPDATED) { 01445 // get new ip address 01446 thisNode.ip = IPAddressResolver().addressOf( 01447 parentModule()->parentModule()).get4(); 01448 joinOverlay(); 01449 } 01450 }
void Pastry::updateTooltip | ( | ) | [virtual] |
updates information shown in tk-environment
01418 { 01419 if (ev.isGUI()) { 01420 std::stringstream ttString; 01421 01422 // show our predecessor and successor in tooltip 01423 ttString << leafSet->getPredecessor() << endl << thisNode << endl 01424 << leafSet->getSuccessor(); 01425 01426 parentModule()->parentModule()->displayString(). 01427 setTagArg("tt", 0, ttString.str().c_str()); 01428 parentModule()->displayString(). 01429 setTagArg("tt", 0, ttString.str().c_str()); 01430 displayString().setTagArg("tt", 0, ttString.str().c_str()); 01431 01432 // draw arrows: 01433 showOverlayNeighborArrow(leafSet->getSuccessor(), true, 01434 "m=m,50,0,50,0;o=red,1"); 01435 showOverlayNeighborArrow(leafSet->getPredecessor(), false, 01436 "m=m,50,100,50,100;o=green,1"); 01437 01438 } 01439 }
NodeVector * Pastry::findNode | ( | const OverlayKey & | key, | |
int | numRedundantNodes, | |||
int | numSiblings, | |||
BaseOverlayMessage * | msg | |||
) | [virtual] |
implement the findNode call
key | the destination key | |
msg | the message to route |
Reimplemented from BaseOverlay.
01530 { 01531 if ((numRedundantNodes > getMaxNumRedundantNodes()) || 01532 (numSiblings > getMaxNumSiblings())) { 01533 01534 opp_error("(Pastry::findNode()) numRedundantNodes or numSiblings " 01535 "too big!"); 01536 } 01537 01538 01539 RECORD_STATS(totalLookups++); 01540 NodeVector* nextHop = new NodeVector(1); 01541 const NodeHandle* next; 01542 PastryFindNodeExtData* findNodeExt = NULL; 01543 if (msg && msg->hasObject("findNodeExt")) 01544 { 01545 findNodeExt = check_and_cast<PastryFindNodeExtData*>( 01546 msg->getObject("findNodeExt")); 01547 } 01548 01549 if (state != READY) 01550 { 01551 return nextHop; 01552 } 01553 else if (key.isUnspecified() || leafSet->isClosestNode(key)) 01554 { 01555 RECORD_STATS(responsibleLookups++); 01556 nextHop->add(thisNode); 01557 } 01558 else 01559 { 01560 // Send state tables on any JOIN message we see: 01561 if (findNodeExt) 01562 { 01563 const TransportAddress& stateRecipient = 01564 findNodeExt->getSendStateTo(); 01565 if (!stateRecipient.isUnspecified()) 01566 { 01567 RECORD_STATS(joinSeen++); 01568 sendStateTables(stateRecipient, PASTRY_STATE_JOIN, 01569 findNodeExt->getJoinHopCount(), false); 01570 } 01571 } 01572 01573 next = &(leafSet->getDestinationNode(key)); 01574 01575 if (next->isUnspecified()) 01576 { 01577 next = &(routingTable->lookupNextHop(key)); 01578 if (!next->isUnspecified()) 01579 RECORD_STATS(routingTableLookups++); 01580 } 01581 else 01582 RECORD_STATS(responsibleLookups++); 01583 01584 if (next->isUnspecified()) 01585 { 01586 RECORD_STATS(closerNodeLookups++); 01587 // call findCloserNode() on all state objects 01588 01589 if (optimizeLookup) 01590 { 01591 const NodeHandle* tmp; 01592 next = &(routingTable->findCloserNode(key, true)); 01593 tmp = &(neighborhoodSet->findCloserNode(key, true)); 01594 01595 if ((! tmp->isUnspecified()) && 01596 (leafSet->isCloser(*tmp, key, *next))) 01597 { 01598 RECORD_STATS(closerNodeLookupsFromNeighborhood++); 01599 next = tmp; 01600 } 01601 01602 tmp = &(leafSet->findCloserNode(key, true)); 01603 if ((! tmp->isUnspecified()) && 01604 (leafSet->isCloser(*tmp, key, *next))) 01605 { 01606 RECORD_STATS(closerNodeLookupsFromNeighborhood--); 01607 next = tmp; 01608 } 01609 } 01610 else 01611 { 01612 next = &(routingTable->findCloserNode(key)); 01613 01614 if (next->isUnspecified()) 01615 { 01616 RECORD_STATS(closerNodeLookupsFromNeighborhood++); 01617 next = &(neighborhoodSet->findCloserNode(key)); 01618 } 01619 01620 if (next->isUnspecified()) 01621 { 01622 RECORD_STATS(closerNodeLookupsFromNeighborhood--); 01623 next = &(leafSet->findCloserNode(key)); 01624 } 01625 } 01626 } 01627 01628 if (!next->isUnspecified()) 01629 { 01630 if (findNodeExt) 01631 { 01632 findNodeExt->setJoinHopCount( 01633 findNodeExt->getJoinHopCount() + 1); 01634 } 01635 nextHop->add(*next); 01636 } 01637 } 01638 01639 bool err; 01640 01641 /* if we're a sibling, return all numSiblings */ 01642 if (isSiblingFor(thisNode, key, numSiblings, &err)) { 01643 if (err == false) { 01644 delete nextHop; 01645 return leafSet->createSiblingVector(key, numSiblings); 01646 } 01647 } 01648 01649 return nextHop; 01650 }
int Pastry::getMaxNumSiblings | ( | ) | [virtual] |
Query the maximum number of siblings (nodes close to a key) that are maintained by this overlay protocol.
Reimplemented from BaseOverlay.
01516 { 01517 return (int) floor(numberOfLeaves/4); 01518 }
int Pastry::getMaxNumRedundantNodes | ( | ) | [virtual] |
Query the maximum number of redundant next hop nodes that are returned by findNode().
Reimplemented from BaseOverlay.
void Pastry::changeState | ( | int | toState | ) | [protected, virtual] |
changes node state
toState | state to change to |
00224 { 00225 if (ringCheck->isScheduled()) cancelEvent(ringCheck); 00226 00227 switch (toState) 00228 { 00229 case INIT: 00230 00231 state = INIT; 00232 00233 if (!thisNode.key.isUnspecified()) 00234 bootstrapOracle->removePeer(thisNode); 00235 00236 if (joinTimeout->isScheduled()) cancelEvent(joinTimeout); 00237 if (readyWait->isScheduled()) cancelEvent(readyWait); 00238 00239 purgeVectors(); 00240 00241 bootstrapNode = bootstrapOracle->getBootstrapNode(); 00242 00243 routingTable->initializeTable(bitsPerDigit, repairTimeout, 00244 thisNode); 00245 leafSet->initializeSet(numberOfLeaves, repairTimeout, thisNode); 00246 neighborhoodSet->initializeSet(numberOfNeighbors, thisNode); 00247 00248 updateTooltip(); 00249 lastStateChange = simTime(); 00250 00251 parentModule()->parentModule()->bubble("entering INIT state"); 00252 00253 break; 00254 00255 case JOIN: 00256 00257 state = JOIN; 00258 00259 // bootstrapNode must be obtained before calling this method, 00260 // for example by calling changeState(INIT) 00261 00262 if (bootstrapNode.isUnspecified()) 00263 { 00264 // no existing pastry network -> first node of a new one 00265 changeState(READY); 00266 return; 00267 } 00268 00269 joinHopCount = 0; 00270 00271 { 00272 PastryJoinMessage* msg = new PastryJoinMessage("JOIN-Request"); 00273 msg->setPastryMsgType(PASTRY_MSG_JOIN); 00274 msg->setSignaling(true); 00275 msg->setJoinHopCount(1); 00276 msg->setSendStateTo(thisNode); 00277 msg->setLength(PASTRYJOIN_L(msg)); 00278 RECORD_STATS(joinSent++; joinBytesSent += msg->byteLength()); 00279 sendToKey(thisNode.key, msg, 0, bootstrapNode); 00280 } 00281 00282 cancelEvent(joinTimeout); 00283 scheduleAt(simTime()+joinTimeoutAmount, joinTimeout); 00284 00285 updateTooltip(); 00286 parentModule()->parentModule()->bubble("entering JOIN state"); 00287 00288 RECORD_STATS(joinTries++); 00289 00290 break; 00291 00292 case READY: 00293 00294 state = READY; 00295 if (ringCheckInterval > 0) 00296 { 00297 scheduleAt(simTime()+ringCheckInterval, ringCheck); 00298 } 00299 00300 bootstrapOracle->registerPeer(thisNode); 00301 00302 // if we are the first node in the network, there's nothing else 00303 // to do 00304 if (bootstrapNode.isUnspecified()) 00305 { 00306 RECORD_STATS(joinTries++); 00307 RECORD_STATS(joins++); 00308 setReadyIcon(true); 00309 return; 00310 } 00311 00312 // determine list of all known nodes as notifyList 00313 notifyList.clear(); 00314 leafSet->dumpToVector(notifyList); 00315 routingTable->dumpToVector(notifyList); 00316 sort(notifyList.begin(), notifyList.end()); 00317 notifyList.erase(unique(notifyList.begin(), notifyList.end()), 00318 notifyList.end()); 00319 00320 parentModule()->parentModule()->bubble("entering READY state"); 00321 00322 // schedule update 00323 cancelEvent(joinUpdateWait); 00324 scheduleAt(simTime() + sendStateWaitAmount, joinUpdateWait); 00325 00326 // schedule second stage 00327 cancelEvent(secondStageWait); 00328 scheduleAt(simTime() + secondStageWaitAmount, secondStageWait); 00329 00330 RECORD_STATS(joins++); 00331 00332 break; 00333 } 00334 setReadyIcon(state == READY); 00335 }
void Pastry::sendStateTables | ( | const TransportAddress & | destination, | |
int | type = PASTRY_STATE_STD , |
|||
... | ||||
) | [protected] |
send a PastryStateMessage directly to a node
destination | destination node | |
type | the type of the state message to be sent | |
... | additional arguments for some types: PASTRY_STATE_JOIN: int hops number of hops to destination node PASTRY_STATE_JOIN: bool last mark the state message to originate from closest node found PASTRY_STATE_UPDATE: simtime_t timestamp use this timestamp for the uptade message |
01293 { 01294 if (destination.ip == thisNode.ip) 01295 opp_error("Pastry: trying to send state to self!"); 01296 01297 int hops = 0; 01298 bool last = false; 01299 simtime_t timestamp = 0; 01300 01301 if ((type == PASTRY_STATE_JOIN) || (type == PASTRY_STATE_UPDATE)) 01302 { 01303 // additional parameters needed: 01304 va_list ap; 01305 va_start(ap, type); 01306 if (type == PASTRY_STATE_JOIN) 01307 { 01308 hops = va_arg(ap, int); 01309 last = static_cast<bool>(va_arg(ap, int)); 01310 } 01311 else 01312 { 01313 timestamp = va_arg(ap, simtime_t); 01314 } 01315 va_end(ap); 01316 } 01317 01318 // create new state msg and set special fields for some types: 01319 PastryStateMessage* stateMsg; 01320 if (type == PASTRY_STATE_JOIN) 01321 { 01322 stateMsg = new PastryStateMessage("STATE (Join)"); 01323 stateMsg->setJoinHopCount(hops); 01324 stateMsg->setLastHop(last); 01325 stateMsg->setTimestamp(simTime()); 01326 } 01327 else if (type == PASTRY_STATE_UPDATE) 01328 { 01329 stateMsg = new PastryStateMessage("STATE (Update)"); 01330 EV << "Pastry: sending state (update) to " << destination << endl; 01331 stateMsg->setTimestamp(timestamp); 01332 } 01333 else 01334 { 01335 stateMsg = new PastryStateMessage("STATE"); 01336 EV << "Pastry: sending state (standard) to " << destination << endl; 01337 stateMsg->setTimestamp(simTime()); 01338 } 01339 01340 // fill in standard content: 01341 stateMsg->setPastryMsgType(PASTRY_MSG_STATE); 01342 stateMsg->setSignaling(true); 01343 stateMsg->setPastryStateMsgType(type); 01344 stateMsg->setSender(thisNode); 01345 routingTable->dumpToStateMessage(stateMsg); 01346 leafSet->dumpToStateMessage(stateMsg); 01347 neighborhoodSet->dumpToStateMessage(stateMsg); 01348 01349 // send... 01350 stateMsg->setLength(PASTRYSTATE_L(stateMsg)); 01351 RECORD_STATS(stateSent++; stateBytesSent += stateMsg->byteLength()); 01352 sendMessageToUDP(destination, stateMsg); 01353 }
void Pastry::sendStateDelayed | ( | const TransportAddress & | destination | ) | [protected] |
send a standard state message with a small delay
destination | destination node |
01356 { 01357 PastrySendState* selfMsg = new PastrySendState("sendStateWait"); 01358 selfMsg->setDest(destination); 01359 sendStateWait.push_back(selfMsg); 01360 scheduleAt(simTime() + sendStateWaitAmount, selfMsg); 01361 }
bool Pastry::isSiblingFor | ( | const NodeHandle & | node, | |
const OverlayKey & | key, | |||
int | numSiblings, | |||
bool * | err | |||
) | [protected, virtual] |
see BaseOverlay.cc
Reimplemented from BaseOverlay.
01367 { 01368 if (key.isUnspecified()) 01369 error("Pastry::isSiblingFor(): key is unspecified!"); 01370 01371 if ((numSiblings == 1) && (node == thisNode)) { 01372 if (leafSet->isClosestNode(key)) { 01373 *err = false; 01374 return true; 01375 } else { 01376 *err = false; 01377 return false; 01378 } 01379 } 01380 01381 NodeVector* result = leafSet->createSiblingVector(key, numSiblings); 01382 01383 if (result == NULL) { 01384 *err = true; 01385 return false; 01386 } 01387 01388 if (result->contains(node.key)) { 01389 delete result; 01390 *err = false; 01391 return true; 01392 } else { 01393 delete result; 01394 *err = true; 01395 return false; 01396 } 01397 01398 /* 01399 const NodeHandle& dest = leafSet->getDestinationNode(key); 01400 if (!dest.isUnspecified()) { 01401 *err = false; 01402 return true; 01403 } else { 01404 01405 *err = true; 01406 return false; 01407 } 01408 */ 01409 }
AbstractLookup * Pastry::createLookup | ( | const BaseRouteMessage * | msg = NULL |
) | [protected, virtual] |
01653 { 01654 PastryFindNodeExtData* findNodeExt = 01655 new PastryFindNodeExtData("findNodeExt"); 01656 01657 if (msg) 01658 { 01659 const PastryMessage* pmsg = dynamic_cast<const PastryMessage*>( 01660 msg->encapsulatedMsg()); 01661 if ((pmsg) && (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN)) 01662 { 01663 const PastryJoinMessage* jmsg = 01664 check_and_cast<const PastryJoinMessage*>(pmsg); 01665 findNodeExt->setSendStateTo(jmsg->getSendStateTo()); 01666 findNodeExt->setJoinHopCount(1); 01667 } 01668 } 01669 findNodeExt->setLength(PASTRYFINDNODEEXTDATA_L); 01670 AbstractLookup* newLookup = new BaseLookup(this, 01671 baseLookupConfig, findNodeExt); 01672 lookups.insert(newLookup); 01673 delete findNodeExt; 01674 return newLookup; 01675 }
void Pastry::forwardMessageRecursive | ( | const TransportAddress & | dest, | |
BaseRouteMessage * | msg | |||
) | [private, virtual] |
Hook for forwarded message in recursive lookup mode.
Default implementation just calls sendMessageToUDP(). This hook can for example be used to detect failed nodes and call handleFailedNode() before the actual forwarding takes place.
dest | destination node | |
msg | message to send |
Reimplemented from BaseOverlay.
00632 { 00633 PastryMessage* pmsg = dynamic_cast<PastryMessage*>( 00634 msg->encapsulatedMsg()); 00635 if ( pmsg && (dest != thisNode) ) 00636 { 00637 if (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN) 00638 { 00639 PastryJoinMessage* jmsg = check_and_cast<PastryJoinMessage*>(pmsg); 00640 RECORD_STATS(joinSeen++; joinBytesSeen += jmsg->byteLength()); 00641 sendStateTables(jmsg->getSendStateTo(), PASTRY_STATE_JOIN, 00642 jmsg->getJoinHopCount(), false); 00643 jmsg->setJoinHopCount(jmsg->getJoinHopCount() + 1); 00644 } 00645 } 00646 00647 if (recFwdQueue.find(dest) != recFwdQueue.end()) 00648 { 00649 // rare case, other message for same next hop is pending: 00650 // send the message and hope it isn't lost. 00651 sendMessageToUDP(dest, msg); 00652 return; 00653 } 00654 00655 if (optimisticForward) 00656 { 00657 // forward now: 00658 sendMessageToUDP(dest, msg); 00659 if (! avoidDuplicates) 00660 { 00661 // and keep copy for possible retry: 00662 recFwdQueue[dest] = static_cast<BaseRouteMessage*>(msg->dup()); 00663 } 00664 } 00665 else 00666 { 00667 // keep message in queue (forward later) 00668 recFwdQueue[dest] = msg; 00669 } 00670 pingNode(dest, pingTimeout, pingRetries, "PING next hop"); 00671 }
void Pastry::doJoinUpdate | ( | void | ) | [private] |
send updated state to all nodes when entering ready state
00674 { 00675 // send "update" state message to all nodes who sent us their state 00676 // during INIT, remove these from notifyList so they don't get our 00677 // state twice 00678 std::vector<TransportAddress>::iterator nListPos; 00679 if (!stReceived.empty()) 00680 { 00681 for (std::vector<PastryStateMessage*>::iterator it = 00682 stReceived.begin(); it != stReceived.end(); it++) 00683 { 00684 sendStateTables((*it)->getSender(), PASTRY_STATE_UPDATE, 00685 (*it)->getTimestamp()); 00686 nListPos = find(notifyList.begin(), notifyList.end(), 00687 (*it)->getSender()); 00688 if (nListPos != notifyList.end()) 00689 { 00690 notifyList.erase(nListPos); 00691 } 00692 delete *it; 00693 } 00694 stReceived.clear(); 00695 } 00696 00697 // send a normal STATE message to all remaining known nodes 00698 for (std::vector<TransportAddress>::iterator it = 00699 notifyList.begin(); it != notifyList.end(); it++) 00700 { 00701 if (*it != thisNode) sendStateTables(*it); 00702 } 00703 notifyList.clear(); 00704 00705 updateTooltip(); 00706 }
void Pastry::doSecondStage | ( | void | ) | [private] |
do the second stage of initialization as described in the paper
00709 { 00710 // "second stage" for locality: 00711 notifyList.clear(); 00712 routingTable->dumpToVector(notifyList); 00713 neighborhoodSet->dumpToVector(notifyList); 00714 sort(notifyList.begin(), notifyList.end()); 00715 notifyList.erase(unique(notifyList.begin(), notifyList.end()), 00716 notifyList.end()); 00717 for (std::vector<TransportAddress>::iterator it = notifyList.begin(); 00718 it != notifyList.end(); it++) 00719 { 00720 if (*it == thisNode) continue; 00721 EV << "second stage: requesting state from " << *it << endl; 00722 PastryStateRequestMessage* msg = 00723 new PastryStateRequestMessage("SREQ"); 00724 msg->setSignaling(true); 00725 msg->setPastryMsgType(PASTRY_MSG_SREQ); 00726 msg->setSendStateTo(thisNode); 00727 msg->setLength(PASTRYSREQ_L(msg)); 00728 RECORD_STATS(stateReqSent++; stateReqBytesSent += 00729 msg->byteLength()); 00730 sendMessageToUDP(*it, msg); 00731 } 00732 notifyList.clear(); 00733 }
void Pastry::purgeVectors | ( | void | ) | [private] |
delete all information/messages caching vectors, used for restarting overlay or finish()
00135 { 00136 PastryStateMessage* stateMsg; 00137 00138 // purge pending state messages 00139 if (!stReceived.empty()) 00140 { 00141 for (std::vector<PastryStateMessage*>::iterator it = 00142 stReceived.begin(); it != stReceived.end(); it++) 00143 { 00144 // check whether one of the pointers is a duplicate of stateCache 00145 if (*it == stateCache) stateCache = NULL; 00146 delete *it; 00147 } 00148 stReceived.clear(); 00149 } 00150 00151 // purge notify list: 00152 notifyList.clear(); 00153 00154 // purge Ping Cache: 00155 pingCache.clear(); 00156 00157 // purge proximity cache for received state messages: 00158 stateReceivedProximities.clear(); 00159 00160 // purge Queue for messages to be forwarded in recursive mode: 00161 for (std::map<TransportAddress, BaseRouteMessage*>::iterator i = 00162 recFwdQueue.begin(); i != recFwdQueue.end(); i++) 00163 { 00164 delete i->second; 00165 } 00166 recFwdQueue.clear(); 00167 00168 // purge Queue for processing multiple STATE messages: 00169 while (! stateCacheQueue.empty()) 00170 { 00171 stateMsg = (PastryStateMessage*) stateCacheQueue.pop(); 00172 delete stateMsg; 00173 } 00174 00175 // delete cached state message: 00176 if (stateCache) 00177 { 00178 delete stateCache; 00179 stateCache = NULL; 00180 } 00181 00182 // purge vector of waiting sendState messages: 00183 if (! sendStateWait.empty()) 00184 { 00185 for (std::vector<PastrySendState*>::iterator it = 00186 sendStateWait.begin(); it != sendStateWait.end(); it++) 00187 { 00188 if ( (*it)->isScheduled() ) cancelEvent(*it); 00189 delete *it; 00190 } 00191 sendStateWait.clear(); 00192 } 00193 }
void Pastry::prePing | ( | const PastryStateMessage * | stateMsg | ) | [private] |
ping all nodes in a given state message.
this is called when a state message arrives while another one is still being processed.
00805 { 00806 int i; 00807 int rt_size; 00808 int ls_size; 00809 int ns_size; 00810 const NodeHandle* node; 00811 PastryPingCache::iterator it; 00812 PastryPingCacheEntry pce; 00813 simtime_t now; 00814 00815 now = simTime(); 00816 pce.inserted = now; 00817 pce.rtt = PASTRY_PROX_PENDING; 00818 rt_size = stateMsg->getRoutingTableArraySize(); 00819 ls_size = stateMsg->getLeafSetArraySize(); 00820 ns_size = stateMsg->getNeighborhoodSetArraySize(); 00821 00822 for (i = 0; i < rt_size + ls_size + ns_size; i++) 00823 { 00824 if (i < rt_size) 00825 node = &(stateMsg->getRoutingTable(i)); 00826 else if (i < (rt_size + ls_size) ) 00827 node = &(stateMsg->getLeafSet(i - rt_size)); 00828 else 00829 node = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size)); 00830 00831 if (node->isUnspecified()) continue; 00832 if (*node == thisNode) continue; 00833 if (node->key == thisNode.key) 00834 { 00835 cerr << "Pastry Warning: Other node with same key found, " 00836 "restarting!" << endl; 00837 joinOverlay(); 00838 return; 00839 } 00840 if (((it = pingCache.find(node->ip)) != pingCache.end()) && 00841 ((now - it->second.inserted) < pingCacheExpireTime)) 00842 { 00843 // proximity known or ping already pending 00844 continue; 00845 } 00846 00847 // update pingCache 00848 pingCache[node->ip] = pce; 00849 00850 // send ping 00851 pingNode(*node, pingTimeout, pingRetries, "PING received state"); 00852 } 00853 }
void Pastry::pingNodes | ( | void | ) | [private] |
ping all nodes in the pastry state message pointed to by private member stateCache
00856 { 00857 int i; 00858 int rt_size; 00859 int ls_size; 00860 int ns_size; 00861 const NodeHandle* node; 00862 std::vector<simtime_t>::iterator proxPos; 00863 PastryPingCache::iterator it; 00864 PastryPingCacheEntry pce; 00865 simtime_t now; 00866 00867 now = simTime(); 00868 pce.inserted = now; 00869 pce.rtt = PASTRY_PROX_PENDING; 00870 00871 rt_size = stateCache->getRoutingTableArraySize(); 00872 proxCache.pr_rt.clear(); 00873 proxCache.pr_rt.resize(rt_size, PASTRY_PROX_PENDING); 00874 00875 ls_size = stateCache->getLeafSetArraySize(); 00876 proxCache.pr_ls.clear(); 00877 proxCache.pr_ls.resize(ls_size, PASTRY_PROX_PENDING); 00878 00879 ns_size = stateCache->getNeighborhoodSetArraySize(); 00880 proxCache.pr_ns.clear(); 00881 proxCache.pr_ns.resize(ns_size, PASTRY_PROX_PENDING); 00882 00883 for (i = 0; i < rt_size + ls_size + ns_size; i++) 00884 { 00885 if (i < rt_size) 00886 { 00887 node = &(stateCache->getRoutingTable(i)); 00888 proxPos = proxCache.pr_rt.begin() + i; 00889 } 00890 else if ( i < (rt_size + ls_size) ) 00891 { 00892 node = &(stateCache->getLeafSet(i - rt_size)); 00893 proxPos = proxCache.pr_ls.begin() + (i - rt_size); 00894 } 00895 else 00896 { 00897 node = &(stateCache->getNeighborhoodSet(i - rt_size - ls_size)); 00898 proxPos = proxCache.pr_ns.begin() + (i - rt_size - ls_size); 00899 } 00900 00901 // proximity is undefined for unspecified nodes: 00902 if (node->isUnspecified()) 00903 { 00904 *proxPos = PASTRY_PROX_UNDEF; 00905 } 00906 00907 // and 0 for own node: 00908 else if (*node == thisNode) 00909 { 00910 *proxPos = 0; 00911 } 00912 00913 else if (node->key == thisNode.key) 00914 { 00915 cerr << "Pastry Warning: Other node with same key found, " 00916 "restarting!" << endl; 00917 joinOverlay(); 00918 return; 00919 } 00920 00921 // else determine real value: 00922 else 00923 { 00924 if ((it = pingCache.find(node->ip)) != pingCache.end()) 00925 { 00926 if ((now - it->second.inserted) < pingCacheExpireTime) 00927 { 00928 *proxPos = it->second.rtt; 00929 if (debugOutput) 00930 { 00931 EV << "Pastry: pingCache HIT" << endl; 00932 } 00933 continue; 00934 } 00935 else 00936 { 00937 if (debugOutput) 00938 { 00939 EV << "Pastry: pingCache OUTDATED" << endl; 00940 } 00941 pingCache.erase(it); 00942 } 00943 } 00944 else if (debugOutput) 00945 { 00946 EV << "Pastry: pingCache MISS" << endl; 00947 } 00948 00949 // update pingCache 00950 pingCache[node->ip] = pce; 00951 00952 // send ping 00953 pingNode(*node, pingTimeout, pingRetries, "PING received state"); 00954 } 00955 } 00956 checkProxCache(); 00957 }
void Pastry::determineAliveTable | ( | const PastryStateMessage * | stateMsg | ) | [private] |
change the aliveTable to match the given stateMsg.
each node that's knowm to be dead from our pingCache gets a value of PASTRY_PROX_INFINITE, all other nodes just get a value of 1
00960 { 00961 int i; 00962 int rt_size; 00963 int ls_size; 00964 int ns_size; 00965 const IPvXAddress* ip; 00966 std::vector<simtime_t>::iterator tblPos; 00967 PastryPingCache::iterator it; 00968 simtime_t now; 00969 00970 now = simTime(); 00971 00972 rt_size = stateMsg->getRoutingTableArraySize(); 00973 aliveTable.pr_rt.clear(); 00974 aliveTable.pr_rt.resize(rt_size, 1); 00975 00976 ls_size = stateMsg->getLeafSetArraySize(); 00977 aliveTable.pr_ls.clear(); 00978 aliveTable.pr_ls.resize(ls_size, 1); 00979 00980 ns_size = stateMsg->getNeighborhoodSetArraySize(); 00981 aliveTable.pr_ns.clear(); 00982 aliveTable.pr_ns.resize(ns_size, 1); 00983 00984 for (i = 0; i < rt_size + ls_size + ns_size; i++) 00985 { 00986 if (i < rt_size) 00987 { 00988 ip = &(stateMsg->getRoutingTable(i).ip); 00989 tblPos = aliveTable.pr_rt.begin() + i; 00990 } 00991 else if ( i < (rt_size + ls_size) ) 00992 { 00993 ip = &(stateMsg->getLeafSet(i - rt_size).ip); 00994 tblPos = aliveTable.pr_ls.begin() + (i - rt_size); 00995 } 00996 else 00997 { 00998 ip = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size).ip); 00999 tblPos = aliveTable.pr_ns.begin() + (i - rt_size - ls_size); 01000 } 01001 01002 if (((it = pingCache.find(*ip)) != pingCache.end()) && 01003 (it->second.rtt == PASTRY_PROX_INFINITE) && 01004 ((now - it->second.inserted) < pingCacheExpireTime)) 01005 { 01006 *tblPos = PASTRY_PROX_INFINITE; 01007 } 01008 } 01009 }
void Pastry::checkProxCache | ( | void | ) | [private] |
checks whether proxCache is complete, takes appropriate actions depending on the protocol state
01012 { 01013 simtime_t now = simTime(); 01014 01015 // no cached STATE message? 01016 if (!stateCache) return; 01017 01018 // no entries in proxCache? 01019 if (proxCache.pr_rt.empty()) return; 01020 if (proxCache.pr_ls.empty()) return; 01021 if (proxCache.pr_ns.empty()) return; 01022 01023 // some entries not yet determined? 01024 if (find(proxCache.pr_rt.begin(), proxCache.pr_rt.end(), 01025 PASTRY_PROX_PENDING) != proxCache.pr_rt.end() 01026 ) return; 01027 if (find(proxCache.pr_ls.begin(), proxCache.pr_ls.end(), 01028 PASTRY_PROX_PENDING) != proxCache.pr_ls.end() 01029 ) return; 01030 if (find(proxCache.pr_ns.begin(), proxCache.pr_ns.end(), 01031 PASTRY_PROX_PENDING) != proxCache.pr_ns.end() 01032 ) return; 01033 01034 if (state == JOIN) 01035 { 01036 stateReceivedProximities.push_back(proxCache); 01037 proxCache.pr_rt.clear(); 01038 proxCache.pr_ls.clear(); 01039 proxCache.pr_ns.clear(); 01040 01041 // collected proximities for all STATE messages? 01042 if (stateReceivedProximities.size() == stReceived.size()) 01043 { 01044 stateCache = NULL; 01045 if (debugOutput) 01046 { 01047 EV << "Pastry: [JOIN] starting to build own state from " 01048 << stReceived.size() << " received state messages..." 01049 << endl; 01050 EV << "Pastry: [JOIN] initializing NeighborhoodSet from " 01051 << stReceived.front()->getJoinHopCount() << ". hop" 01052 << endl; 01053 } 01054 if (!neighborhoodSet->mergeState(stReceived.front(), 01055 stateReceivedProximities.front())) 01056 { 01057 EV << "Pastry: Error initializing own neighborhoodSet while " 01058 "joining! Restarting ..." << endl; 01059 joinOverlay(); 01060 return; 01061 } 01062 if (debugOutput) 01063 { 01064 EV << "Pastry: [JOIN] initializing LeafSet from " 01065 << stReceived.back()->getJoinHopCount() << ". hop" << endl; 01066 } 01067 if (!leafSet->mergeState(stReceived.back(), 01068 stateReceivedProximities.back())) 01069 { 01070 EV << "Pastry: Error initializing own leafSet while " 01071 "joining! Restarting ..." << endl; 01072 joinOverlay(); 01073 return; 01074 } 01075 if (debugOutput) 01076 { 01077 EV << "Pastry: [JOIN] initializing RoutingTable from all hops" 01078 << endl; 01079 } 01080 if (!routingTable->initStateFromMsgVector( 01081 stReceived, stateReceivedProximities)) 01082 { 01083 EV << "Pastry: Error initializing own routingTable " 01084 "while joining! Restarting ..." << endl; 01085 joinOverlay(); 01086 return; 01087 } 01088 lastStateChange = now; 01089 newLeafs(); 01090 changeState(READY); 01091 } 01092 else 01093 { 01094 // process next state message in vector: 01095 stateCache = *(stReceived.begin() + 01096 stateReceivedProximities.size()); 01097 pingNodes(); 01098 } 01099 } 01100 else 01101 { 01102 // state == READY 01103 01104 if (debugOutput) 01105 { 01106 EV << "Pastry: handling STATE message" << endl; 01107 EV << " type: " << 01108 ((stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE)? 01109 "update":"standard") << endl; 01110 if (stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE) 01111 { 01112 EV << " msg timestamp: " << 01113 stateCache->getTimestamp() << endl; 01114 EV << " last state change: " << 01115 lastStateChange << endl; 01116 } 01117 } 01118 01119 if (stateCache->getPastryStateMsgType() == PASTRY_STATE_REPAIR) 01120 { 01121 // try to repair routingtable based on repair message: 01122 const TransportAddress& askRt = 01123 routingTable->repair(stateCache, proxCache); 01124 if (! askRt.isUnspecified()) sendRepairRequest(askRt); 01125 01126 // while not really known, it's safe to assume that a repair 01127 // message changed our state: 01128 lastStateChange = now; 01129 } 01130 else 01131 { 01132 if (((stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE)) 01133 && (stateCache->getTimestamp() <= lastStateChange)) 01134 { 01135 // if we received an update based on our outdated state, 01136 // send new state message: 01137 EV << "Pastry: outdated state from " << stateCache->getSender() 01138 << endl; 01139 sendStateDelayed(stateCache->getSender()); 01140 } 01141 01142 // merge info in own state tables 01143 // except leafset (was already handled in handleStateMessage) 01144 if (neighborhoodSet->mergeState(stateCache, proxCache)) 01145 lastStateChange = now; 01146 01147 if (routingTable->mergeState(stateCache, proxCache)) 01148 lastStateChange = now; 01149 } 01150 01151 updateTooltip(); 01152 01153 // if state message was not an update, send one back: 01154 if (stateCache->getPastryStateMsgType() != PASTRY_STATE_UPDATE) 01155 { 01156 sendStateTables(stateCache->getSender(), PASTRY_STATE_UPDATE, 01157 stateCache->getTimestamp()); 01158 } 01159 01160 delete stateCache; 01161 stateCache = NULL; 01162 proxCache.pr_rt.clear(); 01163 01164 // process next queued message: 01165 if (! stateCacheQueue.empty()) 01166 { 01167 stateCache = (PastryStateMessage*) stateCacheQueue.pop(); 01168 pingNodes(); 01169 } 01170 } 01171 }
void Pastry::sendRepairRequest | ( | const TransportAddress & | ask | ) | [private] |
send a repair request to a given node
ask | request repair from this node |
01248 { 01249 if (ask.isUnspecified()) 01250 opp_error("Pastry::sendRepairRequest(): asked for repair from " 01251 "unspecified node!"); 01252 01253 PastryRepairRequestMessage* msg = new PastryRepairRequestMessage("RREQ"); 01254 msg->setPastryMsgType(PASTRY_MSG_RREQ); 01255 msg->setSignaling(true); 01256 msg->setSendStateTo(thisNode); 01257 msg->setLength(PASTRYRREQ_L(msg)); 01258 RECORD_STATS(repairReqSent++; repairReqBytesSent += msg->byteLength()); 01259 sendMessageToUDP(ask, msg); 01260 }
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.
01263 { 01264 if (state != READY) 01265 { 01266 return false; 01267 } 01268 01269 if (failed.isUnspecified()) 01270 opp_error("Pastry::handleFailedNode(): failed is unspecified!"); 01271 01272 const TransportAddress& lsAsk = leafSet->failedNode(failed); 01273 const TransportAddress& rtAsk = routingTable->failedNode(failed); 01274 neighborhoodSet->failedNode(failed); 01275 01276 if (! lsAsk.isUnspecified()) sendRepairRequest(lsAsk); 01277 if (! rtAsk.isUnspecified()) sendRepairRequest(rtAsk); 01278 01279 newLeafs(); 01280 01281 if (lsAsk.isUnspecified() && (! leafSet->isValid())) 01282 { 01283 EV << "Pastry: lost connection to the network, trying to re-join." 01284 << endl; 01285 joinOverlay(); 01286 return false; 01287 } 01288 01289 return true; 01290 }
void Pastry::joinOverlay | ( | ) | [private, virtual] |
Reimplemented from BaseOverlay.
00208 { 00209 changeState(INIT); 00210 00211 if (bootstrapNode.isUnspecified()) 00212 { 00213 // no existing pastry network -> first node of a new one 00214 changeState(READY); 00215 } 00216 else 00217 { 00218 // join existing pastry network 00219 changeState(JOIN); 00220 } 00221 }
void Pastry::newLeafs | ( | void | ) | [private] |
Pastry API: send newLeafs() to application if enabled.
00196 { 00197 if (! enableNewLeafs) return; 00198 00199 PastryNewLeafsMessage* msg = leafSet->getNewLeafsMessage(); 00200 if (msg) 00201 { 00202 send(msg, "to_app"); 00203 EV << "Pastry: newLeafs() called." << endl; 00204 } 00205 }
int Pastry::joins [protected] |
int Pastry::joinTries [protected] |
int Pastry::joinPartial [protected] |
int Pastry::joinSeen [protected] |
int Pastry::joinBytesSeen [protected] |
int Pastry::joinReceived [protected] |
int Pastry::joinBytesReceived [protected] |
int Pastry::joinSent [protected] |
int Pastry::joinBytesSent [protected] |
int Pastry::stateSent [protected] |
int Pastry::stateBytesSent [protected] |
int Pastry::stateReceived [protected] |
int Pastry::stateBytesReceived [protected] |
int Pastry::repairReqSent [protected] |
int Pastry::repairReqBytesSent [protected] |
int Pastry::repairReqReceived [protected] |
int Pastry::repairReqBytesReceived [protected] |
int Pastry::stateReqSent [protected] |
int Pastry::stateReqBytesSent [protected] |
int Pastry::stateReqReceived [protected] |
int Pastry::stateReqBytesReceived [protected] |
int Pastry::totalLookups [protected] |
int Pastry::responsibleLookups [protected] |
int Pastry::routingTableLookups [protected] |
int Pastry::closerNodeLookups [protected] |
int Pastry::closerNodeLookupsFromNeighborhood [protected] |
PastryRoutingTable* Pastry::routingTable [private] |
PastryLeafSet* Pastry::leafSet [private] |
PastryNeighborhoodSet* Pastry::neighborhoodSet [private] |
uint Pastry::state [private] |
uint Pastry::bitsPerDigit [private] |
uint Pastry::numberOfLeaves [private] |
uint Pastry::numberOfNeighbors [private] |
uint Pastry::pingRetries [private] |
double Pastry::pingTimeout [private] |
double Pastry::readyWaitAmount [private] |
double Pastry::joinTimeoutAmount [private] |
double Pastry::secondStageWaitAmount [private] |
double Pastry::pingCacheExpireTime [private] |
double Pastry::repairTimeout [private] |
double Pastry::ringCheckInterval [private] |
double Pastry::sendStateWaitAmount [private] |
bool Pastry::enableNewLeafs [private] |
bool Pastry::optimizeLookup [private] |
bool Pastry::optimisticForward [private] |
bool Pastry::avoidDuplicates [private] |
bool Pastry::partialJoinPath [private] |
NodeHandle Pastry::bootstrapNode [private] |
std::vector<PastryStateMessage*> Pastry::stReceived [private] |
std::vector<TransportAddress> Pastry::notifyList [private] |
PastryStateMessage* Pastry::stateCache [private] |
cQueue Pastry::stateCacheQueue [private] |
PastryStateMsgProximity Pastry::proxCache [private] |
PastryStateMsgProximity Pastry::aliveTable [private] |
std::vector<PastryStateMsgProximity> Pastry::stateReceivedProximities [private] |
PastryPingCache Pastry::pingCache [private] |
std::map<TransportAddress, BaseRouteMessage*> Pastry::recFwdQueue [private] |
uint Pastry::joinHopCount [private] |
cMessage* Pastry::joinTimeout [private] |
cMessage* Pastry::readyWait [private] |
cMessage* Pastry::secondStageWait [private] |
cMessage* Pastry::joinUpdateWait [private] |
cMessage* Pastry::ringCheck [private] |
std::vector<PastrySendState*> Pastry::sendStateWait [private] |
simtime_t Pastry::lastStateChange [private] |