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

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