BasePastry.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include <sstream>
00025 
00026 #include <IPAddressResolver.h>
00027 #include <IPvXAddress.h>
00028 #include <IInterfaceTable.h>
00029 #include <IPv4InterfaceData.h>
00030 #include <RpcMacros.h>
00031 #include <InitStages.h>
00032 #include <NeighborCache.h>
00033 #include <GlobalStatistics.h>
00034 #include <BootstrapList.h>
00035 #include <assert.h>
00036 
00037 #include "BasePastry.h"
00038 
00039 
00040 void BasePastry::purgeVectors(void)
00041 {
00042     // purge pending state messages
00043     if (!stReceived.empty()) {
00044         for (std::vector<PastryStateMsgHandle>::iterator it =
00045                  stReceived.begin(); it != stReceived.end(); it++) {
00046             // check whether one of the pointers is a duplicate of stateCache
00047             if (it->msg == stateCache.msg) {
00048                 stateCache.msg = NULL;
00049                 stateCache.prox = NULL;
00050             }
00051             delete it->msg;
00052             delete it->prox;
00053         }
00054         stReceived.clear();
00055         stReceivedPos = stReceived.end();
00056     }
00057 
00058     // purge notify list:
00059     notifyList.clear();
00060 
00061     // purge Queue for messages to be forwarded in recursive mode:
00062     for (std::map<TransportAddress, BaseRouteMessage*>::iterator i =
00063         recFwdQueue.begin(); i != recFwdQueue.end(); i++) {
00064         delete i->second;
00065     }
00066     recFwdQueue.clear();
00067 
00068     // purge Queue for processing multiple STATE messages:
00069     while (! stateCacheQueue.empty()) {
00070         delete stateCacheQueue.front().msg;
00071         stateCacheQueue.pop();
00072     }
00073 
00074     // delete cached state message:
00075     if (stateCache.msg) {
00076         delete stateCache.msg;
00077         stateCache.msg = NULL;
00078         delete stateCache.prox;
00079         stateCache.prox = NULL;
00080     }
00081 
00082     // purge vector of waiting sendState messages:
00083     if (! sendStateWait.empty()) {
00084         for (std::vector<PastrySendState*>::iterator it =
00085                  sendStateWait.begin(); it != sendStateWait.end(); it++) {
00086             if ( (*it)->isScheduled() ) cancelEvent(*it);
00087             delete *it;
00088         }
00089         sendStateWait.clear();
00090     }
00091 }
00092 
00093 void BasePastry::baseInit()
00094 {
00095     bitsPerDigit = par("bitsPerDigit");
00096     numberOfLeaves = par("numberOfLeaves");
00097     numberOfNeighbors = par("numberOfNeighbors");
00098     joinTimeoutAmount = par("joinTimeout");
00099     repairTimeout = par("repairTimeout");
00100     enableNewLeafs = par("enableNewLeafs");
00101     optimizeLookup = par("optimizeLookup");
00102     optimisticForward = par("optimisticForward");
00103     avoidDuplicates = par("avoidDuplicates");
00104     sendStateWaitAmount = par("sendStateWaitAmount");
00105     timeoutPing = par("pingTimeout");
00106     pingRetries = par("pingRetries");
00107     useRegularNextHop = par("useRegularNextHop");
00108     alwaysSendUpdate = par("alwaysSendUpdate");
00109 
00110     useDiscovery = false; //TODO
00111 
00112     if (!neighborCache->isEnabled()) {
00113         throw cRuntimeError("NeighborCache is disabled, which is mandatory "
00114                                 "for Pastry/Bamboo. Activate it by setting "
00115                                 "\"**.neighborCache.enableNeighborCache "
00116                                 "= true\" in your omnetpp.ini!");
00117     }
00118 
00119     if (numberOfLeaves % 2) {
00120         EV << "[BasePastry::baseInit() @ " << thisNode.getAddress()
00121            << " (" << thisNode.getKey().toString(16) << ")]\n"
00122            << "    Warning: numberOfLeaves must be even - adding 1."
00123            << endl;
00124         numberOfLeaves++;
00125     }
00126 
00127     routingTable = check_and_cast<PastryRoutingTable*>
00128         (getParentModule()->getSubmodule("pastryRoutingTable"));
00129     leafSet = check_and_cast<PastryLeafSet*>
00130         (getParentModule()->getSubmodule("pastryLeafSet"));
00131     neighborhoodSet = check_and_cast<PastryNeighborhoodSet*>
00132         (getParentModule()->getSubmodule("pastryNeighborhoodSet"));
00133 
00134     stateCache.msg = NULL;
00135     stateCache.prox = NULL;
00136 
00137     rowToAsk = 0;
00138 
00139     // initialize statistics
00140     joins = 0;
00141     joinTries = 0;
00142     joinPartial = 0;
00143     joinSeen = 0;
00144     joinReceived = 0;
00145     joinSent = 0;
00146     stateSent = 0;
00147     stateReceived = 0;
00148     repairReqSent = 0;
00149     repairReqReceived = 0;
00150     stateReqSent = 0;
00151     stateReqReceived = 0;
00152 
00153     joinBytesSeen = 0;
00154     joinBytesReceived = 0;
00155     joinBytesSent = 0;
00156     stateBytesSent = 0;
00157     stateBytesReceived = 0;
00158     repairReqBytesSent = 0;
00159     repairReqBytesReceived = 0;
00160     stateReqBytesSent = 0;
00161     stateReqBytesReceived = 0;
00162 
00163     totalLookups = 0;
00164     responsibleLookups = 0;
00165     routingTableLookups = 0;
00166     closerNodeLookups = 0;
00167     closerNodeLookupsFromNeighborhood = 0;
00168 
00169     leafsetReqSent = 0;
00170     leafsetReqBytesSent = 0;
00171     leafsetReqReceived = 0;
00172     leafsetReqBytesReceived = 0;
00173     leafsetSent = 0;
00174     leafsetBytesSent = 0;
00175     leafsetReceived = 0;
00176     leafsetBytesReceived = 0;
00177 
00178     routingTableReqSent = 0;
00179     routingTableReqBytesSent = 0;
00180     routingTableReqReceived = 0;
00181     routingTableReqBytesReceived = 0;
00182     routingTableSent = 0;
00183     routingTableBytesSent = 0;
00184     routingTableReceived = 0;
00185     routingTableBytesReceived = 0;
00186 
00187     WATCH(joins);
00188     WATCH(joinTries);
00189     WATCH(joinSeen);
00190     WATCH(joinBytesSeen);
00191     WATCH(joinReceived);
00192     WATCH(joinBytesReceived);
00193     WATCH(joinSent);
00194     WATCH(joinBytesSent);
00195     WATCH(stateSent);
00196     WATCH(stateBytesSent);
00197     WATCH(stateReceived);
00198     WATCH(stateBytesReceived);
00199     WATCH(repairReqSent);
00200     WATCH(repairReqBytesSent);
00201     WATCH(repairReqReceived);
00202     WATCH(repairReqBytesReceived);
00203     WATCH(stateReqSent);
00204     WATCH(stateReqBytesSent);
00205     WATCH(stateReqReceived);
00206     WATCH(stateReqBytesReceived);
00207     WATCH(lastStateChange);
00208 
00209     WATCH(leafsetReqSent);
00210     WATCH(leafsetReqBytesSent);
00211     WATCH(leafsetReqReceived);
00212     WATCH(leafsetReqBytesReceived);
00213     WATCH(leafsetSent);
00214     WATCH(leafsetBytesSent);
00215     WATCH(leafsetReceived);
00216     WATCH(leafsetBytesReceived);
00217 
00218     WATCH(routingTableReqSent);
00219     WATCH(routingTableReqBytesSent);
00220     WATCH(routingTableReqReceived);
00221     WATCH(routingTableReqBytesReceived);
00222     WATCH(routingTableSent);
00223     WATCH(routingTableBytesSent);
00224     WATCH(routingTableReceived);
00225     WATCH(routingTableBytesReceived);
00226 }
00227 
00228 
00229 void BasePastry::baseChangeState(int toState)
00230 {
00231     switch (toState) {
00232     case INIT:
00233         state = INIT;
00234 
00235         if (!thisNode.getKey().isUnspecified())
00236             bootstrapList->removeBootstrapNode(thisNode);
00237 
00238         if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00239 
00240         purgeVectors();
00241 
00242         bootstrapNode = bootstrapList->getBootstrapNode();
00243 
00244         routingTable->initializeTable(bitsPerDigit, repairTimeout,
00245                                       thisNode);
00246         leafSet->initializeSet(numberOfLeaves, bitsPerDigit,
00247                                repairTimeout, thisNode,
00248                                this);
00249         neighborhoodSet->initializeSet(numberOfNeighbors, bitsPerDigit,
00250                                        thisNode);
00251 
00252         updateTooltip();
00253         lastStateChange = simTime();
00254 
00255         getParentModule()->getParentModule()->bubble("entering INIT state");
00256 
00257         break;
00258 
00259     case JOINING_2:
00260         state = JOINING_2;
00261 
00262         // bootstrapNode must be obtained before calling this method,
00263         // for example by calling changeState(INIT)
00264 
00265         if (bootstrapNode.isUnspecified()) {
00266             // no existing pastry network -> first node of a new one
00267             changeState(READY);
00268             return;
00269         }
00270 
00271         cancelEvent(joinTimeout);
00272         scheduleAt(simTime() + joinTimeoutAmount, joinTimeout);
00273 
00274         updateTooltip();
00275         getParentModule()->getParentModule()->bubble("entering JOIN state");
00276 
00277         RECORD_STATS(joinTries++);
00278 
00279         break;
00280 
00281     case READY:
00282         assert(state != READY);
00283         state = READY;
00284 
00285          //bootstrapList->registerBootstrapNode(thisNode);
00286 
00287         // if we are the first node in the network, there's nothing else
00288         // to do
00289         if (bootstrapNode.isUnspecified()) {
00290             RECORD_STATS(joinTries++);
00291             RECORD_STATS(joins++);
00292             setOverlayReady(true);
00293             return;
00294         }
00295 
00296         getParentModule()->getParentModule()->bubble("entering READY state");
00297         updateTooltip();
00298         RECORD_STATS(joins++);
00299 
00300         break;
00301 
00302     default: // discovery
00303         break;
00304     }
00305     setOverlayReady(state == READY);
00306 }
00307 
00308 
00309 void BasePastry::newLeafs(void)
00310 {
00311     if (! enableNewLeafs) return;
00312 
00313     PastryNewLeafsMessage* msg = leafSet->getNewLeafsMessage();
00314     if (msg) {
00315         send(msg, "appOut");
00316         EV << "[BasePastry::newLeafs() @ " << thisNode.getAddress()
00317            << " (" << thisNode.getKey().toString(16) << ")]\n"
00318            << "    newLeafs() called."
00319            << endl;
00320     }
00321 }
00322 
00323 
00324 void BasePastry::changeState(int toState)
00325 {
00326 
00327 }
00328 
00329 
00330 bool BasePastry::recursiveRoutingHook(const TransportAddress& dest,
00331                                       BaseRouteMessage* msg)
00332 {
00333     if (dest == thisNode) {
00334         return true;
00335     }
00336 
00337     PastryMessage* pmsg =
00338         dynamic_cast<PastryMessage*>(msg->getEncapsulatedMsg());
00339 
00340     if (pmsg && pmsg->getPastryMsgType() == PASTRY_MSG_JOIN) {
00341         PastryJoinMessage* jmsg = static_cast<PastryJoinMessage*>(pmsg);
00342         if (jmsg->getSendStateTo() != thisNode) {
00343             RECORD_STATS(joinSeen++; joinBytesSeen += jmsg->getByteLength());
00344             // remove node from state if it is rejoining
00345             handleFailedNode(jmsg->getSendStateTo());
00346 
00347             sendStateTables(jmsg->getSendStateTo(), PASTRY_STATE_JOIN,
00348                             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo())
00349                             ->getHopCount(), false);
00350         }
00351     }
00352 
00353     if (recFwdQueue.find(dest) != recFwdQueue.end()) {
00354         // rare case, other message for same next hop is pending:
00355         // send the message and hope it isn't lost.
00356         return true;
00357     }
00358 
00359     assert(msg->getControlInfo());
00360 
00361     if (optimisticForward) {
00362         // forward now:
00363         return true;
00364     } else {
00365         if (routeMsgAcks) throw cRuntimeError("!optimisticForward && "
00366                                                   "routeMsgAcks");
00367         // keep message in queue (forward later)
00368         recFwdQueue[dest] = msg;
00369         pingNode(dest, timeoutPing, pingRetries, NULL,
00370                  "PING next hop", NULL, PING_NEXT_HOP);
00371 
00372         return false;
00373     }
00374 }
00375 
00376 int BasePastry::getNextRowToMaintain()
00377 {
00378     int digit = 0;
00379     int lastRow = routingTable->getLastRow();
00380 
00381     int* choices = new int[lastRow + 1];
00382     int sum = 0;
00383 
00384     for (int i = 0; i < lastRow; ++i) {
00385         sum += (choices[i] = lastRow - i);
00386     }
00387 
00388     int rval = intuniform(0, sum);
00389 
00390     while (true) {
00391         rval -= choices [digit];
00392         if (rval <= 0)
00393             break;
00394         ++digit;
00395     }
00396     delete[] choices;
00397 
00398     return digit;
00399 }
00400 
00401 void BasePastry::doRoutingTableMaintenance()
00402 {
00403     if (sendPullFlag) {
00404         // bamboo
00405         rowToAsk = getNextRowToMaintain();
00406         //uint32_t rrows = routingTable->getLastRow();
00407         //if (++rowToAsk >= rrows) rowToAsk = 0;
00408         const TransportAddress& ask4row = routingTable->getRandomNode(rowToAsk);
00409 
00410         if ((!ask4row.isUnspecified()) && (ask4row != thisNode)) {
00411             PastryRoutingRowRequestMessage* msg = new PastryRoutingRowRequestMessage("ROWREQ");
00412             msg->setPastryMsgType(PASTRY_MSG_ROWREQ);
00413             msg->setStatType(MAINTENANCE_STAT);
00414             msg->setSendStateTo(thisNode);
00415             msg->setRow(rowToAsk + 1);
00416             msg->setBitLength(PASTRYRTREQ_L(msg));
00417 
00418             RECORD_STATS(routingTableReqSent++; routingTableReqBytesSent += msg->getByteLength());
00419 
00420             EV << "[BasePastry::doRoutingTableMaintenance() @ " << thisNode.getAddress()
00421                << " (" << thisNode.getKey().toString(16) << ")]\n"
00422                << "    Sending  Message to Node in Row" << rowToAsk
00423                << endl;
00424 
00425             sendMessageToUDP(ask4row, msg);
00426         }
00427     } else {
00428         // pastry
00429         for (int i = 0; i < routingTable->getLastRow(); i++) {
00430             const TransportAddress& ask4row = routingTable->getRandomNode(i);
00431 
00432             if ((!ask4row.isUnspecified()) && (ask4row != thisNode)) {
00433                 PastryRoutingRowRequestMessage* msg = new PastryRoutingRowRequestMessage("ROWREQ");
00434                 msg->setPastryMsgType(PASTRY_MSG_ROWREQ);
00435                 msg->setStatType(MAINTENANCE_STAT);
00436                 msg->setSendStateTo(thisNode);
00437                 msg->setRow(i + 1);
00438                 msg->setBitLength(PASTRYRTREQ_L(msg));
00439 
00440                 RECORD_STATS(routingTableReqSent++; routingTableReqBytesSent += msg->getByteLength());
00441 
00442                 sendMessageToUDP(ask4row, msg);
00443             } else {
00444                 EV << "[BasePastry::doRoutingTableMaintenance() @ " << thisNode.getAddress()
00445                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00446                    << "    could not send Message to Node in Row" << i
00447                    << endl;
00448             }
00449         }
00450     }
00451 }
00452 
00453 void BasePastry::pingResponse(PingResponse* msg, cPolymorphic* context,
00454                               int rpcId, simtime_t rtt)
00455 {
00456     EV << "[BasePastry::pingResponse() @ " << thisNode.getAddress()
00457        << " (" << thisNode.getKey().toString(16) << ")]\n"
00458        << "    Pong (or Ping-context from NeighborCache) received (from "
00459        << msg->getSrcNode().getAddress() << ")"
00460        << endl;
00461 
00462     const NodeHandle& src = msg->getSrcNode();
00463     assert(!src.isUnspecified());
00464 
00465     // merge single pinged nodes (bamboo global tuning)
00466     if (rpcId == PING_SINGLE_NODE) {
00467         routingTable->mergeNode(src, rtt);
00468         return;
00469     }
00470 
00471     /*// a node with the an equal ID has responded
00472     if ((src.getKey() == thisNode.getKey()) && (src.getAddress() != thisNode.getAddress())) {
00473         EV << "[BasePastry::pingResponse() @ " << thisNode.getAddress()
00474            << " (" << thisNode.getKey().toString(16) << ")]\n"
00475            << "    a node with the an equal ID has responded, rejoining" << endl;
00476         delete context;
00477         //joinOverlay();
00478         return;
00479     }*/
00480 
00481     if (state == DISCOVERY) {
00482         if (nearNodeRtt > rtt) {
00483             nearNode = src;
00484             nearNodeRtt = rtt;
00485             nearNodeImproved = true;
00486         }
00487     }
00488 
00489     if (context != NULL && stateCache.msg && stateCache.prox) {
00490         PingContext* pingContext = check_and_cast<PingContext*>(context);
00491         if (pingContext->nonce != stateCache.nonce) {
00492             delete context;
00493             return;
00494             //throw cRuntimeError("response doesn't fit stateCache");
00495         }
00496         switch (pingContext->stateObject) {
00497             case ROUTINGTABLE: {
00498                 /*node = &(stateCache.msg->getRoutingTable(pingContext->index));
00499                 if((node->isUnspecified()) || (*node != src)) {
00500                     std::cout << simTime() << " " << thisNode.getAddress() << " rt: state from "
00501                               << stateCache.msg->getSender().getAddress() << " *** failed: node "
00502                               << node->ip << " src " << src.getAddress() << std::endl;
00503                     break;
00504                 }*/
00505                 *(stateCache.prox->pr_rt.begin() + pingContext->index) = rtt;
00506                 break;
00507             }
00508             case LEAFSET: {
00509                 /*node = &(stateCache.msg->getLeafSet(pingContext->index));
00510                 if ((node->isUnspecified()) || (*node != src)) {
00511                     std::cout << simTime() << " " << thisNode.getAddress() << " ls: state from "
00512                               << stateCache.msg->getSender().getAddress() << " *** failed: node "
00513                               << node->ip << " src " << src.getAddress() << std::endl;
00514                     break;
00515                 }*/
00516                 *(stateCache.prox->pr_ls.begin() + pingContext->index) = rtt;
00517                 break;
00518             }
00519             case NEIGHBORHOODSET: {
00520                 /*node = &(stateCache.msg->getNeighborhoodSet(pingContext->index));
00521                 if((node->isUnspecified()) || (*node != src)) {
00522                     std::cout << simTime() << " " << thisNode.getAddress() << " ns: state from "
00523                               << stateCache.msg->getSender().getAddress() << " *** failed: node "
00524                               << node->ip << " src " << src.getAddress() << std::endl;
00525                     break;
00526                 }*/
00527                 *(stateCache.prox->pr_ns.begin() + pingContext->index) = rtt;
00528                 break;
00529             }
00530             default: {
00531                 throw cRuntimeError("wrong state object type!");
00532             }
00533         }
00534         checkProxCache();
00535     }
00536     delete context;
00537 
00538     std::map<TransportAddress, BaseRouteMessage*>::iterator pos;
00539     if ((pos = recFwdQueue.find(src)) != recFwdQueue.end()) {
00540         // send message
00541         if (!optimisticForward) {
00542             sendMessageToUDP(pos->first, pos->second);
00543         } else if (!avoidDuplicates) {
00544             delete pos->second;
00545         }
00546         recFwdQueue.erase(pos);
00547     }
00548 }
00549 
00550 
00551 void BasePastry::proxCallback(const TransportAddress& node, int rpcId,
00552                               cPolymorphic *contextPointer, Prox prox)
00553 {
00554     Enter_Method("proxCallback()");
00555 
00556     EV << "[BasePastry::proxCallback() @ " << thisNode.getAddress()
00557            << " (" << thisNode.getKey().toString(16) << ")]\n"
00558            << "    Pong received (from "
00559            << node.getAddress() << ")"
00560            << endl;
00561 
00562     double rtt = ((prox == Prox::PROX_TIMEOUT) ? PASTRY_PROX_INFINITE
00563                                                : prox.proximity);
00564 
00565     // merge single pinged nodes (bamboo global tuning)
00566     if (rpcId == PING_SINGLE_NODE) {
00567         routingTable->mergeNode((const NodeHandle&)node, rtt);
00568         return;
00569     }
00570 
00571     if (contextPointer != NULL && stateCache.msg && stateCache.prox) {
00572         PingContext* pingContext = check_and_cast<PingContext*>(contextPointer);
00573 
00574         if (pingContext->nonce != stateCache.nonce) {
00575             delete contextPointer;
00576             return;
00577         }
00578         // handle failed node
00579         if (rtt == PASTRY_PROX_INFINITE && state== READY) {
00580             handleFailedNode(node); // TODO
00581             updateTooltip();
00582 
00583             // this could initiate a re-join, exit the handler in that
00584             // case because all local data was erased:
00585             if (state != READY) {
00586                 delete contextPointer;
00587                 return;
00588             }
00589         }
00590         switch (pingContext->stateObject) {
00591         case ROUTINGTABLE:
00592             *(stateCache.prox->pr_rt.begin() + pingContext->index) = rtt;
00593             break;
00594 
00595         case LEAFSET:
00596             *(stateCache.prox->pr_ls.begin() + pingContext->index) = rtt;
00597             break;
00598 
00599         case NEIGHBORHOODSET:
00600             *(stateCache.prox->pr_ns.begin() + pingContext->index) = rtt;
00601             break;
00602 
00603         default:
00604             throw cRuntimeError("wrong state object type!");
00605         }
00606         checkProxCache();
00607     }
00608     delete contextPointer;
00609 }
00610 
00611 
00612 void BasePastry::prePing(const PastryStateMessage* stateMsg)
00613 {
00614     uint32_t rt_size = stateMsg->getRoutingTableArraySize();
00615     uint32_t ls_size = stateMsg->getLeafSetArraySize();
00616     uint32_t ns_size = stateMsg->getNeighborhoodSetArraySize();
00617 
00618     for (uint32_t i = 0; i < rt_size + ls_size + ns_size; i++) {
00619         const NodeHandle* node;
00620         if (i < rt_size) {
00621             node = &(stateMsg->getRoutingTable(i));
00622         }
00623         else if (i < (rt_size + ls_size) ) {
00624             node = &(stateMsg->getLeafSet(i - rt_size));
00625         }
00626         else {
00627             node = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size));
00628         }
00629         if ((node->isUnspecified()) || (*node == thisNode)) {
00630             continue;
00631         }
00632         /*if (node->key == thisNode.getKey()) {
00633             cerr << "Pastry Warning: Other node with same key found, "
00634                 "restarting!" << endl;
00635             opp_error("TODO: Other node with same key found...");
00636             joinOverlay(); //segfault
00637             //return;
00638             continue;
00639         }*/
00640 
00641         neighborCache->getProx(*node, NEIGHBORCACHE_DEFAULT, PING_RECEIVED_STATE, this, NULL);
00642     }
00643 }
00644 
00645 void BasePastry::pingNodes(void)
00646 {
00647     EV << "[BasePastry::pingNodes() @ " << thisNode.getAddress()
00648        << " (" << thisNode.getKey().toString(16) << ")]" << endl;
00649 
00650     if (stateCache.msg == NULL) throw cRuntimeError("no state msg");
00651 
00652     assert(stateCache.prox == NULL);
00653     stateCache.prox = new PastryStateMsgProximity();
00654 
00655     uint32_t rt_size = stateCache.msg->getRoutingTableArraySize();
00656     stateCache.prox->pr_rt.resize(rt_size, PASTRY_PROX_UNDEF);
00657 
00658     uint32_t ls_size = stateCache.msg->getLeafSetArraySize();
00659     stateCache.prox->pr_ls.resize(ls_size, PASTRY_PROX_UNDEF);
00660 
00661     uint32_t ns_size = stateCache.msg->getNeighborhoodSetArraySize();
00662     stateCache.prox->pr_ns.resize(ns_size, PASTRY_PROX_UNDEF);
00663 
00664     std::vector< std::pair<const NodeHandle*, PingContext*> > nodesToPing;
00665     // set prox state
00666     for (uint32_t i = 0; i < rt_size + ls_size + ns_size; i++) {
00667         const NodeHandle* node;
00668         std::vector<simtime_t>::iterator proxPos;
00669         PingContext* pingContext = NULL;
00670         StateObject stateObject;
00671         uint32_t index;
00672         if (stateCache.msg == NULL) break;
00673         if (i < rt_size) {
00674             node = &(stateCache.msg->getRoutingTable(i));
00675             proxPos = stateCache.prox->pr_rt.begin() + i;
00676             stateObject = ROUTINGTABLE;
00677             index = i;
00678         } else if ( i < (rt_size + ls_size) ) {
00679             node = &(stateCache.msg->getLeafSet(i - rt_size));
00680             proxPos = stateCache.prox->pr_ls.begin() + (i - rt_size);
00681             stateObject = LEAFSET;
00682             index = i - rt_size;
00683         } else {
00684             node = &(stateCache.msg->getNeighborhoodSet(i - rt_size - ls_size));
00685             proxPos = stateCache.prox->pr_ns.begin() + (i - rt_size - ls_size);
00686             stateObject = NEIGHBORHOODSET;
00687             index = i - rt_size - ls_size;
00688         }
00689         // proximity is undefined for unspecified nodes:
00690         if (!node->isUnspecified()) {
00691             pingContext = new PingContext(stateObject, index,
00692                                           stateCache.nonce);
00693 
00694             Prox prox = neighborCache->getProx(*node, NEIGHBORCACHE_DEFAULT, -1,
00695                                                this, pingContext);
00696             if (prox == Prox::PROX_SELF) {
00697                 *proxPos = 0;
00698             } else if (prox == Prox::PROX_TIMEOUT) {
00699                 *proxPos = PASTRY_PROX_INFINITE;
00700             } else if (prox == Prox::PROX_UNKNOWN) {
00701                 *proxPos = PASTRY_PROX_PENDING;
00702             } else {
00703                 *proxPos = prox.proximity;
00704             }
00705         }
00706     }
00707     checkProxCache();
00708 }
00709 
00710 void BasePastry::determineAliveTable(const PastryStateMessage* stateMsg)
00711 {
00712     uint32_t rt_size = stateMsg->getRoutingTableArraySize();
00713     aliveTable.pr_rt.clear();
00714     aliveTable.pr_rt.resize(rt_size, 1);
00715 
00716     uint32_t ls_size = stateMsg->getLeafSetArraySize();
00717     aliveTable.pr_ls.clear();
00718     aliveTable.pr_ls.resize(ls_size, 1);
00719 
00720     uint32_t ns_size = stateMsg->getNeighborhoodSetArraySize();
00721     aliveTable.pr_ns.clear();
00722     aliveTable.pr_ns.resize(ns_size, 1);
00723 
00724     for (uint32_t i = 0; i < rt_size + ls_size + ns_size; i++) {
00725         const TransportAddress* node;
00726         std::vector<simtime_t>::iterator tblPos;
00727         if (i < rt_size) {
00728             node = &(stateMsg->getRoutingTable(i));
00729             tblPos = aliveTable.pr_rt.begin() + i;
00730         } else if ( i < (rt_size + ls_size) ) {
00731             node = &(stateMsg->getLeafSet(i - rt_size));
00732             tblPos = aliveTable.pr_ls.begin() + (i - rt_size);
00733         } else {
00734             node = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size));
00735             tblPos = aliveTable.pr_ns.begin() + (i - rt_size - ls_size);
00736         }
00737         if (neighborCache->getProx(*node, NEIGHBORCACHE_DEFAULT_IMMEDIATELY) ==
00738                 Prox::PROX_TIMEOUT) {
00739             *tblPos = PASTRY_PROX_INFINITE;
00740         }
00741     }
00742 }
00743 
00744 void BasePastry::sendStateTables(const TransportAddress& destination, int type, ...)
00745 {
00746     if (destination.getAddress() == thisNode.getAddress())
00747         opp_error("Pastry: trying to send state to self!");
00748 
00749     int hops = 0;
00750     bool last = false;
00751     simtime_t timestamp = 0;
00752 
00753     if ((type == PASTRY_STATE_JOIN) || (type == PASTRY_STATE_UPDATE)) {
00754         // additional parameters needed:
00755         va_list ap;
00756         va_start(ap, type);
00757         if (type == PASTRY_STATE_JOIN) {
00758             hops = va_arg(ap, int);
00759             last = static_cast<bool>(va_arg(ap, int));
00760         } else {
00761             timestamp = *va_arg(ap, simtime_t*);
00762         }
00763         va_end(ap);
00764     }
00765 
00766     // create new state msg and set special fields for some types:
00767     PastryStateMessage* stateMsg;
00768     if (type == PASTRY_STATE_JOIN) {
00769         stateMsg = new PastryStateMessage("STATE (Join)");
00770         stateMsg->setJoinHopCount(hops);
00771         stateMsg->setLastHop(last);
00772         stateMsg->setTimestamp(simTime());
00773     } else if (type == PASTRY_STATE_UPDATE) {
00774         stateMsg = new PastryStateMessage("STATE (Update)");
00775         EV << "[BasePastry::sendStateTables() @ " << thisNode.getAddress()
00776            << " (" << thisNode.getKey().toString(16) << ")]\n"
00777            << "    sending state (update) to " << destination
00778            << endl;
00779         stateMsg->setTimestamp(timestamp);
00780     } else if (type == PASTRY_STATE_REPAIR) {
00781         stateMsg = new PastryStateMessage("STATE (Repair)");
00782         stateMsg->setTimestamp(timestamp);
00783         EV << "[BasePastry::sendStateTables() @ " << thisNode.getAddress()
00784            << " (" << thisNode.getKey().toString(16) << ")]\n"
00785            << "    sending state (repair) to " << destination
00786            << endl;
00787     } else {
00788         stateMsg = new PastryStateMessage("STATE");
00789         EV << "[BasePastry::sendStateTables() @ " << thisNode.getAddress()
00790            << " (" << thisNode.getKey().toString(16) << ")]\n"
00791            << "    sending state (standard) to " << destination
00792            << endl;
00793     }
00794 
00795     // fill in standard content:
00796     stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
00797     stateMsg->setStatType(MAINTENANCE_STAT);
00798     stateMsg->setPastryStateMsgType(type);
00799     stateMsg->setSender(thisNode);
00800 
00801     // the following part of the new join works on the assumption, that the node
00802     // routing the join message is close to the joining node
00803     // therefore its switched on together with the discovery algorithm
00804     if ((type == PASTRY_STATE_JOIN) && (useDiscovery)) { //TODO remove dependency on discovery mode
00805         routingTable->dumpRowToMessage(stateMsg, hops); //send just the needed row for new join protocol
00806         if (last) leafSet->dumpToStateMessage(stateMsg);
00807         else stateMsg->setLeafSetArraySize(0);
00808         if (hops == 1) neighborhoodSet->dumpToStateMessage(stateMsg);
00809         else stateMsg->setNeighborhoodSetArraySize(0);
00810     }
00811     else {
00812         routingTable->dumpToStateMessage(stateMsg);
00813         leafSet->dumpToStateMessage(stateMsg);
00814         neighborhoodSet->dumpToStateMessage(stateMsg);
00815     }
00816 
00817     // send...
00818     stateMsg->setBitLength(PASTRYSTATE_L(stateMsg));
00819     RECORD_STATS(stateSent++; stateBytesSent += stateMsg->getByteLength());
00820     sendMessageToUDP(destination, stateMsg);
00821 }
00822 
00823 void BasePastry::sendStateDelayed(const TransportAddress& destination)
00824 {
00825     PastrySendState* selfMsg = new PastrySendState("sendStateWait");
00826     selfMsg->setDest(destination);
00827     sendStateWait.push_back(selfMsg);
00828     scheduleAt(simTime() + sendStateWaitAmount, selfMsg);
00829 }
00830 
00831 void BasePastry::pingTimeout(PingCall* msg,
00832                              const TransportAddress& dest,
00833                              cPolymorphic* context,
00834                              int rpcId)
00835 {
00836     EV << "[BasePastry::sendStateDelayed() @ " << thisNode.getAddress()
00837        << " (" << thisNode.getKey().toString(16) << ")]\n"
00838        << "    Ping timeout occurred (" << dest.getAddress() << ")"
00839        << endl;
00840 
00841     // handle failed node
00842     if (state == READY) {
00843         handleFailedNode(dest); // TODO
00844         updateTooltip();
00845 
00846         // this could initiate a re-join, exit the handler in that
00847         // case because all local data was erased:
00848         if (state != READY) {
00849             delete context;
00850             return;
00851         }
00852     }
00853 
00854     //TODO must be removed
00855     if (context && stateCache.msg && stateCache.prox &&
00856         rpcId == PING_RECEIVED_STATE) {
00857         PingContext* pingContext = check_and_cast<PingContext*>(context);
00858         if (pingContext->nonce != stateCache.nonce) {
00859             delete context;
00860             return;
00861             //std::stringstream temp;
00862             //temp << thisNode << " timeout/call doesn't fit stateCache";
00863             //throw cRuntimeError(temp.str().c_str());
00864         }
00865         //const NodeHandle* node;
00866         switch (pingContext->stateObject) {
00867             case ROUTINGTABLE: {
00868                 /*if (pingContext->index >=
00869                     stateCache.msg->getRoutingTableArraySize()) {
00870                     std::cout << "*** FAILED ***" << std::endl;
00871                     break;
00872                 }
00873                 node = &(stateCache.msg->getRoutingTable(pingContext->index));
00874                 if((node->isUnspecified()) || (dest != *node)) {
00875                     std::cout << msg->getNonce() << " " << simTime() << " " << thisNode.getAddress() << " rt: state from "
00876                     << stateCache.msg->getSender().getAddress() << " *** failed: node "
00877                     << node->ip << " failed dest " << dest.getAddress() << std::endl;
00878                     break;
00879                 }*/
00880                 *(stateCache.prox->pr_rt.begin() + pingContext->index) =
00881                     PASTRY_PROX_INFINITE;
00882                 break;
00883             }
00884             case LEAFSET: {
00885                 /*if (pingContext->index >=
00886                     stateCache.msg->getLeafSetArraySize()) {
00887                     std::cout << "*** FAILED ***" << std::endl;
00888                     break;
00889                 }
00890                 node = &(stateCache.msg->getLeafSet(pingContext->index));
00891                 if((node->isUnspecified()) || (dest != *node)) {
00892                     std::cout << msg->getNonce() << " " << simTime() << " " << thisNode.getAddress() << " ls: state from "
00893                     << stateCache.msg->getSender().getAddress() << " *** failed: node "
00894                     << node->ip << " failed dest " << dest.getAddress() << std::endl;
00895                     break;
00896                 }*/
00897                 *(stateCache.prox->pr_ls.begin() + pingContext->index) =
00898                     PASTRY_PROX_INFINITE;
00899                 break;
00900             }
00901             case NEIGHBORHOODSET: {
00902                 /*if (pingContext->index >=
00903                     stateCache.msg->getNeighborhoodSetArraySize()) {
00904                     std::cout << "*** FAILED ***" << std::endl;
00905                     break;
00906                 }
00907                 node = &(stateCache.msg->getNeighborhoodSet(pingContext->index));
00908                 if((node->isUnspecified()) || (dest != *node)) {
00909                     std::cout << msg->getNonce() << " " << simTime() << " " << thisNode.getAddress() << " ns: state from "
00910                     << stateCache.msg->getSender().getAddress() << " *** failed: node "
00911                     << node->ip << " failed dest " << dest.getAddress() << std::endl;
00912                     break;
00913                 }*/
00914                 *(stateCache.prox->pr_ns.begin() + pingContext->index) =
00915                     PASTRY_PROX_INFINITE;
00916                 break;
00917             }
00918         }
00919         checkProxCache();
00920     }
00921 
00922     delete context;
00923 
00924     if (rpcId == PING_NEXT_HOP) {
00925         // handle forward queue entry
00926         std::map<TransportAddress, BaseRouteMessage*>::iterator pos;
00927         if ((pos = recFwdQueue.find(dest)) == recFwdQueue.end()) return;
00928         BaseRouteMessage* rmsg = pos->second;
00929         recFwdQueue.erase(pos);
00930         if (dynamic_cast<PastryJoinMessage*>(rmsg->getEncapsulatedMsg()) &&
00931                 rmsg->getDestKey() == thisNode.getKey()) {
00932             //std::cout << "join timeout -> rejoin!";
00933             changeState(INIT);
00934             return;
00935         }
00936         assert(rmsg->getControlInfo());
00937         sendToKey(rmsg->getDestKey(), rmsg);
00938     }
00939 }
00940 
00941 void BasePastry::sendRequest(const TransportAddress& ask, int type)
00942 {
00943     assert(ask != thisNode);
00944     std::string msgName("Req: ");
00945     switch (type) {
00946     case PASTRY_REQ_REPAIR:
00947         if (ask.isUnspecified())
00948             opp_error("Pastry::sendRequest(): asked for repair from "
00949                   "unspecified node!");
00950         msgName += "Repair";
00951         break;
00952 
00953     case PASTRY_REQ_STATE:
00954         if (ask.isUnspecified())
00955             opp_error("Pastry::sendRequest(): asked for state from "
00956                   "unspecified node!");
00957         msgName += "State";
00958         break;
00959 
00960     case PASTRY_REQ_LEAFSET:
00961         if (ask.isUnspecified())
00962             opp_error("Pastry::sendRequest(): asked for leafset from "
00963                   "unspecified node!");
00964         msgName += "Leafset";
00965         break;
00966     }
00967     PastryRequestMessage* msg = new PastryRequestMessage(msgName.c_str());
00968     msg->setPastryMsgType(PASTRY_MSG_REQ);
00969     msg->setPastryReqType(type);
00970     msg->setStatType(MAINTENANCE_STAT);
00971     msg->setSendStateTo(thisNode);
00972     msg->setBitLength(PASTRYREQ_L(msg));
00973     sendMessageToUDP(ask, msg);
00974 
00975     switch (type) {
00976     case PASTRY_REQ_REPAIR:
00977         RECORD_STATS(repairReqSent++; repairReqBytesSent += msg->getByteLength());
00978         break;
00979 
00980     case PASTRY_REQ_STATE:
00981         RECORD_STATS(stateReqSent++; stateReqBytesSent += msg->getByteLength());
00982         break;
00983 
00984     case PASTRY_REQ_LEAFSET:
00985         RECORD_STATS(leafsetReqSent++; leafsetReqBytesSent += msg->getByteLength());
00986         break;
00987     }
00988 }
00989 
00990 
00991 void BasePastry::sendLeafset(const TransportAddress& tell, bool pull)
00992 {
00993     if (tell.isUnspecified())
00994         opp_error("Pastry::sendLeafset(): send leafset to "
00995                   "unspecified node!");
00996 
00997     PastryLeafsetMessage* msg = new PastryLeafsetMessage("Leafset");
00998     if (pull) msg->setPastryMsgType(PASTRY_MSG_LEAFSET_PULL);
00999     else msg->setPastryMsgType(PASTRY_MSG_LEAFSET);
01000     msg->setTimestamp(simTime());
01001     msg->setStatType(MAINTENANCE_STAT);
01002     msg->setSender(thisNode);
01003     msg->setSendStateTo(thisNode);
01004     leafSet->dumpToStateMessage(msg);
01005     msg->setBitLength(PASTRYLEAFSET_L(msg));
01006     RECORD_STATS(leafsetSent++; leafsetBytesSent += msg->getByteLength());
01007     sendMessageToUDP(tell, msg);
01008 
01009 
01010 }
01011 
01012 void BasePastry::sendRoutingRow(const TransportAddress& tell, int row)
01013 {
01014     if (tell.isUnspecified())
01015         opp_error("Pastry::sendRoutingTable(): asked for routing Table from "
01016                   "unspecified node!");
01017 
01018     PastryRoutingRowMessage* msg = new PastryRoutingRowMessage("Routing Row");
01019     msg->setPastryMsgType(PASTRY_MSG_RROW);
01020     msg->setStatType(MAINTENANCE_STAT);
01021     //msg->setSendStateTo(thisNode);
01022     msg->setSender(thisNode);
01023     msg->setRow(row);
01024     routingTable->dumpRowToMessage(msg, row);
01025     msg->setBitLength(PASTRYRTABLE_L(msg));
01026     RECORD_STATS(routingTableSent++; routingTableBytesSent += msg->getByteLength());
01027     sendMessageToUDP(tell, msg);
01028 }
01029 
01030 void BasePastry::handleRequestMessage(PastryRequestMessage* msg)
01031 {
01032     assert(msg->getSendStateTo() != thisNode);
01033     uint32_t reqtype = msg->getPastryReqType();
01034     if (reqtype == PASTRY_REQ_REPAIR) {
01035         RECORD_STATS(repairReqReceived++; repairReqBytesReceived +=
01036             msg->getByteLength());
01037         if (state == READY)
01038             sendStateTables(msg->getSendStateTo(),
01039                             PASTRY_STATE_REPAIR);
01040         else
01041             EV << "[BasePastry::handleRequestMessage() @ " << thisNode.getAddress()
01042             << " (" << thisNode.getKey().toString(16) << ")]\n"
01043             << "    received repair request before reaching"
01044             << " READY state, dropping message!"
01045             << endl;
01046         delete msg;
01047     }
01048     else if (reqtype == PASTRY_REQ_STATE) {
01049         RECORD_STATS(stateReqReceived++; stateReqBytesReceived +=
01050             msg->getByteLength());
01051         if (state == READY)
01052             sendStateTables(msg->getSendStateTo());
01053         else
01054             EV << "[BasePastry::handleRequestMessage() @ " << thisNode.getAddress()
01055             << " (" << thisNode.getKey().toString(16) << ")]\n"
01056             << "    received state request before reaching"
01057             << " READY state, dropping message!"
01058             << endl;
01059         delete msg;
01060     }
01061     else if (PASTRY_REQ_LEAFSET) {
01062         RECORD_STATS(leafsetReqReceived++; leafsetReqBytesReceived +=
01063             msg->getByteLength());
01064         if (state == READY) {
01065             sendLeafset(msg->getSendStateTo());
01066         }
01067         else
01068             EV << "[BasePastry::handleRequestMessage() @ " << thisNode.getAddress()
01069             << " (" << thisNode.getKey().toString(16) << ")]\n"
01070             << "    received leafset request before reaching"
01071             << " READY state, dropping message!"
01072             << endl;
01073         delete msg;
01074     }
01075 
01076 }
01077 
01078 void BasePastry::handleLeafsetMessage(PastryLeafsetMessage* msg, bool mergeSender)
01079 {
01080     uint32_t lsSize = msg->getLeafSetArraySize();
01081     PastryStateMessage* stateMsg;
01082 
01083     stateMsg = new PastryStateMessage("STATE");
01084     stateMsg->setTimestamp(msg->getTimestamp());
01085     stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
01086     stateMsg->setStatType(MAINTENANCE_STAT);
01087     stateMsg->setSender(msg->getSender());
01088     stateMsg->setLeafSetArraySize(lsSize);
01089     stateMsg->setNeighborhoodSetArraySize(0);
01090     stateMsg->setRoutingTableArraySize(0);
01091 
01092     for (uint32_t i = 0; i < lsSize; i++) {
01093         stateMsg->setLeafSet(i, msg->getLeafSet(i));
01094     }
01095 
01096     if (mergeSender) {
01097         stateMsg->setLeafSetArraySize(lsSize+1);
01098         stateMsg->setLeafSet(lsSize, msg->getSender());
01099     }
01100 
01101     handleStateMessage(stateMsg);
01102     delete msg;
01103 }
01104 
01105 bool BasePastry::isSiblingFor(const NodeHandle& node,
01106                               const OverlayKey& key,
01107                               int numSiblings,
01108                               bool* err)
01109 {
01110     if (key.isUnspecified())
01111         error("Pastry::isSiblingFor(): key is unspecified!");
01112 
01113     if ((numSiblings == 1) && (node == thisNode)) {
01114         if (leafSet->isClosestNode(key)) {
01115             *err = false;
01116             return true;
01117         } else {
01118             *err = false;
01119             return false;
01120         }
01121     }
01122 
01123     NodeVector* result =  leafSet->createSiblingVector(key, numSiblings);
01124 
01125     if (result == NULL) {
01126         *err = true;
01127         return false;
01128     }
01129 
01130     if (result->contains(node.getKey())) {
01131         delete result;
01132         *err = false;
01133         return true;
01134     } else {
01135         delete result;
01136         *err = true;
01137         return false;
01138     }
01139 
01140     /*
01141       const NodeHandle& dest = leafSet->getDestinationNode(key);
01142       if (!dest.isUnspecified()) {
01143       *err = false;
01144       return true;
01145       } else {
01146 
01147       *err = true;
01148       return false;
01149       }
01150     */
01151 }
01152 
01153 
01154 void BasePastry::handleAppMessage(BaseOverlayMessage* msg)
01155 {
01156     delete msg;
01157 }
01158 
01159 void BasePastry::updateTooltip()
01160 {
01161     if (ev.isGUI()) {
01162         std::stringstream ttString;
01163 
01164         // show our predecessor and successor in tooltip
01165         ttString << leafSet->getPredecessor() << endl << thisNode << endl
01166                  << leafSet->getSuccessor();
01167 
01168         getParentModule()->getParentModule()->getDisplayString().
01169             setTagArg("tt", 0, ttString.str().c_str());
01170         getParentModule()->getDisplayString().
01171             setTagArg("tt", 0, ttString.str().c_str());
01172         getDisplayString().setTagArg("tt", 0, ttString.str().c_str());
01173 
01174         // draw arrows:
01175         showOverlayNeighborArrow(leafSet->getSuccessor(), true,
01176                                  "m=m,50,0,50,0;ls=red,1");
01177         showOverlayNeighborArrow(leafSet->getPredecessor(), false,
01178                                  "m=m,50,100,50,100;ls=green,1");
01179 
01180     }
01181 }
01182 
01183 BasePastry::~BasePastry()
01184 {
01185     cancelAndDelete(joinTimeout);
01186 
01187     purgeVectors();
01188 }
01189 
01190 void BasePastry::finishOverlay()
01191 {
01192     // remove this node from the bootstrap list
01193     if (!thisNode.getKey().isUnspecified()) bootstrapList->removeBootstrapNode(thisNode);
01194 
01195     // collect statistics
01196     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
01197     if (time < GlobalStatistics::MIN_MEASURED) return;
01198 
01199     // join statistics
01200     //if (joinTries > joins)
01201         //std::cout << thisNode << " jt:" << joinTries << " j:" << joins << " jts:"
01202         //          << joinTimeout->isScheduled() << " rws:" << readyWait->isScheduled()
01203         //          << " state:" << state << " time:" << time << std::endl;
01204     // join is on the way...
01205     if (joinTries > 0 && joinTimeout->isScheduled()) joinTries--;
01206     if (joinTries > 0) {
01207         globalStatistics->addStdDev("Pastry: join success ratio", (double)joins / (double)joinTries);
01208         globalStatistics->addStdDev("Pastry: join tries", joinTries);
01209     } else if (state == READY) {
01210         // nodes has joined in init-/transition-phase
01211         globalStatistics->addStdDev("Pastry: join success ratio", 1);
01212         globalStatistics->addStdDev("Pastry: join tries", 1);
01213     } else {
01214         globalStatistics->addStdDev("Pastry: join success ratio", 0);
01215         globalStatistics->addStdDev("Pastry: join tries", 1);
01216     }
01217 
01218     globalStatistics->addStdDev("Pastry: joins with missing replies from routing path/s",
01219                                 joinPartial / time);
01220     globalStatistics->addStdDev("Pastry: JOIN Messages seen/s", joinSeen / time);
01221     globalStatistics->addStdDev("Pastry: bytes of JOIN Messages seen/s", joinBytesSeen / time);
01222     globalStatistics->addStdDev("Pastry: JOIN Messages received/s", joinReceived / time);
01223     globalStatistics->addStdDev("Pastry: bytes of JOIN Messages received/s",
01224                                 joinBytesReceived / time);
01225     globalStatistics->addStdDev("Pastry: JOIN Messages sent/s", joinSent / time);
01226     globalStatistics->addStdDev("Pastry: bytes of JOIN Messages sent/s", joinBytesSent / time);
01227     globalStatistics->addStdDev("Pastry: STATE Messages sent/s", stateSent / time);
01228     globalStatistics->addStdDev("Pastry: bytes of STATE Messages sent/s", stateBytesSent / time);
01229     globalStatistics->addStdDev("Pastry: STATE Messages received/s", stateReceived / time);
01230     globalStatistics->addStdDev("Pastry: bytes of STATE Messages received/s",
01231                                 stateBytesReceived / time);
01232     globalStatistics->addStdDev("Pastry: REPAIR Requests sent/s", repairReqSent / time);
01233     globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests sent/s",
01234                                 repairReqBytesSent / time);
01235     globalStatistics->addStdDev("Pastry: REPAIR Requests received/s", repairReqReceived / time);
01236     globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests received/s",
01237                                 repairReqBytesReceived / time);
01238     globalStatistics->addStdDev("Pastry: STATE Requests sent/s", stateReqSent / time);
01239     globalStatistics->addStdDev("Pastry: bytes of STATE Requests sent/s", stateReqBytesSent / time);
01240     globalStatistics->addStdDev("Pastry: STATE Requests received/s", stateReqReceived / time);
01241     globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s",
01242                                 stateReqBytesReceived / time);
01243 
01244     globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s",
01245                                 stateReqBytesReceived / time);
01246 
01247     globalStatistics->addStdDev("Pastry: total number of lookups", totalLookups);
01248     globalStatistics->addStdDev("Pastry: responsible lookups", responsibleLookups);
01249     globalStatistics->addStdDev("Pastry: lookups in routing table", routingTableLookups);
01250     globalStatistics->addStdDev("Pastry: lookups using closerNode()", closerNodeLookups);
01251     globalStatistics->addStdDev("Pastry: lookups using closerNode() with result from "
01252                                 "neighborhood set", closerNodeLookupsFromNeighborhood);
01253     globalStatistics->addStdDev("Pastry: LEAFSET Requests sent/s", leafsetReqSent / time);
01254     globalStatistics->addStdDev("Pastry: bytes of LEAFSET Requests sent/s", leafsetReqBytesSent / time);
01255     globalStatistics->addStdDev("Pastry: LEAFSET Requests received/s", leafsetReqReceived / time);
01256     globalStatistics->addStdDev("Pastry: bytes of LEAFSET Requests received/s",
01257                                 leafsetReqBytesReceived / time);
01258     globalStatistics->addStdDev("Pastry: LEAFSET Messages sent/s", leafsetSent / time);
01259     globalStatistics->addStdDev("Pastry: bytes of LEAFSET Messages sent/s", leafsetBytesSent / time);
01260     globalStatistics->addStdDev("Pastry: LEAFSET Messages received/s", leafsetReceived / time);
01261     globalStatistics->addStdDev("Pastry: bytes of LEAFSET Messages received/s",
01262                                 leafsetBytesReceived / time);
01263     globalStatistics->addStdDev("Pastry: ROUTING TABLE Requests sent/s", routingTableReqSent / time);
01264     globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Requests sent/s", routingTableReqBytesSent / time);
01265     globalStatistics->addStdDev("Pastry: ROUTING TABLE Requests received/s", routingTableReqReceived / time);
01266     globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Requests received/s",
01267                                 routingTableReqBytesReceived / time);
01268     globalStatistics->addStdDev("Pastry: ROUTING TABLE Messages sent/s", routingTableSent / time);
01269     globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Messages sent/s", routingTableBytesSent / time);
01270     globalStatistics->addStdDev("Pastry: ROUTING TABLE Messages received/s", routingTableReceived / time);
01271     globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Messages received/s",
01272                                 routingTableBytesReceived / time);
01273 
01274 }
01275 
01276 int BasePastry::getMaxNumSiblings()
01277 {
01278     return (int)floor(numberOfLeaves / 2.0);
01279 }
01280 
01281 int BasePastry::getMaxNumRedundantNodes()
01282 {
01283     return (int)floor(numberOfLeaves);
01284 }
01285 
01286 NodeVector* BasePastry::findNode(const OverlayKey& key,
01287                                  int numRedundantNodes,
01288                                  int numSiblings,
01289                                  BaseOverlayMessage* msg)
01290 {
01291     if ((numRedundantNodes > getMaxNumRedundantNodes()) ||
01292         (numSiblings > getMaxNumSiblings())) {
01293 
01294         opp_error("(Pastry::findNode()) numRedundantNodes or numSiblings "
01295                   "too big!");
01296     }
01297     RECORD_STATS(totalLookups++);
01298 
01299     NodeVector* nextHops = new NodeVector(numRedundantNodes);
01300 
01301     const NodeHandle* next;
01302     PastryFindNodeExtData* findNodeExt = NULL;
01303     if (msg && msg->hasObject("findNodeExt")) {
01304         findNodeExt =
01305             check_and_cast<PastryFindNodeExtData*>(msg->
01306                                                    getObject("findNodeExt"));
01307     }
01308 
01309     if (state != READY) {
01310         return nextHops;
01311     } else if (key.isUnspecified() || leafSet->isClosestNode(key)) {
01312         RECORD_STATS(responsibleLookups++);
01313         nextHops->add(thisNode);
01314     } else {
01315         // Send state tables on any JOIN message we see:
01316         if (findNodeExt) {
01317             const TransportAddress& stateRecipient =
01318                 findNodeExt->getSendStateTo();
01319             if (!stateRecipient.isUnspecified()) {
01320                 RECORD_STATS(joinSeen++);
01321                 sendStateTables(stateRecipient, PASTRY_STATE_JOIN,
01322                                 findNodeExt->getJoinHopCount(), false);
01323             }
01324         }
01325 
01326         next = &(leafSet->getDestinationNode(key));
01327 
01328         if (next->isUnspecified()) {
01329             next = &(routingTable->lookupNextHop(key));
01330             if (!next->isUnspecified()) {
01331                 RECORD_STATS(routingTableLookups++);
01332             }
01333         } else {
01334             RECORD_STATS(responsibleLookups++);
01335         }
01336 
01337         if (next->isUnspecified()) {
01338             RECORD_STATS(closerNodeLookups++);
01339             // call findCloserNode() on all state objects
01340             if (optimizeLookup) {
01341                 const NodeHandle* tmp;
01342                 next = &(routingTable->findCloserNode(key, true));
01343                 tmp = &(neighborhoodSet->findCloserNode(key, true));
01344 
01345                 if ((! tmp->isUnspecified()) &&
01346                     (leafSet->isCloser(*tmp, key, *next))) {
01347                     RECORD_STATS(closerNodeLookupsFromNeighborhood++);
01348                     next = tmp;
01349                 }
01350 
01351                 tmp = &(leafSet->findCloserNode(key, true));
01352                 if ((! tmp->isUnspecified()) &&
01353                     (leafSet->isCloser(*tmp, key, *next))) {
01354                     RECORD_STATS(closerNodeLookupsFromNeighborhood--);
01355                     next = tmp;
01356                 }
01357             } else {
01358                 next = &(routingTable->findCloserNode(key));
01359 
01360                 if (next->isUnspecified()) {
01361                     RECORD_STATS(closerNodeLookupsFromNeighborhood++);
01362                     next = &(neighborhoodSet->findCloserNode(key));
01363                 }
01364 
01365                 if (next->isUnspecified()) {
01366                     RECORD_STATS(closerNodeLookupsFromNeighborhood--);
01367                     next = &(leafSet->findCloserNode(key));
01368                 }
01369             }
01370         }
01371 
01372         if (!next->isUnspecified()) {
01373             if (findNodeExt) {
01374                 findNodeExt->setJoinHopCount(findNodeExt->getJoinHopCount() + 1);
01375             }
01376             nextHops->add(*next);
01377         }
01378     }
01379 
01380     bool err;
01381 
01382     /* if we're a sibling, return all numSiblings */
01383     if ((numSiblings >= 0) && isSiblingFor(thisNode, key, numSiblings, &err)) {
01384         if (err == false) {
01385             delete nextHops;
01386             return  leafSet->createSiblingVector(key, numSiblings);
01387         }
01388     }
01389 
01390     if (/*(nextHops->size() > 0) &&*/ (numRedundantNodes > 1)) {
01391 
01392         //memleak... comp should be a ptr and deleted in NodeVector::~NodeVector()...
01393         //KeyDistanceComparator<KeyRingMetric>* comp =
01394         //    new KeyDistanceComparator<KeyRingMetric>( key );
01395 
01396         KeyDistanceComparator<KeyRingMetric> comp(key);
01397         NodeVector* additionalHops = new NodeVector( numRedundantNodes, &comp );
01398 
01399         routingTable->findCloserNodes(key, additionalHops);
01400         leafSet->findCloserNodes(key, additionalHops);
01401         neighborhoodSet->findCloserNodes(key, additionalHops);
01402 
01403         if (useRegularNextHop && (nextHops->size() > 0) &&
01404             (*additionalHops)[0] != (*nextHops)[0]) {
01405             for (uint32_t i = 0; i < additionalHops->size(); i++) {
01406                 if ((*additionalHops)[i] != (*nextHops)[0])
01407                     nextHops->push_back((*additionalHops)[i]);
01408             }
01409             delete additionalHops;
01410         } else {
01411             delete nextHops;
01412             return additionalHops;
01413         }
01414     }
01415     return nextHops;
01416 }
01417 AbstractLookup* BasePastry::createLookup(RoutingType routingType,
01418                                          const BaseOverlayMessage* msg,
01419                                          const cObject* dummy,
01420                                          bool appLookup)
01421 {
01422     assert(dummy == NULL);
01423     PastryFindNodeExtData* findNodeExt =
01424         new PastryFindNodeExtData("findNodeExt");
01425 
01426     if (msg) {
01427         const PastryMessage* pmsg =
01428             dynamic_cast<const PastryMessage*>(msg->getEncapsulatedMsg());
01429         if ((pmsg) && (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN)) {
01430             const PastryJoinMessage* jmsg =
01431                 check_and_cast<const PastryJoinMessage*>(pmsg);
01432             findNodeExt->setSendStateTo(jmsg->getSendStateTo());
01433             findNodeExt->setJoinHopCount(1);
01434         }
01435     }
01436     findNodeExt->setBitLength(PASTRYFINDNODEEXTDATA_L);
01437 
01438     AbstractLookup* newLookup = BaseOverlay::createLookup(routingType,
01439                                                           msg, findNodeExt,
01440                                                           appLookup);
01441 
01442     delete findNodeExt;
01443     return newLookup;
01444 }
01445 
01446 bool stateMsgIsSmaller(const PastryStateMsgHandle& hnd1,
01447                        const PastryStateMsgHandle& hnd2)
01448 {
01449     return (hnd1.msg->getJoinHopCount() < hnd2.msg->getJoinHopCount());
01450 }
01451 
01452 std::ostream& operator<<(std::ostream& os, const PastryStateMsgProximity pr)
01453 {
01454     os << "PastryStateMsgProximity {" << endl;
01455     os << "  pr_rt {" << endl;
01456     for (std::vector<simtime_t>::const_iterator i = pr.pr_rt.begin();
01457          i != pr.pr_rt.end(); ++i) {
01458         os << "    " << *i << endl;
01459     }
01460     os << "  }" << endl;
01461     os << "  pr_ls {" << endl;
01462     for (std::vector<simtime_t>::const_iterator i = pr.pr_ls.begin();
01463          i != pr.pr_ls.end(); ++i) {
01464         os << "    " << *i << endl;
01465     }
01466     os << "  }" << endl;
01467     os << "  pr_ns {" << endl;
01468     for (std::vector<simtime_t>::const_iterator i = pr.pr_ns.begin();
01469          i != pr.pr_ns.end(); ++i) {
01470         os << "    " << *i << endl;
01471     }
01472     os << "  }" << endl;
01473     os << "}" << endl;
01474     return os;
01475 }

Generated on Tue Sep 8 17:26:51 2009 for OverSim by  doxygen 1.5.8