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)
 handles self-messages
virtual void handleUDPMessage (BaseOverlayMessage *msg)
 processes messages from underlay
virtual void handleRpcResponse (BaseResponseMessage *msg, int rpcId, simtime_t rtt)
 process RPC responses
virtual void handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, int rpcID, const OverlayKey &destKey)
 handle RPC timeouts
void handleStateMessage (PastryStateMessage *msg)
 processes state messages, merging with own state tables
virtual void handleAppMessage (BaseOverlayMessage *msg)
 processes messages from application
virtual void finishOverlay ()
 collects statisticts
virtual void receiveChangeNotification (int category, cPolymorphic *details)
 callback-method for events at the NotificationBoard
virtual void updateTooltip ()
 updates information shown in tk-environment
virtual NodeVectorfindNode (const OverlayKey &key, int numRedundantNodes, int numSiblings, BaseOverlayMessage *msg)
 implement the findNode call
int getMaxNumSiblings ()
 Query the maximum number of siblings (nodes close to a key) that are maintained by this overlay protocol.
int getMaxNumRedundantNodes ()
 Query the maximum number of redundant next hop nodes that are returned by findNode().

Protected Member Functions

virtual void changeState (int toState)
 changes node state
void sendStateTables (const TransportAddress &destination, int type=PASTRY_STATE_STD,...)
 send a PastryStateMessage directly to a node
void sendStateDelayed (const TransportAddress &destination)
 send a standard state message with a small delay
virtual bool isSiblingFor (const NodeHandle &node, const OverlayKey &key, int numSiblings, bool *err)
 see BaseOverlay.cc
virtual 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 ()
 
See also:
BaseOverlay.cc

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


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]

handles self-messages

Parameters:
msg the self-message

Reimplemented from BaseOverlay.

00338 {
00339 
00340     if (msg->isName("joinTimeout"))
00341     {
00342         EV << "Pastry: join timeout expired, restarting..." << endl;
00343         joinOverlay();
00344     }
00345     else if (msg->isName("readyWait"))
00346     {
00347         if (partialJoinPath)
00348         {
00349             RECORD_STATS(joinPartial++);
00350             sort(stReceived.begin(), stReceived.end(), stateMsgIsSmaller);
00351 
00352             // start pinging the nodes found in the first state message:
00353             stateReceivedProximities.clear();
00354             stateCache = stReceived.front();
00355             EV << "Pastry: joining despite some missing STATE messages."
00356                 << endl;
00357             pingNodes();
00358         }
00359         else
00360         {
00361             EV << "Pastry: timeout waiting for missing state messages in JOIN "
00362                 "state, restarting..." << endl;
00363             joinOverlay();
00364         }
00365     }
00366     else if (msg->isName("joinUpdateWait"))
00367     {
00368         EV << "Pastry: sending state updates to all nodes." << endl;
00369         doJoinUpdate();
00370     }
00371     else if (msg->isName("secondStageWait"))
00372     {
00373         EV << "Pastry: sending STATE requests to all nodes in second stage "
00374             "of initialization." << endl;
00375         doSecondStage();
00376     }
00377     else if (msg->isName("ringCheck"))
00378     {
00379         if (state == READY)
00380         {
00381             // ping direct neighbors on the ring:
00382             const NodeHandle& pred = leafSet->getPredecessor();
00383             const NodeHandle& succ = leafSet->getSuccessor();
00384             if (! pred.isUnspecified())
00385             {
00386                 pingNode(pred, pingTimeout, pingRetries, "PING ring check");
00387             }
00388             if (! succ.isUnspecified())
00389             {
00390                 pingNode(succ, pingTimeout, pingRetries, "PING ring check");
00391             }
00392         }
00393         scheduleAt(simTime()+ringCheckInterval, ringCheck);
00394     }
00395     else if (msg->isName("sendStateWait"))
00396     {
00397         PastrySendState* sendStateMsg = check_and_cast<PastrySendState*>(msg);
00398 
00399         std::vector<PastrySendState*>::iterator pos =
00400             std::find(sendStateWait.begin(), sendStateWait.end(),
00401                     sendStateMsg);
00402         if (pos != sendStateWait.end()) sendStateWait.erase(pos);
00403 
00404         sendStateTables(sendStateMsg->getDest());
00405         delete sendStateMsg;
00406     }
00407 }

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

processes messages from underlay

Parameters:
msg message from UDP

Implements BaseOverlay.

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

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

process RPC responses

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

Reimplemented from RpcListener.

00737 {
00738     const NodeHandle& src = msg->getSrcNode();
00739     const NodeHandle* node;
00740     int i;
00741     int n;
00742     PastryPingCacheEntry pce;
00743     std::map<TransportAddress, BaseRouteMessage*>::iterator pos;
00744 
00745     RPC_SWITCH_START(msg)
00746         RPC_ON_RESPONSE(Ping)
00747         {
00748             // insert into pingCache
00749             pce.inserted = simTime();
00750             pce.rtt = rtt;
00751             pingCache[src.ip] = pce;
00752 
00753             if (stateCache)
00754             {
00755                 // look for node in routing table of processed state message:
00756                 n = stateCache->getRoutingTableArraySize();
00757                 for (i = 0; i < n; i++)
00758                 {
00759                     node = &(stateCache->getRoutingTable(i));
00760                     if ((!node->isUnspecified()) && (*node == src))
00761                         *(proxCache.pr_rt.begin()+i) = rtt;
00762                 }
00763 
00764                 // look for node in leaf set of processed state message:
00765                 n = stateCache->getLeafSetArraySize();
00766                 for (i = 0; i < n; i++)
00767                 {
00768                     node = &(stateCache->getLeafSet(i));
00769                     if ((!node->isUnspecified()) && (*node == src))
00770                         *(proxCache.pr_ls.begin()+i) = rtt;
00771                 }
00772 
00773                 // look for node in neighb. set of processed state message:
00774                 n = stateCache->getNeighborhoodSetArraySize();
00775                 for (i = 0; i < n; i++)
00776                 {
00777                     node = &(stateCache->getNeighborhoodSet(i));
00778                     if ((!node->isUnspecified()) && (*node == src))
00779                         *(proxCache.pr_ns.begin()+i) = rtt;
00780                 }
00781 
00782                 checkProxCache();
00783             }
00784 
00785             if ((pos = recFwdQueue.find(src)) != recFwdQueue.end())
00786             {
00787                 // send message
00788                 if (!optimisticForward)
00789                 {
00790                     sendMessageToUDP(pos->first, pos->second);
00791                 }
00792                 else if (!avoidDuplicates)
00793                 {
00794                     delete pos->second;
00795                 }
00796                 recFwdQueue.erase(pos);
00797             }
00798 
00799             break;
00800         }
00801     RPC_SWITCH_END()
00802 }

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

