Pastry Class Reference

#include <Pastry.h>

Inheritance diagram for Pastry:

BaseOverlay RpcListener List of all members.

Detailed Description

Pastry overlay module.

Author:
Felix Palmen
See also:
BaseOverlay


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 handleRpc (BaseCallMessage *msg)
 process RPC messages
virtual void handleRpcResponse (BaseResponseMessage *msg, int rpcId, simtime_t rtt)
 process RPC responses
virtual void handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, int rpcID)
 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 NodeVectorfindNode (const OverlayKey &key, BaseOverlayMessage *msg)
 implement the findNode call

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
virtual bool isResponsible (const OverlayKey &key)
 Query if the node knowns the k-neighborhood for a key.
virtual AbstractLookupcreateLookup (const BaseRouteMessage *msg=NULL)
 Creates a abstract iterative lookup instance.

Protected Attributes

int joins
int joinTries
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

Private Member Functions

virtual void forwardMessageRecursive (const TransportAddress &dest, BaseRouteMessage *msg)
 Hook for forwarded message in recursive lookup mode.
void rpcPing (PingCall *call)
 handle "Ping" RPC
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 pingNodes (void)
 ping all nodes in the routing table and neighborhood set of the pastry state message pointed to by private member stateCache
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
void reJoin (void)
 try to re-join the network after a lost connection
void newLeafs (void)
 Pastry API: send newLeafs() to application if enabled.

Private Attributes

PastryRoutingTableroutingTable
PastryLeafSetleafSet
PastryNeighborhoodSetneighborhoodSet
uint state
uint bitsPerDigit
uint numberOfLeaves
uint numberOfNeighbors
double readyWaitAmount
double joinTimeoutAmount
double secondStageWaitAmount
double pingCacheExpireTime
double repairTimeout
double ringCheckInterval
bool enableNewLeafs
bool optimizeLookup
bool optimisticForward
bool avoidDuplicates
NodeHandle bootstrapNode
std::vector< PastryStateMessage * > stReceived
std::vector< TransportAddressnotifyList
PastryStateMessagestateCache
cQueue stateCacheQueue
PastryStateMsgProximity proxCache
std::vector< PastryStateMsgProximitystateReceivedProximities
PastryPingCache pingCache
std::map< TransportAddress,
BaseRouteMessage * > 
recFwdQueue
uint joinHopCount
cMessage * joinTimeout
cMessage * readyWait
cMessage * secondStageWait
cMessage * ringCheck
simtime_t lastStateChange


Member Function Documentation

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

changes node state

Parameters:
toState state to change to
00223 {
00224     if (ringCheck->isScheduled()) cancelEvent(ringCheck);
00225 
00226     switch (toState)
00227     {
00228         case INIT:
00229             
00230             state = INIT;
00231 
00232             if (!thisNode.key.isUnspecified())
00233                 bootstrapOracle->removePeer(thisNode);
00234 
00235             if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00236             if (readyWait->isScheduled()) cancelEvent(readyWait);
00237 
00238             purgeVectors();
00239             
00240             thisNode.key = OverlayKey::random();
00241             callUpdate(thisNode, true);
00242             bootstrapNode = bootstrapOracle->getBootstrapNode();
00243             
00244             routingTable->initializeTable(bitsPerDigit, repairTimeout,
00245                     thisNode);
00246             leafSet->initializeSet(numberOfLeaves, repairTimeout, thisNode);
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             joinHopCount = 0;
00260 
00261             {
00262                 PastryJoinMessage* msg = new PastryJoinMessage("JOIN-Request");
00263                 msg->setPastryMsgType(PASTRY_MSG_JOIN);
00264                 msg->setSignaling(true);
00265                 msg->setJoinHopCount(1);
00266                 msg->setSendStateTo(thisNode);
00267                 msg->setLength(PASTRYJOIN_L(msg));
00268                 RECORD_STATS(joinSent++; joinBytesSent += msg->byteLength());
00269                 sendToKey(thisNode.key, msg, 0, bootstrapNode);
00270             }
00271             
00272             cancelEvent(joinTimeout);
00273             scheduleAt(simTime()+joinTimeoutAmount, joinTimeout);
00274 
00275             updateTooltip();
00276             parentModule()->parentModule()->bubble("entering JOIN state");
00277 
00278             RECORD_STATS(joinTries++);
00279 
00280             break;
00281         
00282         case READY:
00283 
00284             state = READY;
00285             if (ringCheckInterval > 0)
00286             {
00287                 scheduleAt(simTime()+ringCheckInterval, ringCheck);
00288             }
00289 
00290             bootstrapOracle->registerPeer(thisNode);
00291 
00292             // if we are the first node in the network, there's nothing else
00293             // to do
00294             if (bootstrapNode.isUnspecified())
00295             {
00296                 RECORD_STATS(joinTries++);
00297                 RECORD_STATS(joins++);
00298                 setReadyIcon(true);
00299                 return;
00300             }
00301 
00302             // determine list of all known nodes as notifyList
00303             notifyList.clear();
00304             leafSet->dumpToVector(notifyList);
00305             routingTable->dumpToVector(notifyList);
00306             sort(notifyList.begin(), notifyList.end());
00307             notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00308                     notifyList.end());
00309         
00310             // send "update" state message to all nodes who sent us their state
00311             // during INIT, remove these from notifyList so they don't get our
00312             // state twice
00313             std::vector<TransportAddress>::iterator nListPos;
00314             if (!stReceived.empty())
00315             {
00316                 for (std::vector<PastryStateMessage*>::iterator it =
00317                         stReceived.begin(); it != stReceived.end(); it++)
00318                 {
00319                     sendStateTables((*it)->getSender(), PASTRY_STATE_UPDATE,
00320                             (*it)->getTimestamp());
00321                     nListPos = find(notifyList.begin(), notifyList.end(),
00322                             (*it)->getSender());
00323                     if (nListPos != notifyList.end())
00324                     {
00325                         notifyList.erase(nListPos);
00326                     }
00327                     if (debugOutput)
00328                     {
00329                         EV << "Pastry::changeState() deleting STATE message "
00330                             << static_cast<void*>(*it) << endl;
00331                     }
00332                     delete *it;
00333                 }
00334                 stReceived.clear();
00335             }
00336 
00337             // send a normal STATE message to all remaining known nodes
00338             for (std::vector<TransportAddress>::iterator it =
00339                     notifyList.begin(); it != notifyList.end(); it++)
00340             {
00341                 if (*it != thisNode) sendStateTables(*it);
00342             }
00343 
00344             updateTooltip();
00345             parentModule()->parentModule()->bubble("entering READY state");
00346 
00347             // schedule second stage
00348             cancelEvent(secondStageWait);
00349             scheduleAt(simTime() + secondStageWaitAmount, secondStageWait);
00350 
00351             RECORD_STATS(joins++);
00352 
00353             break;
00354     }
00355     setReadyIcon(state == READY);
00356 }

void Pastry::checkProxCache ( void   )  [private]

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

