IterativePathLookup Class Reference

#include <IterativeLookup.h>

List of all members.


Detailed Description

This class implements a path lookup.

Author:
Sebastian Mies

Protected Member Functions

bool accepts (int rpcId)
void handleResponse (FindNodeResponse *msg)
void handleTimeout (BaseCallMessage *msg, const TransportAddress &dest, int rpcId)
void handleFailedNodeResponse (const NodeHandle &src, cMessage *findNodeExt, bool retry)
 IterativePathLookup (IterativeLookup *lookup)
virtual ~IterativePathLookup ()
virtual FindNodeCall * createRpcMessage (cMessage *findNodeExt=NULL)
 Creates a find node call message.
int add (const NodeHandle &handle, const NodeHandle &source=NodeHandle::UNSPECIFIED_NODE)
 Adds a NodeHandle to next hops.

Protected Attributes

IterativeLookuplookup
int hops
int step
int pendingRpcs
bool finished
bool success
LookupVector nextHops
std::map< TransportAddress,
NodeHandle
oldNextHops

Private Member Functions

void sendRpc (int num, cMessage *FindNodeExt=NULL)
void sendNewRpcAfterTimeout (cMessage *findNodeExt)

Friends

class IterativeLookup

Constructor & Destructor Documentation

IterativePathLookup::IterativePathLookup ( IterativeLookup lookup  )  [protected]

00622 {
00623     this->lookup = lookup;
00624     this->hops = 0;
00625     this->step = 0;
00626     this->pendingRpcs = 0;
00627     this->finished = false;
00628     this->success = false;
00629 
00630     if (lookup->routingType == EXHAUSTIVE_ITERATIVE_ROUTING) {
00631         // need to add some extra space for backup nodes, if we have to
00632         // remove failed nodes from the nextHops vector
00633         this->nextHops = LookupVector(2*(lookup->config.redundantNodes),
00634                                       lookup);
00635     } else {
00636         this->nextHops = LookupVector((lookup->config.redundantNodes),
00637                                       lookup);
00638     }
00639 }

IterativePathLookup::~IterativePathLookup (  )  [protected, virtual]

00642 {}


Member Function Documentation

bool IterativePathLookup::accepts ( int  rpcId  )  [protected]

Referenced by IterativeLookup::handleRpcResponse().

00645 {
00646     if (finished) {
00647         return false;
00648     }
00649 
00650     // shall we use all responses, or only
00651     // the first one (rpcId == step)?
00652     if (lookup->config.useAllParallelResponses
00653         && lookup->config.merge) {
00654 
00655         return true;
00656     }
00657 
00658     return (rpcId == step);
00659 }

void IterativePathLookup::handleResponse ( FindNodeResponse *  msg  )  [protected]

Referenced by IterativeLookup::handleRpcResponse().