handle RPC timeouts

Parameters:
msg the RPC call that timed out
dest the destination node of the RPC call
rpcID the RPC identifier
01175 {
01176     const NodeHandle* node;
01177     int i;
01178     int n;
01179     PastryPingCacheEntry pce;
01180     std::map<TransportAddress, BaseRouteMessage*>::iterator pos;
01181     
01182     RPC_SWITCH_START(msg)
01183         RPC_ON_CALL(Ping)
01184         {
01185             EV << "Pastry: Ping timeout occured." << endl;
01186 
01187             // update ping cache:
01188             pce.inserted = simTime();
01189             pce.rtt = PASTRY_PROX_INFINITE;
01190             pingCache[dest.ip] = pce;
01191 
01192             // handle failed node
01193             if (state == READY)
01194             {
01195                 handleFailedNode(dest);
01196 
01197                 // this could initiate a re-join, exit the handler in that
01198                 // case because all local data was erased:
01199                 if (state != READY) break;
01200             }
01201 
01202             if (stateCache && msg->isName("PING received state"))
01203             {
01204                 // look for node in routing table of processed state message:
01205                 n = stateCache->getRoutingTableArraySize();
01206                 for (i = 0; i < n; i++)
01207                 {
01208                     node = &(stateCache->getRoutingTable(i));
01209                     if ((!node->isUnspecified()) && (node->ip == dest.ip))
01210                         *(proxCache.pr_rt.begin() + i) = PASTRY_PROX_INFINITE;
01211                 }
01212                 
01213                 // look for node in leaf set of processed state message:
01214                 n = stateCache->getLeafSetArraySize();
01215                 for (i = 0; i < n; i++)
01216                 {
01217                     node = &(stateCache->getLeafSet(i));
01218                     if ((!node->isUnspecified()) && (node->ip == dest.ip))
01219                         *(proxCache.pr_ls.begin() + i) = PASTRY_PROX_INFINITE;
01220                 }
01221 
01222                 // look for node in neighborhood set of processed state message:
01223                 n = stateCache->getNeighborhoodSetArraySize();
01224                 for (i = 0; i < n; i++)
01225                 {
01226                     node = &(stateCache->getNeighborhoodSet(i));
01227                     if ((!node->isUnspecified()) && (node->ip == dest.ip))
01228                         *(proxCache.pr_ns.begin() + i) = PASTRY_PROX_INFINITE;
01229                 }
01230                 checkProxCache();
01231             }
01232 
01233             if (msg->isName("PING next hop"))
01234             {
01235                 // handle forward queue entry
01236                 if ((pos = recFwdQueue.find(dest)) == recFwdQueue.end()) break;
01237                 BaseRouteMessage* rmsg = pos->second;
01238                 recFwdQueue.erase(pos);
01239                 sendToKey(rmsg->getDestKey(), rmsg);
01240             }
01241 
01242             break;
01243         }
01244     RPC_SWITCH_END()
01245 }

void Pastry::handleStateMessage ( PastryStateMessage *  msg  ) 

processes state messages, merging with own state tables

Parameters:
msg the pastry state message
00496 {
00497     if (debugOutput)
00498     {
00499         EV << "Pastry::handleStateMessage() new STATE message to process "
00500             << static_cast<void*>(msg) << " in state " <<
00501             ((state == READY)?"READY":((state == JOIN)?"JOIN":"INIT"))
00502             << endl;
00503         if (state == JOIN)
00504         {
00505             EV << " ***   own joinHopCount:  " << joinHopCount << endl;
00506             EV << " ***   already received:  " << stReceived.size() << endl;
00507             EV << " ***   last-hop flag:     " << msg->getLastHop() << endl;
00508             EV << " ***   msg joinHopCount:  "
00509                 << msg->getJoinHopCount() << endl;
00510         }   
00511     }
00512     if (state == INIT)
00513     {
00514         EV << "Pastry: can't handle state messages until at least reaching "
00515             "JOIN state." << endl;
00516         delete msg;
00517         return;
00518     }
00519     
00520     // in JOIN state, store all received state Messages, need them later:
00521     if (state == JOIN)
00522     {
00523         if (joinHopCount && stReceived.size() == joinHopCount)
00524         {
00525             EV << "Pastry: Warning: dropping state message received after "
00526                 "all needed state messages were collected in JOIN state."
00527                 << endl;
00528             delete msg;
00529             return;
00530         }
00531 
00532         stReceived.push_back(msg);
00533         prePing(msg);
00534             
00535         if (msg->getLastHop())
00536         {
00537             if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00538 
00539             if (msg->getSender().key == thisNode.key)
00540             {
00541                 EV << "Pastry: Error: OverlayKey already in use, restarting!"
00542                     << endl;
00543                 joinOverlay();
00544                 return;
00545             }
00546 
00547             if (joinHopCount)
00548             {
00549                 EV << "Pastry: Error: received a second `last' state message! "
00550                     "Restarting ..." << endl;
00551                 joinOverlay();
00552                 return;
00553             }
00554                 
00555             joinHopCount = msg->getJoinHopCount();
00556             if (stReceived.size() < joinHopCount)
00557             {
00558                 // some states still missing:
00559                 cancelEvent(readyWait);
00560                 scheduleAt(simTime()+readyWaitAmount, readyWait);
00561             }
00562         }
00563 
00564         if (joinHopCount)
00565         {
00566             if (stReceived.size() > joinHopCount)
00567             {
00568                 EV << "Pastry: Error: too many state messages received in "
00569                     "JOIN state! Restarting ..." << endl;
00570                 joinOverlay();
00571                 return;
00572             }
00573             if (stReceived.size() == joinHopCount)
00574             {
00575                 // all state messages are here, sort by hopcount:
00576                 sort(stReceived.begin(), stReceived.end(),
00577                         stateMsgIsSmaller);
00578 
00579                 // start pinging the nodes found in the first state message:
00580                 stateReceivedProximities.clear();
00581                 stateCache = stReceived.front();
00582                 EV << "Pastry: have all STATE messages, now pinging nodes."
00583                     << endl;
00584                 pingNodes();
00585 
00586                 // cancel timeout:
00587                 if (readyWait->isScheduled()) cancelEvent(readyWait);
00588             }
00589         }
00590         return;
00591     }
00592 
00593     // determine aliveTable to prevent leafSet from merging nodes that are
00594     // known to be dead:
00595     determineAliveTable(msg);
00596 
00597     if (msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR)
00598     {
00599         // try to repair leafset based on repair message right now
00600         const TransportAddress& askLs = leafSet->repair(msg, aliveTable);
00601         if (! askLs.isUnspecified()) sendRepairRequest(askLs);
00602 
00603         // while not really known, it's safe to assume that a repair
00604         // message changed our state:
00605         lastStateChange = simTime();
00606         newLeafs();
00607     }
00608     else if (leafSet->mergeState(msg, aliveTable))
00609     {
00610         // merged state into leafset right now 
00611         lastStateChange = simTime();
00612         newLeafs();
00613     }
00614 
00615     // in READY state, only ping nodes to get proximity metric:
00616     if (!stateCache)
00617     {
00618         // no state message is processed right now, start immediately:
00619         stateCache = msg;
00620         pingNodes();
00621     }
00622     else
00623     {
00624         // enqueue message for later processing:
00625         stateCacheQueue.insert(msg);
00626         prePing(msg);
00627     }
00628 }

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