00862 {
00863     simtime_t now = simTime();
00864 
00865     // no cached STATE message?
00866     if (!stateCache) return;
00867 
00868     // no entries in proxCache?
00869     if (proxCache.pr_rt.empty()) return;
00870     if (proxCache.pr_ls.empty()) return;
00871     if (proxCache.pr_ns.empty()) return;
00872 
00873     // some entries not yet determined?
00874     if (find(proxCache.pr_rt.begin(), proxCache.pr_rt.end(),
00875                 PASTRY_PROX_PENDING) != proxCache.pr_rt.end()
00876        ) return;
00877     if (find(proxCache.pr_ls.begin(), proxCache.pr_ls.end(),
00878                 PASTRY_PROX_PENDING) != proxCache.pr_ls.end()
00879        ) return;
00880     if (find(proxCache.pr_ns.begin(), proxCache.pr_ns.end(),
00881                 PASTRY_PROX_PENDING) != proxCache.pr_ns.end()
00882        ) return;
00883 
00884     if (state == JOIN)
00885     {
00886         stateReceivedProximities.push_back(proxCache);
00887         proxCache.pr_rt.clear();
00888         proxCache.pr_ls.clear();
00889         proxCache.pr_ns.clear();
00890 
00891         // collected proximities for all STATE messages?
00892         if (stateReceivedProximities.size() == stReceived.size())
00893         {
00894             stateCache = NULL;
00895             if (debugOutput)
00896             {
00897                 EV << "Pastry: [JOIN] starting to build own state from "
00898                     << stReceived.size() << " received state messages..."
00899                     << endl;
00900                 EV << "Pastry: [JOIN] initializing NeighborhoodSet from "
00901                     << stReceived.front()->getJoinHopCount() << ". hop"
00902                     << endl;
00903             }
00904             if (!neighborhoodSet->mergeState(stReceived.front(),
00905                         stateReceivedProximities.front()))
00906             {
00907                 EV << "Pastry: Error initializing own neighborhoodSet while "
00908                     "joining! Restarting ..." << endl;
00909                 changeState(INIT);
00910                 changeState(JOIN);
00911                 return;
00912             }
00913             if (debugOutput)
00914             {
00915                 EV << "Pastry: [JOIN] initializing LeafSet from "
00916                     << stReceived.back()->getJoinHopCount() << ". hop" << endl;
00917             }
00918             if (!leafSet->mergeState(stReceived.back(),
00919                         stateReceivedProximities.back()))
00920             {
00921                 EV << "Pastry: Error initializing own leafSet while "
00922                     "joining! Restarting ..." << endl;
00923                 changeState(INIT);
00924                 changeState(JOIN);
00925                 return;
00926             }
00927             if (debugOutput)
00928             {
00929                 EV << "Pastry: [JOIN] initializing RoutingTable from all hops"
00930                     << endl;
00931             }
00932             if (!routingTable->initStateFromMsgVector(
00933                         stReceived, stateReceivedProximities))
00934             {
00935                 EV << "Pastry: Error initializing own routingTable "
00936                     "while joining! Restarting ..." << endl;
00937                 changeState(INIT);
00938                 changeState(JOIN);
00939                 return;
00940             }
00941             lastStateChange = now;
00942             newLeafs();
00943             changeState(READY);
00944         }
00945         else
00946         {
00947             // process next state message in vector:
00948             stateCache = *(stReceived.begin() +
00949                     stateReceivedProximities.size());
00950             pingNodes();
00951         }
00952     }
00953     else
00954     {
00955         // state == READY
00956 
00957         if (debugOutput)
00958         {
00959             EV << "Pastry: handling STATE message" << endl;
00960             EV << "        type: " <<
00961                 ((stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE)?
00962                  "update":"standard") << endl;
00963             if (stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE)
00964             {
00965                 EV << "        msg timestamp:      " <<
00966                     stateCache->getTimestamp() << endl;
00967                 EV << "        last state change:  " <<
00968                     lastStateChange << endl;
00969             }
00970         }
00971         
00972         if (stateCache->getPastryStateMsgType() == PASTRY_STATE_REPAIR)
00973         {
00974             // try to repair own states based on repair message:
00975             const TransportAddress& askRt =
00976                     routingTable->repair(stateCache, proxCache);
00977             if (! askRt.isUnspecified()) sendRepairRequest(askRt);
00978             
00979             const TransportAddress& askLs =
00980                     leafSet->repair(stateCache, proxCache);
00981             if (! askLs.isUnspecified()) sendRepairRequest(askLs);
00982 
00983             // while not really known, it's safe to assume that a repair
00984             // message changed our state:
00985             lastStateChange = now;
00986             newLeafs();
00987         }
00988         else if ((stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE)
00989                 && (stateCache->getTimestamp() < lastStateChange))
00990         {
00991             // if we received an update based on our outdated state,
00992             // send new state message:
00993             EV << "Pastry: outdated state from " << stateCache->getSender()
00994                 << endl;
00995             sendStateTables(stateCache->getSender());
00996         }
00997         else
00998         {
00999             // merge info in own state tables:
01000             if (neighborhoodSet->mergeState(stateCache, proxCache))
01001                 lastStateChange = now;
01002 
01003             if (leafSet->mergeState(stateCache, proxCache))
01004                 lastStateChange = now;
01005             
01006             if (routingTable->mergeState(stateCache, proxCache))
01007                 lastStateChange = now;
01008 
01009             newLeafs();
01010         }
01011 
01012         updateTooltip();
01013         
01014         // if state message was not an update, send one back:
01015         if (stateCache->getPastryStateMsgType() != PASTRY_STATE_UPDATE)
01016         {
01017             sendStateTables(stateCache->getSender(), PASTRY_STATE_UPDATE,
01018                     stateCache->getTimestamp());
01019         }
01020         
01021         if (debugOutput)
01022         {
01023             EV << "Pastry::checkProxCache() deleting STATE message "
01024                 << static_cast<void*>(stateCache) << endl;
01025         }
01026         delete stateCache;
01027         stateCache = NULL;
01028         proxCache.pr_rt.clear();
01029 
01030         // process next queued message:
01031         if (! stateCacheQueue.empty())
01032         {
01033             stateCache = (PastryStateMessage*) stateCacheQueue.pop();
01034             pingNodes();
01035         }
01036     }
01037 }

AbstractLookup * Pastry::createLookup ( const BaseRouteMessage msg = NULL  )  [protected, virtual]

Creates a abstract iterative lookup instance.

Parameters:
msg pointer to the message for which the lookup is created. Derived classes can use it to construct an object with additional info for the lookup class.
Returns:
AbstractLookup* The new lookup instance.

Reimplemented from BaseOverlay.

01407 {
01408     PastryFindNodeExtData* findNodeExt =
01409         new PastryFindNodeExtData("findNodeExt");
01410 
01411     if (msg)
01412     {
01413         const PastryMessage* pmsg = dynamic_cast<const PastryMessage*>(
01414                 msg->encapsulatedMsg());
01415         if ((pmsg) && (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN))
01416         {
01417             const PastryJoinMessage* jmsg =
01418                 check_and_cast<const PastryJoinMessage*>(pmsg);
01419             findNodeExt->setSendStateTo(jmsg->getSendStateTo());
01420             findNodeExt->setJoinHopCount(1);
01421         }
01422     }
01423     findNodeExt->setLength(PASTRYFINDNODEEXTDATA_L);
01424     AbstractLookup* newLookup = new BaseLookup(this,
01425             baseLookupConfig, findNodeExt);
01426     lookups.insert(newLookup);
01427     delete findNodeExt;
01428     return newLookup;
01429 }

