linkcache.cc
来自「在Linux下做的QuadTree的程序」· CC 代码 · 共 712 行
CC
712 行
#include <god.h>#include "path.h"#include "routecache.h"#include <list.h>#ifdef DSR_CACHE_STATS#include <cmu/dsr/cache_stats.h>#endif#define CURRENT_TIME Scheduler::instance().clock()bool cache_ignore_hints = false; // ignore all hints?bool cache_use_overheard_routes = true; // Specifies whether or not to retain links after they go badstatic bool lc_cache_negative_links = false;// When inserting/deleting link A->B, also insert/delete B->A.static bool lc_bidirectional_links = true;// Evict "unreachable" links from the cache.static bool lc_evict_unreachable_links = false;// The maximum number of nodes supported by the cache.#define LC_MAX_NODES 50static int verbose_debug = 0;///////////////////////////////////////////////////////////////////////////class Link {public: Link(nsaddr_t dst) { ln_dst = dst; ln_flags = ln_cost = 0; ln_timeout = 0.0; ln_t = 0.0; ln_linktype = LT_NONE; ln_logstat = LS_UNLOGGED; } LIST_ENTRY(Link) ln_link; nsaddr_t ln_dst; int ln_flags; // link status information#define LINK_FLAG_UP 0x01 /* * Right now all links have the same cost (1). - josh */ int ln_cost; // cost of using the link /* * the use of ln_timeout to expire links from the * cache has not yet been implemented. - josh */ double ln_timeout; // when the link expires#define LINK_TIMEOUT 0.0 // mirror the values kept in class ID Time ln_t; Link_Type ln_linktype; Log_Status ln_logstat;};LIST_HEAD(LinkHead, Link);class LinkCache : public RouteCache {friend class MobiHandler;public: LinkCache(); void noticeDeadLink(const ID&from, const ID& to, Time t); // the link from->to isn't working anymore, purge routes containing // it from the cache void noticeRouteUsed(const Path& route, Time t, const ID& who_from); // tell the cache about a route we saw being used void addRoute(const Path& route, Time t, const ID& who_from); // add this route to the cache (presumably we did a route request // to find this route and don't want to lose it) bool findRoute(ID dest, Path& route, int for_me = 0); // if there is a cached path from us to dest returns true and fills in // the route accordingly. returns false otherwise // if for_use, then we assume that the node really wants to keep // the returned route so it will be promoted to primary storage // if not there already int command(int argc, const char*const* argv);protected: LinkHead lcache[LC_MAX_NODES + 1]; // note the zeroth index is not used int addLink(const ID& from, const ID& to, int flags, int cost = 1, double timeout = LINK_TIMEOUT); int delLink(const ID& from, const ID& to); Link* findLink(int from, int to); void purgeLink(void); void dumpLink(void); void Link_to_ID(Link* l, ID& id);#ifdef DSR_CACHE_STATS void checkLink_logall(const ID& from, const ID& to, int action); void checkLink(const ID& from, const ID& to, int action); void periodic_checkCache(); struct cache_stats stat;#endifprivate: //////////////////////////////////////////////////////////// // Dijkstra's Algorithm int dirty; u_int32_t d[LC_MAX_NODES + 1]; u_int32_t pi[LC_MAX_NODES + 1]; bool S[LC_MAX_NODES + 1];#define INFINITY 0x7fffffff void init_single_source(int s); void relax(u_int32_t u, u_int32_t v, u_int32_t w); int extract_min_q(void); void dijkstra(void); void dump_dijkstra(int dst);};///////////////////////////////////////////////////////////////////////////RouteCache *makeRouteCache(){ return new LinkCache();}LinkCache::LinkCache() : RouteCache(){ int i = 0; for(i = 0; i <= LC_MAX_NODES; i++) { LIST_INIT(&lcache[i]); }#ifdef DSR_CACHE_STATS stat.reset();#endif dirty = 1;}intLinkCache::command(int argc, const char*const* argv){ if(argc == 2 && strcasecmp(argv[1], "startdsr") == 0) { if (ID(1,::IP) == net_id) trace("Sconfig %.5f using LINKCACHE", Scheduler::instance().clock()); // FALL-THROUGH } if(argc == 3) { if (strcasecmp(argv[1], "ip-addr") == 0) { assert(atoi(argv[2]) <= LC_MAX_NODES); // don't return } } return RouteCache::command(argc, argv);}voidLinkCache::noticeDeadLink(const ID& from, const ID& to, Time){ Link *l = findLink(from.addr, to.addr); if(lc_cache_negative_links == true) { if(l) { l->ln_flags &= ~LINK_FLAG_UP; l->ln_timeout = LINK_TIMEOUT; } else { addLink(from, to, 0); } } else { if(l) {#ifdef DSR_CACHE_STATS checkLink(from, to, ACTION_DEAD_LINK);#endif (void) delLink(from, to); } }}voidLinkCache::noticeRouteUsed(const Path& p, Time t, const ID& who_from){ Path stub; int c; if(pre_noticeRouteUsed(p, stub, t, who_from) == 0) return; #ifdef DSR_CACHE_STATS int link_notice_count = stat.link_notice_count; int link_notice_bad_count = stat.link_notice_bad_count; #endif /* * Add each link in the "path" to the route cache. */ for(c = 0; c < stub.length() - 1; c++) { if(addLink(stub[c], stub[c+1], LINK_FLAG_UP)) {#ifdef DSR_CACHE_STATS checkLink(stub[c], stub[c+1], ACTION_NOTICE_ROUTE);#endif } }#ifdef DSR_CACHE_STATS if(stat.link_notice_count > link_notice_count) stat.route_notice_count++; if(stat.link_notice_bad_count > link_notice_bad_count) stat.route_notice_bad_count++;#endif}voidLinkCache::addRoute(const Path& route, Time t, const ID& who_from){ Path rt; int c; if(pre_addRoute(route, rt, t, who_from) == 0) return; #ifdef DSR_CACHE_STATS int link_add_count = stat.link_add_count; int link_add_bad_count = stat.link_add_bad_count; #endif for(c = 0; c < rt.length() - 1; c++) { if(addLink(rt[c], rt[c+1], LINK_FLAG_UP)) {#ifdef DSR_CACHE_STATS checkLink(rt[c], rt[c+1], ACTION_ADD_ROUTE);#endif } }#ifdef DSR_CACHE_STATS if(stat.link_add_count > link_add_count) stat.route_add_count++; if(stat.link_add_bad_count > link_add_bad_count) stat.route_add_bad_count++;#endif}boolLinkCache::findRoute(ID dest, Path& route, int for_me = 0){ u_int32_t v; int rpath[MAX_SR_LEN]; u_int32_t roff = 0; if(verbose_debug) dumpLink(); /* * Compute all of the shortest paths... */ if(dirty) { dijkstra(); // remove all of the links for nodes that are unreachable if(lc_evict_unreachable_links == true) { purgeLink(); } } if(verbose_debug) dump_dijkstra(dest.addr); /* * Trace backwards to figure out the path to DEST */ for(v = dest.addr; d[v] < INFINITY; v = pi[v]) { assert(v >= 1 && v <= LC_MAX_NODES); if (roff >= MAX_SR_LEN) { // path between us and dest is too long to be useful break; } rpath[roff] = v; roff++; if(v == net_id.addr) break; } if(roff < 2 || d[v] == INFINITY || roff >= MAX_SR_LEN) {#ifdef DSR_CACHE_STATS stat.route_find_count += 1; if (for_me) stat.route_find_for_me += 1; stat.route_find_miss_count += 1;#endif return false; // no path } /* * Build the path that we need... */ ID id; route.reset(); id.addr = net_id.addr; // source route is rooted at "us" id.type = ::IP; id.link_type = LT_NONE; id.log_stat = LS_NONE; route.appendToPath(id); for(v = 1; v < roff ; v++) { assert((int) (roff - v - 1) >= 0 && (roff - v - 1) < MAX_SR_LEN); Link *l = findLink(route[v-1].addr, rpath[roff - v - 1]); assert(l); id.addr = rpath[roff - v - 1]; id.type = ::IP; id.link_type = LT_NONE; id.log_stat = LS_NONE; route.appendToPath(id); route[v-1].t = l->ln_t; route[v-1].link_type = l->ln_linktype; route[v-1].log_stat = l->ln_logstat; } #ifdef DSR_CACHE_STATS int bad = checkRoute_logall(&route, ACTION_FIND_ROUTE, 0); stat.route_find_count += 1; if (for_me) stat.route_find_for_me += 1; stat.route_find_bad_count += bad ? 1 : 0; stat.link_find_count += route.length() - 1; stat.link_find_bad_count += bad;#endif return true;}voidLinkCache::Link_to_ID(Link *l, ID& id){ id.addr = l->ln_dst; id.type = ::IP; id.t = l->ln_t; id.link_type = l->ln_linktype; id.log_stat = l->ln_logstat;}////////////////////////////////////////////////////////////////////////////* * Dijkstra's algorithm taken from CLR. */voidLinkCache::init_single_source(int s){ int v; for(v = 1; v <= LC_MAX_NODES; v++) { d[v] = INFINITY; pi[v] = 0; // invalid node ID S[v] = false; } d[s] = 0;}voidLinkCache::relax(u_int32_t u, u_int32_t v, u_int32_t w){ assert(d[u] < INFINITY); if(d[v] > d[u] + w) { d[v] = d[u] + w; pi[v] = u; }}intLinkCache::extract_min_q(){ int u; int min_u = 0; for(u = 1; u <= LC_MAX_NODES; u++) { if(S[u] == false && d[u] < INFINITY && (min_u == 0 || d[u] < d[min_u])) { min_u = u; } } return min_u; // (min_u == 0) ==> no valid link}voidLinkCache::dijkstra(){ int u; Link *v; init_single_source(net_id.addr); while((u = extract_min_q()) != 0) { S[u] = true; v = lcache[u].lh_first; for( ; v; v = v->ln_link.le_next) { if(v->ln_flags & LINK_FLAG_UP) { relax(u, v->ln_dst, v->ln_cost); } } } dirty = 0; // all of the info is up-to-date}voidLinkCache::dump_dijkstra(int dst){ static char tbuf[512]; u_int32_t u, toff = 0; bzero(tbuf, sizeof(tbuf)); sprintf(tbuf, "SRC %.9f _%s_ dijkstra *%d* ", CURRENT_TIME, net_id.dump(), dst); toff = strlen(tbuf); for(u = 1; u <= LC_MAX_NODES; u++) { if(d[u] < INFINITY) { sprintf(tbuf+toff, "%d,%d,%d ", u, d[u], pi[u]); toff = strlen(tbuf); assert(toff < sizeof(tbuf)); } } trace("%s", tbuf);} ///////////////////////////////////////////////////////////////////////////intLinkCache::addLink(const ID& from, const ID& to, int flags, int cost, double timeout){ Link *l; int rc = 0; if((l = findLink(from.addr, to.addr)) == 0) { l = new Link(to.addr); assert(l); LIST_INSERT_HEAD(&lcache[from.addr], l, ln_link); dirty = 1; rc = 1; } l->ln_t = CURRENT_TIME; l->ln_linktype = from.link_type; l->ln_flags |= flags; l->ln_cost = cost; l->ln_timeout = timeout; if(lc_bidirectional_links == false) return rc; /* * Add the "other" direction of the link... */ if((l = findLink(to.addr, from.addr)) == 0) { l = new Link(from.addr); assert(l); LIST_INSERT_HEAD(&lcache[to.addr], l, ln_link); dirty = 1; } l->ln_t = CURRENT_TIME; l->ln_linktype = from.link_type; l->ln_flags |= flags; l->ln_cost = cost; l->ln_timeout = timeout; return rc;}intLinkCache::delLink(const ID& from, const ID& to){ Link *l; int rc = 0; if((l = findLink(from.addr, to.addr))) { LIST_REMOVE(l, ln_link); delete l; dirty = 1; rc = 1; } if(lc_bidirectional_links == false) return rc; /* * Remove the "other" direction of the link... */ if((l = findLink(to.addr, from.addr))) { LIST_REMOVE(l, ln_link); delete l; dirty = 1; } return rc;}Link*LinkCache::findLink(int from, int to){ Link *l; for(l = lcache[from].lh_first; l; l = l->ln_link.le_next) { if(l->ln_dst == to) { return l; } } return 0;}voidLinkCache::purgeLink(){ int u; Link *l; for(u = 1; u <= LC_MAX_NODES; u++) { if(d[u] == INFINITY) { ID from, to; from.addr = u; from.type = ::IP; from.link_type = LT_NONE; from.log_stat = LS_NONE; l = lcache[u].lh_first; for( ; l; l = l->ln_link.le_next) { Link_to_ID(l, to); checkLink_logall(from, to, ACTION_EVICT); (void) delLink(from, to); } } }}voidLinkCache::dumpLink(){ Link *l; int i; static char tbuf[512]; u_int32_t toff = 0; bzero(tbuf, sizeof(tbuf)); sprintf(tbuf, "SRC %.9f _%s_ dump-link ", CURRENT_TIME, net_id.dump()); toff = strlen(tbuf); for(i = 1; i <= LC_MAX_NODES; i++) { for(l = lcache[i].lh_first; l; l = l->ln_link.le_next) { sprintf(tbuf+toff, "%d->%d, ", i, l->ln_dst); toff = strlen(tbuf); assert(toff < sizeof(tbuf)); } } trace("%s", tbuf);}#ifdef DSR_CACHE_STATS/* * Called only from "purgeLink" */voidLinkCache::checkLink_logall(const ID& from, const ID& to, int action){ Link *l = findLink(from.addr, to.addr); assert(action == ACTION_EVICT); assert(l); if(God::instance()->hops(from.addr, to.addr) != 1) { trace("SRC %.9f _%s_ %s [%d %d] %s->%s dead %d %.9f", CURRENT_TIME, net_id.dump(), action_name[action], 0, 0, from.dump(), to.dump(), l->ln_linktype, l->ln_t); }}voidLinkCache::checkLink(const ID& from, const ID& to, int action){ Link *l = findLink(from.addr, to.addr); int alive = 0; assert(l); if(God::instance()->hops(from.addr, to.addr) != 1) { if(l->ln_logstat == LS_UNLOGGED) { trace("SRC %.9f _%s_ %s [%d %d] %s->%s dead %d %.9f", CURRENT_TIME, net_id.dump(), action_name[action], 0, 0, from.dump(), to.dump(), l->ln_linktype, l->ln_t); l->ln_logstat = LS_LOGGED; } } else { alive = 1; if(l->ln_logstat == LS_LOGGED) { trace("SRC %.9f _%s_ resurrected-link [%d %d] %s->%s dead %d %.9f", CURRENT_TIME, net_id.dump(), 0, 0, from.dump(), to.dump(), l->ln_linktype, l->ln_t); l->ln_logstat = LS_UNLOGGED; } } switch(action) { case ACTION_ADD_ROUTE: stat.link_add_count += 1; if(alive == 0){ stat.link_add_bad_count += 1; } if(l->ln_linktype == LT_TESTED) stat.link_add_tested += 1; break; case ACTION_NOTICE_ROUTE: stat.link_notice_count += 1; if(alive == 0){ stat.link_notice_bad_count += 1; } if(l->ln_linktype == LT_TESTED) stat.link_notice_tested += 1; break; }}voidLinkCache::periodic_checkCache(){ int c; int link_count = 0; int link_bad_count = 0; double link_bad_time = 0.0; int link_bad_tested = 0; int link_good_tested = 0; for(c = 1; c <= LC_MAX_NODES; c++) { Link *v = lcache[c].lh_first; for( ; v; v = v->ln_link.le_next) { link_count += 1; if(God::instance()->hops(c, v->ln_dst) != 1) { link_bad_count += 1; link_bad_time += CURRENT_TIME - v->ln_t; if(v->ln_linktype == LT_TESTED) link_bad_tested += 1; } else { if(v->ln_linktype == LT_TESTED) link_good_tested += 1; } } } trace("SRC %.9f _%s_ cache-summary %d %d %d %d | %d %.9f %d %d | %d %d %d %d %d | %d %d %d %d %d | %d %d %d %d %d %d", CURRENT_TIME, net_id.dump(), 0, //route_count, 0, // route_bad_count, link_count, // subroute_count, 0, // subroute_bad_count, link_bad_count, link_bad_count ? link_bad_time/link_bad_count : 0.0, link_bad_tested, link_good_tested, stat.route_add_count, // always 0 -- not increment stat.route_add_bad_count, // always 0 -- not increment stat.link_add_count, // stat.subroute_add_count, stat.link_add_bad_count, // stat.subroute_add_bad_count, stat.link_add_tested, stat.route_notice_count, stat.route_notice_bad_count, stat.link_notice_count, // stat.subroute_notice_count, stat.link_notice_bad_count, // stat.subroute_notice_bad_count, stat.link_notice_tested, stat.route_find_count, stat.route_find_for_me, stat.route_find_bad_count, stat.route_find_miss_count, stat.subroute_find_count, stat.subroute_find_bad_count); stat.reset();}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?