processes messages from application

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

void Pastry::finishOverlay (  )  [virtual]

collects statisticts

Reimplemented from BaseOverlay.

01453 {
01454     // destroy self timer messages
01455     if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
01456     if (readyWait->isScheduled()) cancelEvent(readyWait);
01457     if (joinUpdateWait->isScheduled()) cancelEvent(joinUpdateWait);
01458     if (secondStageWait->isScheduled()) cancelEvent(secondStageWait);
01459     if (ringCheck->isScheduled()) cancelEvent(ringCheck);
01460 
01461     delete joinTimeout;
01462     delete readyWait;
01463     delete joinUpdateWait;
01464     delete secondStageWait;
01465     delete ringCheck;
01466 
01467     purgeVectors();
01468 
01469     // remove this node from the bootstrap list
01470     if (!thisNode.key.isUnspecified()) bootstrapOracle->removePeer(thisNode);
01471 
01472     // collect statistics
01473     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
01474     if(time == 0) return;
01475 
01476     globalStatistics->addStdDev("Pastry: Successful Joins/s", joins / time);
01477     globalStatistics->addStdDev("Pastry: overall join tries/s", joinTries / time);
01478     globalStatistics->addStdDev("Pastry: joins with missing replies from routing path/s",
01479                                 joinPartial / time);
01480     globalStatistics->addStdDev("Pastry: JOIN Messages seen/s", joinSeen / time);
01481     globalStatistics->addStdDev("Pastry: bytes of JOIN Messages seen/s", joinBytesSeen / time);
01482     globalStatistics->addStdDev("Pastry: JOIN Messages received/s", joinReceived / time);
01483     globalStatistics->addStdDev("Pastry: bytes of JOIN Messages received/s",
01484                                 joinBytesReceived / time);
01485     globalStatistics->addStdDev("Pastry: JOIN Messages sent/s", joinSent / time);
01486     globalStatistics->addStdDev("Pastry: bytes of JOIN Messages sent/s", joinBytesSent / time);
01487     globalStatistics->addStdDev("Pastry: STATE Messages sent/s", stateSent / time);
01488     globalStatistics->addStdDev("Pastry: bytes of STATE Messages sent/s", stateBytesSent / time);
01489     globalStatistics->addStdDev("Pastry: STATE Messages received/s", stateReceived / time);
01490     globalStatistics->addStdDev("Pastry: bytes of STATE Messages received/s",
01491                                 stateBytesReceived / time);
01492     globalStatistics->addStdDev("Pastry: REPAIR Requests sent/s", repairReqSent / time);
01493     globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests sent/s",
01494                                 repairReqBytesSent / time);
01495     globalStatistics->addStdDev("Pastry: REPAIR Requests received/s", repairReqReceived / time);
01496     globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests received/s",
01497                                 repairReqBytesReceived / time);
01498     globalStatistics->addStdDev("Pastry: STATE Requests sent/s", stateReqSent / time);
01499     globalStatistics->addStdDev("Pastry: bytes of STATE Requests sent/s", stateReqBytesSent / time);
01500     globalStatistics->addStdDev("Pastry: STATE Requests received/s", stateReqReceived / time);
01501     globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s",
01502                                 stateReqBytesReceived / time);
01503 
01504     globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s",
01505                                 stateReqBytesReceived / time);
01506 
01507     globalStatistics->addStdDev("Pastry: total number of lookups", totalLookups);
01508     globalStatistics->addStdDev("Pastry: responsible lookups", responsibleLookups);
01509     globalStatistics->addStdDev("Pastry: lookups in routing table", routingTableLookups);
01510     globalStatistics->addStdDev("Pastry: lookups using closerNode()", closerNodeLookups);
01511     globalStatistics->addStdDev("Pastry: lookups using closerNode() with result from "
01512                                 "neighborhood set", closerNodeLookupsFromNeighborhood);
01513 }

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

callback-method for events at the NotificationBoard

Parameters:
category ... TODO ...
details ... TODO ...
01442 {
01443     Enter_Method_Silent();
01444     if (category == NF_HOSTPOSITION_UPDATED) {
01445         // get new ip address
01446         thisNode.ip = IPAddressResolver().addressOf(
01447             parentModule()->parentModule()).get4();
01448         joinOverlay();
01449     }
01450 }

void Pastry::updateTooltip (  )  [virtual]

updates information shown in tk-environment

01418 {
01419     if (ev.isGUI()) {
01420         std::stringstream ttString;
01421 
01422         // show our predecessor and successor in tooltip
01423         ttString << leafSet->getPredecessor() << endl << thisNode << endl
01424             << leafSet->getSuccessor();
01425 
01426         parentModule()->parentModule()->displayString().
01427         setTagArg("tt", 0, ttString.str().c_str());
01428         parentModule()->displayString().
01429         setTagArg("tt", 0, ttString.str().c_str());
01430         displayString().setTagArg("tt", 0, ttString.str().c_str());
01431 
01432         // draw arrows:
01433         showOverlayNeighborArrow(leafSet->getSuccessor(), true,
01434                 "m=m,50,0,50,0;o=red,1");
01435         showOverlayNeighborArrow(leafSet->getPredecessor(), false,
01436                 "m=m,50,100,50,100;o=green,1");
01437 
01438     }
01439 }

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

implement the findNode call

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

Reimplemented from BaseOverlay.