void Pastry::doSecondStage ( void   )  [private]

do the second stage of initialization as described in the paper

00664 {
00665     // "second stage" for locality:
00666     notifyList.clear();
00667     routingTable->dumpToVector(notifyList);
00668     neighborhoodSet->dumpToVector(notifyList);
00669     sort(notifyList.begin(), notifyList.end());
00670     notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00671             notifyList.end());
00672     for (std::vector<TransportAddress>::iterator it = notifyList.begin();
00673             it != notifyList.end(); it++)
00674     {
00675         if (*it == thisNode) continue;
00676         EV << "second stage: requesting state from " << *it << endl;
00677         PastryStateRequestMessage* msg =
00678                 new PastryStateRequestMessage("SREQ");
00679         msg->setSignaling(true);
00680         msg->setPastryMsgType(PASTRY_MSG_SREQ);
00681         msg->setSendStateTo(thisNode);
00682         msg->setLength(PASTRYSREQ_L(msg));
00683         RECORD_STATS(stateReqSent++; stateReqBytesSent +=
00684                 msg->byteLength());
00685         sendMessageToUDP(*it, msg);
00686     }
00687 }

NodeVector * Pastry::findNode ( const OverlayKey key,
BaseOverlayMessage msg 
) [virtual]

implement the findNode call

Parameters:
key the destination key
msg the message to route
Returns:
NodeVector containing the next hop

Reimplemented from BaseOverlay.

01308 {
01309     NodeVector* nextHop = new NodeVector(1);
01310     const NodeHandle* next;
01311     PastryFindNodeExtData* findNodeExt = NULL;
01312     if (msg && msg->hasObject("findNodeExt"))
01313     {
01314         findNodeExt = check_and_cast<PastryFindNodeExtData*>(
01315                 msg->getObject("findNodeExt"));
01316     }
01317 
01318     if (state != READY)
01319     {
01320         return nextHop;
01321     }
01322     else if (key.isUnspecified() || leafSet->isClosestNode(key))
01323     {
01324         nextHop->add(thisNode);
01325         if ((! key.isUnspecified()) && (findNodeExt))
01326         {
01327             // final hop of a JOIN message, send state tables:
01328             const TransportAddress& stateRecipient =
01329                 findNodeExt->getSendStateTo();
01330             if (!stateRecipient.isUnspecified())
01331             {
01332                 sendStateTables(stateRecipient, PASTRY_STATE_JOIN,
01333                         findNodeExt->getJoinHopCount(), true);
01334             }
01335         }
01336     }
01337     else
01338     {
01339         // Send state tables on any JOIN message we see:
01340         if (findNodeExt)
01341         {
01342             const TransportAddress& stateRecipient =
01343                 findNodeExt->getSendStateTo();
01344             if (!stateRecipient.isUnspecified())
01345             {
01346                 RECORD_STATS(joinSeen++);
01347                 sendStateTables(stateRecipient, PASTRY_STATE_JOIN,
01348                         findNodeExt->getJoinHopCount(), false);
01349             }
01350         }
01351 
01352         next = &(leafSet->getDestinationNode(key));
01353 
01354         if (next->isUnspecified())
01355             next = &(routingTable->lookupNextHop(key));
01356 
01357         if (next->isUnspecified())
01358         {
01359             // call findCloserNode() on all state objects
01360 
01361             if (optimizeLookup)
01362             {
01363                 const NodeHandle* tmp;
01364                 next = &(routingTable->findCloserNode(key, true));
01365                 tmp = &(neighborhoodSet->findCloserNode(key, true));
01366 
01367                 if ((! tmp->isUnspecified()) &&
01368                         (leafSet->isCloser(*tmp, key, *next)))
01369                 {
01370                     next = tmp;
01371                 }
01372 
01373                 tmp = &(leafSet->findCloserNode(key, true));
01374                 if ((! tmp->isUnspecified()) &&
01375                         (leafSet->isCloser(*tmp, key, *next)))
01376                 {
01377                     next = tmp;
01378                 }
01379             }
01380             else
01381             {
01382                 next = &(routingTable->findCloserNode(key));
01383 
01384                 if (next->isUnspecified())
01385                     next = &(neighborhoodSet->findCloserNode(key));
01386 
01387                 if (next->isUnspecified())
01388                     next = &(leafSet->findCloserNode(key));
01389             }
01390         }
01391 
01392         if (!next->isUnspecified())
01393         {
01394             if (findNodeExt)
01395             {
01396                 findNodeExt->setJoinHopCount(
01397                         findNodeExt->getJoinHopCount() + 1);
01398             }
01399             nextHop->add(*next);
01400         }
01401     }
01402     
01403     return nextHop;
01404 }

void Pastry::finishOverlay (  )  [virtual]

collects statisticts

Reimplemented from BaseOverlay.

01261 {
01262     // collect statistics
01263 
01264     recordScalar("Pastry: Successful Joins", joins);
01265     recordScalar("Pastry: overall join tries", joinTries);
01266     recordScalar("Pastry: JOIN Messages seen", joinSeen);
01267     recordScalar("Pastry: bytes of JOIN Messages seen", joinBytesSeen);
01268     recordScalar("Pastry: JOIN Messages received", joinReceived);
01269     recordScalar("Pastry: bytes of JOIN Messages received",
01270             joinBytesReceived);
01271     recordScalar("Pastry: JOIN Messages sent", joinSent);
01272     recordScalar("Pastry: bytes of JOIN Messages sent", joinBytesSent);
01273     recordScalar("Pastry: STATE Messages sent", stateSent);
01274     recordScalar("Pastry: bytes of STATE Messages sent", stateBytesSent);
01275     recordScalar("Pastry: STATE Messages received", stateReceived);
01276     recordScalar("Pastry: bytes of STATE Messages received",
01277             stateBytesReceived);
01278     recordScalar("Pastry: REPAIR Requests sent", repairReqSent);
01279     recordScalar("Pastry: bytes of REPAIR Requests sent",
01280             repairReqBytesSent);
01281     recordScalar("Pastry: REPAIR Requests received", repairReqReceived);
01282     recordScalar("Pastry: bytes of REPAIR Requests received",
01283             repairReqBytesReceived);
01284     recordScalar("Pastry: STATE Requests sent", stateReqSent);
01285     recordScalar("Pastry: bytes of STATE Requests sent", stateReqBytesSent);
01286     recordScalar("Pastry: STATE Requests received", stateReqReceived);
01287     recordScalar("Pastry: bytes of STATE Requests received",
01288             stateReqBytesReceived);
01289 
01290     // destroy self timer messages
01291     if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
01292     if (readyWait->isScheduled()) cancelEvent(readyWait);
01293     if (secondStageWait->isScheduled()) cancelEvent(secondStageWait);
01294     if (ringCheck->isScheduled()) cancelEvent(ringCheck);
01295 
01296     delete joinTimeout;
01297     delete readyWait;
01298     delete secondStageWait;
01299     delete ringCheck;
01300 
01301     purgeVectors();
01302 
01303     // remove this node from the bootstrap list
01304     if (!thisNode.key.isUnspecified()) bootstrapOracle->removePeer(thisNode);
01305 }

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.

Parameters:
dest destination node
msg message to send

Reimplemented from BaseOverlay.

