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