01530 {
01531     if ((numRedundantNodes > getMaxNumRedundantNodes()) ||
01532         (numSiblings > getMaxNumSiblings())) {
01533 
01534         opp_error("(Pastry::findNode()) numRedundantNodes or numSiblings "
01535                   "too big!");
01536     }
01537 
01538 
01539     RECORD_STATS(totalLookups++);
01540     NodeVector* nextHop = new NodeVector(1);
01541     const NodeHandle* next;
01542     PastryFindNodeExtData* findNodeExt = NULL;
01543     if (msg && msg->hasObject("findNodeExt"))
01544     {
01545         findNodeExt = check_and_cast<PastryFindNodeExtData*>(
01546                 msg->getObject("findNodeExt"));
01547     }
01548 
01549     if (state != READY)
01550     {
01551         return nextHop;
01552     }
01553     else if (key.isUnspecified() || leafSet->isClosestNode(key))
01554     {
01555         RECORD_STATS(responsibleLookups++);
01556         nextHop->add(thisNode);
01557     }
01558     else
01559     {
01560         // Send state tables on any JOIN message we see:
01561         if (findNodeExt)
01562         {
01563             const TransportAddress& stateRecipient =
01564                 findNodeExt->getSendStateTo();
01565             if (!stateRecipient.isUnspecified())
01566             {
01567                 RECORD_STATS(joinSeen++);
01568                 sendStateTables(stateRecipient, PASTRY_STATE_JOIN,
01569                         findNodeExt->getJoinHopCount(), false);
01570             }
01571         }
01572 
01573         next = &(leafSet->getDestinationNode(key));
01574 
01575         if (next->isUnspecified())
01576         {
01577             next = &(routingTable->lookupNextHop(key));
01578             if (!next->isUnspecified())
01579                 RECORD_STATS(routingTableLookups++);
01580         }
01581         else
01582             RECORD_STATS(responsibleLookups++);
01583 
01584         if (next->isUnspecified())
01585         {
01586             RECORD_STATS(closerNodeLookups++);
01587             // call findCloserNode() on all state objects
01588 
01589             if (optimizeLookup)
01590             {
01591                 const NodeHandle* tmp;
01592                 next = &(routingTable->findCloserNode(key, true));
01593                 tmp = &(neighborhoodSet->findCloserNode(key, true));
01594 
01595                 if ((! tmp->isUnspecified()) &&
01596                         (leafSet->isCloser(*tmp, key, *next)))
01597                 {
01598                     RECORD_STATS(closerNodeLookupsFromNeighborhood++);
01599                     next = tmp;
01600                 }
01601 
01602                 tmp = &(leafSet->findCloserNode(key, true));
01603                 if ((! tmp->isUnspecified()) &&
01604                         (leafSet->isCloser(*tmp, key, *next)))
01605                 {
01606                     RECORD_STATS(closerNodeLookupsFromNeighborhood--);
01607                     next = tmp;
01608                 }
01609             }
01610             else
01611             {
01612                 next = &(routingTable->findCloserNode(key));
01613 
01614                 if (next->isUnspecified())
01615                 {
01616                     RECORD_STATS(closerNodeLookupsFromNeighborhood++);
01617                     next = &(neighborhoodSet->findCloserNode(key));
01618                 }
01619 
01620                 if (next->isUnspecified())
01621                 {
01622                     RECORD_STATS(closerNodeLookupsFromNeighborhood--);
01623                     next = &(leafSet->findCloserNode(key));
01624                 }
01625             }
01626         }
01627 
01628         if (!next->isUnspecified())
01629         {
01630             if (findNodeExt)
01631             {
01632                 findNodeExt->setJoinHopCount(
01633                         findNodeExt->getJoinHopCount() + 1);
01634             }
01635             nextHop->add(*next);
01636         }
01637     }
01638 
01639     bool err;
01640 
01641     /* if we're a sibling, return all numSiblings */
01642     if (isSiblingFor(thisNode, key, numSiblings, &err)) {
01643         if (err == false) {
01644             delete nextHop;
01645             return  leafSet->createSiblingVector(key, numSiblings);
01646         }
01647     }
01648     
01649     return nextHop;
01650 }

int Pastry::getMaxNumSiblings (  )  [virtual]

Query the maximum number of siblings (nodes close to a key) that are maintained by this overlay protocol.

Returns:
int number of siblings.

Reimplemented from BaseOverlay.

01516 {
01517     return (int) floor(numberOfLeaves/4);
01518 }

int Pastry::getMaxNumRedundantNodes (  )  [virtual]

Query the maximum number of redundant next hop nodes that are returned by findNode().

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

Reimplemented from BaseOverlay.

01521 {
01522     return 1;
01523 }

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             neighborhoodSet->initializeSet(numberOfNeighbors, thisNode);
00247 
00248             updateTooltip();
00249             lastStateChange = simTime();
00250     
00251             parentModule()->parentModule()->bubble("entering INIT state");
00252 
00253             break;
00254 
00255         case JOIN:
00256 
00257             state = JOIN;
00258 
00259             // bootstrapNode must be obtained before calling this method,
00260             // for example by calling changeState(INIT)
00261             
00262             if (bootstrapNode.isUnspecified())
00263             {
00264                 // no existing pastry network -> first node of a new one
00265                 changeState(READY);
00266                 return;
00267             }
00268 
00269             joinHopCount = 0;
00270 
00271             {
00272                 PastryJoinMessage* msg = new PastryJoinMessage("JOIN-Request");
00273                 msg->setPastryMsgType(PASTRY_MSG_JOIN);
00274                 msg->setSignaling(true);
00275                 msg->setJoinHopCount(1);
00276                 msg->setSendStateTo(thisNode);
00277                 msg->setLength(PASTRYJOIN_L(msg));
00278                 RECORD_STATS(joinSent++; joinBytesSent += msg->byteLength());
00279                 sendToKey(thisNode.key, msg, 0, bootstrapNode);
00280             }
00281             
00282             cancelEvent(joinTimeout);
00283             scheduleAt(simTime()+joinTimeoutAmount, joinTimeout);
00284 
00285             updateTooltip();
00286             parentModule()->parentModule()->bubble("entering JOIN state");
00287 
00288             RECORD_STATS(joinTries++);
00289 
00290             break;
00291         
00292         case READY:
00293 
00294             state = READY;
00295             if (ringCheckInterval > 0)
00296             {
00297                 scheduleAt(simTime()+ringCheckInterval, ringCheck);
00298             }
00299 
00300             bootstrapOracle->registerPeer(thisNode);
00301 
00302             // if we are the first node in the network, there's nothing else
00303             // to do
00304             if (bootstrapNode.isUnspecified())
00305             {
00306                 RECORD_STATS(joinTries++);
00307                 RECORD_STATS(joins++);
00308                 setReadyIcon(true);
00309                 return;
00310             }
00311 
00312             // determine list of all known nodes as notifyList
00313             notifyList.clear();
00314             leafSet->dumpToVector(notifyList);
00315             routingTable->dumpToVector(notifyList);
00316             sort(notifyList.begin(), notifyList.end());
00317             notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00318                     notifyList.end());
00319         
00320             parentModule()->parentModule()->bubble("entering READY state");
00321 
00322             // schedule update
00323             cancelEvent(joinUpdateWait);
00324             scheduleAt(simTime() + sendStateWaitAmount, joinUpdateWait);
00325     
00326             // schedule second stage
00327             cancelEvent(secondStageWait);
00328             scheduleAt(simTime() + secondStageWaitAmount, secondStageWait);
00329 
00330             RECORD_STATS(joins++);
00331 
00332             break;
00333     }
00334     setReadyIcon(state == READY);
00335 }

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

