#include <IterativeLookup.h>
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 | |
IterativeLookup * | lookup |
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 |
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 }
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.
findNodeExt | Pointer to a optional cMessage, that may contain overlay specific data to be attached to FindNode RPCs and BaseRouteMessages |
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 }
friend class IterativeLookup [friend] |
IterativeLookup* IterativePathLookup::lookup [protected] |
Referenced by accepts(), add(), createRpcMessage(), handleFailedNodeResponse(), handleResponse(), handleTimeout(), sendNewRpcAfterTimeout(), and sendRpc().
int IterativePathLookup::hops [protected] |
int IterativePathLookup::step [protected] |
Referenced by accepts(), handleResponse(), IterativePathLookup(), and sendRpc().
int IterativePathLookup::pendingRpcs [protected] |
Referenced by handleResponse(), handleTimeout(), IterativePathLookup(), sendNewRpcAfterTimeout(), and sendRpc().
bool IterativePathLookup::finished [protected] |
bool IterativePathLookup::success [protected] |
LookupVector IterativePathLookup::nextHops [protected] |
Referenced by add(), handleFailedNodeResponse(), handleResponse(), handleTimeout(), IterativePathLookup(), and sendRpc().
std::map<TransportAddress, NodeHandle> IterativePathLookup::oldNextHops [protected] |
Referenced by handleFailedNodeResponse(), handleResponse(), handleTimeout(), and sendRpc().