Bamboo.cc
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
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
00078 changeState(READY);
00079 } else {
00080
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, sourceRoute);
00112
00113 if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00114 scheduleAt(simTime() + joinTimeoutAmount, joinTimeout);
00115 }
00116
00117 break;
00118
00119 case READY:
00120
00121
00122 cancelEvent(localTuningTimer);
00123 scheduleAt(simTime() + routingTableMaintenanceInterval, localTuningTimer);
00124
00125 cancelEvent(leafsetMaintenanceTimer);
00126
00127 scheduleAt(simTime() + 0.2 , 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
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
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 int digit = getNextRowToMaintain();
00358
00359
00360
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
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
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
00412 simtime_t now = simTime();
00413
00414
00415 if (!(stateCache.msg && stateCache.prox)) return;
00416
00417
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
00426
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
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
00481 lastStateChange = simTime();
00482 newLeafs();
00483 updateTooltip();
00484
00485
00486 stateCache = handle;
00487 pingNodes();
00488
00489 return;
00490 }
00491
00492
00493
00494 determineAliveTable(msg);
00495 if (leafSet->mergeState(msg, &aliveTable)) {
00496
00497 lastStateChange = simTime();
00498 newLeafs();
00499 updateTooltip();
00500 }
00501
00502 if (!stateCache.msg) {
00503
00504 stateCache = handle;
00505 pingNodes();
00506 } else {
00507
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
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