send a PastryStateMessage directly to a node

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
01293 {
01294     if (destination.ip == thisNode.ip)
01295         opp_error("Pastry: trying to send state to self!");
01296 
01297     int hops = 0;
01298     bool last = false;
01299     simtime_t timestamp = 0;
01300 
01301     if ((type == PASTRY_STATE_JOIN) || (type == PASTRY_STATE_UPDATE))
01302     {
01303         // additional parameters needed:
01304         va_list ap;
01305         va_start(ap, type);
01306         if (type == PASTRY_STATE_JOIN)
01307         {
01308             hops = va_arg(ap, int);
01309             last = static_cast<bool>(va_arg(ap, int));
01310         }
01311         else
01312         {
01313             timestamp = va_arg(ap, simtime_t);
01314         }
01315         va_end(ap);
01316     }
01317     
01318     // create new state msg and set special fields for some types:
01319     PastryStateMessage* stateMsg;
01320     if (type == PASTRY_STATE_JOIN)
01321     {
01322         stateMsg = new PastryStateMessage("STATE (Join)");
01323         stateMsg->setJoinHopCount(hops);
01324         stateMsg->setLastHop(last);
01325         stateMsg->setTimestamp(simTime());
01326     }
01327     else if (type == PASTRY_STATE_UPDATE)
01328     {
01329         stateMsg = new PastryStateMessage("STATE (Update)");
01330         EV << "Pastry: sending state (update) to " << destination << endl;
01331         stateMsg->setTimestamp(timestamp);
01332     }
01333     else
01334     {
01335         stateMsg = new PastryStateMessage("STATE");
01336         EV << "Pastry: sending state (standard) to " << destination << endl;
01337         stateMsg->setTimestamp(simTime());
01338     }
01339     
01340     // fill in standard content:
01341     stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
01342     stateMsg->setSignaling(true);
01343     stateMsg->setPastryStateMsgType(type);
01344     stateMsg->setSender(thisNode);
01345     routingTable->dumpToStateMessage(stateMsg);
01346     leafSet->dumpToStateMessage(stateMsg);
01347     neighborhoodSet->dumpToStateMessage(stateMsg);
01348 
01349     // send...
01350     stateMsg->setLength(PASTRYSTATE_L(stateMsg));
01351     RECORD_STATS(stateSent++; stateBytesSent += stateMsg->byteLength());
01352     sendMessageToUDP(destination, stateMsg);
01353 }

void Pastry::sendStateDelayed ( const TransportAddress destination  )  [protected]

send a standard state message with a small delay

Parameters:
destination destination node
01356 {
01357     PastrySendState* selfMsg = new PastrySendState("sendStateWait");
01358     selfMsg->setDest(destination);
01359     sendStateWait.push_back(selfMsg);
01360     scheduleAt(simTime() + sendStateWaitAmount, selfMsg);
01361 }

bool Pastry::isSiblingFor ( const NodeHandle node,
const OverlayKey key,
int  numSiblings,
bool *  err 
) [protected, virtual]

see BaseOverlay.cc

Reimplemented from BaseOverlay.

01367 {
01368     if (key.isUnspecified())
01369         error("Pastry::isSiblingFor(): key is unspecified!");
01370 
01371     if ((numSiblings == 1) && (node == thisNode)) {
01372         if (leafSet->isClosestNode(key)) {
01373             *err = false;
01374             return true;
01375         } else {
01376             *err = false;
01377             return false;
01378         }
01379     }
01380 
01381     NodeVector* result =  leafSet->createSiblingVector(key, numSiblings);
01382 
01383     if (result == NULL) {
01384         *err = true;
01385         return false;
01386     }
01387 
01388     if (result->contains(node.key)) {
01389         delete result;
01390         *err = false;
01391         return true;
01392     } else {
01393         delete result;
01394         *err = true;
01395         return false;
01396     }
01397 
01398 /*
01399     const NodeHandle& dest = leafSet->getDestinationNode(key);
01400     if (!dest.isUnspecified()) {
01401         *err = false;
01402         return true;
01403     } else {
01404 
01405         *err = true;
01406         return false;
01407     }
01408 */
01409 }

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

01653 {
01654     PastryFindNodeExtData* findNodeExt =
01655         new PastryFindNodeExtData("findNodeExt");
01656 
01657     if (msg)
01658     {
01659         const PastryMessage* pmsg = dynamic_cast<const PastryMessage*>(
01660                 msg->encapsulatedMsg());
01661         if ((pmsg) && (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN))
01662         {
01663             const PastryJoinMessage* jmsg =
01664                 check_and_cast<const PastryJoinMessage*>(pmsg);
01665             findNodeExt->setSendStateTo(jmsg->getSendStateTo());
01666             findNodeExt->setJoinHopCount(1);
01667         }
01668     }
01669     findNodeExt->setLength(PASTRYFINDNODEEXTDATA_L);
01670     AbstractLookup* newLookup = new BaseLookup(this,
01671             baseLookupConfig, findNodeExt);
01672     lookups.insert(newLookup);
01673     delete findNodeExt;
01674     return newLookup;
01675 }

void Pastry::forwardMessageRecursive ( const TransportAddress dest,
BaseRouteMessage *  msg 
) [private, virtual]

Hook for forwarded message in recursive lookup mode.

Default implementation just calls sendMessageToUDP(). This hook can for example be used to detect failed nodes and call handleFailedNode() before the actual forwarding takes place.

