NeighborCache.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 
00025 #include <cassert>
00026 
00027 #include <TransportAddress.h>
00028 #include <NodeHandle.h>
00029 #include <PeerInfo.h>
00030 #include <GlobalStatisticsAccess.h>
00031 #include <CoordMessages_m.h>
00032 #include <GlobalNodeListAccess.h>
00033 #include <hashWatch.h>
00034 
00035 #include "NeighborCache.h"
00036 
00037 
00038 const std::vector<double> NeighborCache::coordsDummy;
00039 
00040 std::ostream& operator<<(std::ostream& os,
00041                          const NeighborCache::NeighborCacheEntry& entry)
00042 {
00043     if (entry.rttState == NeighborCache::RTTSTATE_VALID) {
00044         os << entry.rtt;
00045     } else {
00046         if (entry.rttState == NeighborCache::RTTSTATE_TIMEOUT) os << "TIMEOUT";
00047         else if (entry.rttState == NeighborCache::RTTSTATE_UNKNOWN) os << "UNKNOWN";
00048         else if (entry.rttState == NeighborCache::RTTSTATE_WAITING) os << "WAITING";
00049     }
00050     os << " (inserted: " << entry.insertTime;
00051 
00052     os << ", #contexts: "
00053        << entry.waitingContexts.size();
00054 
00055     if (!entry.nodeRef.isUnspecified()) os <<  ", <KEY>";
00056 
00057     //TODO entry.coordsInfo
00058 
00059     os << ")";
00060 
00061     return os;
00062 }
00063 
00064 
00065 Define_Module(NeighborCache);
00066 
00067 void NeighborCache::initializeApp(int stage)
00068 {
00069     if (stage != MAX_STAGE_COMPONENTS) {
00070         return;
00071     }
00072 
00073     neighborCache.clear();
00074     WATCH_UNORDERED_MAP(neighborCache);
00075 
00076     enableNeighborCache = par("enableNeighborCache");
00077     rttExpirationTime = par("rttExpirationTime");
00078     maxSize = par("maxSize");
00079     doDiscovery =par("doDiscovery");
00080 
00081     // set default query types
00082     std::string temp = par("defaultQueryType").stdstringValue();
00083     if (temp == "exact")
00084         defaultQueryType = NEIGHBORCACHE_EXACT;
00085     else if (temp == "exact_timeout")
00086         defaultQueryType = NEIGHBORCACHE_EXACT_TIMEOUT;
00087     else if (temp == "available")
00088         defaultQueryType = NEIGHBORCACHE_AVAILABLE;
00089     else if (temp == "estimated")
00090         defaultQueryType = NEIGHBORCACHE_ESTIMATED;
00091     else throw cRuntimeError((std::string("Wrong query type: ")
00092                              + temp).c_str());
00093 
00094     temp = par("defaultQueryTypeI").stdstringValue();
00095     if (temp == "available")
00096         defaultQueryTypeI = NEIGHBORCACHE_AVAILABLE;
00097     else if (temp == "estimated")
00098         defaultQueryTypeI = NEIGHBORCACHE_ESTIMATED;
00099     else throw cRuntimeError((std::string("Wrong query type (I): ")
00100                              + temp).c_str());
00101 
00102     temp = par("defaultQueryTypeQ").stdstringValue();
00103     if (temp == "exact")
00104         defaultQueryTypeQ = NEIGHBORCACHE_EXACT;
00105     else if (temp == "exact_timeout")
00106         defaultQueryTypeQ = NEIGHBORCACHE_EXACT_TIMEOUT;
00107     else if (temp == "query")
00108         defaultQueryTypeQ = NEIGHBORCACHE_QUERY;
00109     else throw cRuntimeError((std::string("Wrong query type (Q): ")
00110                              + temp).c_str());
00111 
00112     temp = par("ncsType").stdstringValue();
00113     if (temp == "none") ncs = NULL;
00114     else if (temp == "vivaldi") ncs = new Vivaldi();
00115     else if (temp == "svivaldi") ncs = new SVivaldi();
00116     else if (temp == "gnp") ncs = new Nps(); //TODO
00117     else if (temp == "nps") ncs = new Nps();
00118     else throw cRuntimeError((std::string("Wrong NCS type: ")
00119                               + temp).c_str());
00120 
00121     if (ncs) ncs->init(this);
00122 
00123     globalStatistics = GlobalStatisticsAccess().get();
00124 
00125     misses = 0;
00126     hits = 0;
00127 
00128     rttHistory = par("rttHistory");
00129     timeoutAccuracyLimit = par("timeoutAccuracyLimit");
00130 
00131     numMsg = 0;
00132     absoluteError = 0.0;
00133     relativeError = 0.0;
00134     numRttErrorToHigh = 0;
00135     numRttErrorToLow = 0;
00136     lastAbsoluteErrorPerNode.clear();
00137     WATCH(absoluteError);
00138     WATCH(relativeError);
00139     WATCH(numMsg);
00140 }
00141 
00142 
00143 void NeighborCache::finishApp()
00144 {
00145     if ((misses + hits) != 0) {
00146         globalStatistics
00147             ->addStdDev("NeighborCache: Ping hit rate",
00148                         ((double)hits / (double)(misses + hits)));
00149     }
00150 
00151     if (ncs && numMsg > 0) {
00152         globalStatistics->addStdDev("NeighborCache: NCS absolute RTT error",
00153                                     absoluteError / (double)numMsg);
00154         globalStatistics->addStdDev("NeighborCache: NCS relative RTT error",
00155                                     relativeError / (double)numMsg);
00156         globalStatistics->addStdDev("NeighborCache: number of messages/s",
00157                                     numMsg / SIMTIME_DBL(simTime() - creationTime));
00158         globalStatistics->addStdDev("NeighborCache: NCS percentage of RTT errors to high",
00159                                     (double)numRttErrorToHigh / (double)numMsg);
00160         globalStatistics->addStdDev("NeighborCache: NCS percentage of RTT errors to low",
00161                                     (double)numRttErrorToLow / (double)numMsg);
00162     }
00163 }
00164 
00165 
00166 NeighborCache::~NeighborCache()
00167 {
00168     delete ncs;
00169 }
00170 
00171 bool NeighborCache::insertNodeContext(const TransportAddress& handle,
00172                                      cPolymorphic* context,
00173                                      ProxListener* rpcListener,
00174                                      int rpcId)
00175 {
00176     if (!enableNeighborCache) return false;
00177     if (neighborCache.count(handle) == 0) {
00178         NeighborCacheEntry& entry = neighborCache[handle];
00179 
00180         entry.insertTime = simTime();
00181         entry.rttState = RTTSTATE_WAITING;
00182 
00183         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime,
00184                                                      handle));
00185 
00186         cleanupCache();
00187 
00188         assert(neighborCache.size() == neighborCacheExpireMap.size());
00189         return false;
00190     } else {
00191         NeighborCacheEntry& entry = neighborCache[handle];
00192 
00193         // waiting?
00194         if (entry.rttState == RTTSTATE_WAITING) {
00195             WaitingContext temp(rpcListener, context, rpcId);
00196             entry.waitingContexts.push_back(temp);
00197 
00198             return true;
00199         } else {
00200             if (entry.waitingContexts.size() > 0) {
00201                 throw cRuntimeError("not waiting for response,"
00202                                     " but additional contexts found!");
00203             }
00204 
00205             updateEntry(handle, entry.insertTime);
00206 
00207             entry.rttState = RTTSTATE_WAITING;
00208             entry.insertTime = simTime();
00209 
00210             return false;
00211         }
00212     }
00213 }
00214 
00215 
00216 NeighborCache::WaitingContexts NeighborCache::getNodeContexts(const TransportAddress& handle)
00217 {
00218     if (neighborCache.count(handle) == 0)
00219         throw cRuntimeError("NeighborCache error!");
00220     WaitingContexts temp = neighborCache[handle].waitingContexts;
00221     neighborCache[handle].waitingContexts.clear();
00222 
00223     return temp;
00224 }
00225 
00226 
00227 void NeighborCache::setNodeTimeout(const TransportAddress& handle)
00228 {
00229     //if (!enableNeighborCache) return;
00230 
00231     if (neighborCache.count(handle) == 0) {
00232         NeighborCacheEntry& entry = neighborCache[handle];
00233 
00234         entry.insertTime = simTime();
00235         entry.rttState = RTTSTATE_TIMEOUT;
00236 
00237         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime,
00238                                                      handle));
00239         cleanupCache();
00240     } else {
00241         NeighborCacheEntry& entry = neighborCache[handle];
00242 
00243         updateEntry(handle, entry.insertTime);
00244 
00245         entry.insertTime = simTime();
00246         entry.rttState = RTTSTATE_TIMEOUT;
00247 
00248         WaitingContexts waitingContexts = getNodeContexts(handle);
00249 
00250         for (uint32_t i = 0; i < waitingContexts.size(); ++i) {
00251             assert(waitingContexts[i].proxListener || !waitingContexts[i].proxContext);
00252             if (waitingContexts[i].proxListener) {
00253                 waitingContexts[i].proxListener->proxCallback(handle,
00254                                                               waitingContexts[i].id,
00255                                                               waitingContexts[i].proxContext,
00256                                                               Prox::PROX_TIMEOUT);
00257             }
00258         }
00259     }
00260     assert(neighborCache.size() == neighborCacheExpireMap.size());
00261 }
00262 
00263 
00264 void NeighborCache::updateNode(const NodeHandle& add, simtime_t rtt,
00265                                const NodeHandle& srcRoute,
00266                                AbstractNcsNodeInfo* ncsInfo)
00267 {
00268     Enter_Method_Silent();
00269 
00270     EV << "[NeighborCache::updateNode() @ " << thisNode.getAddress()
00271            << " (" << thisNode.getKey().toString(16) << ")]\n"
00272            << "    inserting rtt(" << rtt << ") of node " << add.getAddress()
00273            << endl;
00274 
00275     if (rtt <= 0) {
00276         delete ncsInfo;
00277         return; //TODO broose
00278     }
00279 
00280     bool deleteInfo = false;
00281 
00282     //if (enableNeighborCache) {
00283     if (neighborCache.count(add) == 0) {
00284         NeighborCacheEntry& entry = neighborCache[add];
00285 
00286         entry.insertTime = simTime();
00287         entry.rtt = rtt;
00288         entry.rttState = RTTSTATE_VALID;
00289         entry.nodeRef = add;
00290         entry.coordsInfo = ncsInfo;
00291         entry.lastRtts.push_back(rtt);
00292 
00293         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime, add));
00294 
00295         cleanupCache();
00296     } else {
00297         updateEntry(add, neighborCache[add].insertTime);
00298 
00299         NeighborCacheEntry& entry = neighborCache[add];
00300 
00301         entry.insertTime = simTime();
00302         if (entry.rttState != RTTSTATE_VALID || entry.rtt > rtt)
00303             entry.rtt = rtt;
00304         entry.rttState = RTTSTATE_VALID;
00305         entry.nodeRef = add;
00306 
00307         entry.lastRtts.push_back(rtt);
00308         if (entry.lastRtts.size()  > rttHistory) {
00309             entry.lastRtts.pop_front();
00310         }
00311 
00312         if (ncsInfo) {
00313             if (entry.coordsInfo) {
00314                 entry.coordsInfo->update(*ncsInfo);
00315                 deleteInfo = true;
00316             } else {
00317                 entry.coordsInfo = ncsInfo;
00318             }
00319         }
00320 
00321         WaitingContexts waitingContexts = getNodeContexts(add);
00322 
00323         for (uint32_t i = 0; i < waitingContexts.size(); ++i) {
00324             if (waitingContexts[i].proxListener) {
00325                 waitingContexts[i].proxListener
00326                 ->proxCallback(add,
00327                                waitingContexts[i].id,
00328                                waitingContexts[i].proxContext,
00329                                Prox(rtt, 1));
00330             }
00331         }
00332     }
00333     assert(neighborCache.size() == neighborCacheExpireMap.size());
00334 
00335     calcRttError(add, rtt);
00336 
00337     if (ncs) ncs->processCoordinates(rtt, *ncsInfo);
00338 
00339     // delete ncsInfo if old info is used
00340     if (deleteInfo) delete ncsInfo;
00341 }
00342 void NeighborCache::updateNcsInfo(const TransportAddress& node,
00343                                   AbstractNcsNodeInfo* ncsInfo)
00344 {
00345     Enter_Method_Silent();
00346 
00347     EV << "[NeighborCache::updateNcsInfo() @ " << thisNode.getAddress()
00348        << " (" << thisNode.getKey().toString(16) << ")]\n"
00349        << "    inserting new NcsInfo of node " << node.getAddress()
00350        << endl;
00351 
00352     if (neighborCache.count(node) == 0) {
00353         NeighborCacheEntry& entry = neighborCache[node];
00354 
00355         entry.insertTime = simTime();
00356         entry.coordsInfo = ncsInfo;
00357 
00358         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime, node));
00359 
00360         cleanupCache();
00361     } else {
00362         updateEntry(node, neighborCache[node].insertTime);
00363 
00364         NeighborCacheEntry& entry = neighborCache[node];
00365 
00366         if (ncsInfo) {
00367             if (entry.coordsInfo) {
00368                 entry.coordsInfo->update(*ncsInfo);
00369                 delete ncsInfo;
00370             } else {
00371                 entry.coordsInfo = ncsInfo;
00372             }
00373         }
00374     }
00375 }
00376 
00377 
00378 NeighborCache::Rtt NeighborCache::getNodeRtt(const TransportAddress &add)
00379 {
00380     // cache disabled or entry not there
00381     if (!enableNeighborCache ||
00382         add.isUnspecified() ||
00383         (neighborCache.count(add) == 0)) {
00384         misses++;
00385         return std::make_pair(0.0, RTTSTATE_UNKNOWN);
00386     }
00387 
00388     NeighborCacheEntry &entry = neighborCache[add];
00389 
00390     if (entry.rttState == RTTSTATE_WAITING ||
00391         entry.rttState == RTTSTATE_UNKNOWN)
00392         return std::make_pair(entry.rtt, entry.rttState);
00393     // entry expired
00394     if ((simTime() - entry.insertTime) >= rttExpirationTime) {
00395         entry.rttState = RTTSTATE_UNKNOWN;
00396         return std::make_pair(entry.rtt, RTTSTATE_UNKNOWN);
00397     }
00398     hits++;
00399     assert(!(entry.rtt == 0.0 && entry.rttState == RTTSTATE_VALID));
00400     return std::make_pair(entry.rtt, entry.rttState);
00401 }
00402 
00403 
00404 const NodeHandle& NeighborCache::getNodeHandle(const TransportAddress &add)
00405 {
00406     if (neighborCache.count(add) == 0) {
00407         throw cRuntimeError("NeighborCache.cc: getNodeHandle was asked for "
00408                             "a non-existent node reference.");
00409     }
00410     return neighborCache[add].nodeRef;
00411 }
00412 
00413 
00414 bool NeighborCache::cleanupCache()
00415 {
00416     bool result = false;
00417     uint32_t size = neighborCache.size();
00418 
00419     if (size > maxSize) {
00420         neighborCacheExpireMapIterator it;
00421         for (uint32_t i = 0; i < (size - (maxSize / 2)); ++i) {
00422             it = neighborCacheExpireMap.begin();
00423             if ((neighborCache[it->second].rttState == RTTSTATE_WAITING) ||
00424                 (neighborCache[it->second].insertTime == simTime())) {
00425                 break;
00426             }
00427             neighborCache.erase(it->second);
00428             neighborCacheExpireMap.erase(it);
00429             result = true;
00430         }
00431     }
00432     assert(neighborCache.size() == neighborCacheExpireMap.size());
00433     return result;
00434 }
00435 
00436 
00437 void NeighborCache::updateEntry(const TransportAddress& address,
00438                                 simtime_t insertTime)
00439 {
00440     neighborCacheExpireMapIterator it =
00441         neighborCacheExpireMap.lower_bound(insertTime);
00442     while (it->second != address) ++it;
00443     neighborCacheExpireMap.erase(it);
00444     neighborCacheExpireMap.insert(std::make_pair(simTime(),
00445                                                  address));
00446     assert(neighborCache.size() == neighborCacheExpireMap.size());
00447 }
00448 
00449 //TODO
00450 TransportAddress NeighborCache::getNearestNode(uint8_t maxLayer)
00451 {
00452     TransportAddress nearestNode = TransportAddress::UNSPECIFIED_NODE;
00453     simtime_t nearestNodeRtt = MAXTIME;
00454     NeighborCacheIterator it;
00455 
00456     for(it = neighborCache.begin(); it != neighborCache.end(); it++ ) {
00457         if (it->second.rtt < nearestNodeRtt &&
00458             it->second.rtt > 0 /*&&
00459             it->second.coordsInfo.npsLayer < maxLayer+1 &&
00460             it->second.coordsInfo.npsLayer > 0*/) {
00461             nearestNode.setAddress(it->first.getAddress());
00462             nearestNodeRtt = it->second.rtt;
00463             nearestNode.setPort(it->second.nodeRef.getPort());
00464         }
00465     }
00466 
00467     return nearestNode;
00468 }
00469 
00470 
00471 bool NeighborCache::isEntry(const TransportAddress &node)
00472 {
00473     if (neighborCache.count(node) > 0) return true;
00474     return false;
00475 }
00476 
00477 
00478 // Vivaldi stuff
00479 double NeighborCache::getAvgAbsPredictionError()
00480 {
00481     /*
00482     //TODO retain and consider the last measured RTTs not the last error(s)
00483     double absoluteDiff = 0.0;
00484     uint32_t numNeighbors = 0;
00485 
00486     for (std::map<TransportAddress, std::vector<double> >::iterator it =
00487         lastAbsoluteErrorPerNode.begin(); it != lastAbsoluteErrorPerNode.end();
00488         it++) {
00489         double tempAbsoluteDiff = 0.0;
00490         for (uint32_t i = 0; i < it->second.size(); i++) {
00491             tempAbsoluteDiff += it->second.at(i);
00492         }
00493         absoluteDiff += (tempAbsoluteDiff / it->second.size());
00494         numNeighbors++;
00495     }
00496 
00497     absoluteDiff /= numNeighbors;
00498     return (absoluteDiff > 1.0) ? 1.0 : absoluteDiff;
00499      */
00500 
00501     // old version
00502     //if (neighborCache.size() < 2 || sampleSize == 0) return 1.0;
00503 
00504     double absoluteDiff = 0;
00505     uint32_t numNeighbors = 0;
00506     uint32_t sampleSize = 32; //test
00507 
00508     for (std::map<simtime_t, TransportAddress>::reverse_iterator it =
00509          neighborCacheExpireMap.rbegin();
00510          it != neighborCacheExpireMap.rend() &&
00511          numNeighbors < sampleSize; ++it) {
00512         NeighborCacheEntry& cacheEntry = neighborCache[it->second];
00513 
00514         double dist = ncs->getOwnNcsInfo().getDistance(*cacheEntry.coordsInfo);
00515 
00516         if (dist != 0 && cacheEntry.rttState == RTTSTATE_VALID) {
00517             double predictionError = fabs(dist - SIMTIME_DBL(cacheEntry.rtt));
00518 
00519             //test: error weighted
00520             //if (it->second.coordErr < 1) {
00521             //    predictionError /= it->second.coordErr;
00522             //}
00523             //test: age weighted
00524             //if ((simTime() - it->second.insertTime) > 1) {
00525             //    predictionError /= (simTime() - it->second.insertTime);
00526             //}
00527 
00528             numNeighbors++;
00529             absoluteDiff += predictionError;
00530         }
00531     }
00532     assert(numNeighbors != 0);
00533     absoluteDiff /= numNeighbors;
00534 
00535     return (absoluteDiff > 1.0) ? 1.0 : absoluteDiff;
00536 }
00537 
00538 
00539 void NeighborCache::handleReadyMessage(CompReadyMessage* readyMsg)
00540 {
00541     if (readyMsg->getReady() && readyMsg->getComp() == BOOTSTRAPLIST_COMP) {
00542         if (doDiscovery) {
00543             //TODO
00544             // 1. ask bootstrap node for other nodes and his coordinates
00545             // 2. probe other nodes and optionally ask them for more nodes
00546             //    (try to get close as well as distant nodes)
00547             // sendReadyMessage();
00548         } else {
00549             sendReadyMessage();
00550         }
00551     }
00552     delete readyMsg;
00553 }
00554 
00555 
00556 void NeighborCache::handleTimerEvent(cMessage* msg)
00557 {
00558     if (ncs) {
00559         ncs->handleTimerEvent(msg);
00560     }
00561 }
00562 
00563 
00564 bool NeighborCache::handleRpcCall(BaseCallMessage* msg)
00565 {
00566     if (ncs) {
00567         return ncs->handleRpcCall(msg);
00568     }
00569 
00570     return false;
00571 }
00572 
00573 // Prox stuff
00574 Prox NeighborCache::getProx(const TransportAddress &node,
00575                               NeighborCacheQueryType type,
00576                               int rpcId,
00577                               ProxListener *listener,
00578                               cPolymorphic *contextPointer)
00579 {
00580     Enter_Method("getProx()");
00581 
00582     if (!enableNeighborCache) {
00583         queryProx(node, rpcId, listener, contextPointer);
00584         return Prox::PROX_UNKNOWN;
00585     }
00586 
00587     if (node == overlay->getThisNode()) {
00588         delete contextPointer;
00589         return Prox::PROX_SELF;
00590     }
00591 
00592     bool sendQuery = false;
00593     Prox result = Prox::PROX_UNKNOWN;
00594     Rtt rtt = getNodeRtt(node);
00595 
00596     //countGetProxTotal++;
00597     if (type == NEIGHBORCACHE_DEFAULT) type = defaultQueryType;
00598     else if (type == NEIGHBORCACHE_DEFAULT_IMMEDIATELY) type = defaultQueryTypeI;
00599     else if (type == NEIGHBORCACHE_DEFAULT_QUERY) type = defaultQueryTypeQ;
00600 
00601     switch(type) {
00602         case NEIGHBORCACHE_EXACT:
00603             if (rtt.second == RTTSTATE_TIMEOUT) {
00604                 // if timeout, return unknown, and send a query!
00605                 sendQuery = true;
00606             } else if (rtt.second == RTTSTATE_WAITING) {
00607                 // if a query was sent, return UNKNOWN
00608                 sendQuery = true; //just inserting a context, no real ping is sent
00609             } else if (rtt.second == RTTSTATE_UNKNOWN) {
00610                 // if no entry known, send a query and return UNKNOWN
00611                 sendQuery = true;
00612             } else {
00613                 // else, return whatever we have
00614                 result = rtt.first;
00615             }
00616             break;
00617         case NEIGHBORCACHE_EXACT_TIMEOUT:
00618             if (rtt.second == RTTSTATE_TIMEOUT) {
00619                 // if timeout, return that
00620                 result = Prox::PROX_TIMEOUT;
00621             } else if (rtt.second == RTTSTATE_WAITING) {
00622                 // if a query was sent, return UNKNOWN
00623                 sendQuery = true; //just inserting a context, no real ping is sent
00624             } else if (rtt.second == RTTSTATE_UNKNOWN) {
00625                 // if no entry known, send a query and return UNKNOWN
00626                 sendQuery = true;
00627             } else {
00628                 // else, return whatever we have
00629                 result = rtt.first;
00630             }
00631             break;
00632         case NEIGHBORCACHE_ESTIMATED:
00633             if (rtt.second == RTTSTATE_TIMEOUT) {
00634                 // if timeout, return that
00635                 result = Prox::PROX_TIMEOUT;
00636             } else if (rtt.second == RTTSTATE_WAITING) {
00637                 // if a query was sent, return an estimate
00638                 result = estimateProx(node);
00639             } else if (rtt.second == RTTSTATE_UNKNOWN) {
00640                 // if no entry known, return an estimate
00641                 result = estimateProx(node);
00642             } else {
00643                 // else return whatever we have
00644                 result = rtt.first;
00645             }
00646             break;
00647         case NEIGHBORCACHE_AVAILABLE:
00648             if (rtt.second == RTTSTATE_TIMEOUT) {
00649                 // if timeout, return that.
00650                 result = Prox::PROX_TIMEOUT;
00651             } else if ((rtt.second == RTTSTATE_WAITING) ||
00652                        (rtt.second == RTTSTATE_UNKNOWN)) {
00653                 // if a query was sent or entry unknown, return UNKNOWN
00654             } else {
00655                 // else return what we have
00656                 result = rtt.first;
00657             }
00658             break;
00659         case NEIGHBORCACHE_QUERY:
00660             // simply send a query and return UNKNOWN
00661             sendQuery = true;
00662             break;
00663         default:
00664             throw cRuntimeError("Unknown query type!");
00665             break;
00666 
00667     }
00668     if (sendQuery) {
00669         if (!insertNodeContext(node, contextPointer, listener, rpcId)) {
00670             queryProx(node, rpcId, listener, contextPointer);
00671         }
00672     } else delete contextPointer;
00673 
00674     return result;
00675 }
00676 
00677 Prox NeighborCache::estimateProx(const TransportAddress &node)
00678 {
00679     Enter_Method("estimateProx()");
00680 
00681     Rtt rtt = getNodeRtt(node);
00682 
00683     if (rtt.second != RTTSTATE_UNKNOWN) return rtt.first;
00684 
00685     if (ncs && neighborCache.count(node)) {
00686         return getCoordinateBasedProx(node);
00687     }
00688 
00689     return Prox::PROX_UNKNOWN;
00690 }
00691 
00692 void NeighborCache::queryProx(const TransportAddress &node,
00693                               int rpcId,
00694                               ProxListener *listener,
00695                               cPolymorphic *contextPointer)
00696 {
00697     Enter_Method("queryProx()");
00698 
00699     WaitingContext temp(listener, contextPointer, rpcId);
00700 
00701     if (neighborCache.count(node) == 0) {
00702         NeighborCacheEntry& entry = neighborCache[node];
00703 
00704         entry.waitingContexts.push_back(temp);
00705         neighborCacheExpireMap.insert(std::make_pair(entry.insertTime,
00706                                                      node));
00707         cleanupCache();
00708     } else {
00709         NeighborCacheEntry& entry = neighborCache[node];
00710         entry.waitingContexts.push_back(temp);
00711     }
00712     assert(neighborCache.size() == neighborCacheExpireMap.size());
00713 
00714     // TODO: this ping traffic is accounted application data traffic!
00715     pingNode(node, -1, 0, NULL, "PING");
00716 }
00717 
00718 Prox NeighborCache::getCoordinateBasedProx(const TransportAddress& node)
00719 {
00720     if (ncs && isEntry(node)) {
00721         const AbstractNcsNodeInfo* temp = getNodeCoordsInfo(node);
00722         if (temp) return ncs->getCoordinateBasedProx(*temp);
00723     }
00724     return Prox::PROX_UNKNOWN;
00725 }
00726 
00727 
00728 const AbstractNcsNodeInfo* NeighborCache::getNodeCoordsInfo(const TransportAddress &node)
00729 {
00730     if (neighborCache.count(node) == 0) {
00731         throw cRuntimeError("NeighborCache.cc: getNodeCoords was asked for "
00732                             "a non-existent node reference.");
00733     }
00734     return neighborCache[node].coordsInfo;
00735 }
00736 
00737 
00738 void NeighborCache::calcRttError(const NodeHandle& handle, simtime_t rtt)
00739 {
00740     if (!ncs) return;
00741 
00742     // Check if data collection can start
00743     if (!globalStatistics->isMeasuring()) return;
00744 
00745     Prox prox = getCoordinateBasedProx(handle);
00746     if (prox == Prox::PROX_UNKNOWN) return;
00747 
00748     //calculate absolute rtt error of the last message
00749     double tempRttError = prox.proximity - SIMTIME_DBL(rtt);
00750 
00751     if (tempRttError < 0){
00752         tempRttError *= -1;
00753         ++numRttErrorToLow;
00754     } else ++numRttErrorToHigh;
00755 
00756     numMsg++;
00757     absoluteError += tempRttError;
00758     relativeError += tempRttError / SIMTIME_DBL(rtt);
00759 
00760     globalStatistics->recordOutVector("NCS: absolute Rtt Error",
00761                                       tempRttError);
00762     globalStatistics->recordOutVector("NCS: relative Rtt Error",
00763                                       (tempRttError / SIMTIME_DBL(rtt)));
00764 }
00765 
00766 
00767 /*simtime_t NeighborCache::getMeanRtt(const TransportAddress &node)
00768 {
00769     if (neighborCache.count(node) == 0) {
00770         throw cRuntimeError("NeighborCache.cc: getMeanRtt was asked for"
00771                             "a non-existent node reference.");
00772     }
00773 
00774     uint16_t size = neighborCache[node].lastRtts.size();
00775     if (size == 0) return -1;
00776 
00777     simtime_t rttSum = 0;
00778     for (int i = 0; i < size; i++){
00779         rttSum += neighborCache[node].lastRtts[i];
00780     }
00781     return (rttSum / size);
00782 }
00783 
00784 // TODO remove meanRtt
00785 double NeighborCache::getVarRtt(const TransportAddress &node, simtime_t &meanRtt)
00786 {
00787     if (neighborCache.count(node) == 0) {
00788         throw cRuntimeError("NeighborCache.cc: getMeanRtt was asked for"
00789                             "a non-existent node reference.");
00790     }
00791 
00792     uint16_t size = neighborCache[node].lastRtts.size();
00793     if (size == 0) return -1.0;
00794     if (size == 1) return 0.0;
00795 
00796     meanRtt = getMeanRtt(node);
00797     if (SIMTIME_DBL(meanRtt) == -1.0) return 0.0;
00798 
00799     double sum = 0.0;
00800     for (int i = 0; i < size; i++){
00801         simtime_t tempRtt = neighborCache[node].lastRtts.at(i) - meanRtt;
00802         sum += (SIMTIME_DBL(tempRtt) * SIMTIME_DBL(tempRtt));
00803     }
00804 
00805     //std::cout << "mean: " << meanRtt << ", var: " << (sum / size) << std::endl;
00806     return (sum / size); //TODO -1?
00807 }*/
00808 
00809 std::pair<simtime_t, simtime_t> NeighborCache::getMeanVarRtt(const TransportAddress &node,
00810                                                              bool returnVar)
00811 {
00812     if (neighborCache.count(node) == 0) {
00813         throw cRuntimeError("NeighborCache.cc: getMeanVarRtt was asked for"
00814                             "a non-existent node reference.");
00815     }
00816 
00817     uint16_t size = neighborCache[node].lastRtts.size();
00818     if (size == 0) return std::make_pair(-1.0,-1.0);
00819 
00820     simtime_t rttSum = 0;
00821     for (int i = 0; i < size; i++){
00822         rttSum += neighborCache[node].lastRtts[i];
00823     }
00824     simtime_t meanRtt = rttSum / size;
00825     if (!returnVar) {
00826         return std::make_pair(meanRtt, -1.0);
00827     }
00828     if (size == 1) {
00829         return std::make_pair(meanRtt, 0.0);
00830     }
00831 
00832     double sum = 0.0;
00833     for (int i = 0; i < size; i++){
00834         simtime_t tempRtt = neighborCache[node].lastRtts.at(i) - meanRtt;
00835         sum += (SIMTIME_DBL(tempRtt) * SIMTIME_DBL(tempRtt));
00836     }
00837 
00838     //std::cout << "mean: " << meanRtt << ", var: " << (sum / size) << std::endl;
00839     return std::make_pair(meanRtt, (sum / size));
00840 }
00841 
00842 
00843 simtime_t NeighborCache::getNodeTimeout(const NodeHandle &node)
00844 {
00845     simtime_t timeout = getRttBasedTimeout(node);
00846     if (timeout == -1 && ncs) return getNcsBasedTimeout(node);
00847     return timeout;
00848 }
00849 
00850 
00851 //Calculate timeout with RTT
00852 simtime_t NeighborCache::getRttBasedTimeout(const NodeHandle &node)
00853 {
00854     simtime_t timeout = -1;
00855 
00856     // check if an entry is available in NeighborCache
00857     if (isEntry(node)) {
00858         std::pair<simtime_t, simtime_t> temp = getMeanVarRtt(node, true);
00859         simtime_t meanRtt = temp.first;
00860         simtime_t varRtt = temp.second;
00861 
00862         // TODO return value even if node has timed out
00863         if (meanRtt == -1) return -1;
00864         if (varRtt > 0) {
00865             // like TCP
00866             timeout = meanRtt + 4 * varRtt;
00867         } else {
00868             // only one RTT is available
00869             timeout = meanRtt * 1.2;
00870         }
00871         // adjustment
00872         timeout *= RTT_TIMEOUT_ADJUSTMENT;
00873         //if (timeout > SIMTIME_DBL(defaultTimeout)) return -1;
00874     }
00875     return timeout;
00876 }
00877 
00878 //Calculate timeout with Vivaldi/GNP/...
00879 simtime_t NeighborCache::getNcsBasedTimeout(const NodeHandle &node)
00880 {
00881     double timeout = -1;
00882     Prox prox = Prox::PROX_UNKNOWN;
00883 
00884     // check if an entry is available in NeighborCache
00885     if (isEntry(node)) {
00886         prox = getProx(node, NEIGHBORCACHE_ESTIMATED);
00887 
00888         if (prox != Prox::PROX_UNKNOWN  && prox != Prox::PROX_TIMEOUT &&
00889             prox.proximity > 0 && prox.accuracy > timeoutAccuracyLimit) {
00890             timeout = prox.proximity + (6 * (1 - prox.accuracy));
00891             timeout += NCS_TIMEOUT_CONSTANT;
00892         } else return -1;
00893 
00894         if (/*timeout > SIMTIME_DBL(defaultTimeout) ||*/ timeout < 0)
00895             return -1;
00896     }
00897     return timeout;
00898 }
00899 
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3