00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00043 while (! stateCacheQueue.empty()) {
00044 delete stateCacheQueue.front().msg;
00045 delete stateCacheQueue.front().prox;
00046 stateCacheQueue.pop();
00047 }
00048
00049
00050 delete stateCache.msg;
00051 stateCache.msg = NULL;
00052 delete stateCache.prox;
00053 stateCache.prox = NULL;
00054
00055
00056 if (! sendStateWait.empty()) {
00057 for (std::vector<PastrySendState*>::iterator it =
00058 sendStateWait.begin(); it != sendStateWait.end(); it++) {
00059 if ( (*it)->isScheduled() ) cancelEvent(*it);
00060 delete *it;
00061 }
00062 sendStateWait.clear();
00063 }
00064 }
00065
00066 void BasePastry::baseInit()
00067 {
00068 bitsPerDigit = par("bitsPerDigit");
00069 numberOfLeaves = par("numberOfLeaves");
00070 numberOfNeighbors = par("numberOfNeighbors");
00071 joinTimeoutAmount = par("joinTimeout");
00072 repairTimeout = par("repairTimeout");
00073 enableNewLeafs = par("enableNewLeafs");
00074 optimizeLookup = par("optimizeLookup");
00075 useRegularNextHop = par("useRegularNextHop");
00076 alwaysSendUpdate = par("alwaysSendUpdate");
00077 proximityNeighborSelection = par("proximityNeighborSelection");
00078
00079 if (!neighborCache->isEnabled()) {
00080 throw cRuntimeError("NeighborCache is disabled, which is mandatory "
00081 "for Pastry/Bamboo. Activate it by setting "
00082 "\"**.neighborCache.enableNeighborCache "
00083 "= true\" in your omnetpp.ini!");
00084 }
00085
00086 if (numberOfLeaves % 2) {
00087 EV << "[BasePastry::baseInit() @ " << thisNode.getAddress()
00088 << " (" << thisNode.getKey().toString(16) << ")]\n"
00089 << " Warning: numberOfLeaves must be even - adding 1."
00090 << endl;
00091 numberOfLeaves++;
00092 }
00093
00094 routingTable = check_and_cast<PastryRoutingTable*>
00095 (getParentModule()->getSubmodule("pastryRoutingTable"));
00096 leafSet = check_and_cast<PastryLeafSet*>
00097 (getParentModule()->getSubmodule("pastryLeafSet"));
00098 neighborhoodSet = check_and_cast<PastryNeighborhoodSet*>
00099 (getParentModule()->getSubmodule("pastryNeighborhoodSet"));
00100
00101 stateCache.msg = NULL;
00102 stateCache.prox = NULL;
00103
00104 rowToAsk = 0;
00105
00106
00107 joins = 0;
00108 joinTries = 0;
00109 joinPartial = 0;
00110 joinSeen = 0;
00111 joinReceived = 0;
00112 joinSent = 0;
00113 stateSent = 0;
00114 stateReceived = 0;
00115 repairReqSent = 0;
00116 repairReqReceived = 0;
00117 stateReqSent = 0;
00118 stateReqReceived = 0;
00119
00120 joinBytesSeen = 0;
00121 joinBytesReceived = 0;
00122 joinBytesSent = 0;
00123 stateBytesSent = 0;
00124 stateBytesReceived = 0;
00125 repairReqBytesSent = 0;
00126 repairReqBytesReceived = 0;
00127 stateReqBytesSent = 0;
00128 stateReqBytesReceived = 0;
00129
00130 totalLookups = 0;
00131 responsibleLookups = 0;
00132 routingTableLookups = 0;
00133 closerNodeLookups = 0;
00134 closerNodeLookupsFromNeighborhood = 0;
00135
00136 leafsetReqSent = 0;
00137 leafsetReqBytesSent = 0;
00138 leafsetReqReceived = 0;
00139 leafsetReqBytesReceived = 0;
00140 leafsetSent = 0;
00141 leafsetBytesSent = 0;
00142 leafsetReceived = 0;
00143 leafsetBytesReceived = 0;
00144
00145 routingTableReqSent = 0;
00146 routingTableReqBytesSent = 0;
00147 routingTableReqReceived = 0;
00148 routingTableReqBytesReceived = 0;
00149 routingTableSent = 0;
00150 routingTableBytesSent = 0;
00151 routingTableReceived = 0;
00152 routingTableBytesReceived = 0;
00153
00154 WATCH(joins);
00155 WATCH(joinTries);
00156 WATCH(joinSeen);
00157 WATCH(joinBytesSeen);
00158 WATCH(joinReceived);
00159 WATCH(joinBytesReceived);
00160 WATCH(joinSent);
00161 WATCH(joinBytesSent);
00162 WATCH(stateSent);
00163 WATCH(stateBytesSent);
00164 WATCH(stateReceived);
00165 WATCH(stateBytesReceived);
00166 WATCH(repairReqSent);
00167 WATCH(repairReqBytesSent);
00168 WATCH(repairReqReceived);
00169 WATCH(repairReqBytesReceived);
00170 WATCH(stateReqSent);
00171 WATCH(stateReqBytesSent);
00172 WATCH(stateReqReceived);
00173 WATCH(stateReqBytesReceived);
00174 WATCH(lastStateChange);
00175
00176 WATCH(leafsetReqSent);
00177 WATCH(leafsetReqBytesSent);
00178 WATCH(leafsetReqReceived);
00179 WATCH(leafsetReqBytesReceived);
00180 WATCH(leafsetSent);
00181 WATCH(leafsetBytesSent);
00182 WATCH(leafsetReceived);
00183 WATCH(leafsetBytesReceived);
00184
00185 WATCH(routingTableReqSent);
00186 WATCH(routingTableReqBytesSent);
00187 WATCH(routingTableReqReceived);
00188 WATCH(routingTableReqBytesReceived);
00189 WATCH(routingTableSent);
00190 WATCH(routingTableBytesSent);
00191 WATCH(routingTableReceived);
00192 WATCH(routingTableBytesReceived);
00193 }
00194
00195
00196 void BasePastry::baseChangeState(int toState)
00197 {
00198 switch (toState) {
00199 case INIT:
00200 state = INIT;
00201
00202 if (!thisNode.getKey().isUnspecified())
00203 bootstrapList->removeBootstrapNode(thisNode);
00204
00205 if (joinTimeout->isScheduled()) cancelEvent(joinTimeout);
00206
00207 purgeVectors();
00208
00209 bootstrapNode = bootstrapList->getBootstrapNode();
00210
00211 routingTable->initializeTable(bitsPerDigit, repairTimeout, thisNode);
00212 leafSet->initializeSet(numberOfLeaves, bitsPerDigit,
00213 repairTimeout, thisNode, this);
00214 neighborhoodSet->initializeSet(numberOfNeighbors, bitsPerDigit,
00215 thisNode);
00216
00217 updateTooltip();
00218 lastStateChange = simTime();
00219
00220 getParentModule()->getParentModule()->bubble("entering INIT state");
00221
00222 break;
00223
00224 case JOINING_2:
00225 state = JOINING_2;
00226
00227
00228
00229
00230 if (bootstrapNode.isUnspecified()) {
00231
00232 changeState(READY);
00233 return;
00234 }
00235
00236 cancelEvent(joinTimeout);
00237 scheduleAt(simTime() + joinTimeoutAmount, joinTimeout);
00238
00239 updateTooltip();
00240 getParentModule()->getParentModule()->bubble("entering JOIN state");
00241
00242 RECORD_STATS(joinTries++);
00243
00244 break;
00245
00246 case READY:
00247 assert(state != READY);
00248 state = READY;
00249
00250
00251
00252
00253
00254 if (bootstrapNode.isUnspecified()) {
00255 RECORD_STATS(joinTries++);
00256 RECORD_STATS(joins++);
00257 setOverlayReady(true);
00258 return;
00259 }
00260
00261 getParentModule()->getParentModule()->bubble("entering READY state");
00262 updateTooltip();
00263 RECORD_STATS(joins++);
00264
00265 break;
00266
00267 default:
00268 break;
00269 }
00270 setOverlayReady(state == READY);
00271 }
00272
00273
00274 void BasePastry::newLeafs(void)
00275 {
00276 if (! enableNewLeafs) return;
00277
00278 PastryNewLeafsMessage* msg = leafSet->getNewLeafsMessage();
00279 if (msg) {
00280 send(msg, "appOut");
00281 EV << "[BasePastry::newLeafs() @ " << thisNode.getAddress()
00282 << " (" << thisNode.getKey().toString(16) << ")]\n"
00283 << " newLeafs() called."
00284 << endl;
00285 }
00286 }
00287
00288
00289 void BasePastry::changeState(int toState)
00290 {
00291
00292 }
00293
00294
00295 void BasePastry::pingResponse(PingResponse* msg, cPolymorphic* context,
00296 int rpcId, simtime_t rtt)
00297 {
00298 EV << "[BasePastry::pingResponse() @ " << thisNode.getAddress()
00299 << " (" << thisNode.getKey().toString(16) << ")]\n"
00300 << " Pong (or Ping-context from NeighborCache) received (from "
00301 << msg->getSrcNode().getAddress() << ")"
00302 << endl;
00303
00304 const NodeHandle& src = msg->getSrcNode();
00305 assert(!src.isUnspecified());
00306
00307
00308 if (rpcId == PING_SINGLE_NODE) {
00309 routingTable->mergeNode(src, proximityNeighborSelection ?
00310 rtt : SimTime::getMaxTime());
00311 return;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 if (context != NULL && stateCache.msg && stateCache.prox) {
00325 PingContext* pingContext = check_and_cast<PingContext*>(context);
00326 if (pingContext->nonce != stateCache.nonce) {
00327 delete context;
00328 return;
00329
00330 }
00331 switch (pingContext->stateObject) {
00332 case ROUTINGTABLE: {
00333
00334
00335
00336
00337
00338
00339
00340 *(stateCache.prox->pr_rt.begin() + pingContext->index) = rtt;
00341 break;
00342 }
00343 case LEAFSET: {
00344
00345
00346
00347
00348
00349
00350
00351 *(stateCache.prox->pr_ls.begin() + pingContext->index) = rtt;
00352 break;
00353 }
00354 case NEIGHBORHOODSET: {
00355
00356
00357
00358
00359
00360
00361
00362 *(stateCache.prox->pr_ns.begin() + pingContext->index) = rtt;
00363 break;
00364 }
00365 default: {
00366 throw cRuntimeError("wrong state object type!");
00367 }
00368 }
00369 checkProxCache();
00370 }
00371 delete context;
00372 }
00373
00374
00375 void BasePastry::proxCallback(const TransportAddress& node, int rpcId,
00376 cPolymorphic *contextPointer, Prox prox)
00377 {
00378 Enter_Method("proxCallback()");
00379
00380 EV << "[BasePastry::proxCallback() @ " << thisNode.getAddress()
00381 << " (" << thisNode.getKey().toString(16) << ")]\n"
00382 << " Pong received (from "
00383 << node.getAddress() << ")"
00384 << endl;
00385
00386 double rtt = ((prox == Prox::PROX_TIMEOUT) ? PASTRY_PROX_INFINITE
00387 : prox.proximity);
00388
00389
00390 if (rpcId == PING_SINGLE_NODE) {
00391 routingTable->mergeNode((const NodeHandle&)node,
00392 proximityNeighborSelection ?
00393 rtt : SimTime::getMaxTime());
00394 delete contextPointer;
00395 return;
00396 }
00397
00398 if (contextPointer != NULL && stateCache.msg && stateCache.prox) {
00399 PingContext* pingContext = check_and_cast<PingContext*>(contextPointer);
00400
00401 if (pingContext->nonce != stateCache.nonce) {
00402 delete contextPointer;
00403 return;
00404 }
00405
00406 if (rtt == PASTRY_PROX_INFINITE && state== READY) {
00407 handleFailedNode(node);
00408 updateTooltip();
00409
00410
00411
00412 if (state != READY) {
00413 delete contextPointer;
00414 return;
00415 }
00416 }
00417 switch (pingContext->stateObject) {
00418 case ROUTINGTABLE:
00419 *(stateCache.prox->pr_rt.begin() + pingContext->index) = rtt;
00420 break;
00421
00422 case LEAFSET:
00423 *(stateCache.prox->pr_ls.begin() + pingContext->index) = rtt;
00424 break;
00425
00426 case NEIGHBORHOODSET:
00427 *(stateCache.prox->pr_ns.begin() + pingContext->index) = rtt;
00428 break;
00429
00430 default:
00431 throw cRuntimeError("wrong state object type!");
00432 }
00433 checkProxCache();
00434 }
00435 delete contextPointer;
00436 }
00437
00438
00439 void BasePastry::prePing(const PastryStateMessage* stateMsg)
00440 {
00441 uint32_t rt_size = stateMsg->getRoutingTableArraySize();
00442 uint32_t ls_size = stateMsg->getLeafSetArraySize();
00443 uint32_t ns_size = stateMsg->getNeighborhoodSetArraySize();
00444
00445 for (uint32_t i = 0; i < rt_size + ls_size + ns_size; i++) {
00446 const NodeHandle* node;
00447 if (i < rt_size) {
00448 node = &(stateMsg->getRoutingTable(i));
00449 }
00450 else if (i < (rt_size + ls_size) ) {
00451 node = &(stateMsg->getLeafSet(i - rt_size));
00452 }
00453 else {
00454 node = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size));
00455 }
00456 if ((node->isUnspecified()) || (*node == thisNode)) {
00457 continue;
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 neighborCache->getProx(*node, NEIGHBORCACHE_DEFAULT, PING_RECEIVED_STATE, this, NULL);
00469 }
00470 }
00471
00472 void BasePastry::pingNodes(void)
00473 {
00474 EV << "[BasePastry::pingNodes() @ " << thisNode.getAddress()
00475 << " (" << thisNode.getKey().toString(16) << ")]" << endl;
00476
00477 if (stateCache.msg == NULL) throw cRuntimeError("no state msg");
00478
00479 assert(stateCache.prox == NULL);
00480 stateCache.prox = new PastryStateMsgProximity();
00481
00482 uint32_t rt_size = stateCache.msg->getRoutingTableArraySize();
00483 stateCache.prox->pr_rt.resize(rt_size, PASTRY_PROX_UNDEF);
00484
00485 uint32_t ls_size = stateCache.msg->getLeafSetArraySize();
00486 stateCache.prox->pr_ls.resize(ls_size, PASTRY_PROX_UNDEF);
00487
00488 uint32_t ns_size = stateCache.msg->getNeighborhoodSetArraySize();
00489 stateCache.prox->pr_ns.resize(ns_size, PASTRY_PROX_UNDEF);
00490
00491 std::vector< std::pair<const NodeHandle*, PingContext*> > nodesToPing;
00492
00493 for (uint32_t i = 0; i < rt_size + ls_size + ns_size; i++) {
00494 const NodeHandle* node;
00495 std::vector<simtime_t>::iterator proxPos;
00496 PingContext* pingContext = NULL;
00497 StateObject stateObject;
00498 uint32_t index;
00499 if (stateCache.msg == NULL) break;
00500 if (i < rt_size) {
00501 node = &(stateCache.msg->getRoutingTable(i));
00502 proxPos = stateCache.prox->pr_rt.begin() + i;
00503 stateObject = ROUTINGTABLE;
00504 index = i;
00505 } else if ( i < (rt_size + ls_size) ) {
00506 node = &(stateCache.msg->getLeafSet(i - rt_size));
00507 proxPos = stateCache.prox->pr_ls.begin() + (i - rt_size);
00508 stateObject = LEAFSET;
00509 index = i - rt_size;
00510 } else {
00511 node = &(stateCache.msg->getNeighborhoodSet(i - rt_size - ls_size));
00512 proxPos = stateCache.prox->pr_ns.begin() + (i - rt_size - ls_size);
00513 stateObject = NEIGHBORHOODSET;
00514 index = i - rt_size - ls_size;
00515 }
00516
00517 if (!node->isUnspecified()) {
00518 pingContext = new PingContext(stateObject, index,
00519 stateCache.nonce);
00520
00521 Prox prox = neighborCache->getProx(*node, NEIGHBORCACHE_DEFAULT, -1,
00522 this, pingContext);
00523 if (prox == Prox::PROX_SELF) {
00524 *proxPos = 0;
00525 } else if (prox == Prox::PROX_TIMEOUT) {
00526 *proxPos = PASTRY_PROX_INFINITE;
00527 } else if (prox == Prox::PROX_UNKNOWN) {
00528 *proxPos = PASTRY_PROX_PENDING;
00529 } else {
00530 *proxPos = prox.proximity;
00531 }
00532 }
00533 }
00534 checkProxCache();
00535 }
00536
00537 void BasePastry::determineAliveTable(const PastryStateMessage* stateMsg)
00538 {
00539 uint32_t rt_size = stateMsg->getRoutingTableArraySize();
00540 aliveTable.pr_rt.clear();
00541 aliveTable.pr_rt.resize(rt_size, 1);
00542
00543 uint32_t ls_size = stateMsg->getLeafSetArraySize();
00544 aliveTable.pr_ls.clear();
00545 aliveTable.pr_ls.resize(ls_size, 1);
00546
00547 uint32_t ns_size = stateMsg->getNeighborhoodSetArraySize();
00548 aliveTable.pr_ns.clear();
00549 aliveTable.pr_ns.resize(ns_size, 1);
00550
00551 for (uint32_t i = 0; i < rt_size + ls_size + ns_size; i++) {
00552 const TransportAddress* node;
00553 std::vector<simtime_t>::iterator tblPos;
00554 if (i < rt_size) {
00555 node = &(stateMsg->getRoutingTable(i));
00556 tblPos = aliveTable.pr_rt.begin() + i;
00557 } else if ( i < (rt_size + ls_size) ) {
00558 node = &(stateMsg->getLeafSet(i - rt_size));
00559 tblPos = aliveTable.pr_ls.begin() + (i - rt_size);
00560 } else {
00561 node = &(stateMsg->getNeighborhoodSet(i - rt_size - ls_size));
00562 tblPos = aliveTable.pr_ns.begin() + (i - rt_size - ls_size);
00563 }
00564 if (neighborCache->getProx(*node, NEIGHBORCACHE_DEFAULT_IMMEDIATELY) ==
00565 Prox::PROX_TIMEOUT) {
00566 *tblPos = PASTRY_PROX_INFINITE;
00567 }
00568 }
00569 }
00570
00571 void BasePastry::sendStateTables(const TransportAddress& destination,
00572 int type, ...)
00573 {
00574 if (destination.getAddress() == thisNode.getAddress())
00575 opp_error("Pastry: trying to send state to self!");
00576
00577 int hops = 0;
00578 bool last = false;
00579 simtime_t timestamp = 0;
00580
00581 if ((type == PASTRY_STATE_JOIN) ||
00582 (type == PASTRY_STATE_MINJOIN) ||
00583 (type == PASTRY_STATE_UPDATE)) {
00584
00585 va_list ap;
00586 va_start(ap, type);
00587 if (type == PASTRY_STATE_JOIN || type == PASTRY_STATE_MINJOIN) {
00588 hops = va_arg(ap, int);
00589 last = static_cast<bool>(va_arg(ap, int));
00590 } else {
00591 timestamp = *va_arg(ap, simtime_t*);
00592 }
00593 va_end(ap);
00594 }
00595
00596
00597 PastryStateMessage* stateMsg;
00598 if (type == PASTRY_STATE_JOIN || type == PASTRY_STATE_MINJOIN) {
00599 stateMsg = new PastryStateMessage("STATE (Join)");
00600 stateMsg->setJoinHopCount(hops);
00601 stateMsg->setLastHop(last);
00602 stateMsg->setTimestamp(simTime());
00603 } else if (type == PASTRY_STATE_UPDATE) {
00604 stateMsg = new PastryStateMessage("STATE (Update)");
00605 EV << "[BasePastry::sendStateTables() @ " << thisNode.getAddress()
00606 << " (" << thisNode.getKey().toString(16) << ")]\n"
00607 << " sending state (update) to " << destination
00608 << endl;
00609 stateMsg->setTimestamp(timestamp);
00610 } else if (type == PASTRY_STATE_REPAIR) {
00611 stateMsg = new PastryStateMessage("STATE (Repair)");
00612 stateMsg->setTimestamp(timestamp);
00613 EV << "[BasePastry::sendStateTables() @ " << thisNode.getAddress()
00614 << " (" << thisNode.getKey().toString(16) << ")]\n"
00615 << " sending state (repair) to " << destination
00616 << endl;
00617 } else {
00618 stateMsg = new PastryStateMessage("STATE");
00619 EV << "[BasePastry::sendStateTables() @ " << thisNode.getAddress()
00620 << " (" << thisNode.getKey().toString(16) << ")]\n"
00621 << " sending state (standard) to " << destination
00622 << endl;
00623 }
00624
00625
00626 stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
00627 stateMsg->setStatType(MAINTENANCE_STAT);
00628 stateMsg->setPastryStateMsgType(type);
00629 stateMsg->setSender(thisNode);
00630
00631
00632
00633
00634 if (type == PASTRY_STATE_MINJOIN) {
00635
00636 routingTable->dumpRowToMessage(stateMsg, hops);
00637 if (last) leafSet->dumpToStateMessage(stateMsg);
00638 else stateMsg->setLeafSetArraySize(0);
00639 if (hops == 1) neighborhoodSet->dumpToStateMessage(stateMsg);
00640 else stateMsg->setNeighborhoodSetArraySize(0);
00641 } else {
00642 routingTable->dumpToStateMessage(stateMsg);
00643 leafSet->dumpToStateMessage(stateMsg);
00644 neighborhoodSet->dumpToStateMessage(stateMsg);
00645 }
00646
00647
00648 stateMsg->setBitLength(PASTRYSTATE_L(stateMsg));
00649 RECORD_STATS(stateSent++; stateBytesSent += stateMsg->getByteLength());
00650 sendMessageToUDP(destination, stateMsg);
00651 }
00652
00653 void BasePastry::sendStateDelayed(const TransportAddress& destination)
00654 {
00655 PastrySendState* selfMsg = new PastrySendState("sendStateWait");
00656 selfMsg->setDest(destination);
00657 sendStateWait.push_back(selfMsg);
00658 scheduleAt(simTime() + 0.0001, selfMsg);
00659 }
00660
00661 void BasePastry::pingTimeout(PingCall* msg,
00662 const TransportAddress& dest,
00663 cPolymorphic* context,
00664 int rpcId)
00665 {
00666 EV << "[BasePastry::sendStateDelayed() @ " << thisNode.getAddress()
00667 << " (" << thisNode.getKey().toString(16) << ")]\n"
00668 << " Ping timeout occurred (" << dest.getAddress() << ")"
00669 << endl;
00670
00671
00672 if (state == READY) {
00673 handleFailedNode(dest);
00674 updateTooltip();
00675
00676
00677
00678 if (state != READY) {
00679 delete context;
00680 return;
00681 }
00682 }
00683
00684
00685 if (context && stateCache.msg && stateCache.prox &&
00686 rpcId == PING_RECEIVED_STATE) {
00687 PingContext* pingContext = check_and_cast<PingContext*>(context);
00688 if (pingContext->nonce != stateCache.nonce) {
00689 delete context;
00690 return;
00691
00692
00693
00694 }
00695
00696 switch (pingContext->stateObject) {
00697 case ROUTINGTABLE: {
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710 *(stateCache.prox->pr_rt.begin() + pingContext->index) =
00711 PASTRY_PROX_INFINITE;
00712 break;
00713 }
00714 case LEAFSET: {
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 *(stateCache.prox->pr_ls.begin() + pingContext->index) =
00728 PASTRY_PROX_INFINITE;
00729 break;
00730 }
00731 case NEIGHBORHOODSET: {
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 *(stateCache.prox->pr_ns.begin() + pingContext->index) =
00745 PASTRY_PROX_INFINITE;
00746 break;
00747 }
00748 }
00749 checkProxCache();
00750 }
00751
00752 delete context;
00753 }
00754
00755 void BasePastry::sendRequest(const TransportAddress& ask, int type)
00756 {
00757 assert(ask != thisNode);
00758 std::string msgName("Req: ");
00759 switch (type) {
00760 case PASTRY_REQ_REPAIR:
00761 if (ask.isUnspecified())
00762 throw cRuntimeError("Pastry::sendRequest(): asked for repair from "
00763 "unspecified node!");
00764 msgName += "Repair";
00765 break;
00766
00767 case PASTRY_REQ_STATE:
00768 if (ask.isUnspecified())
00769 throw cRuntimeError("Pastry::sendRequest(): asked for state from "
00770 "unspecified node!");
00771 msgName += "State";
00772 break;
00773
00774 case PASTRY_REQ_LEAFSET:
00775 if (ask.isUnspecified())
00776 throw cRuntimeError("Pastry::sendRequest(): asked for leafset from "
00777 "unspecified node!");
00778 msgName += "Leafset";
00779 break;
00780 }
00781 PastryRequestMessage* msg = new PastryRequestMessage(msgName.c_str());
00782 msg->setPastryMsgType(PASTRY_MSG_REQ);
00783 msg->setPastryReqType(type);
00784 msg->setStatType(MAINTENANCE_STAT);
00785 msg->setSendStateTo(thisNode);
00786 msg->setBitLength(PASTRYREQ_L(msg));
00787 sendMessageToUDP(ask, msg);
00788
00789 switch (type) {
00790 case PASTRY_REQ_REPAIR:
00791 RECORD_STATS(repairReqSent++; repairReqBytesSent += msg->getByteLength());
00792 break;
00793
00794 case PASTRY_REQ_STATE:
00795 RECORD_STATS(stateReqSent++; stateReqBytesSent += msg->getByteLength());
00796 break;
00797
00798 case PASTRY_REQ_LEAFSET:
00799 RECORD_STATS(leafsetReqSent++; leafsetReqBytesSent += msg->getByteLength());
00800 break;
00801 }
00802 }
00803
00804
00805 void BasePastry::sendLeafset(const TransportAddress& tell, bool pull)
00806 {
00807 if (tell.isUnspecified())
00808 opp_error("Pastry::sendLeafset(): send leafset to "
00809 "unspecified node!");
00810
00811 PastryLeafsetMessage* msg = new PastryLeafsetMessage("Leafset");
00812 if (pull) msg->setPastryMsgType(PASTRY_MSG_LEAFSET_PULL);
00813 else msg->setPastryMsgType(PASTRY_MSG_LEAFSET);
00814 msg->setTimestamp(simTime());
00815 msg->setStatType(MAINTENANCE_STAT);
00816 msg->setSender(thisNode);
00817 msg->setSendStateTo(thisNode);
00818 leafSet->dumpToStateMessage(msg);
00819 msg->setBitLength(PASTRYLEAFSET_L(msg));
00820 RECORD_STATS(leafsetSent++; leafsetBytesSent += msg->getByteLength());
00821 sendMessageToUDP(tell, msg);
00822
00823
00824 }
00825
00826 void BasePastry::sendRoutingRow(const TransportAddress& tell, int row)
00827 {
00828 if (tell.isUnspecified())
00829 opp_error("Pastry::sendRoutingTable(): asked for routing Table from "
00830 "unspecified node!");
00831
00832 PastryRoutingRowMessage* msg = new PastryRoutingRowMessage("Routing Row");
00833 msg->setPastryMsgType(PASTRY_MSG_RROW);
00834 msg->setStatType(MAINTENANCE_STAT);
00835
00836 msg->setSender(thisNode);
00837 msg->setRow(row);
00838 routingTable->dumpRowToMessage(msg, row);
00839 msg->setBitLength(PASTRYRTABLE_L(msg));
00840 RECORD_STATS(routingTableSent++; routingTableBytesSent += msg->getByteLength());
00841 sendMessageToUDP(tell, msg);
00842 }
00843
00844 void BasePastry::handleRequestMessage(PastryRequestMessage* msg)
00845 {
00846 assert(msg->getSendStateTo() != thisNode);
00847 uint32_t reqtype = msg->getPastryReqType();
00848 if (reqtype == PASTRY_REQ_REPAIR) {
00849 RECORD_STATS(repairReqReceived++; repairReqBytesReceived +=
00850 msg->getByteLength());
00851 if (state == READY)
00852 sendStateTables(msg->getSendStateTo(),
00853 PASTRY_STATE_REPAIR);
00854 else
00855 EV << "[BasePastry::handleRequestMessage() @ " << thisNode.getAddress()
00856 << " (" << thisNode.getKey().toString(16) << ")]\n"
00857 << " received repair request before reaching"
00858 << " READY state, dropping message!"
00859 << endl;
00860 delete msg;
00861 }
00862 else if (reqtype == PASTRY_REQ_STATE) {
00863 RECORD_STATS(stateReqReceived++; stateReqBytesReceived +=
00864 msg->getByteLength());
00865 if (state == READY)
00866 sendStateTables(msg->getSendStateTo());
00867 else
00868 EV << "[BasePastry::handleRequestMessage() @ " << thisNode.getAddress()
00869 << " (" << thisNode.getKey().toString(16) << ")]\n"
00870 << " received state request before reaching"
00871 << " READY state, dropping message!"
00872 << endl;
00873 delete msg;
00874 }
00875 else if (PASTRY_REQ_LEAFSET) {
00876 RECORD_STATS(leafsetReqReceived++; leafsetReqBytesReceived +=
00877 msg->getByteLength());
00878 if (state == READY) {
00879 sendLeafset(msg->getSendStateTo());
00880 }
00881 else
00882 EV << "[BasePastry::handleRequestMessage() @ " << thisNode.getAddress()
00883 << " (" << thisNode.getKey().toString(16) << ")]\n"
00884 << " received leafset request before reaching"
00885 << " READY state, dropping message!"
00886 << endl;
00887 delete msg;
00888 }
00889
00890 }
00891
00892 void BasePastry::handleLeafsetMessage(PastryLeafsetMessage* msg, bool mergeSender)
00893 {
00894 uint32_t lsSize = msg->getLeafSetArraySize();
00895 PastryStateMessage* stateMsg;
00896
00897 stateMsg = new PastryStateMessage("STATE");
00898 stateMsg->setTimestamp(msg->getTimestamp());
00899 stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
00900 stateMsg->setStatType(MAINTENANCE_STAT);
00901 stateMsg->setSender(msg->getSender());
00902 stateMsg->setLeafSetArraySize(lsSize);
00903 stateMsg->setNeighborhoodSetArraySize(0);
00904 stateMsg->setRoutingTableArraySize(0);
00905
00906 for (uint32_t i = 0; i < lsSize; i++) {
00907 stateMsg->setLeafSet(i, msg->getLeafSet(i));
00908 }
00909
00910 if (mergeSender) {
00911 stateMsg->setLeafSetArraySize(lsSize+1);
00912 stateMsg->setLeafSet(lsSize, msg->getSender());
00913 }
00914
00915 handleStateMessage(stateMsg);
00916 delete msg;
00917 }
00918
00919 bool BasePastry::isSiblingFor(const NodeHandle& node,
00920 const OverlayKey& key,
00921 int numSiblings,
00922 bool* err)
00923 {
00924 if (key.isUnspecified())
00925 error("Pastry::isSiblingFor(): key is unspecified!");
00926
00927 if ((numSiblings == 1) && (node == thisNode)) {
00928 if (leafSet->isClosestNode(key)) {
00929 *err = false;
00930 return true;
00931 } else {
00932 *err = false;
00933 return false;
00934 }
00935 }
00936
00937 NodeVector* result = leafSet->createSiblingVector(key, numSiblings);
00938
00939 if (result == NULL) {
00940 *err = true;
00941 return false;
00942 }
00943
00944 if (result->contains(node.getKey())) {
00945 delete result;
00946 *err = false;
00947 return true;
00948 } else {
00949 delete result;
00950 *err = true;
00951 return false;
00952 }
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965 }
00966
00967
00968 void BasePastry::handleAppMessage(BaseOverlayMessage* msg)
00969 {
00970 delete msg;
00971 }
00972
00973 void BasePastry::updateTooltip()
00974 {
00975 if (ev.isGUI()) {
00976 std::stringstream ttString;
00977
00978
00979 ttString << leafSet->getPredecessor() << endl << thisNode << endl
00980 << leafSet->getSuccessor();
00981
00982 getParentModule()->getParentModule()->getDisplayString().
00983 setTagArg("tt", 0, ttString.str().c_str());
00984 getParentModule()->getDisplayString().
00985 setTagArg("tt", 0, ttString.str().c_str());
00986 getDisplayString().setTagArg("tt", 0, ttString.str().c_str());
00987
00988
00989 showOverlayNeighborArrow(leafSet->getSuccessor(), true,
00990 "m=m,50,0,50,0;ls=red,1");
00991 showOverlayNeighborArrow(leafSet->getPredecessor(), false,
00992 "m=m,50,100,50,100;ls=green,1");
00993
00994 }
00995 }
00996
00997 BasePastry::~BasePastry()
00998 {
00999 cancelAndDelete(joinTimeout);
01000
01001 purgeVectors();
01002 }
01003
01004 void BasePastry::finishOverlay()
01005 {
01006
01007 if (!thisNode.getKey().isUnspecified()) bootstrapList->removeBootstrapNode(thisNode);
01008
01009
01010 simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
01011 if (time < GlobalStatistics::MIN_MEASURED) return;
01012
01013
01014
01015
01016
01017
01018
01019 if (joinTries > 0 && joinTimeout->isScheduled()) joinTries--;
01020 if (joinTries > 0) {
01021 globalStatistics->addStdDev("Pastry: join success ratio", (double)joins / (double)joinTries);
01022 globalStatistics->addStdDev("Pastry: join tries", joinTries);
01023 } else if (state == READY) {
01024
01025 globalStatistics->addStdDev("Pastry: join success ratio", 1);
01026 globalStatistics->addStdDev("Pastry: join tries", 1);
01027 } else {
01028 globalStatistics->addStdDev("Pastry: join success ratio", 0);
01029 globalStatistics->addStdDev("Pastry: join tries", 1);
01030 }
01031
01032 globalStatistics->addStdDev("Pastry: joins with missing replies from routing path/s",
01033 joinPartial / time);
01034 globalStatistics->addStdDev("Pastry: JOIN Messages seen/s", joinSeen / time);
01035 globalStatistics->addStdDev("Pastry: bytes of JOIN Messages seen/s", joinBytesSeen / time);
01036 globalStatistics->addStdDev("Pastry: JOIN Messages received/s", joinReceived / time);
01037 globalStatistics->addStdDev("Pastry: bytes of JOIN Messages received/s",
01038 joinBytesReceived / time);
01039 globalStatistics->addStdDev("Pastry: JOIN Messages sent/s", joinSent / time);
01040 globalStatistics->addStdDev("Pastry: bytes of JOIN Messages sent/s", joinBytesSent / time);
01041 globalStatistics->addStdDev("Pastry: STATE Messages sent/s", stateSent / time);
01042 globalStatistics->addStdDev("Pastry: bytes of STATE Messages sent/s", stateBytesSent / time);
01043 globalStatistics->addStdDev("Pastry: STATE Messages received/s", stateReceived / time);
01044 globalStatistics->addStdDev("Pastry: bytes of STATE Messages received/s",
01045 stateBytesReceived / time);
01046 globalStatistics->addStdDev("Pastry: REPAIR Requests sent/s", repairReqSent / time);
01047 globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests sent/s",
01048 repairReqBytesSent / time);
01049 globalStatistics->addStdDev("Pastry: REPAIR Requests received/s", repairReqReceived / time);
01050 globalStatistics->addStdDev("Pastry: bytes of REPAIR Requests received/s",
01051 repairReqBytesReceived / time);
01052 globalStatistics->addStdDev("Pastry: STATE Requests sent/s", stateReqSent / time);
01053 globalStatistics->addStdDev("Pastry: bytes of STATE Requests sent/s", stateReqBytesSent / time);
01054 globalStatistics->addStdDev("Pastry: STATE Requests received/s", stateReqReceived / time);
01055 globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s",
01056 stateReqBytesReceived / time);
01057
01058 globalStatistics->addStdDev("Pastry: bytes of STATE Requests received/s",
01059 stateReqBytesReceived / time);
01060
01061 globalStatistics->addStdDev("Pastry: total number of lookups", totalLookups);
01062 globalStatistics->addStdDev("Pastry: responsible lookups", responsibleLookups);
01063 globalStatistics->addStdDev("Pastry: lookups in routing table", routingTableLookups);
01064 globalStatistics->addStdDev("Pastry: lookups using closerNode()", closerNodeLookups);
01065 globalStatistics->addStdDev("Pastry: lookups using closerNode() with result from "
01066 "neighborhood set", closerNodeLookupsFromNeighborhood);
01067 globalStatistics->addStdDev("Pastry: LEAFSET Requests sent/s", leafsetReqSent / time);
01068 globalStatistics->addStdDev("Pastry: bytes of LEAFSET Requests sent/s", leafsetReqBytesSent / time);
01069 globalStatistics->addStdDev("Pastry: LEAFSET Requests received/s", leafsetReqReceived / time);
01070 globalStatistics->addStdDev("Pastry: bytes of LEAFSET Requests received/s",
01071 leafsetReqBytesReceived / time);
01072 globalStatistics->addStdDev("Pastry: LEAFSET Messages sent/s", leafsetSent / time);
01073 globalStatistics->addStdDev("Pastry: bytes of LEAFSET Messages sent/s", leafsetBytesSent / time);
01074 globalStatistics->addStdDev("Pastry: LEAFSET Messages received/s", leafsetReceived / time);
01075 globalStatistics->addStdDev("Pastry: bytes of LEAFSET Messages received/s",
01076 leafsetBytesReceived / time);
01077 globalStatistics->addStdDev("Pastry: ROUTING TABLE Requests sent/s", routingTableReqSent / time);
01078 globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Requests sent/s", routingTableReqBytesSent / time);
01079 globalStatistics->addStdDev("Pastry: ROUTING TABLE Requests received/s", routingTableReqReceived / time);
01080 globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Requests received/s",
01081 routingTableReqBytesReceived / time);
01082 globalStatistics->addStdDev("Pastry: ROUTING TABLE Messages sent/s", routingTableSent / time);
01083 globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Messages sent/s", routingTableBytesSent / time);
01084 globalStatistics->addStdDev("Pastry: ROUTING TABLE Messages received/s", routingTableReceived / time);
01085 globalStatistics->addStdDev("Pastry: bytes of ROUTING TABLE Messages received/s",
01086 routingTableBytesReceived / time);
01087
01088 }
01089
01090 int BasePastry::getMaxNumSiblings()
01091 {
01092 return (int)floor(numberOfLeaves / 2.0);
01093 }
01094
01095 int BasePastry::getMaxNumRedundantNodes()
01096 {
01097 return (int)floor(numberOfLeaves);
01098 }
01099
01100 NodeVector* BasePastry::findNode(const OverlayKey& key,
01101 int numRedundantNodes,
01102 int numSiblings,
01103 BaseOverlayMessage* msg)
01104 {
01105 if ((numRedundantNodes > getMaxNumRedundantNodes()) ||
01106 (numSiblings > getMaxNumSiblings())) {
01107
01108 opp_error("(Pastry::findNode()) numRedundantNodes or numSiblings "
01109 "too big!");
01110 }
01111 RECORD_STATS(totalLookups++);
01112
01113 NodeVector* nextHops = new NodeVector(numRedundantNodes);
01114
01115 if (state != READY) {
01116 return nextHops;
01117 } else if (key.isUnspecified() || leafSet->isClosestNode(key)) {
01118 RECORD_STATS(responsibleLookups++);
01119 nextHops->add(thisNode);
01120 } else {
01121 const NodeHandle* next = &(leafSet->getDestinationNode(key));
01122
01123 if (next->isUnspecified()) {
01124 next = &(routingTable->lookupNextHop(key));
01125 if (!next->isUnspecified()) {
01126 RECORD_STATS(routingTableLookups++);
01127 }
01128 } else {
01129 RECORD_STATS(responsibleLookups++);
01130 }
01131
01132 if (next->isUnspecified()) {
01133 RECORD_STATS(closerNodeLookups++);
01134
01135 if (optimizeLookup) {
01136 const NodeHandle* tmp;
01137 next = &(routingTable->findCloserNode(key, true));
01138 tmp = &(neighborhoodSet->findCloserNode(key, true));
01139
01140 if ((! tmp->isUnspecified()) &&
01141 (leafSet->isCloser(*tmp, key, *next))) {
01142 RECORD_STATS(closerNodeLookupsFromNeighborhood++);
01143 next = tmp;
01144 }
01145
01146 tmp = &(leafSet->findCloserNode(key, true));
01147 if ((! tmp->isUnspecified()) &&
01148 (leafSet->isCloser(*tmp, key, *next))) {
01149 RECORD_STATS(closerNodeLookupsFromNeighborhood--);
01150 next = tmp;
01151 }
01152 } else {
01153 next = &(routingTable->findCloserNode(key));
01154
01155 if (next->isUnspecified()) {
01156 RECORD_STATS(closerNodeLookupsFromNeighborhood++);
01157 next = &(neighborhoodSet->findCloserNode(key));
01158 }
01159
01160 if (next->isUnspecified()) {
01161 RECORD_STATS(closerNodeLookupsFromNeighborhood--);
01162 next = &(leafSet->findCloserNode(key));
01163 }
01164 }
01165 }
01166
01167 iterativeJoinHook(msg, !next->isUnspecified());
01168
01169 if (!next->isUnspecified()) {
01170 nextHops->add(*next);
01171 }
01172 }
01173
01174 bool err;
01175
01176
01177 if ((numSiblings >= 0) && isSiblingFor(thisNode, key, numSiblings, &err)) {
01178 if (err == false) {
01179 delete nextHops;
01180 return leafSet->createSiblingVector(key, numSiblings);
01181 }
01182 }
01183
01184 if ( (numRedundantNodes > 1)) {
01185
01186
01187
01188
01189
01190 KeyDistanceComparator<KeyRingMetric> comp(key);
01191
01192 NodeVector* additionalHops = new NodeVector( numRedundantNodes, &comp );
01193
01194 routingTable->findCloserNodes(key, additionalHops);
01195 leafSet->findCloserNodes(key, additionalHops);
01196 neighborhoodSet->findCloserNodes(key, additionalHops);
01197
01198 if (useRegularNextHop && (nextHops->size() > 0) &&
01199 (*additionalHops)[0] != (*nextHops)[0]) {
01200 for (uint32_t i = 0; i < additionalHops->size(); i++) {
01201 if ((*additionalHops)[i] != (*nextHops)[0])
01202 nextHops->push_back((*additionalHops)[i]);
01203 }
01204 delete additionalHops;
01205 } else {
01206 delete nextHops;
01207 return additionalHops;
01208 }
01209 }
01210 return nextHops;
01211 }
01212 AbstractLookup* BasePastry::createLookup(RoutingType routingType,
01213 const BaseOverlayMessage* msg,
01214 const cObject* dummy,
01215 bool appLookup)
01216 {
01217 assert(dummy == NULL);
01218 PastryFindNodeExtData* findNodeExt =
01219 new PastryFindNodeExtData("findNodeExt");
01220
01221 if (msg) {
01222 const PastryMessage* pmsg =
01223 dynamic_cast<const PastryMessage*>(msg->getEncapsulatedPacket());
01224 if ((pmsg) && (pmsg->getPastryMsgType() == PASTRY_MSG_JOIN)) {
01225 const PastryJoinMessage* jmsg =
01226 check_and_cast<const PastryJoinMessage*>(pmsg);
01227 findNodeExt->setSendStateTo(jmsg->getSendStateTo());
01228 findNodeExt->setJoinHopCount(1);
01229 }
01230 }
01231 findNodeExt->setBitLength(PASTRYFINDNODEEXTDATA_L);
01232
01233 AbstractLookup* newLookup = BaseOverlay::createLookup(routingType,
01234 msg, findNodeExt,
01235 appLookup);
01236
01237 delete findNodeExt;
01238 return newLookup;
01239 }
01240
01241 bool stateMsgIsSmaller(const PastryStateMsgHandle& hnd1,
01242 const PastryStateMsgHandle& hnd2)
01243 {
01244 return (hnd1.msg->getJoinHopCount() < hnd2.msg->getJoinHopCount());
01245 }
01246
01247
01248 std::ostream& operator<<(std::ostream& os, const PastryStateMsgProximity& pr)
01249 {
01250 os << "PastryStateMsgProximity {" << endl;
01251 os << " pr_rt {" << endl;
01252 for (std::vector<simtime_t>::const_iterator i = pr.pr_rt.begin();
01253 i != pr.pr_rt.end(); ++i) {
01254 os << " " << *i << endl;
01255 }
01256 os << " }" << endl;
01257 os << " pr_ls {" << endl;
01258 for (std::vector<simtime_t>::const_iterator i = pr.pr_ls.begin();
01259 i != pr.pr_ls.end(); ++i) {
01260 os << " " << *i << endl;
01261 }
01262 os << " }" << endl;
01263 os << " pr_ns {" << endl;
01264 for (std::vector<simtime_t>::const_iterator i = pr.pr_ns.begin();
01265 i != pr.pr_ns.end(); ++i) {
01266 os << " " << *i << endl;
01267 }
01268 os << " }" << endl;
01269 os << "}" << endl;
01270 return os;
01271 }
01272
01273
01274
01275 OverlayKey BasePastry::distance(const OverlayKey& x,
01276 const OverlayKey& y,
01277 bool useAlternative) const
01278 {
01279 if (!useAlternative) return KeyRingMetric().distance(x, y);
01280 return KeyPrefixMetric().distance(x, y);
01281 }