Parameters:
dest destination node
msg message to send

Reimplemented from BaseOverlay.

00632 {
00633     PastryMessage* pmsg = dynamic_cast<PastryMessage*>(
00634             msg->encapsulatedMsg());
00635     if ( pmsg && (dest != thisNode) )
00636     {
00637         if (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN)
00638         {
00639             PastryJoinMessage* jmsg = check_and_cast<PastryJoinMessage*>(pmsg);
00640             RECORD_STATS(joinSeen++; joinBytesSeen += jmsg->byteLength());
00641             sendStateTables(jmsg->getSendStateTo(), PASTRY_STATE_JOIN,
00642                     jmsg->getJoinHopCount(), false);
00643             jmsg->setJoinHopCount(jmsg->getJoinHopCount() + 1);
00644         }
00645     }
00646 
00647     if (recFwdQueue.find(dest) != recFwdQueue.end())
00648     {
00649         // rare case, other message for same next hop is pending:
00650         // send the message and hope it isn't lost.
00651         sendMessageToUDP(dest, msg);
00652         return;
00653     }
00654 
00655     if (optimisticForward)
00656     {
00657         // forward now:
00658         sendMessageToUDP(dest, msg);
00659         if (! avoidDuplicates)
00660         {
00661             // and keep copy for possible retry:
00662             recFwdQueue[dest] = static_cast<BaseRouteMessage*>(msg->dup());
00663         }
00664     }
00665     else
00666     {
00667         // keep message in queue (forward later)
00668         recFwdQueue[dest] = msg;
00669     }
00670     pingNode(dest, pingTimeout, pingRetries, "PING next hop");
00671 }

void Pastry::doJoinUpdate ( void   )  [private]

send updated state to all nodes when entering ready state

00674 {
00675     // send "update" state message to all nodes who sent us their state
00676     // during INIT, remove these from notifyList so they don't get our
00677     // state twice
00678     std::vector<TransportAddress>::iterator nListPos;
00679     if (!stReceived.empty())
00680     {
00681         for (std::vector<PastryStateMessage*>::iterator it =
00682                 stReceived.begin(); it != stReceived.end(); it++)
00683         {
00684             sendStateTables((*it)->getSender(), PASTRY_STATE_UPDATE,
00685                     (*it)->getTimestamp());
00686             nListPos = find(notifyList.begin(), notifyList.end(),
00687                     (*it)->getSender());
00688             if (nListPos != notifyList.end())
00689             {
00690                 notifyList.erase(nListPos);
00691             }
00692             delete *it;
00693         }
00694         stReceived.clear();
00695     }
00696 
00697     // send a normal STATE message to all remaining known nodes
00698     for (std::vector<TransportAddress>::iterator it =
00699             notifyList.begin(); it != notifyList.end(); it++)
00700     {
00701         if (*it != thisNode) sendStateTables(*it);
00702     }
00703     notifyList.clear();
00704 
00705     updateTooltip();
00706 }

void Pastry::doSecondStage ( void   )  [private]

do the second stage of initialization as described in the paper

00709 {
00710     // "second stage" for locality:
00711     notifyList.clear();
00712     routingTable->dumpToVector(notifyList);
00713     neighborhoodSet->dumpToVector(notifyList);
00714     sort(notifyList.begin(), notifyList.end());
00715     notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00716             notifyList.end());
00717     for (std::vector<TransportAddress>::iterator it = notifyList.begin();
00718             it != notifyList.end(); it++)
00719     {
00720         if (*it == thisNode) continue;
00721         EV << "second stage: requesting state from " << *it << endl;
00722         PastryStateRequestMessage* msg =
00723                 new PastryStateRequestMessage("SREQ");
00724         msg->setSignaling(true);
00725         msg->setPastryMsgType(PASTRY_MSG_SREQ);
00726         msg->setSendStateTo(thisNode);
00727         msg->setLength(PASTRYSREQ_L(msg));
00728         RECORD_STATS(stateReqSent++; stateReqBytesSent +=
00729                 msg->byteLength());
00730         sendMessageToUDP(*it, msg);
00731     }
00732     notifyList.clear();
00733 }

void Pastry::purgeVectors ( void   )  [private]

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

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

void Pastry::prePing ( const PastryStateMessage *  stateMsg  )  [private]

ping all nodes in a given state message.

this is called when a state message arrives while another one is still being processed.

00805 {
00806     int i;
00807     int rt_size;
00808     int ls_size;
00809     int ns_size;
00810     const NodeHandle* node;
00811     PastryPingCache::iterator it;
00812     PastryPingCacheEntry pce;
00813     simtime_t now;
00814     
00815     now = simTime();
00816     pce.inserted = now;
00817     pce.rtt = PASTRY_PROX_PENDING;
00818     rt_size = stateMsg->getRoutingTableArraySize();
00819     ls_size = stateMsg->getLeafSetArraySize();
00820     ns_size = stateMsg->getNeighborhoodSetArraySize();
00821 
00822     for (i = 0; i < rt_size + ls_size + ns_size; i++)
00823     {
00824         if (i < rt_size)
00825             node = &(stateMsg->getRoutingTable(i));
00826         else if (i < (rt_size + ls_size) )
00827             node = &(stateMsg->getLeafSet(i - rt_size));
00828         else
00829             node = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size));
00830 
00831         if (node->isUnspecified()) continue;
00832         if (*node == thisNode) continue;
00833         if (node->key == thisNode.key)
00834         {
00835             cerr << "Pastry Warning: Other node with same key found, "
00836                 "restarting!" << endl;
00837             joinOverlay();
00838             return;
00839         }
00840         if (((it = pingCache.find(node->ip)) != pingCache.end()) &&
00841                 ((now - it->second.inserted) < pingCacheExpireTime))
00842         {
00843             // proximity known or ping already pending
00844             continue;
00845         }
00846 
00847         // update pingCache
00848         pingCache[node->ip] = pce;
00849 
00850         // send ping
00851         pingNode(*node, pingTimeout, pingRetries, "PING received state");
00852     }
00853 }

void Pastry::pingNodes ( void   )  [private]

ping all nodes in the pastry state message pointed to by private member stateCache

