Bamboo.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 <cassert>
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 <GlobalStatistics.h>
00033 #include <LookupListener.h>
00034 #include <AbstractLookup.h>
00035 
00036 #include "Bamboo.h"
00037 
00038 Define_Module(Bamboo);
00039 
00040 Bamboo::~Bamboo()
00041 {
00042     // destroy self timer messages
00043     cancelAndDelete(localTuningTimer);
00044     cancelAndDelete(leafsetMaintenanceTimer);
00045     cancelAndDelete(globalTuningTimer);
00046 }
00047 
00048 void Bamboo::initializeOverlay(int stage)
00049 {
00050     if ( stage != MIN_STAGE_OVERLAY )
00051         return;
00052 
00053     // Bamboo provides KBR services
00054     kbr = true;
00055 
00056     baseInit();
00057 
00058     localTuningInterval = par("localTuningInterval");
00059     leafsetMaintenanceInterval = par("leafsetMaintenanceInterval");
00060     globalTuningInterval = par("globalTuningInterval");
00061 
00062     joinTimeout = new cMessage("joinTimeout");
00063 
00064     localTuningTimer = new cMessage("repairTaskTimer");
00065     leafsetMaintenanceTimer = new cMessage("leafsetMaintenanceTimer");
00066     globalTuningTimer = new cMessage("globalTuningTimer");
00067 }
00068 
00069 void Bamboo::joinOverlay()
00070 {
00071     changeState(INIT);
00072 
00073     if (bootstrapNode.isUnspecified()) {
00074         // no existing pastry network -> first node of a new one
00075         changeState(READY);
00076     } else {
00077         // join existing pastry network
00078         changeState(JOINING_2);
00079     }
00080 }
00081 
00082 void Bamboo::changeState(int toState)
00083 {
00084     baseChangeState(toState);
00085 
00086     switch (toState) {
00087     case INIT:
00088 
00089         break;
00090 
00091     case DISCOVERY:
00092 
00093         break;
00094 
00095     case JOINING_2: {
00096         PastryLeafsetMessage* msg = new PastryLeafsetMessage("Leafset");
00097         msg->setPastryMsgType(PASTRY_MSG_LEAFSET_PULL);
00098         msg->setStatType(MAINTENANCE_STAT);
00099         msg->setSender(thisNode);
00100         msg->setSendStateTo(thisNode);
00101         leafSet->dumpToStateMessage(msg);
00102         msg->setBitLength(PASTRYLEAFSET_L(msg));
00103         RECORD_STATS(leafsetSent++; leafsetBytesSent += msg->getByteLength());
00104         std::vector<TransportAddress> sourceRoute;
00105         sourceRoute.push_back(bootstrapNode);
00106         sendToKey(thisNode.getKey(), msg, 0/*1*/, sourceRoute);
00107 
00108         if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00109         scheduleAt(simTime() + joinTimeoutAmount, joinTimeout);
00110     }
00111 
00112     break;
00113 
00114     case READY:
00115 
00116         // schedule routing table maintenance task
00117         cancelEvent(localTuningTimer);
00118         scheduleAt(simTime() + localTuningInterval, localTuningTimer);
00119 
00120         cancelEvent(leafsetMaintenanceTimer);
00121         //scheduleAt(simTime() + leafsetMaintenanceInterval, leafsetMaintenanceTimer);
00122         scheduleAt(simTime() + 0.2 /* 200ms */, leafsetMaintenanceTimer);
00123 
00124         cancelEvent(globalTuningTimer);
00125         scheduleAt(simTime() + globalTuningInterval, globalTuningTimer);
00126 
00127         break;
00128     }
00129 }
00130 
00131 void Bamboo::handleTimerEvent(cMessage* msg)
00132 {
00133     if (msg == joinTimeout) {
00134         EV << "[Bamboo::handleTimerEvent() @ " << thisNode.getAddress()
00135            << " (" << thisNode.getKey().toString(16) << ")]\n"
00136            << "    join timeout expired, restarting..."
00137            << endl;
00138         joinOverlay();
00139     } else if (msg == localTuningTimer) {
00140         EV << "[Bamboo::handleTimerEvent() @ " << thisNode.getAddress()
00141            << " (" << thisNode.getKey().toString(16) << ")]\n"
00142            << "    starting local tuning "
00143            << "(aka neighbor's neighbors / routing table maintenance)"
00144            << endl;
00145         doLocalTuning();
00146         scheduleAt(simTime() + localTuningInterval, localTuningTimer);
00147     } else if (msg == leafsetMaintenanceTimer) {
00148         EV << "[Bamboo::handleTimerEvent() @ " << thisNode.getAddress()
00149            << " (" << thisNode.getKey().toString(16) << ")]\n"
00150            << "    starting leafset maintenance"
00151            << endl;
00152         doLeafsetMaintenance();
00153         scheduleAt(simTime() + leafsetMaintenanceInterval,
00154                    leafsetMaintenanceTimer);
00155     } else if (msg == globalTuningTimer) {
00156         EV << "[Bamboo::handleTimerEvent() @ " << thisNode.getAddress()
00157            << " (" << thisNode.getKey().toString(16) << ")]\n"
00158            << "    starting global tuning"
00159            << endl;
00160         doGlobalTuning();
00161         scheduleAt(simTime() + globalTuningInterval, globalTuningTimer);
00162     }
00163 }
00164 
00165 void Bamboo::handleUDPMessage(BaseOverlayMessage* msg)
00166 {
00167     PastryMessage* pastryMsg = check_and_cast<PastryMessage*>(msg);
00168     uint32_t type = pastryMsg->getPastryMsgType();
00169 
00170     if (debugOutput) {
00171         EV << "[Bamboo::handleUDPMessage() @ " << thisNode.getAddress()
00172            << " (" << thisNode.getKey().toString(16) << ")]\n"
00173            << "    incoming message of type ";
00174         switch(type) {
00175         case PASTRY_MSG_STD:
00176             EV << "PASTRY_MSG_STD";
00177             break;
00178         case PASTRY_MSG_JOIN:
00179             EV << "PASTRY_MSG_JOIN";
00180             break;
00181         case PASTRY_MSG_STATE:
00182             EV << "PASTRY_MSG_STATE";
00183             break;
00184         case PASTRY_MSG_LEAFSET:
00185             EV << "PASTRY_MSG_LEAFSET";
00186             break;
00187         case PASTRY_MSG_LEAFSET_PULL:
00188             EV << "PASTRY_MSG_LEAFSET_PULL";
00189             break;
00190         case PASTRY_MSG_ROWREQ:
00191             EV << "PASTRY_MSG_ROWREQ";
00192             break;
00193         case PASTRY_MSG_RROW:
00194             EV << "PASTRY_MSG_RROW";
00195             break;
00196         case PASTRY_MSG_REQ:
00197             EV << "PASTRY_MSG_REQ";
00198             break;
00199         default:
00200             EV << "UNKNOWN (" << type <<")";
00201             break;
00202         }
00203         EV << endl;
00204     }
00205 
00206     switch (type) {
00207     case PASTRY_MSG_STD:
00208         opp_error("Pastry received PastryMessage of unknown type!");
00209         break;
00210     case PASTRY_MSG_JOIN:
00211 
00212         break;
00213 
00214     case PASTRY_MSG_LEAFSET: {
00215         PastryLeafsetMessage* lmsg =
00216             check_and_cast<PastryLeafsetMessage*>(pastryMsg);
00217         RECORD_STATS(leafsetReceived++; leafsetBytesReceived +=
00218             lmsg->getByteLength());
00219 
00220         if (state == JOINING_2) {
00221             cancelEvent(joinTimeout);
00222         }
00223 
00224         if ((state == JOINING_2) || (state == READY)) {
00225             handleLeafsetMessage(lmsg, true);
00226         } else {
00227             delete lmsg;
00228         }
00229     }
00230         break;
00231 
00232     case PASTRY_MSG_LEAFSET_PULL: {
00233         PastryLeafsetMessage* lmsg =
00234             check_and_cast<PastryLeafsetMessage*>(pastryMsg);
00235         RECORD_STATS(leafsetReceived++; leafsetBytesReceived +=
00236             lmsg->getByteLength());
00237 
00238         if (state == READY) {
00239             sendLeafset(lmsg->getSendStateTo());
00240             handleLeafsetMessage(lmsg, true);
00241 
00242         } else {
00243             delete lmsg;
00244         }
00245     }
00246         break;
00247 
00248     case PASTRY_MSG_ROWREQ: {
00249 
00250         PastryRoutingRowRequestMessage* rtrmsg =
00251             check_and_cast<PastryRoutingRowRequestMessage*>(pastryMsg);
00252         RECORD_STATS(routingTableReqReceived++; routingTableReqBytesReceived +=
00253             rtrmsg->getByteLength());
00254         if (state == READY)
00255             if (rtrmsg->getRow() == -1)
00256                 sendRoutingRow(rtrmsg->getSendStateTo(), routingTable->getLastRow());
00257                 else if (rtrmsg->getRow() > routingTable->getLastRow())
00258                     EV << "[Bamboo::handleUDPMessage() @ " << thisNode.getAddress()
00259                        << " (" << thisNode.getKey().toString(16) << ")]\n"
00260                        << "    received request for nonexistent routing"
00261                        << "table row, dropping message!" << endl;
00262                 else sendRoutingRow(rtrmsg->getSendStateTo(), rtrmsg->getRow());
00263         else
00264             EV << "[Bamboo::handleUDPMessage() @ " << thisNode.getAddress()
00265                << " (" << thisNode.getKey().toString(16) << ")]\n"
00266                << "    received routing table request before reaching "
00267                << "READY state, dropping message!" << endl;
00268        delete rtrmsg;
00269     }
00270         break;
00271 
00272     case PASTRY_MSG_RROW: {
00273         PastryRoutingRowMessage* rtmsg =
00274             check_and_cast<PastryRoutingRowMessage*>(pastryMsg);
00275         RECORD_STATS(routingTableReceived++; routingTableBytesReceived +=
00276             rtmsg->getByteLength());
00277 
00278         if (state == READY) {
00279             // create state message to probe all nodes from row message
00280             PastryStateMessage* stateMsg = new PastryStateMessage("STATE");
00281             stateMsg->setTimestamp(rtmsg->getTimestamp());
00282             stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
00283             stateMsg->setStatType(MAINTENANCE_STAT);
00284             stateMsg->setSender(rtmsg->getSender());
00285             stateMsg->setLeafSetArraySize(0);
00286             stateMsg->setNeighborhoodSetArraySize(0);
00287             stateMsg->setRoutingTableArraySize(rtmsg->getRoutingTableArraySize());
00288 
00289             for (uint32_t i = 0; i < rtmsg->getRoutingTableArraySize(); i++) {
00290                 stateMsg->setRoutingTable(i, rtmsg->getRoutingTable(i));
00291             }
00292 
00293             handleStateMessage(stateMsg);
00294         }
00295 
00296         delete rtmsg;
00297     }
00298     break;
00299 
00300     case PASTRY_MSG_REQ: {
00301         PastryRequestMessage* lrmsg =
00302             check_and_cast<PastryRequestMessage*>(pastryMsg);
00303         handleRequestMessage(lrmsg);
00304     }
00305         break;
00306 
00307     case PASTRY_MSG_STATE: {
00308         PastryStateMessage* stateMsg =
00309             check_and_cast<PastryStateMessage*>(msg);
00310         RECORD_STATS(stateReceived++; stateBytesReceived +=
00311                      stateMsg->getByteLength());
00312         handleStateMessage(stateMsg);
00313     }
00314         break;
00315     }
00316 }
00317 
00318 void Bamboo::doLeafsetMaintenance(void)
00319 {
00320     const TransportAddress& ask = leafSet->getRandomNode();
00321     if (!ask.isUnspecified()) {
00322         sendLeafset(ask, true);
00323         EV << "[Bamboo::doLeafsetMaintenance()]\n"
00324            << "    leafset maintenance: pulling leafset from "
00325            << ask << endl;
00326     }
00327 }
00328 
00329 
00330 int Bamboo::getNextRowToMaintain()
00331 {
00332     int digit = 0;
00333     int lastRow = routingTable->getLastRow();
00334 
00335     int* choices = new int[lastRow + 1];
00336     int sum = 0;
00337 
00338     for (int i = 0; i < lastRow; ++i) {
00339         sum += (choices[i] = lastRow - i);
00340     }
00341 
00342     int rval = intuniform(0, sum);
00343 
00344     while (true) {
00345         rval -= choices [digit];
00346         if (rval <= 0)
00347             break;
00348         ++digit;
00349     }
00350     delete[] choices;
00351 
00352     return digit;
00353 }
00354 
00355 
00356 void Bamboo::doLocalTuning()
00357 {
00358     rowToAsk = getNextRowToMaintain();
00359 
00360     const TransportAddress& ask4row = routingTable->getRandomNode(rowToAsk);
00361 
00362     if ((!ask4row.isUnspecified()) && (ask4row != thisNode)) {
00363         PastryRoutingRowRequestMessage* msg =
00364             new PastryRoutingRowRequestMessage("ROWREQ");
00365         msg->setPastryMsgType(PASTRY_MSG_ROWREQ);
00366         msg->setStatType(MAINTENANCE_STAT);
00367         msg->setSendStateTo(thisNode);
00368         msg->setRow(rowToAsk + 1);
00369         msg->setBitLength(PASTRYRTREQ_L(msg));
00370 
00371         RECORD_STATS(routingTableReqSent++;
00372                      routingTableReqBytesSent += msg->getByteLength());
00373 
00374         EV << "[Bamboo::doLocalTuning() @ " << thisNode.getAddress()
00375            << " (" << thisNode.getKey().toString(16) << ")]\n"
00376            << "    Sending  Message to Node in Row" << rowToAsk
00377            << endl;
00378 
00379         sendMessageToUDP(ask4row, msg);
00380     }
00381 }
00382 
00383 
00384 void Bamboo::doGlobalTuning(void)
00385 {
00386     int digit = getNextRowToMaintain();
00387 
00388     // would be a better alternative
00389     //OverlayKey OverlayKey::randomSuffix(uint pos) const;
00390 
00391     uint32_t maxDigitIndex = OverlayKey::getLength() - bitsPerDigit;
00392     uint32_t maxKeyIndex = OverlayKey::getLength() - 1;
00393     OverlayKey newKey = OverlayKey::random();
00394     while (newKey.getBitRange(maxDigitIndex - digit * bitsPerDigit, bitsPerDigit) ==
00395            thisNode.getKey().getBitRange(maxDigitIndex - digit * bitsPerDigit, bitsPerDigit)) {
00396         newKey = OverlayKey::random();
00397     }
00398 
00399     assert(digit * bitsPerDigit < OverlayKey::getLength());
00400     for (uint16_t i = 0; i < digit * bitsPerDigit; ++i) {
00401         newKey[maxKeyIndex - i] = thisNode.getKey().getBit(maxKeyIndex - i);
00402     }
00403 
00404     createLookup()->lookup(newKey, 1, 0, 0, new BambooLookupListener(this));
00405 }
00406 
00407 bool Bamboo::handleFailedNode(const TransportAddress& failed)
00408 {
00409     if (state != READY) {
00410         return false;
00411     }
00412 
00413     if (failed.isUnspecified()) {
00414         throw cRuntimeError("Bamboo::handleFailedNode(): failed is unspecified!");
00415     }
00416 
00417     const TransportAddress& lsAsk = leafSet->failedNode(failed);
00418     routingTable->failedNode(failed);
00419     neighborhoodSet->failedNode(failed);
00420 
00421     if (lsAsk.isUnspecified() && (! leafSet->isValid())) {
00422         EV << "[Bamboo::handleFailedNode()]\n"
00423            << "    lost connection to the network, trying to re-join."
00424            << endl;
00425         join();
00426         return false;
00427     }
00428 
00429     return true;
00430 }
00431 
00432 void Bamboo::checkProxCache(void)
00433 {
00434     if (state == JOINING_2) {
00435         changeState(READY);
00436         return;
00437     }
00438 
00439     // state == READY
00440     simtime_t now = simTime();
00441 
00442     // no cached STATE message?
00443     if (!(stateCache.msg && stateCache.prox)) return;
00444 
00445     // some entries not yet determined?
00446     if (find(stateCache.prox->pr_rt.begin(), stateCache.prox->pr_rt.end(),
00447              PASTRY_PROX_PENDING) != stateCache.prox->pr_rt.end()) return;
00448     if (find(stateCache.prox->pr_ls.begin(), stateCache.prox->pr_ls.end(),
00449              PASTRY_PROX_PENDING) != stateCache.prox->pr_ls.end()) return;
00450     if (find(stateCache.prox->pr_ns.begin(), stateCache.prox->pr_ns.end(),
00451              PASTRY_PROX_PENDING) != stateCache.prox->pr_ns.end()) return;
00452 
00453     // merge info in own state tables
00454     // except leafset (was already handled in handleStateMessage)
00455     if (neighborhoodSet->mergeState(stateCache.msg, stateCache.prox)) {
00456         lastStateChange = now;
00457     }
00458 
00459     if (routingTable->mergeState(stateCache.msg, stateCache.prox)) {
00460         lastStateChange = now;
00461         EV << "[Bamboo::checkProxCache()]\n"
00462            << "    Merged nodes into routing table."
00463            << endl;
00464     }
00465 
00466     updateTooltip();
00467 
00468     delete stateCache.msg;
00469     stateCache.msg = NULL;
00470     delete stateCache.prox;
00471     stateCache.prox = NULL;
00472 
00473     // process next queued message:
00474     if (! stateCacheQueue.empty()) {
00475         stateCache = stateCacheQueue.front();
00476               stateCacheQueue.pop();
00477         pingNodes();
00478     }
00479 }
00480 
00481 void Bamboo::handleStateMessage(PastryStateMessage* msg)
00482 {
00483     if (debugOutput) {
00484         EV << "[Bamboo::handleStateMessage() @ " << thisNode.getAddress()
00485            << " (" << thisNode.getKey().toString(16) << ")]\n"
00486            << "    new STATE message to process "
00487            << static_cast<void*>(msg) << " in state "
00488            << ((state == READY)?"READY":((state == JOINING_2)?"JOIN":"INIT"))
00489            << endl;
00490     }
00491 
00492     if (state == INIT) {
00493         EV << "[Bamboo::handleStateMessage() @ " << thisNode.getAddress()
00494            << " (" << thisNode.getKey().toString(16) << ")]\n"
00495            << "    can't handle state messages until at least reaching JOIN state."
00496            << endl;
00497         delete msg;
00498         return;
00499     }
00500 
00501     PastryStateMsgHandle handle(msg);
00502 
00503     if (state == JOINING_2) {
00504         determineAliveTable(msg);
00505         leafSet->mergeState(msg, &aliveTable);
00506         // merged state into leafset right now
00507         lastStateChange = simTime();
00508         newLeafs();
00509         updateTooltip();
00510 
00511         // no state message is processed right now, start immediately:
00512        stateCache = handle;
00513        pingNodes();
00514 
00515         return;
00516     }
00517 
00518     // determine aliveTable to prevent leafSet from merging nodes that are
00519     // known to be dead:
00520     determineAliveTable(msg);
00521     if (leafSet->mergeState(msg, &aliveTable)) {
00522         // merged state into leafset right now
00523         lastStateChange = simTime();
00524         newLeafs();
00525         updateTooltip();
00526     }
00527     // in READY state, only ping nodes to get proximity metric:
00528     if (!stateCache.msg) {
00529         // no state message is processed right now, start immediately:
00530         stateCache = handle;
00531         if (proximityNeighborSelection) {
00532             pingNodes();
00533         } else {
00534             simtime_t now = simTime();
00535             if (neighborhoodSet->mergeState(stateCache.msg, NULL)) {
00536                 lastStateChange = now;
00537             }
00538             if (routingTable->mergeState(stateCache.msg, NULL)) {
00539                 lastStateChange = now;
00540                 EV << "[Bamboo::checkProxCache()]\n"
00541                    << "    Merged nodes into routing table."
00542                    << endl;
00543             }
00544         }
00545     } else {
00546         // enqueue message for later processing:
00547         stateCacheQueue.push(handle);
00548         if (proximityNeighborSelection) prePing(msg);
00549     }
00550 }
00551 
00552 void Bamboo::lookupFinished(AbstractLookup *lookup)
00553 {
00554     EV << "[Bamboo::lookupFinished()]\n";
00555     if (lookup->isValid()) {
00556         EV  << "    Lookup successful" << endl;
00557         const NodeVector& result = lookup->getResult();
00558         if (result[0] != thisNode) {
00559             if (proximityNeighborSelection) {
00560                 // Global Tuning PING
00561                 Prox prox = neighborCache->getProx(result[0],
00562                                                    NEIGHBORCACHE_DEFAULT,
00563                                                    PING_SINGLE_NODE,
00564                                                    this, NULL);
00565                 if (prox != Prox::PROX_UNKNOWN) {
00566                     routingTable->mergeNode(result[0], prox.proximity);
00567                 }
00568             } else {
00569                 routingTable->mergeNode(result[0], -1.0);
00570             }
00571         }
00572     } else {
00573         EV << "    Lookup failed" << endl;
00574     }
00575 }
00576 
Generated on Wed May 26 16:21:13 2010 for OverSim by  doxygen 1.6.3