00662 {
00663     if (finished)
00664         return;
00665 
00666     const NodeHandle& source = msg->getSrcNode();
00667     std::map<TransportAddress, NodeHandle>::iterator oldPos;
00668     oldPos = oldNextHops.find(source);
00669     if (oldPos != oldNextHops.end()) oldNextHops.erase(oldPos);
00670 
00671     // don't count local hops
00672     if (lookup->overlay->getThisNode() != source) {
00673         hops++;
00674     }
00675 
00676     lookup->setVisited(source);
00677 
00678     if (source.key == lookup->key) {
00679 
00680 //        cout << "received response from destination for key " << lookup->key
00681 //             << " with isSibling = " << msg->getSiblings() << endl;
00682     }
00683 
00684     step++;
00685 
00686     // decrease pending rpcs
00687     pendingRpcs--;
00688 
00689     if (msg->getClosestNodesArraySize() != 0) {
00690         // mode: merge or replace
00691         if (!lookup->config.merge) {
00692             nextHops.clear();
00693         }
00694     } else {
00695         //cout << "findNode() returned 0 nodes!" << endl;
00696     }
00697 
00698     int numNewRpcs = 0;
00699 
00700     // add new next hops
00701     for (uint i=0; i < msg->getClosestNodesArraySize(); i++) {
00702         const NodeHandle& handle = msg->getClosestNodes(i);
00703 
00704         // add NodeHandle to next hops and siblings
00705         int pos = add(handle, source);
00706 
00707         // only send new rpcs if we've learned about new nodes
00708         if ((pos >= 0) && (pos < lookup->config.redundantNodes)) {
00709             numNewRpcs++;
00710         }
00711 
00712         // check if node was found
00713         if ((lookup->numSiblings == 0) && (handle.key == lookup->key)
00714                 && (!lookup->config.secure)) {
00715 
00716             lookup->addSibling(handle);
00717 
00718             finished = true;
00719             success = true;
00720             return;
00721         } else {
00722             if (lookup->numSiblings != 0 && !lookup->config.secure
00723                 && (lookup->routingType != EXHAUSTIVE_ITERATIVE_ROUTING)
00724                 && msg->getSiblings()) {
00725 
00726                 //cout << "adding sibling " << handle << endl;
00727                 lookup->addSibling(handle);
00728             }
00729         }
00730     }
00731 
00732 #if 0
00733     cout << "nextHops.size " << nextHops.size()
00734          << " find node response " << msg->getClosestNodesArraySize()
00735          << " config " << lookup->config.redundantNodes << endl;
00736 
00737     cout << "looking for " << lookup->key << endl;
00738 
00739     for (uint i=0; i < msg->getClosestNodesArraySize(); i++) {
00740         cout << "find node " << msg->getClosestNodes(i) << endl;
00741     }
00742 
00743     cout << "next Hops " << nextHops << endl;
00744 #endif
00745 
00746     // check if sibling lookup is finished
00747     if ((lookup->routingType != EXHAUSTIVE_ITERATIVE_ROUTING)
00748             && msg->getSiblings()
00749             && msg->getClosestNodesArraySize() != 0 &&
00750             lookup->numSiblings != 0 && !lookup->config.secure) {
00751 
00752         finished = true;
00753         success = true;
00754         return;
00755     }
00756 
00757     // extract find node extension object
00758     cMessage* findNodeExt = NULL;
00759     if (msg->hasObject("findNodeExt")) {
00760         findNodeExt = (cMessage*)msg->removeObject("findNodeExt");
00761     }
00762 
00763     // If config.newRpcOnEveryResponse is true, send a new RPC
00764     // even if there was no lookup progress
00765     if ((numNewRpcs == 0) && lookup->config.newRpcOnEveryResponse) {
00766         numNewRpcs = 1;
00767     }
00768 
00769     // send next rpcs
00770     sendRpc(min(numNewRpcs, lookup->config.parallelRpcs), findNodeExt);
00771 
00772     delete findNodeExt;
00773 }

void IterativePathLookup::handleTimeout ( BaseCallMessage *  msg,
const TransportAddress dest,
int  rpcId 
) [protected]

Referenced by IterativeLookup::handleRpcResponse(), and IterativeLookup::handleRpcTimeout().

00789 {
00790     if (finished)
00791         return;
00792 
00793     EV << "[IterativePathLookup::handleTimeout()]\n"
00794        << "    Timeout of RPC " << rpcId
00795        << endl;
00796 
00797     //std::cout << lookup->overlay->getThisNode() << ": Path timeout for node"
00798     //          << dest << endl;
00799 
00800     if ((lookup->routingType == EXHAUSTIVE_ITERATIVE_ROUTING)
00801             && lookup->getDead(dest)) {
00802         nextHops.erase(nextHops.findIterator((
00803                 dynamic_cast<const NodeHandle&>(dest)).key));
00804     }
00805 
00806     std::map<TransportAddress, NodeHandle>::iterator oldPos;
00807     oldPos = oldNextHops.find(dest);
00808 
00809     // decrease pending rpcs
00810     pendingRpcs--;
00811 
00812     cMessage* findNodeExt = NULL;
00813     if (msg && msg->hasObject("findNodeExt")) {
00814         findNodeExt = static_cast<cMessage*>(
00815                 msg->removeObject("findNodeExt"));
00816     }
00817 
00818     if (oldPos == oldNextHops.end() || (!lookup->config.failedNodeRpcs)) {
00819         sendNewRpcAfterTimeout(findNodeExt);
00820         delete findNodeExt;
00821     } else {
00822         if (oldPos->second.isUnspecified()) {
00823             FindNodeCall* findNodeCall = dynamic_cast<FindNodeCall*>(msg);
00824             // answer was from local findNode()
00825 
00826             if (findNodeCall && lookup->overlay->handleFailedNode(dest)) {
00827                 NodeVector* retry = lookup->overlay->findNode(
00828                    findNodeCall->getLookupKey(), -1, lookup->numSiblings, msg);
00829 
00830                 for (NodeVector::iterator i = retry->begin(); i != retry->end(); i++) {
00831                     nextHops.add(LookupEntry(*i, NodeHandle::UNSPECIFIED_NODE, false));
00832                 }
00833 
00834                 delete retry;
00835             }
00836 
00837             sendNewRpcAfterTimeout(findNodeExt);
00838             delete findNodeExt;
00839 
00840         } else {
00841             FailedNodeCall* call = new FailedNodeCall("FailedNodeCall");
00842             call->setFailedNode(dest);
00843             call->setLength(FAILEDNODECALL_L(call));
00844             if (findNodeExt) {
00845                 call->addObject(findNodeExt);
00846                 call->addLength(findNodeExt->length());
00847             }
00848             lookup->overlay->countFailedNodeCall(call);
00849             lookup->overlay->sendUdpRpcCall(oldPos->second, call, NULL,
00850                                             -1, 0, -1, lookup);
00851         }
00852     }
00853 }

