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 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
00075 changeState(READY);
00076 } else {
00077
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, sourceRoute);
00107
00108 if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00109 scheduleAt(simTime() + joinTimeoutAmount, joinTimeout);
00110 }
00111
00112 break;
00113
00114 case READY:
00115
00116
00117 cancelEvent(localTuningTimer);
00118 scheduleAt(simTime() + localTuningInterval, localTuningTimer);
00119
00120 cancelEvent(leafsetMaintenanceTimer);
00121
00122 scheduleAt(simTime() + 0.2 , 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
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
00389
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
00440 simtime_t now = simTime();
00441
00442
00443 if (!(stateCache.msg && stateCache.prox)) return;
00444
00445
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
00454
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
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
00507 lastStateChange = simTime();
00508 newLeafs();
00509 updateTooltip();
00510
00511
00512 stateCache = handle;
00513 pingNodes();
00514
00515 return;
00516 }
00517
00518
00519
00520 determineAliveTable(msg);
00521 if (leafSet->mergeState(msg, &aliveTable)) {
00522
00523 lastStateChange = simTime();
00524 newLeafs();
00525 updateTooltip();
00526 }
00527
00528 if (!stateCache.msg) {
00529
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
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
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