00856 {
00857     int i;
00858     int rt_size;
00859     int ls_size;
00860     int ns_size;
00861     const NodeHandle* node;
00862     std::vector<simtime_t>::iterator proxPos;
00863     PastryPingCache::iterator it;
00864     PastryPingCacheEntry pce;
00865     simtime_t now;
00866 
00867     now = simTime();
00868     pce.inserted = now;
00869     pce.rtt = PASTRY_PROX_PENDING;
00870 
00871     rt_size = stateCache->getRoutingTableArraySize();
00872     proxCache.pr_rt.clear();
00873     proxCache.pr_rt.resize(rt_size, PASTRY_PROX_PENDING);
00874 
00875     ls_size = stateCache->getLeafSetArraySize();
00876     proxCache.pr_ls.clear();
00877     proxCache.pr_ls.resize(ls_size, PASTRY_PROX_PENDING);
00878 
00879     ns_size = stateCache->getNeighborhoodSetArraySize();
00880     proxCache.pr_ns.clear();
00881     proxCache.pr_ns.resize(ns_size, PASTRY_PROX_PENDING);
00882 
00883     for (i = 0; i < rt_size + ls_size + ns_size; i++)
00884     {
00885         if (i < rt_size)
00886         {
00887             node = &(stateCache->getRoutingTable(i));
00888             proxPos = proxCache.pr_rt.begin() + i;
00889         }
00890         else if ( i < (rt_size + ls_size) )
00891         {
00892             node = &(stateCache->getLeafSet(i - rt_size));
00893             proxPos = proxCache.pr_ls.begin() + (i - rt_size);
00894         }
00895         else
00896         {
00897             node = &(stateCache->getNeighborhoodSet(i - rt_size - ls_size));
00898             proxPos = proxCache.pr_ns.begin() + (i - rt_size - ls_size);
00899         }
00900 
00901         // proximity is undefined for unspecified nodes:
00902         if (node->isUnspecified())
00903         {
00904             *proxPos = PASTRY_PROX_UNDEF;
00905         }
00906 
00907         // and 0 for own node:
00908         else if (*node == thisNode)
00909         {
00910             *proxPos = 0;
00911         }
00912 
00913         else if (node->key == thisNode.key)
00914         {
00915             cerr << "Pastry Warning: Other node with same key found, "
00916                 "restarting!" << endl;
00917             joinOverlay();
00918             return;
00919         }
00920 
00921         // else determine real value:
00922         else
00923         {
00924             if ((it = pingCache.find(node->ip)) != pingCache.end())
00925             {
00926                 if ((now - it->second.inserted) < pingCacheExpireTime)
00927                 {
00928                     *proxPos = it->second.rtt;
00929                     if (debugOutput)
00930                     {
00931                         EV << "Pastry: pingCache HIT" << endl;
00932                     }
00933                     continue;
00934                 }
00935                 else
00936                 {
00937                     if (debugOutput)
00938                     {
00939                         EV << "Pastry: pingCache OUTDATED" << endl;
00940                     }
00941                     pingCache.erase(it);
00942                 }
00943             }
00944             else if (debugOutput)
00945             {
00946                 EV << "Pastry: pingCache MISS" << endl;
00947             }
00948 
00949             // update pingCache
00950             pingCache[node->ip] = pce;
00951 
00952             // send ping
00953             pingNode(*node, pingTimeout, pingRetries, "PING received state");
00954         }
00955     }
00956     checkProxCache();
00957 }

void Pastry::determineAliveTable ( const PastryStateMessage *  stateMsg  )  [private]

change the aliveTable to match the given stateMsg.

each node that's knowm to be dead from our pingCache gets a value of PASTRY_PROX_INFINITE, all other nodes just get a value of 1

00960 {
00961     int i;
00962     int rt_size;
00963     int ls_size;
00964     int ns_size;
00965     const IPvXAddress* ip;
00966     std::vector<simtime_t>::iterator tblPos;
00967     PastryPingCache::iterator it;
00968     simtime_t now;
00969 
00970     now = simTime();
00971 
00972     rt_size = stateMsg->getRoutingTableArraySize();
00973     aliveTable.pr_rt.clear();
00974     aliveTable.pr_rt.resize(rt_size, 1);
00975 
00976     ls_size = stateMsg->getLeafSetArraySize();
00977     aliveTable.pr_ls.clear();
00978     aliveTable.pr_ls.resize(ls_size, 1);
00979 
00980     ns_size = stateMsg->getNeighborhoodSetArraySize();
00981     aliveTable.pr_ns.clear();
00982     aliveTable.pr_ns.resize(ns_size, 1);
00983 
00984     for (i = 0; i < rt_size + ls_size + ns_size; i++)
00985     {
00986         if (i < rt_size)
00987         {
00988             ip = &(stateMsg->getRoutingTable(i).ip);
00989             tblPos = aliveTable.pr_rt.begin() + i;
00990         }
00991         else if ( i < (rt_size + ls_size) )
00992         {
00993             ip = &(stateMsg->getLeafSet(i - rt_size).ip);
00994             tblPos = aliveTable.pr_ls.begin() + (i - rt_size);
00995         }
00996         else
00997         {
00998             ip = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size).ip);
00999             tblPos = aliveTable.pr_ns.begin() + (i - rt_size - ls_size);
01000         }
01001 
01002         if (((it = pingCache.find(*ip)) != pingCache.end()) &&
01003                 (it->second.rtt == PASTRY_PROX_INFINITE) &&
01004                 ((now - it->second.inserted) < pingCacheExpireTime))
01005         {
01006             *tblPos = PASTRY_PROX_INFINITE;
01007         }
01008     }
01009 }

void Pastry::checkProxCache ( void   )  [private]

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