void IterativePathLookup::handleFailedNodeResponse ( const NodeHandle src,
cMessage *  findNodeExt,
bool  retry 
) [protected]

00857 {
00858     if (finished) {
00859         return;
00860     }
00861 
00862     std::map<TransportAddress, NodeHandle>::iterator oldPos;
00863     for (oldPos = oldNextHops.begin(); oldPos != oldNextHops.end(); oldPos++) {
00864         if ((! oldPos->second.isUnspecified()) &&
00865             (oldPos->second == src)) break;
00866     }
00867 
00868     if (oldPos == oldNextHops.end()) {
00869         return;
00870     }
00871 
00872     std::map<TransportAddress, NodeHandle>::iterator oldSrcPos =
00873         oldNextHops.find(src);
00874     const NodeHandle* oldSrc = &NodeHandle::UNSPECIFIED_NODE;
00875 
00876     if (oldSrcPos != oldNextHops.end()) {
00877         oldSrc = &(oldSrcPos->second);
00878     }
00879 
00880     if (retry) {
00881         // FIXME: This is needed for a node to be asked again when detecting
00882         // a failed node. It could pose problems when parallel lookups and
00883         // failed node recovery are both needed at the same time!
00884         lookup->setVisited(src, false);
00885 
00886         nextHops.add(LookupEntry(src, *oldSrc, false));
00887     }
00888 
00889     oldNextHops.erase(oldPos);
00890 
00891     sendNewRpcAfterTimeout(findNodeExt);
00892 }

void IterativePathLookup::sendRpc ( int  num,
cMessage *  FindNodeExt = NULL 
) [private]

Referenced by handleResponse(), sendNewRpcAfterTimeout(), and IterativeLookup::start().

00895 {
00896     // path finished? yes -> quit
00897     if (finished)
00898         return;
00899 
00900     // check for maximum hop count
00901     if (lookup->hopCountMax && (hops >= lookup->hopCountMax)) {
00902         EV << "[IterativePathLookup::sendRpc()]\n"
00903            << "    Max hop count exceeded - lookup failed!"
00904            << endl;
00905         //cout << "[IterativePathLookup::sendRpc()]\n"
00906         //     << "    Max hop count exceeded - lookup failed!"
00907         //     << endl;
00908 
00909         finished = true;
00910         success = false;
00911 
00912         return;
00913     }
00914 
00915     // if strictParallelRpcs is true, limit concurrent in-flight requests
00916     // to config.parallelRpcs
00917     if (lookup->config.strictParallelRpcs) {
00918         num = min(num, lookup->config.parallelRpcs - pendingRpcs);
00919     }
00920 
00921     // try all remaining nodes
00922     if ((num == 0) && (pendingRpcs == 0)
00923             && !lookup->config.finishOnFirstUnchanged) {
00924         num = lookup->config.parallelRpcs;
00925         //cout << "trying all remaining nodes ("
00926         //     << lookup->numSiblings << ")" << endl;
00927     }
00928 
00929     // send rpc messages
00930     LookupVector::iterator it = nextHops.begin();
00931     int i = 0;
00932     for (LookupVector::iterator it = nextHops.begin();
00933          ((num > 0) && (i < lookup->config.redundantNodes)
00934           && (it != nextHops.end())); it++, i++)  {
00935 
00936         // ignore nodes to which we've already sent an RPC
00937         if (it->alreadyUsed || lookup->getDead(it->handle)) continue;
00938 
00939         // check if node has already been visited? no ->
00940         // TODO: doesn't work with Broose
00941         if (!lookup->getVisited(it->handle)) {
00942             // send rpc to node increase pending rpcs
00943             pendingRpcs++;
00944             num--;
00945             FindNodeCall* call = createRpcMessage(findNodeExt);
00946             lookup->overlay->countFindNodeCall(call);
00947             lookup->sendRpc(it->handle, call, this, step);
00948             oldNextHops[it->handle] = it->source;
00949 
00950             //cout << "Sending RPC to " << it->handle
00951             //     << " ( " << num << " more )"
00952             //     << " thisNode = " << lookup->overlay->getThisNode().key << endl;
00953 
00954             // mark node as already used
00955             it->alreadyUsed = true;
00956         } else {
00957             //EV << "[IterativePathLookup::sendRpc()]\n"
00958             //   << "    Last next hop ("
00959             //   << it->handle
00960             //   << ") already visited."
00961             //   << endl;
00962 
00963 //            std::cout << "visited:" << std::endl;
00964 //            for (TransportAddress::Set::iterator it = lookup->visited.begin();
00965 //            it != lookup->visited.end(); it++)
00966 //                std::cout << *it << std::endl;
00967 //
00968 //            std::cout << "nextHops:" << std::endl;
00969 //            for (NodePairVector::iterator it = nextHops.begin();
00970 //                 it != nextHops.end(); it++)
00971 //                std::cout << it->first << std::endl;
00972         }
00973     }
00974 
00975     // no rpc sent, no pending rpcs?
00976     // -> failed for normal lookups
00977     // -> exhaustive lookups are always successful
00978     if (pendingRpcs == 0) {
00979         if (lookup->routingType == EXHAUSTIVE_ITERATIVE_ROUTING) {
00980             int i = 0;
00981             for (LookupVector::iterator it = nextHops.begin();
00982                  ((i < lookup->config.redundantNodes)
00983                          && (it != nextHops.end())); it++, i++)  {
00984                 lookup->addSibling(it->handle);
00985             }
00986 
00987             success = true;
00988         } else {
00989             success = false;
00990             //cout << "failed nextHops for key " << lookup->key << endl;
00991             //cout << nextHops << endl;
00992         }
00993 
00994         finished = true;
00995     }
00996     //cout << endl;
00997 }

