Pastry Class Reference

#include <Pastry.h>

Inheritance diagram for Pastry:

BaseOverlay BaseRpc 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)
 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 NodeVectorfindNode (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 AbstractLookupcreateLookup (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

PastryRoutingTableroutingTable
PastryLeafSetleafSet
PastryNeighborhoodSetneighborhoodSet
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< TransportAddressnotifyList
PastryStateMessage * stateCache
cQueue stateCacheQueue
PastryStateMsgProximity proxCache
PastryStateMsgProximity aliveTable
std::vector< PastryStateMsgProximitystateReceivedProximities
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


Member Function Documentation

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

Initializes derived-class-attributes.


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

Parameters:
stage the init stage

Reimplemented from BaseOverlay.

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.

Parameters:
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.

Parameters:
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.

Parameters:
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.

Parameters:
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

Parameters:
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]

processes messages from application

Parameters:
msg message from application
01414 {
01415     delete msg;
01416 }

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.

Parameters:
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.
Returns:
NodeVector with closest nodes.

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.

Returns:
int number of siblings.

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().

Returns:
int number of redundant nodes returned by findNode().

Reimplemented from BaseOverlay.

01511 {
01512     return 1;
01513 }

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

changes node state

Parameters:
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

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
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

Parameters:
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.

Parameters:
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
Returns:
bool true, if the node is responsible for the key.

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.

Parameters:
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

Parameters:
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

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

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 }


Friends And Related Function Documentation

friend class PastryLeafSet [friend]


Member Data Documentation

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]


The documentation for this class was generated from the following files:
Generated on Wed Sep 26 12:13:02 2007 for ITM OverSim by  doxygen 1.5.1