00609 {
00610     PastryMessage* pmsg = dynamic_cast<PastryMessage*>(
00611             msg->encapsulatedMsg());
00612     if ( pmsg && (dest != thisNode) )
00613     {
00614         if (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN)
00615         {
00616             PastryJoinMessage* jmsg = check_and_cast<PastryJoinMessage*>(pmsg);
00617             RECORD_STATS(joinSeen++; joinBytesSeen += jmsg->byteLength());
00618             sendStateTables(jmsg->getSendStateTo(), PASTRY_STATE_JOIN,
00619                     jmsg->getJoinHopCount(), false);
00620             jmsg->setJoinHopCount(jmsg->getJoinHopCount() + 1);
00621         }
00622     }
00623 
00624     if (recFwdQueue.find(dest) != recFwdQueue.end())
00625     {
00626         // rare case, other message for same next hop is pending:
00627         // send the message and hope it isn't lost.
00628         sendMessageToUDP(dest, msg);
00629         return;
00630     }
00631 
00632     if (optimisticForward)
00633     {
00634         // forward now:
00635         sendMessageToUDP(dest, msg);
00636         if (! avoidDuplicates)
00637         {
00638             // and keep copy for possible retry:
00639             recFwdQueue[dest] = static_cast<BaseRouteMessage*>(msg->dup());
00640         }
00641     }
00642     else
00643     {
00644         // keep message in queue (forward later)
00645         recFwdQueue[dest] = msg;
00646     }
00647     sendRpcMessage(dest, new PingCall("PING next hop"),
00648             NULL, OverlayKey::UNSPECIFIED_KEY, -1, 5.0, 2);
00649 }

void Pastry::handleAppMessage ( BaseOverlayMessage msg  )  [virtual]

processes messages from application

Parameters:
msg message from application
01225 {
01226     delete msg;
01227 }

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

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

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

Reimplemented from BaseOverlay.

01133 {
01134     if (state != READY)
01135     {
01136         return false;
01137     }
01138 
01139     if (failed.isUnspecified())
01140         opp_error("Pastry::handleFailedNode(): failed is unspecified!");
01141 
01142     const TransportAddress& lsAsk = leafSet->failedNode(failed);
01143     const TransportAddress& rtAsk = routingTable->failedNode(failed);
01144     neighborhoodSet->failedNode(failed);
01145 
01146     if (! lsAsk.isUnspecified()) sendRepairRequest(lsAsk);
01147     if (! rtAsk.isUnspecified()) sendRepairRequest(rtAsk);
01148 
01149     newLeafs();
01150 
01151     if (lsAsk.isUnspecified() && (! leafSet->isValid()))
01152     {
01153         EV << "Pastry: lost connection to the network, trying to re-join."
01154             << endl;
01155         reJoin();
01156     }
01157 
01158     return true;
01159 }

void Pastry::handleRpc ( BaseCallMessage msg  )  [virtual]

process RPC messages

Parameters:
msg the RPC call message

Reimplemented from BaseOverlay.

00652 {
00653     RPC_SWITCH_START(msg)
00654         RPC_DELEGATE(Ping, rpcPing);
00655     RPC_SWITCH_END()
00656 }

void Pastry::handleRpcResponse ( BaseResponseMessage msg,
int  rpcId,
simtime_t  rtt 
) [virtual]

process RPC responses

Parameters:
msg the RPC response message
rpcId the RPC identifier
rtt round-trip time

Reimplemented from RpcListener.

00691 {
00692     const NodeHandle& src = msg->getSrcNode();
00693     const NodeHandle* node;
00694     int i;
00695     int n;
00696     PastryPingCacheEntry pce;
00697     std::map<TransportAddress, BaseRouteMessage*>::iterator pos;
00698 
00699     RPC_SWITCH_START(msg)
00700         RPC_ON_RESPONSE(Ping)
00701         {
00702             if (stateCache)
00703             {
00704                 // insert into pingCache
00705                 pce.inserted = simTime();
00706                 pce.rtt = rtt;
00707                 pingCache[src.ip] = pce;
00708 
00709                 // look for node in routing table of processed state message:
00710                 n = stateCache->getRoutingTableArraySize();
00711                 for (i = 0; i < n; i++)
00712                 {
00713                     node = &(stateCache->getRoutingTable(i));
00714                     if ((!node->isUnspecified()) && (*node == src))
00715                         *(proxCache.pr_rt.begin()+i) = rtt;
00716                 }
00717 
00718                 // look for node in leaf set of processed state message:
00719                 n = stateCache->getLeafSetArraySize();
00720                 for (i = 0; i < n; i++)
00721                 {
00722                     node = &(stateCache->getLeafSet(i));
00723                     if ((!node->isUnspecified()) && (*node == src))
00724                         *(proxCache.pr_ls.begin()+i) = rtt;
00725                 }
00726 
00727                 // look for node in neighb. set of processed state message:
00728                 n = stateCache->getNeighborhoodSetArraySize();
00729                 for (i = 0; i < n; i++)
00730                 {
00731                     node = &(stateCache->getNeighborhoodSet(i));
00732                     if ((!node->isUnspecified()) && (*node == src))
00733                         *(proxCache.pr_ns.begin()+i) = rtt;
00734                 }
00735 
00736                 checkProxCache();
00737             }
00738 
00739             if ((pos = recFwdQueue.find(src)) != recFwdQueue.end())
00740             {
00741                 // insert into pingCache
00742                 pce.inserted = simTime();
00743                 pce.rtt = rtt;
00744                 pingCache[src.ip] = pce;
00745 
00746                 // send message
00747                 if (!optimisticForward)
00748                 {
00749                     sendMessageToUDP(pos->first, pos->second);
00750                 }
00751                 else if (!avoidDuplicates)
00752                 {
00753                     delete pos->second;
00754                 }
00755                 recFwdQueue.erase(pos);
00756             }
00757 
00758             break;
00759         }
00760     RPC_SWITCH_END()
00761 }

void Pastry::handleRpcTimeout ( BaseCallMessage msg,
const TransportAddress dest,
int  rpcID 
) [virtual]

handle RPC timeouts

Parameters:
msg the RPC call that timed out
dest the destination node of the RPC call
rpcID the RPC identifier

Reimplemented from RpcListener.