void IterativePathLookup::sendNewRpcAfterTimeout ( cMessage *  findNodeExt  )  [private]

Referenced by handleFailedNodeResponse(), and handleTimeout().

00776 {
00777     // two alternatives to react on a timeout
00778     if (lookup->config.newRpcOnEveryTimeout) {
00779         // always send one new RPC for every timeout
00780         sendRpc(1, findNodeExt);
00781     } else if (pendingRpcs == 0) {
00782         // wait until all RPCs have timed out and then send alpha new RPCs
00783         sendRpc(lookup->config.parallelRpcs, findNodeExt);
00784     }
00785 }

FindNodeCall * IterativePathLookup::createRpcMessage ( cMessage *  findNodeExt = NULL  )  [protected, virtual]

Creates a find node call message.

This method can be overridden to add some additional state information to the FindNodeCall message.

Parameters:
findNodeExt Pointer to a optional cMessage, that may contain overlay specific data to be attached to FindNode RPCs and BaseRouteMessages
Returns:
Pointer to a new FindNodeCall message.

Referenced by sendRpc().

01000 {
01001     // create default find node call message
01002     FindNodeCall* call = new FindNodeCall( "FindNodeCall" );
01003 
01004     if (lookup->appLookup) {
01005         call->setStatType(APP_LOOKUP_STAT);
01006     } else {
01007         call->setStatType(MAINTENANCE_STAT);
01008     }
01009 
01010     call->setLookupKey(lookup->key);
01011     call->setNumRedundantNodes(lookup->config.redundantNodes);
01012     call->setNumSiblings(lookup->numSiblings);
01013     call->setLength(FINDNODECALL_L(call));
01014 
01015     // duplicate extension object
01016     if (findNodeExt != NULL) {
01017         call->addObject((cObject*)findNodeExt->dup());
01018         call->addLength(findNodeExt->length());
01019     }
01020 
01021     return call;
01022 }

int IterativePathLookup::add ( const NodeHandle handle,
const NodeHandle source = NodeHandle::UNSPECIFIED_NODE 
) [protected]

Adds a NodeHandle to next hops.

Referenced by IterativeLookup::start().

01025 {
01026     if (lookup->config.merge) {
01027         return nextHops.add(LookupEntry(handle, source, false));
01028     } else {
01029         nextHops.push_back(LookupEntry(handle, source, false));
01030         return (nextHops.size() - 1);
01031     }
01032 }


Friends And Related Function Documentation

friend class IterativeLookup [friend]


Member Data Documentation

int IterativePathLookup::hops [protected]

int IterativePathLookup::step [protected]

bool IterativePathLookup::success [protected]


The documentation for this class was generated from the following files:

Generated on Fri Sep 19 13:05:07 2008 for ITM OverSim by  doxygen 1.5.5