PastryRoutingTable.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 
00024 #include "PastryRoutingTable.h"
00025 
00026 Define_Module(PastryRoutingTable);
00027 
00028 uint32_t PastryRoutingTable::digitAt(uint32_t n,
00029                                      const OverlayKey& key) const
00030 {
00031     return key.getBitRange(OverlayKey::getLength() - ++n * bitsPerDigit, bitsPerDigit);
00032 }
00033 
00034 void PastryRoutingTable::earlyInit(void)
00035 {
00036     WATCH_VECTOR(rows);
00037 }
00038 
00039 void PastryRoutingTable::initializeTable(uint32_t bitsPerDigit,
00040                                          double repairTimeout,
00041                                          const NodeHandle& owner)
00042 {
00043     this->owner = owner;
00044     this->repairTimeout = repairTimeout;
00045     this->bitsPerDigit = bitsPerDigit;
00046     nodesPerRow = 1 << bitsPerDigit; // 2 ^ bitsPerDigit
00047 
00048     // forget old routing table contents in case of restart:
00049     if (!rows.empty()) rows.clear();
00050 
00051     // clear pending repair requests:
00052     if (!awaitingRepair.empty()) awaitingRepair.clear();
00053 
00054     // Create first row in table:
00055     addRow();
00056 }
00057 
00058 const PastryExtendedNode& PastryRoutingTable::nodeAt(uint32_t row, uint32_t col) const
00059 {
00060     if (rows.size() <= row) return unspecNode();
00061     if (col >= nodesPerRow) return unspecNode();
00062 
00063     return *((rows.begin()+row)->begin()+col);
00064 }
00065 
00066 const NodeHandle& PastryRoutingTable::lookupNextHop(const OverlayKey& destination)
00067 {
00068     if (destination == owner.getKey()) opp_error("trying to lookup own key!");
00069 
00070     uint32_t shl = owner.getKey().sharedPrefixLength(destination) / bitsPerDigit;
00071     uint32_t digit = digitAt(shl, destination);
00072 
00073     if (shl >= rows.size()) {
00074         EV << "Pastry: Unable to find next hop for " << destination
00075         << ", row is empty." << endl;
00076         return NodeHandle::UNSPECIFIED_NODE;
00077     }
00078 
00079     const PastryExtendedNode& next = nodeAt(shl, digit);
00080 
00081     if (next.node.isUnspecified()) {
00082         EV << "Pastry: Unable to find next hop for " << destination <<
00083         ", routing table entry is empty." << endl;
00084     }
00085     return next.node;
00086 }
00087 
00088 const NodeHandle& PastryRoutingTable::findCloserNode(const OverlayKey& destination,
00089                                                      bool optimize)
00090 {
00091     if (destination == owner.getKey())
00092         opp_error("trying to find closer node to own key!");
00093 
00094     const PastryExtendedNode* entry;
00095 
00096     if (optimize) {
00097         // pointer to later return value, initialize to unspecified, so
00098         // the specialCloserCondition() check will be done against our own
00099         // node as long as no node closer to the destination than our own was
00100         // found.
00101         const NodeHandle* ret = &NodeHandle::UNSPECIFIED_NODE;
00102 
00103         // a numerically closer node can only be found in the row containing
00104         // nodes with the same prefix length and in the row above.
00105         int shl = owner.getKey().sharedPrefixLength(destination) / bitsPerDigit;
00106         int digit = digitAt(shl, destination);
00107         int x = digitAt(shl, owner.getKey()); // position index of own node
00108 
00109         // first try the row with same prefix length:
00110         int n = nodesPerRow;
00111         int a = digit - 1; // position index of search to the left
00112         int b = digit + 1; // position index of search to the right
00113 
00114         while ((a >= 0) || (b < n)) {
00115             // no need to continue search in one direction when own entry is
00116             // reached:
00117             if (a == x) a = -1;
00118             if (b == x) b = n;
00119 
00120             if (a >= 0) {
00121                 entry = &(nodeAt(shl, a));
00122                 if ((!entry->node.isUnspecified()) &&
00123                         specialCloserCondition(entry->node, destination, *ret))
00124                     ret = &(entry->node);
00125                 a--;
00126             }
00127             if (b < n) {
00128                 entry = &(nodeAt(shl, b));
00129                 if ((!entry->node.isUnspecified()) &&
00130                         specialCloserCondition(entry->node, destination, *ret))
00131                     ret = &(entry->node);
00132                 b++;
00133             }
00134         }
00135 
00136         // it this was not the first row, two more nodes to check:
00137         if (shl != 0) {
00138             // go up one row:
00139             x = digitAt(--shl, owner.getKey());
00140 
00141             if (destination < owner.getKey()) {
00142                 entry = &(nodeAt(shl, digit - 1));
00143                 if ((!entry->node.isUnspecified()) &&
00144                         specialCloserCondition(entry->node, destination, *ret))
00145                     ret = &(entry->node);
00146             } else {
00147                 entry = &(nodeAt(shl, digit + 1));
00148                 if ((!entry->node.isUnspecified()) &&
00149                         specialCloserCondition(entry->node, destination, *ret))
00150                     ret = &(entry->node);
00151             }
00152         }
00153 
00154         return *ret; // still unspecified if no closer node was found
00155     } else {
00156         // no optimization, return the first closer node found
00157         for (uint32_t y = 0; y < rows.size(); ++y) {
00158             for (uint32_t x = 0; x < nodesPerRow; ++x) {
00159                 entry = &(nodeAt(y, x));
00160                 if ((!entry->node.isUnspecified()) &&
00161                         specialCloserCondition(entry->node, destination))
00162                     return entry->node;
00163             }
00164         }
00165 
00166         return NodeHandle::UNSPECIFIED_NODE;
00167     }
00168 }
00169 
00170 void PastryRoutingTable::findCloserNodes(const OverlayKey& destination,
00171                                          NodeVector* nodes)
00172 {
00173     //TODO
00174     const PastryExtendedNode* entry;
00175 
00176     for (uint32_t y = 0; y < rows.size(); ++y) {
00177         for (uint32_t x = 0; x < nodesPerRow; ++x) {
00178             entry = &(nodeAt(y, x));
00179             if (!entry->node.isUnspecified()
00180             /* && specialCloserCondition(entry->node, destination)*/)
00181                 nodes->add(entry->node);
00182         }
00183     }
00184 }
00185 
00186 void PastryRoutingTable::dumpToStateMessage(PastryStateMessage* msg) const
00187 {
00188     uint32_t i = 0;
00189     uint32_t size = 0;
00190     std::vector<PRTRow>::const_iterator itRows;
00191     PRTRow::const_iterator itCols;
00192 
00193     msg->setRoutingTableArraySize(rows.size() * nodesPerRow);
00194 
00195     for (itRows = rows.begin(); itRows != rows.end(); itRows++) {
00196         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00197             if (!itCols->node.isUnspecified()) {
00198                 ++size;
00199                 msg->setRoutingTable(i++, itCols->node);
00200             }
00201         }
00202     }
00203     msg->setRoutingTableArraySize(size);
00204 
00205 }
00206 
00207 void PastryRoutingTable::dumpRowToMessage(PastryRoutingRowMessage* msg,
00208                                           int row) const
00209 {
00210     uint32_t i = 0;
00211     uint32_t size = 0;
00212     std::vector<PRTRow>::const_iterator itRows;
00213     PRTRow::const_iterator itCols;
00214 
00215     msg->setRoutingTableArraySize(nodesPerRow);
00216     if (row == -1) {
00217         itRows = rows.end() - 1;
00218     } else if (row > (int)rows.size()) {
00219         EV << "asked for nonexistent row";
00220         return;
00221     } else {
00222         itRows = rows.begin() + row - 1;
00223     }
00224     for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00225         if (!itCols->node.isUnspecified()) {
00226             ++size;
00227             msg->setRoutingTable(i++, itCols->node);
00228         }
00229     }
00230     msg->setRoutingTableArraySize(size);
00231 }
00232 
00233 //TODO ugly duplication of code
00234 void PastryRoutingTable::dumpRowToMessage(PastryStateMessage* msg,
00235                                           int row) const
00236 {
00237     uint32_t i = 0;
00238     uint32_t size = 0;
00239     std::vector<PRTRow>::const_iterator itRows;
00240     PRTRow::const_iterator itCols;
00241 
00242     msg->setRoutingTableArraySize(nodesPerRow);
00243     if ((row == -1) || (row > (int)rows.size())) {
00244         itRows = rows.end() - 1;
00245     } else if (row > (int)rows.size()) {
00246         EV << "asked for nonexistent row";
00247         return;
00248     } else {
00249         itRows = rows.begin() + row - 1;
00250     }
00251     for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00252         if (!itCols->node.isUnspecified()) {
00253             ++size;
00254             msg->setRoutingTable(i++, itCols->node);
00255         }
00256     }
00257 }
00258 
00259 int PastryRoutingTable::getLastRow()
00260 {
00261     return rows.size();
00262 }
00263 
00264 const TransportAddress& PastryRoutingTable::getRandomNode(int row)
00265 {
00266     std::vector<PRTRow>::const_iterator itRows;
00267     PRTRow::const_iterator itCols;
00268     uint32_t rnd;
00269 
00270     itRows = rows.begin() + row;
00271     if (itRows >= rows.end()) {
00272         EV << "[PastryRoutingTable::getRandomNode()]\n"
00273            << "    tried to get random Node from nonexistent row"
00274            << endl;
00275     }
00276     rnd = intuniform(0, nodesPerRow - 1, 0);
00277     itCols = itRows->begin() + rnd;
00278     while (itCols != itRows->end()) {
00279         if (!itCols->node.isUnspecified()) return itCols->node;
00280         else itCols++;
00281     }
00282     itCols = itRows->begin() + rnd;
00283     while (itCols >= itRows->begin()) {
00284         if (!itCols->node.isUnspecified()) return itCols->node;
00285         else itCols--;
00286     }
00287     return TransportAddress::UNSPECIFIED_NODE;
00288 }
00289 
00290 bool PastryRoutingTable::mergeNode(const NodeHandle& node, simtime_t prox)
00291 {
00292     if (node.getKey() == owner.getKey())
00293         opp_error("trying to merge node with same key!");
00294 
00295     uint32_t shl;
00296     uint32_t digit;
00297     PRTRow::iterator position;
00298 
00299     shl = owner.getKey().sharedPrefixLength(node.getKey()) / bitsPerDigit;
00300     digit = digitAt(shl, node.getKey());
00301 
00302     while (rows.size() <= shl) addRow();
00303     position = (rows.begin() + shl)->begin() + digit;
00304     if (position->node.isUnspecified() || (prox < position->rtt)) {
00305         EV << "[PastryRoutingTable::mergeNode()]\n"
00306            << "    Node " << owner.getKey()
00307            << endl;
00308         EV << "        placing node " << node.getKey() << "in row "
00309            << shl << ", col" << digit << endl;
00310         if (! position->node.isUnspecified()) {
00311             EV << "        (replaced because of better proximity: "
00312             << prox << " < " << position->rtt << ")" << endl;
00313         }
00314         position->node = node;
00315         position->rtt = prox;
00316         return true;
00317     }
00318     return false;
00319 }
00320 
00321 bool PastryRoutingTable::initStateFromHandleVector(const std::vector<PastryStateMsgHandle>& handles)
00322 {
00323     std::vector<PastryStateMsgHandle>::const_iterator it;
00324     int hopCheck = 0;
00325 
00326     for (it = handles.begin(); it != handles.end(); ++it) {
00327         if (it->msg->getJoinHopCount() != ++hopCheck) return false;
00328         mergeState(it->msg, it->prox);
00329     }
00330     return true;
00331 }
00332 
00333 void PastryRoutingTable::dumpToVector(std::vector<TransportAddress>& affected)
00334 const
00335 {
00336     std::vector<PRTRow>::const_iterator itRows;
00337     PRTRow::const_iterator itCols;
00338 
00339     for (itRows = rows.begin(); itRows != rows.end(); itRows++)
00340         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++)
00341             if (!itCols->node.isUnspecified())
00342                 affected.push_back(itCols->node);
00343 }
00344 
00345 void PastryRoutingTable::addRow(void)
00346 {
00347     PRTRow row(nodesPerRow, unspecNode());
00348 
00349     // place own node at correct position:
00350     (row.begin() + digitAt(rows.size(), owner.getKey()))->node = owner;
00351     rows.push_back(row);
00352 }
00353 
00354 std::ostream& operator<<(std::ostream& os, const PRTRow& row)
00355 {
00356     os << "Pastry IRoutingTable row {" << endl;
00357     for (PRTRow::const_iterator i = row.begin(); i != row.end(); i++) {
00358         os << "        " << i->node << " ; Ping: ";
00359         if (i->rtt != SimTime::getMaxTime())
00360             os << i->rtt << endl;
00361         else os << "<unknown>" << endl;
00362     }
00363     os << "    }";
00364     return os;
00365 }
00366 
00367 const TransportAddress& PastryRoutingTable::failedNode(const TransportAddress& failed)
00368 {
00369     std::vector<PRTRow>::iterator itRows;
00370     PRTRow::iterator itCols;
00371     PRTTrackRepair tmpTrack;
00372 
00373     bool found = false;
00374 
00375     // find node in table:
00376     for (itRows = rows.begin(); itRows != rows.end(); itRows++) {
00377         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00378             if ((! itCols->node.isUnspecified()) &&
00379                     (itCols->node.getAddress() == failed.getAddress())) {
00380                 itCols->node = NodeHandle::UNSPECIFIED_NODE;
00381                 itCols->rtt = PASTRY_PROX_UNDEF;
00382                 found = true;
00383                 break;
00384             }
00385         }
00386         if (found) break;
00387     }
00388 
00389     // not found, nothing to do:
00390     if (!found) return TransportAddress::UNSPECIFIED_NODE;
00391 
00392     // else fill temporary record:
00393     tmpTrack.failedRow = itRows - rows.begin();
00394     tmpTrack.failedCol = itCols - itRows->begin();
00395     tmpTrack.node = TransportAddress::UNSPECIFIED_NODE;
00396     findNextNodeToAsk(tmpTrack);
00397     tmpTrack.timestamp = simTime();
00398 
00399     if (tmpTrack.node.isUnspecified())
00400         return TransportAddress::UNSPECIFIED_NODE;
00401     awaitingRepair.push_back(tmpTrack);
00402     return awaitingRepair.back().node;
00403 }
00404 
00405 const TransportAddress& PastryRoutingTable::repair(const PastryStateMessage* msg,
00406                                                    const PastryStateMsgProximity* prox)
00407 {
00408     std::vector<PRTTrackRepair>::iterator it;
00409     simtime_t now = simTime();
00410 
00411     // first eliminate outdated entries in awaitingRepair:
00412     for (it = awaitingRepair.begin(); it != awaitingRepair.end();) {
00413         if (it->timestamp < (now - repairTimeout))
00414             it = awaitingRepair.erase(it);
00415         else it++;
00416     }
00417 
00418     // don't expect any more repair messages:
00419     if (awaitingRepair.empty()) return TransportAddress::UNSPECIFIED_NODE;
00420 
00421     // look for source node in our list:
00422     for (it = awaitingRepair.begin(); it != awaitingRepair.end(); it++)
00423         if (it->node == msg->getSender()) break;
00424 
00425     // if not found, return from function:
00426     if (it == awaitingRepair.end()) return TransportAddress::UNSPECIFIED_NODE;
00427 
00428     // merge state:
00429     mergeState(msg, prox);
00430 
00431     // repair not yet done?
00432     if (nodeAt(it->failedRow, it->failedCol).node.isUnspecified()) {
00433         // ask next node
00434         findNextNodeToAsk(*it);
00435         if (it->node.isUnspecified()) {
00436             // no more nodes to ask, give up:
00437             EV << "[PastryRoutingTable::repair()]\n"
00438                << "    RoutingTable giving up repair attempt."
00439                << endl;
00440             awaitingRepair.erase(it);
00441             return TransportAddress::UNSPECIFIED_NODE;
00442         }
00443         else return it->node;
00444     }
00445 
00446     // repair done: clean up
00447     EV << "[PastryRoutingTable::repair()]\n"
00448        << "    RoutingTable repair was successful."
00449        << endl;
00450     return TransportAddress::UNSPECIFIED_NODE;
00451 }
00452 
00453 void PastryRoutingTable::findNextNodeToAsk(PRTTrackRepair& track) const
00454 {
00455     const TransportAddress* ask;
00456 
00457     if (track.node.isUnspecified()) {
00458         track.askedRow = track.failedRow;
00459         if (track.failedCol == 0)
00460             track.askedCol = 1;
00461         else
00462             track.askedCol = 0;
00463         ask = static_cast<const TransportAddress*>(
00464                 &(nodeAt(track.askedRow, track.askedCol).node));
00465         track.node = *ask;
00466         if ( (! track.node.isUnspecified()) &&
00467                 (track.node != owner) )
00468             return;
00469     }
00470 
00471     do {
00472         // point to next possible position in routing table:
00473         track.askedCol++;
00474         if ((track.askedRow == track.failedRow) &&
00475                 (track.askedCol == track.failedCol)) track.askedCol++;
00476         if (track.askedCol == nodesPerRow) {
00477             if ((track.askedRow > track.askedCol) ||
00478                     (track.askedRow == (rows.size() - 1))) {
00479                 // no more nodes that could be asked, give up:
00480                 track.node = TransportAddress::UNSPECIFIED_NODE;
00481                 return;
00482             }
00483             track.askedRow++;
00484             track.askedCol = 0;
00485         }
00486 
00487         ask = static_cast<const TransportAddress*>(
00488                 &(nodeAt(track.askedRow, track.askedCol).node));
00489 
00490 //        if (!ask->isUnspecified() && !track.node.isUnspecified() && track.node == *ask)
00491 //            std::cout << "burp! " << owner.getKey() << " " << (static_cast<const NodeHandle*>(ask))->key << "\n("
00492 //            << track.failedRow << ", " << track.failedCol << ") -> ("
00493 //            << track.askedRow << ", " << track.askedCol << ")"
00494 //            << std::endl;
00495 
00496         if (track.node.isUnspecified() ||
00497             (!ask->isUnspecified() && track.node != *ask))
00498             track.node = *ask; //only happens if track.node == owner
00499         else track.node = TransportAddress::UNSPECIFIED_NODE;
00500     }
00501     while (track.node.isUnspecified() || (track.node == owner) );
00502 }
00503 

Generated on Tue Sep 8 17:26:53 2009 for OverSim by  doxygen 1.5.8