01041 {
01042     const NodeHandle* node;
01043     int i;
01044     int n;
01045     PastryPingCacheEntry pce;
01046     std::map<TransportAddress, BaseRouteMessage*>::iterator pos;
01047     
01048     // update ping cache:
01049     pce.inserted = simTime();
01050     pce.rtt = PASTRY_PROX_INFINITE;
01051     pingCache[dest.ip] = pce;
01052 
01053     RPC_SWITCH_START(msg)
01054         RPC_ON_CALL(Ping)
01055         {
01056             EV << "Pastry: Ping timeout occured." << endl;
01057 
01058             if (msg->isName("PING ring check"))
01059             {
01060                 // direct neighbor on the ring found dead:
01061                 handleFailedNode(dest);
01062                 break;
01063             }
01064 
01065             if (stateCache && msg->isName("PING received state"))
01066             {
01067                 // look for node in routing table of processed state message:
01068                 n = stateCache->getRoutingTableArraySize();
01069                 for (i = 0; i < n; i++)
01070                 {
01071                     node = &(stateCache->getRoutingTable(i));
01072                     if ((!node->isUnspecified()) && (node->ip == dest.ip))
01073                         *(proxCache.pr_rt.begin() + i) = PASTRY_PROX_INFINITE;
01074                 }
01075                 
01076                 // look for node in leaf set of processed state message:
01077                 n = stateCache->getLeafSetArraySize();
01078                 for (i = 0; i < n; i++)
01079                 {
01080                     node = &(stateCache->getLeafSet(i));
01081                     if ((!node->isUnspecified()) && (node->ip == dest.ip))
01082                         *(proxCache.pr_ls.begin() + i) = PASTRY_PROX_INFINITE;
01083                 }
01084 
01085                 // look for node in neighborhood set of processed state message:
01086                 n = stateCache->getNeighborhoodSetArraySize();
01087                 for (i = 0; i < n; i++)
01088                 {
01089                     node = &(stateCache->getNeighborhoodSet(i));
01090                     if ((!node->isUnspecified()) && (node->ip == dest.ip))
01091                         *(proxCache.pr_ns.begin() + i) = PASTRY_PROX_INFINITE;
01092                 }
01093                 checkProxCache();
01094             }
01095 
01096             if (msg->isName("PING next hop"))
01097             {
01098                 // handle failed node:
01099                 handleFailedNode(dest);
01100 
01101                 // this could initiate a re-join, exit the handler in that
01102                 // case because all local data was erased:
01103                 if (state != READY) break;
01104 
01105                 // handle forward queue entry
01106                 if ((pos = recFwdQueue.find(dest)) == recFwdQueue.end()) break;
01107                 BaseRouteMessage* rmsg = pos->second;
01108                 recFwdQueue.erase(pos);
01109                 sendToKey(rmsg->getDestKey(), rmsg);
01110             }
01111 
01112             break;
01113         }
01114     RPC_SWITCH_END()
01115 }

void Pastry::handleStateMessage ( PastryStateMessage msg  ) 

processes state messages, merging with own state tables