01012 {
01013     simtime_t now = simTime();
01014 
01015     // no cached STATE message?
01016     if (!stateCache) return;
01017 
01018     // no entries in proxCache?
01019     if (proxCache.pr_rt.empty()) return;
01020     if (proxCache.pr_ls.empty()) return;
01021     if (proxCache.pr_ns.empty()) return;
01022 
01023     // some entries not yet determined?
01024     if (find(proxCache.pr_rt.begin(), proxCache.pr_rt.end(),
01025                 PASTRY_PROX_PENDING) != proxCache.pr_rt.end()
01026        ) return;
01027     if (find(proxCache.pr_ls.begin(), proxCache.pr_ls.end(),
01028                 PASTRY_PROX_PENDING) != proxCache.pr_ls.end()
01029        ) return;
01030     if (find(proxCache.pr_ns.begin(), proxCache.pr_ns.end(),
01031                 PASTRY_PROX_PENDING) != proxCache.pr_ns.end()
01032        ) return;
01033 
01034     if (state == JOIN)
01035     {
01036         stateReceivedProximities.push_back(proxCache);
01037         proxCache.pr_rt.clear();
01038         proxCache.pr_ls.clear();
01039         proxCache.pr_ns.clear();
01040 
01041         // collected proximities for all STATE messages?
01042         if (stateReceivedProximities.size() == stReceived.size())
01043         {
01044             stateCache = NULL;
01045             if (debugOutput)
01046             {
01047                 EV << "Pastry: [JOIN] starting to build own state from "
01048                     << stReceived.size() << " received state messages..."
01049                     << endl;
01050                 EV << "Pastry: [JOIN] initializing NeighborhoodSet from "
01051                     << stReceived.front()->getJoinHopCount() << ". hop"
01052                     << endl;
01053             }
01054             if (!neighborhoodSet->mergeState(stReceived.front(),
01055                         stateReceivedProximities.front()))
01056             {
01057                 EV << "Pastry: Error initializing own neighborhoodSet while "
01058                     "joining! Restarting ..." << endl;
01059                 joinOverlay();
01060                 return;
01061             }
01062             if (debugOutput)
01063             {
01064                 EV << "Pastry: [JOIN] initializing LeafSet from "
01065                     << stReceived.back()->getJoinHopCount() << ". hop" << endl;
01066             }
01067             if (!leafSet->mergeState(stReceived.back(),
01068                         stateReceivedProximities.back()))
01069             {
01070                 EV << "Pastry: Error initializing own leafSet while "
01071                     "joining! Restarting ..." << endl;
01072                 joinOverlay();
01073                 return;
01074             }
01075             if (debugOutput)
01076             {
01077                 EV << "Pastry: [JOIN] initializing RoutingTable from all hops"
01078                     << endl;
01079             }
01080             if (!routingTable->initStateFromMsgVector(
01081                         stReceived, stateReceivedProximities))
01082             {
01083                 EV << "Pastry: Error initializing own routingTable "
01084                     "while joining! Restarting ..." << endl;
01085                 joinOverlay();
01086                 return;
01087             }
01088             lastStateChange = now;
01089             newLeafs();
01090             changeState(READY);
01091         }
01092         else
01093         {
01094             // process next state message in vector:
01095             stateCache = *(stReceived.begin() +
01096                     stateReceivedProximities.size());
01097             pingNodes();
01098         }
01099     }
01100     else
01101     {
01102         // state == READY
01103 
01104         if (debugOutput)
01105         {
01106             EV << "Pastry: handling STATE message" << endl;
01107             EV << "        type: " <<
01108                 ((stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE)?
01109                  "update":"standard") << endl;
01110             if (stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE)
01111             {
01112                 EV << "        msg timestamp:      " <<
01113                     stateCache->getTimestamp() << endl;
01114                 EV << "        last state change:  " <<
01115                     lastStateChange << endl;
01116             }
01117         }
01118         
01119         if (stateCache->getPastryStateMsgType() == PASTRY_STATE_REPAIR)
01120         {
01121             // try to repair routingtable based on repair message:
01122             const TransportAddress& askRt =
01123                     routingTable->repair(stateCache, proxCache);
01124             if (! askRt.isUnspecified()) sendRepairRequest(askRt);
01125             
01126             // while not really known, it's safe to assume that a repair
01127             // message changed our state:
01128             lastStateChange = now;
01129         }
01130         else
01131         {
01132             if (((stateCache->getPastryStateMsgType() == PASTRY_STATE_UPDATE))
01133                     && (stateCache->getTimestamp() <= lastStateChange))
01134             {
01135                 // if we received an update based on our outdated state,
01136                 // send new state message:
01137                 EV << "Pastry: outdated state from " << stateCache->getSender()
01138                     << endl;
01139                 sendStateDelayed(stateCache->getSender());
01140             }
01141 
01142             // merge info in own state tables
01143             // except leafset (was already handled in handleStateMessage)
01144             if (neighborhoodSet->mergeState(stateCache, proxCache))
01145                 lastStateChange = now;
01146 
01147             if (routingTable->mergeState(stateCache, proxCache))
01148                 lastStateChange = now;
01149         }
01150 
01151         updateTooltip();
01152         
01153         // if state message was not an update, send one back:
01154         if (stateCache->getPastryStateMsgType() != PASTRY_STATE_UPDATE)
01155         {
01156             sendStateTables(stateCache->getSender(), PASTRY_STATE_UPDATE,
01157                     stateCache->getTimestamp());
01158         }
01159         
01160         delete stateCache;
01161         stateCache = NULL;
01162         proxCache.pr_rt.clear();
01163 
01164         // process next queued message:
01165         if (! stateCacheQueue.empty())
01166         {
01167             stateCache = (PastryStateMessage*) stateCacheQueue.pop();
01168             pingNodes();
01169         }
01170     }
01171 }

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

send a repair request to a given node

Parameters:
ask request repair from this node
01248 {
01249     if (ask.isUnspecified())
01250         opp_error("Pastry::sendRepairRequest(): asked for repair from "
01251                 "unspecified node!");
01252     
01253     PastryRepairRequestMessage* msg = new PastryRepairRequestMessage("RREQ");
01254     msg->setPastryMsgType(PASTRY_MSG_RREQ);
01255     msg->setSignaling(true);
01256     msg->setSendStateTo(thisNode);
01257     msg->setLength(PASTRYRREQ_L(msg));
01258     RECORD_STATS(repairReqSent++; repairReqBytesSent += msg->byteLength());
01259     sendMessageToUDP(ask, msg);
01260 }

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

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

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

Reimplemented from BaseOverlay.

01263 {
01264     if (state != READY)
01265     {
01266         return false;
01267     }
01268 
01269     if (failed.isUnspecified())
01270         opp_error("Pastry::handleFailedNode(): failed is unspecified!");
01271 
01272     const TransportAddress& lsAsk = leafSet->failedNode(failed);
01273     const TransportAddress& rtAsk = routingTable->failedNode(failed);
01274     neighborhoodSet->failedNode(failed);
01275 
01276     if (! lsAsk.isUnspecified()) sendRepairRequest(lsAsk);
01277     if (! rtAsk.isUnspecified()) sendRepairRequest(rtAsk);
01278 
01279     newLeafs();
01280 
01281     if (lsAsk.isUnspecified() && (! leafSet->isValid()))
01282     {
01283         EV << "Pastry: lost connection to the network, trying to re-join."
01284             << endl;
01285         joinOverlay();
01286         return false;
01287     }
01288 
01289     return true;
01290 }

void Pastry::joinOverlay (  )  [private, virtual]

See also:
BaseOverlay.cc

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 }


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 Tue Jul 24 16:51:19 2007 for ITM OverSim by  doxygen 1.5.1