Parameters:
msg the pastry state message
00493 {
00494     if (debugOutput)
00495     {
00496         EV << "Pastry::handleStateMessage() new STATE message to process "
00497             << static_cast<void*>(msg) << " in state " <<
00498             ((state == READY)?"READY":((state == JOIN)?"JOIN":"INIT"))
00499             << endl;
00500         if (state == JOIN)
00501         {
00502             EV << " ***   own joinHopCount:  " << joinHopCount << endl;
00503             EV << " ***   already received:  " << stReceived.size() << endl;
00504             EV << " ***   last-hop flag:     " << msg->getLastHop() << endl;
00505             EV << " ***   msg joinHopCount:  "
00506                 << msg->getJoinHopCount() << endl;
00507         }   
00508     }
00509     if (state == INIT)
00510     {
00511         EV << "Pastry: can't handle state messages until at least reaching "
00512             "JOIN state." << endl;
00513         if (debugOutput)
00514         {
00515             EV << "Pastry::handleStateMessage() deleting STATE message "
00516                 << static_cast<void*>(msg) << endl;
00517         }
00518         delete msg;
00519         return;
00520     }
00521     
00522     // in JOIN state, store all received state Messages, need them later:
00523     if (state == JOIN)
00524     {
00525         if (joinHopCount && stReceived.size() == joinHopCount)
00526         {
00527             EV << "Pastry: Warning: dropping state message received after "
00528                 "all needed state messages were collected in JOIN state."
00529                 << endl;
00530             if (debugOutput)
00531             {
00532                 EV << "Pastry::handleStateMessage() deleting STATE message "
00533                     << static_cast<void*>(msg) << endl;
00534             }
00535             delete msg;
00536             return;
00537         }
00538 
00539         stReceived.push_back(msg);
00540             
00541         if (msg->getLastHop())
00542         {
00543             if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00544 
00545             if (joinHopCount)
00546             {
00547                 EV << "Pastry: Error: received a second `last' state message! "
00548                     "Restarting ..." << endl;
00549                 changeState(INIT);
00550                 changeState(JOIN);
00551                 return;
00552             }
00553                 
00554             joinHopCount = msg->getJoinHopCount();
00555             if (stReceived.size() < joinHopCount)
00556             {
00557                 // some states still missing:
00558                 cancelEvent(readyWait);
00559                 scheduleAt(simTime()+readyWaitAmount, readyWait);
00560             }
00561         }
00562 
00563         if (joinHopCount)
00564         {
00565             if (stReceived.size() > joinHopCount)
00566             {
00567                 EV << "Pastry: Error: too many state messages received in "
00568                     "JOIN state! Restarting ..." << endl;
00569                 changeState(INIT);
00570                 changeState(JOIN);
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     // in READY state, only ping nodes to get proximity metric:
00594     if (!stateCache)
00595     {
00596         // no state message is processed right now, start immediately:
00597         stateCache = msg;
00598         pingNodes();
00599     }
00600     else
00601     {
00602         // enqueue message for later processing:
00603         stateCacheQueue.insert(msg);
00604     }
00605 }

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

handles self-messages

Parameters:
msg the self-message

Reimplemented from BaseOverlay.

00359 {
00360 
00361     if (msg->isName("joinTimeout"))
00362     {
00363         EV << "Pastry: join timeout expired, restarting..." << endl;
00364         changeState(INIT);
00365         changeState(JOIN);
00366     }
00367     else if (msg->isName("readyWait"))
00368     {
00369         EV << "Pastry: timeout waiting for missing state messages in JOIN "
00370             "state, restarting..." << endl;
00371         changeState(INIT);
00372         changeState(JOIN);
00373     }
00374     else if (msg->isName("secondStageWait"))
00375     {
00376         EV << "Pastry: sending STATE requests to all nodes in second stage "
00377             "of initialization." << endl;
00378         doSecondStage();
00379     }
00380     else if (msg->isName("ringCheck"))
00381     {
00382         if (state == READY)
00383         {
00384             // ping direct neighbors on the ring:
00385             const NodeHandle& pred = leafSet->getPredecessor();
00386             const NodeHandle& succ = leafSet->getSuccessor();
00387             if (! pred.isUnspecified())
00388             {
00389                 sendRpcMessage(pred, new PingCall("PING ring check"),
00390                         NULL, OverlayKey::UNSPECIFIED_KEY, -1, 5.0, 2);
00391             }
00392             if (! succ.isUnspecified())
00393             {
00394                 sendRpcMessage(succ, new PingCall("PING ring check"),
00395                         NULL, OverlayKey::UNSPECIFIED_KEY, -1, 5.0, 2);
00396             }
00397         }
00398         scheduleAt(simTime()+ringCheckInterval, ringCheck);
00399     }
00400 }

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

processes messages from underlay

Parameters:
msg message from UDP

Implements BaseOverlay.

00403 {
00404     PastryMessage* pastryMsg = check_and_cast<PastryMessage*>(msg);
00405     uint type = pastryMsg->getPastryMsgType();
00406 
00407     if (debugOutput)
00408     {
00409         EV << "Pastry: incoming message of type ";
00410         switch(type)
00411         {
00412             case PASTRY_MSG_STD: EV << "PASTRY_MSG_STD"; break;
00413             case PASTRY_MSG_JOIN: EV << "PASTRY_MSG_JOIN"; break;
00414             case PASTRY_MSG_STATE: EV << "PASTRY_MSG_STATE"; break;
00415             case PASTRY_MSG_RREQ: EV << "PASTRY_MSG_RREQ"; break;
00416             case PASTRY_MSG_SREQ: EV << "PASTRY_MSG_SREQ"; break;
00417             default: EV << "UNKNOWN (" << type <<")"; break;
00418         }
00419         EV << endl;
00420     }
00421     
00422     switch (type)
00423     {
00424         case PASTRY_MSG_STD:
00425             opp_error("Pastry received PastryMessage of unknown type!");
00426             break;
00427             
00428         case PASTRY_MSG_JOIN:
00429             {
00430                 PastryJoinMessage* jmsg =
00431                     check_and_cast<PastryJoinMessage*>(pastryMsg);
00432                 RECORD_STATS(joinReceived++; joinBytesReceived +=
00433                         jmsg->byteLength());
00434                 if (! iterativeLookup)
00435                 {
00436                     // in iterative lookup mode, this is handled by findNode()
00437                     if (state == READY)
00438                         sendStateTables(jmsg->getSendStateTo(),
00439                                 PASTRY_STATE_JOIN, jmsg->getJoinHopCount(),
00440                                 true);
00441                     else
00442                         EV << "Pastry: received join message before reaching "
00443                             << "READY state, dropping message!" << endl;
00444                 }
00445                 delete jmsg;
00446             }
00447             break;
00448 
00449         case PASTRY_MSG_RREQ:
00450             {
00451                 PastryRepairRequestMessage* rrmsg =
00452                     check_and_cast<PastryRepairRequestMessage*>(pastryMsg);
00453                 RECORD_STATS(repairReqReceived++; repairReqBytesReceived +=
00454                             rrmsg->byteLength());
00455                 if (state == READY)
00456                     sendStateTables(rrmsg->getSendStateTo(),
00457                             PASTRY_STATE_REPAIR);
00458                 else
00459                     EV << "Pastry: received repair request before reaching "
00460                         << "READY state, dropping message!" << endl;
00461                 delete rrmsg;
00462             }
00463             break;
00464                         
00465         case PASTRY_MSG_SREQ:
00466             {
00467                 PastryStateRequestMessage* srmsg =
00468                     check_and_cast<PastryStateRequestMessage*>(pastryMsg);
00469                 RECORD_STATS(stateReqReceived++; stateReqBytesReceived +=
00470                             srmsg->byteLength());
00471                 if (state == READY)
00472                     sendStateTables(srmsg->getSendStateTo());
00473                 else
00474                     EV << "Pastry: received state request before reaching "
00475                         << "READY state, dropping message!" << endl;
00476                 delete srmsg;
00477             }
00478             break;
00479 
00480         case PASTRY_MSG_STATE:
00481             {
00482                 PastryStateMessage* stateMsg =
00483                     check_and_cast<PastryStateMessage*>(msg);
00484                 RECORD_STATS(stateReceived++; stateBytesReceived +=
00485                             stateMsg->byteLength());
00486                 handleStateMessage(stateMsg);
00487             }
00488             break;
00489     }
00490 }

void Pastry::initializeOverlay ( int  stage  )  [virtual]

Initializes derived-class-attributes.


Initializes derived-class-attributes, called by BaseOverlay::initialize(). By default this method is called once. If more stages are needed one can overload numInitStages() and add more stages.

Parameters:
stage the init stage

Reimplemented from BaseOverlay.

00037 {
00038     if ( stage != MIN_STAGE_OVERLAY )
00039         return;
00040 
00041     bitsPerDigit = par("bitsPerDigit");
00042     numberOfLeaves = par("numberOfLeaves");
00043     numberOfNeighbors = par("numberOfNeighbors");
00044     joinTimeoutAmount = par("joinTimeout");
00045     readyWaitAmount = par("readyWait");
00046     secondStageWaitAmount = par("secondStageWait");
00047     pingCacheExpireTime = par("pingCacheExpireTime");
00048     repairTimeout = par("repairTimeout");
00049     enableNewLeafs = par("enableNewLeafs");
00050     optimizeLookup = par("optimizeLookup");
00051     optimisticForward = par("optimisticForward");
00052     avoidDuplicates = par("avoidDuplicates");
00053     ringCheckInterval = par("ringCheckInterval");
00054 
00055     if (numberOfLeaves % 2)
00056     {
00057         EV << "Pastry: Warning: numberOfLeaves must be even - adding 1.";
00058         numberOfLeaves++;
00059     }
00060 
00061     routingTable = check_and_cast<PastryRoutingTable*>
00062         (parentModule()->submodule("pastryRoutingTable"));
00063     leafSet = check_and_cast<PastryLeafSet*>
00064         (parentModule()->submodule("pastryLeafSet"));
00065     neighborhoodSet = check_and_cast<PastryNeighborhoodSet*>
00066         (parentModule()->submodule("pastryNeighborhoodSet"));
00067 
00068     joinTimeout = new cMessage("joinTimeout");
00069     readyWait = new cMessage("readyWait");
00070     secondStageWait = new cMessage("secondStageWait");
00071     ringCheck = new cMessage("ringCheck");
00072 
00073     stateCache = NULL;
00074     
00075     // initialize statistics
00076     joins = 0;
00077     joinTries = 0;
00078     joinSeen = 0;
00079     joinReceived = 0;
00080     joinSent = 0;
00081     stateSent = 0;
00082     stateReceived = 0;
00083     repairReqSent = 0;
00084     repairReqReceived = 0;
00085     stateReqSent = 0;
00086     stateReqReceived = 0;
00087 
00088     joinBytesSeen = 0;
00089     joinBytesReceived = 0;
00090     joinBytesSent = 0;
00091     stateBytesSent = 0;
00092     stateBytesReceived = 0;
00093     repairReqBytesSent = 0;
00094     repairReqBytesReceived = 0;
00095     stateReqBytesSent = 0;
00096     stateReqBytesReceived = 0;
00097 
00098     WATCH(joins);
00099     WATCH(joinTries);
00100     WATCH(joinSeen);
00101     WATCH(joinBytesSeen);
00102     WATCH(joinReceived);
00103     WATCH(joinBytesReceived);
00104     WATCH(joinSent);
00105     WATCH(joinBytesSent);
00106     WATCH(stateSent);
00107     WATCH(stateBytesSent);
00108     WATCH(stateReceived);
00109     WATCH(stateBytesReceived);
00110     WATCH(repairReqSent);
00111     WATCH(repairReqBytesSent);
00112     WATCH(repairReqReceived);
00113     WATCH(repairReqBytesReceived);
00114     WATCH(stateReqSent);
00115     WATCH(stateReqBytesSent);
00116     WATCH(stateReqReceived);
00117     WATCH(stateReqBytesReceived);
00118     WATCH(lastStateChange);
00119     WATCH(proxCache);
00120     WATCH_VECTOR(stateReceivedProximities);
00121 
00122 
00123     changeState(INIT);
00124 
00125     if (bootstrapNode.isUnspecified())
00126     {
00127         changeState(READY);
00128     }
00129     else
00130     {
00131         changeState(JOIN);
00132     }
00133 }

bool Pastry::isResponsible ( const OverlayKey key  )  [protected, virtual]

Query if the node knowns the k-neighborhood for a key.

Query if the node knowns the complete k-neighborhood for the given key. Usually these are all nodes, that are responsible for the key. If there is no k-neighborhood in a specific overlay protocol, this method simply returns true, if the node is responsible for the key.

Parameters:
key destination key
Returns:
bool true, if the node knows the k-neighborhood for key.

Reimplemented from BaseOverlay.

01218 {
01219     if (leafSet->isClosestNode(key)) return true;
01220     const NodeHandle& dest = leafSet->getDestinationNode(key);
01221     return (! dest.isUnspecified());
01222 }

void Pastry::newLeafs ( void   )  [private]

Pastry API: send newLeafs() to application if enabled.

00195 {
00196     if (! enableNewLeafs) return;
00197 
00198     PastryNewLeafsMessage* msg = leafSet->getNewLeafsMessage();
00199     if (msg)
00200     {
00201         send(msg, "to_app");
00202         EV << "Pastry: newLeafs() called." << endl;
00203     }
00204 }

void Pastry::pingNodes ( void   )  [private]

ping all nodes in the routing table and neighborhood set of the pastry state message pointed to by private member stateCache

00764 {
00765     int i;
00766     int rt_size;
00767     int ls_size;
00768     int ns_size;
00769     const NodeHandle* node;
00770     std::vector<simtime_t>::iterator proxPos;
00771     PingCall* call;
00772     PastryPingCache::iterator it;
00773 
00774     rt_size = stateCache->getRoutingTableArraySize();
00775     proxCache.pr_rt.clear();
00776     proxCache.pr_rt.resize(rt_size, PASTRY_PROX_PENDING);
00777 
00778     ls_size = stateCache->getLeafSetArraySize();
00779     proxCache.pr_ls.clear();
00780     proxCache.pr_ls.resize(ls_size, PASTRY_PROX_PENDING);
00781 
00782     ns_size = stateCache->getNeighborhoodSetArraySize();
00783     proxCache.pr_ns.clear();
00784     proxCache.pr_ns.resize(ns_size, PASTRY_PROX_PENDING);
00785 
00786     std::vector<OverlayKey>* pinged = new std::vector<OverlayKey>;
00787     pinged->reserve(rt_size + ls_size + ns_size);
00788     std::vector<OverlayKey>::iterator pingedPos;
00789 
00790     for (i = 0; i < rt_size + ls_size + ns_size; i++)
00791     {
00792         if (i < rt_size)
00793         {
00794             node = &(stateCache->getRoutingTable(i));
00795             proxPos = proxCache.pr_rt.begin() + i;
00796         }
00797         else if ( i < (rt_size + ls_size) )
00798         {
00799             node = &(stateCache->getLeafSet(i - rt_size));
00800             proxPos = proxCache.pr_ls.begin() + (i - rt_size);
00801         }
00802         else
00803         {
00804             node = &(stateCache->getNeighborhoodSet(i - rt_size - ls_size));
00805             proxPos = proxCache.pr_ns.begin() + (i - rt_size - ls_size);
00806         }
00807 
00808         // proximity is undefined for unspecified nodes:
00809         if (node->isUnspecified())
00810         {
00811             *proxPos = PASTRY_PROX_UNDEF;
00812         }
00813 
00814         // and 0 for own node:
00815         else if (*node == thisNode)
00816         {
00817             *proxPos = 0;
00818         }
00819 
00820         // else determine real value:
00821         else
00822         {
00823             if ((it = pingCache.find(node->ip)) != pingCache.end())
00824             {
00825                 if ((simTime() - it->second.inserted) < pingCacheExpireTime)
00826                 {
00827                     *proxPos = it->second.rtt;
00828                     if (debugOutput)
00829                     {
00830                         EV << "Pastry: pingCache HIT" << endl;
00831                     }
00832                     continue;
00833                 }
00834                 else
00835                 {
00836                     if (debugOutput)
00837                     {
00838                         EV << "Pastry: pingCache OUTDATED" << endl;
00839                     }
00840                     pingCache.erase(it);
00841                 }
00842             }
00843             else if (debugOutput)
00844             {
00845                 EV << "Pastry: pingCache MISS" << endl;
00846             }
00847             if ((pingedPos = find(pinged->begin(), pinged->end(), node->key))
00848                     == pinged->end())
00849             {
00850                 pinged->push_back(node->key);
00851                 call = new PingCall("PING received state");
00852                 sendRpcMessage(*node, call, NULL,
00853                         OverlayKey::UNSPECIFIED_KEY, -1, 5.0, 2);
00854             }
00855         }
00856     }
00857     delete pinged;
00858     checkProxCache();
00859 }

void Pastry::purgeVectors ( void   )  [private]

delete all information/messages caching vectors, used for restarting overlay or finish()

00136 {
00137     PastryStateMessage* stateMsg;
00138 
00139     // purge pending state messages
00140     if (!stReceived.empty())
00141     {   
00142         for (std::vector<PastryStateMessage*>::iterator it =
00143                 stReceived.begin(); it != stReceived.end(); it++)
00144         {
00145             // check whether one of the pointers is a duplicate of stateCache
00146             if (*it == stateCache) stateCache = NULL;
00147             if (debugOutput)
00148             {
00149                 EV << "Pastry::purgeVectors() deleting STATE message "
00150                     << static_cast<void*>(*it) << endl;
00151             }
00152             delete *it;
00153         }
00154         stReceived.clear();
00155     }
00156 
00157     // purge notify list:
00158     notifyList.clear();
00159 
00160     // purge Ping Cache:
00161     pingCache.clear();
00162 
00163     // purge proximity cache for received state messages:
00164     stateReceivedProximities.clear();
00165 
00166     // purge Queue for messages to be forwarded in recursive mode:
00167     for (std::map<TransportAddress, BaseRouteMessage*>::iterator i =
00168             recFwdQueue.begin(); i != recFwdQueue.end(); i++)
00169     {
00170         delete i->second;
00171     }
00172     recFwdQueue.clear();
00173 
00174     // purge Queue for processing multiple STATE messages:
00175     while (! stateCacheQueue.empty())
00176     {
00177         stateMsg = (PastryStateMessage*) stateCacheQueue.pop();
00178         delete stateMsg;
00179     }
00180     
00181     // delete cached state message:
00182     if (stateCache)
00183     {
00184         if (debugOutput)
00185         {
00186             EV << "Pastry::purgeVectors() deleting STATE message "
00187                 << static_cast<void*>(stateCache) << endl;
00188         }
00189         delete stateCache;
00190         stateCache = NULL;
00191     }
00192 }

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

callback-method for events at the NotificationBoard

Parameters:
category ... TODO ...
details ... TODO ...
01254 {
01255     // get new ip address
01256     thisNode.ip = IPAddressResolver().addressOf(
01257         parentModule()->parentModule()).get4();
01258 }

void Pastry::reJoin ( void   )  [private]

try to re-join the network after a lost connection

00207 {
00208     if (ringCheck->isScheduled()) cancelEvent(ringCheck);
00209     if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00210     if (readyWait->isScheduled()) cancelEvent(readyWait);
00211     bootstrapOracle->removePeer(thisNode);
00212     purgeVectors();
00213     bootstrapNode = bootstrapOracle->getBootstrapNode();
00214     routingTable->initializeTable(bitsPerDigit, repairTimeout, thisNode);
00215     leafSet->initializeSet(numberOfLeaves, repairTimeout, thisNode);
00216     neighborhoodSet->initializeSet(numberOfNeighbors, thisNode);
00217     updateTooltip();
00218     lastStateChange = simTime();
00219     changeState(JOIN);
00220 }

void Pastry::rpcPing ( PingCall call  )  [private]

handle "Ping" RPC

Parameters:
call the RPC call message
00659 {
00660     sendRpcResponse(call, new PingResponse("PING response"));
00661 }

void Pastry::sendRepairRequest ( const TransportAddress ask  )  [private]

send a repair request to a given node

Parameters:
ask request repair from this node
01118 {
01119     if (ask.isUnspecified())
01120         opp_error("Pastry::sendRepairRequest(): asked for repair from "
01121                 "unspecified node!");
01122     
01123     PastryRepairRequestMessage* msg = new PastryRepairRequestMessage("RREQ");
01124     msg->setPastryMsgType(PASTRY_MSG_RREQ);
01125     msg->setSignaling(true);
01126     msg->setSendStateTo(thisNode);
01127     msg->setLength(PASTRYRREQ_L(msg));
01128     RECORD_STATS(repairReqSent++; repairReqBytesSent += msg->byteLength());
01129     sendMessageToUDP(ask, msg);
01130 }

void Pastry::sendStateTables ( const TransportAddress destination,
int  type = PASTRY_STATE_STD,
  ... 
) [protected]

send a PastryStateMessage directly to a node

Parameters:
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
01162 {
01163     int hops = 0;
01164     bool last = false;
01165     simtime_t timestamp = 0;
01166 
01167     if ((type == PASTRY_STATE_JOIN) || (type == PASTRY_STATE_UPDATE))
01168     {
01169         // additional parameters needed:
01170         va_list ap;
01171         va_start(ap, type);
01172         if (type == PASTRY_STATE_JOIN)
01173         {
01174             hops = va_arg(ap, int);
01175             last = static_cast<bool>(va_arg(ap, int));
01176         }
01177         else
01178         {
01179             timestamp = va_arg(ap, simtime_t);
01180         }
01181         va_end(ap);
01182     }
01183     
01184     // create new state message and fill in standard content:
01185     PastryStateMessage* stateMsg = new PastryStateMessage("STATE");
01186     stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
01187     stateMsg->setSignaling(true);
01188     stateMsg->setPastryStateMsgType(type);
01189     stateMsg->setSender(thisNode);
01190     routingTable->dumpToStateMessage(stateMsg);
01191     leafSet->dumpToStateMessage(stateMsg);
01192     neighborhoodSet->dumpToStateMessage(stateMsg);
01193 
01194     // special fields for some types:
01195     if (type == PASTRY_STATE_JOIN)
01196     {
01197         stateMsg->setJoinHopCount(hops);
01198         stateMsg->setLastHop(last);
01199     }
01200     
01201     if (type == PASTRY_STATE_UPDATE)
01202     {
01203         EV << "Pastry: sending state (update) to " << destination << endl;
01204         stateMsg->setTimestamp(timestamp);
01205     }
01206     else
01207     {
01208         EV << "Pastry: sending state (standard) to " << destination << endl;
01209         stateMsg->setTimestamp(simTime());
01210     }
01211     
01212     stateMsg->setLength(PASTRYSTATE_L(stateMsg));
01213     RECORD_STATS(stateSent++; stateBytesSent += stateMsg->byteLength());
01214     sendMessageToUDP(destination, stateMsg);
01215 }

void Pastry::updateTooltip (  )  [virtual]

updates information shown in tk-environment

01230 {
01231     if (ev.isGUI()) {
01232         std::stringstream ttString;
01233 
01234         // show our predecessor and successor in tooltip
01235         ttString << leafSet->getPredecessor() << endl << thisNode << endl
01236             << leafSet->getSuccessor();
01237 
01238         parentModule()->parentModule()->displayString().
01239         setTagArg("tt", 0, ttString.str().c_str());
01240         parentModule()->displayString().
01241         setTagArg("tt", 0, ttString.str().c_str());
01242         displayString().setTagArg("tt", 0, ttString.str().c_str());
01243 
01244         // draw arrows:
01245         showOverlayNeighborArrow(leafSet->getSuccessor(), true,
01246                 "m=m,50,0,50,0;o=red,1");
01247         showOverlayNeighborArrow(leafSet->getPredecessor(), false,
01248                 "m=m,50,100,50,100;o=green,1");
01249 
01250     }
01251 }


Member Data Documentation

bool Pastry::avoidDuplicates [private]

uint Pastry::bitsPerDigit [private]

NodeHandle Pastry::bootstrapNode [private]

bool Pastry::enableNewLeafs [private]

int Pastry::joinBytesReceived [protected]

int Pastry::joinBytesSeen [protected]

int Pastry::joinBytesSent [protected]

uint Pastry::joinHopCount [private]

int Pastry::joinReceived [protected]

int Pastry::joins [protected]

int Pastry::joinSeen [protected]

int Pastry::joinSent [protected]

cMessage* Pastry::joinTimeout [private]

double Pastry::joinTimeoutAmount [private]

int Pastry::joinTries [protected]

simtime_t Pastry::lastStateChange [private]

PastryLeafSet* Pastry::leafSet [private]

PastryNeighborhoodSet* Pastry::neighborhoodSet [private]

std::vector<TransportAddress> Pastry::notifyList [private]

uint Pastry::numberOfLeaves [private]

uint Pastry::numberOfNeighbors [private]

bool Pastry::optimisticForward [private]

bool Pastry::optimizeLookup [private]

PastryPingCache Pastry::pingCache [private]

double Pastry::pingCacheExpireTime [private]

PastryStateMsgProximity Pastry::proxCache [private]

cMessage* Pastry::readyWait [private]

double Pastry::readyWaitAmount [private]

std::map<TransportAddress, BaseRouteMessage*> Pastry::recFwdQueue [private]

int Pastry::repairReqBytesReceived [protected]

int Pastry::repairReqBytesSent [protected]

int Pastry::repairReqReceived [protected]

int Pastry::repairReqSent [protected]

double Pastry::repairTimeout [private]

cMessage* Pastry::ringCheck [private]

double Pastry::ringCheckInterval [private]

PastryRoutingTable* Pastry::routingTable [private]

cMessage* Pastry::secondStageWait [private]

double Pastry::secondStageWaitAmount [private]

uint Pastry::state [private]

int Pastry::stateBytesReceived [protected]

int Pastry::stateBytesSent [protected]

PastryStateMessage* Pastry::stateCache [private]

cQueue Pastry::stateCacheQueue [private]

int Pastry::stateReceived [protected]

std::vector<PastryStateMsgProximity> Pastry::stateReceivedProximities [private]

int Pastry::stateReqBytesReceived [protected]

int Pastry::stateReqBytesSent [protected]

int Pastry::stateReqReceived [protected]

int Pastry::stateReqSent [protected]

int Pastry::stateSent [protected]

std::vector<PastryStateMessage*> Pastry::stReceived [private]


The documentation for this class was generated from the following files:
Generated on Fri May 11 14:52:40 2007 for ITM OverSim by  doxygen 1.4.7