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         // TODO: verify this - added by ib
00221         msg->setRoutingTableArraySize(0);
00222         return;
00223     } else {
00224         itRows = rows.begin() + row - 1;
00225     }
00226     for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00227         if (!itCols->node.isUnspecified()) {
00228             ++size;
00229             msg->setRoutingTable(i++, itCols->node);
00230         }
00231     }
00232     msg->setRoutingTableArraySize(size);
00233 }
00234 
00235 //TODO ugly duplication of code
00236 void PastryRoutingTable::dumpRowToMessage(PastryStateMessage* msg,
00237                                           int row) const
00238 {
00239     uint32_t i = 0;
00240     uint32_t size = 0;
00241     std::vector<PRTRow>::const_iterator itRows;
00242     PRTRow::const_iterator itCols;
00243 
00244     msg->setRoutingTableArraySize(nodesPerRow);
00245     if ((row == -1) || (row > (int)rows.size())) {
00246         itRows = rows.end() - 1;
00247     } else if (row > (int)rows.size()) {
00248         EV << "asked for nonexistent row";
00249         // TODO: verify this - added by ib
00250         msg->setRoutingTableArraySize(0);
00251         return;
00252     } else {
00253         itRows = rows.begin() + row - 1;
00254     }
00255     for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00256         if (!itCols->node.isUnspecified()) {
00257             ++size;
00258             msg->setRoutingTable(i++, itCols->node);
00259         }
00260     }
00261     // TODO: verify this - added by ib
00262     msg->setRoutingTableArraySize(size);
00263 }
00264 
00265 int PastryRoutingTable::getLastRow()
00266 {
00267     return rows.size();
00268 }
00269 
00270 const TransportAddress& PastryRoutingTable::getRandomNode(int row)
00271 {
00272     std::vector<PRTRow>::const_iterator itRows;
00273     PRTRow::const_iterator itCols;
00274     uint32_t rnd;
00275 
00276     itRows = rows.begin() + row;
00277     if (itRows >= rows.end()) {
00278         EV << "[PastryRoutingTable::getRandomNode()]\n"
00279            << "    tried to get random Node from nonexistent row"
00280            << endl;
00281     }
00282     rnd = intuniform(0, nodesPerRow - 1, 0);
00283     itCols = itRows->begin() + rnd;
00284     while (itCols != itRows->end()) {
00285         if (!itCols->node.isUnspecified()) return itCols->node;
00286         else itCols++;
00287     }
00288     itCols = itRows->begin() + rnd;
00289     while (itCols >= itRows->begin()) {
00290         if (!itCols->node.isUnspecified()) return itCols->node;
00291         else itCols--;
00292     }
00293     return TransportAddress::UNSPECIFIED_NODE;
00294 }
00295 
00296 bool PastryRoutingTable::mergeNode(const NodeHandle& node, simtime_t prox)
00297 {
00298     if (node.getKey() == owner.getKey())
00299         opp_error("trying to merge node with same key!");
00300 
00301     uint32_t shl;
00302     uint32_t digit;
00303     PRTRow::iterator position;
00304 
00305     shl = owner.getKey().sharedPrefixLength(node.getKey()) / bitsPerDigit;
00306     digit = digitAt(shl, node.getKey());
00307 
00308     while (rows.size() <= shl) addRow();
00309     position = (rows.begin() + shl)->begin() + digit;
00310     if (position->node.isUnspecified() || (prox < position->rtt)) {
00311         EV << "[PastryRoutingTable::mergeNode()]\n"
00312            << "    Node " << owner.getKey()
00313            << endl;
00314         EV << "        placing node " << node.getKey() << "in row "
00315            << shl << ", col" << digit << endl;
00316         if (! position->node.isUnspecified()) {
00317             EV << "        (replaced because of better proximity: "
00318             << prox << " < " << position->rtt << ")" << endl;
00319         }
00320         position->node = node;
00321         position->rtt = prox;
00322         return true;
00323     }
00324     return false;
00325 }
00326 
00327 bool PastryRoutingTable::initStateFromHandleVector(const std::vector<PastryStateMsgHandle>& handles)
00328 {
00329     std::vector<PastryStateMsgHandle>::const_iterator it;
00330     int hopCheck = 0;
00331 
00332     for (it = handles.begin(); it != handles.end(); ++it) {
00333         if (it->msg->getJoinHopCount() != ++hopCheck) return false;
00334         mergeState(it->msg, it->prox);
00335     }
00336     return true;
00337 }
00338 
00339 void PastryRoutingTable::dumpToVector(std::vector<TransportAddress>& affected)
00340 const
00341 {
00342     std::vector<PRTRow>::const_iterator itRows;
00343     PRTRow::const_iterator itCols;
00344 
00345     for (itRows = rows.begin(); itRows != rows.end(); itRows++)
00346         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++)
00347             if (!itCols->node.isUnspecified())
00348                 affected.push_back(itCols->node);
00349 }
00350 
00351 void PastryRoutingTable::addRow(void)
00352 {
00353     PRTRow row(nodesPerRow, unspecNode());
00354 
00355     // place own node at correct position:
00356     (row.begin() + digitAt(rows.size(), owner.getKey()))->node = owner;
00357     rows.push_back(row);
00358 }
00359 
00360 std::ostream& operator<<(std::ostream& os, const PRTRow& row)
00361 {
00362     os << "Pastry IRoutingTable row {" << endl;
00363     for (PRTRow::const_iterator i = row.begin(); i != row.end(); i++) {
00364         os << "        " << i->node << " ; Ping: ";
00365         if (i->rtt != SimTime::getMaxTime())
00366             os << i->rtt << endl;
00367         else os << "<unknown>" << endl;
00368     }
00369     os << "    }";
00370     return os;
00371 }
00372 
00373 const TransportAddress& PastryRoutingTable::failedNode(const TransportAddress& failed)
00374 {
00375     std::vector<PRTRow>::iterator itRows;
00376     PRTRow::iterator itCols;
00377     PRTTrackRepair tmpTrack;
00378 
00379     bool found = false;
00380 
00381     // find node in table:
00382     for (itRows = rows.begin(); itRows != rows.end(); itRows++) {
00383         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00384             if ((! itCols->node.isUnspecified()) &&
00385                     (itCols->node.getAddress() == failed.getAddress())) {
00386                 itCols->node = NodeHandle::UNSPECIFIED_NODE;
00387                 itCols->rtt = PASTRY_PROX_UNDEF;
00388                 found = true;
00389                 break;
00390             }
00391         }
00392         if (found) break;
00393     }
00394 
00395     // not found, nothing to do:
00396     if (!found) return TransportAddress::UNSPECIFIED_NODE;
00397 
00398     // else fill temporary record:
00399     tmpTrack.failedRow = itRows - rows.begin();
00400     tmpTrack.failedCol = itCols - itRows->begin();
00401     tmpTrack.node = TransportAddress::UNSPECIFIED_NODE;
00402     findNextNodeToAsk(tmpTrack);
00403     tmpTrack.timestamp = simTime();
00404 
00405     if (tmpTrack.node.isUnspecified())
00406         return TransportAddress::UNSPECIFIED_NODE;
00407     awaitingRepair.push_back(tmpTrack);
00408     return awaitingRepair.back().node;
00409 }
00410 
00411 const TransportAddress& PastryRoutingTable::repair(const PastryStateMessage* msg,
00412                                                    const PastryStateMsgProximity* prox)
00413 {
00414     std::vector<PRTTrackRepair>::iterator it;
00415     simtime_t now = simTime();
00416 
00417     // first eliminate outdated entries in awaitingRepair:
00418     for (it = awaitingRepair.begin(); it != awaitingRepair.end();) {
00419         if (it->timestamp < (now - repairTimeout))
00420             it = awaitingRepair.erase(it);
00421         else it++;
00422     }
00423 
00424     // don't expect any more repair messages:
00425     if (awaitingRepair.empty()) return TransportAddress::UNSPECIFIED_NODE;
00426 
00427     // look for source node in our list:
00428     for (it = awaitingRepair.begin(); it != awaitingRepair.end(); it++)
00429         if (it->node == msg->getSender()) break;
00430 
00431     // if not found, return from function:
00432     if (it == awaitingRepair.end()) return TransportAddress::UNSPECIFIED_NODE;
00433 
00434     // merge state:
00435     mergeState(msg, prox);
00436 
00437     // repair not yet done?
00438     if (nodeAt(it->failedRow, it->failedCol).node.isUnspecified()) {
00439         // ask next node
00440         findNextNodeToAsk(*it);
00441         if (it->node.isUnspecified()) {
00442             // no more nodes to ask, give up:
00443             EV << "[PastryRoutingTable::repair()]\n"
00444                << "    RoutingTable giving up repair attempt."
00445                << endl;
00446             awaitingRepair.erase(it);
00447             return TransportAddress::UNSPECIFIED_NODE;
00448         }
00449         else return it->node;
00450     }
00451 
00452     // repair done: clean up
00453     EV << "[PastryRoutingTable::repair()]\n"
00454        << "    RoutingTable repair was successful."
00455        << endl;
00456     return TransportAddress::UNSPECIFIED_NODE;
00457 }
00458 
00459 void PastryRoutingTable::findNextNodeToAsk(PRTTrackRepair& track) const
00460 {
00461     const TransportAddress* ask;
00462 
00463     if (track.node.isUnspecified()) {
00464         track.askedRow = track.failedRow;
00465         if (track.failedCol == 0)
00466             track.askedCol = 1;
00467         else
00468             track.askedCol = 0;
00469         ask = static_cast<const TransportAddress*>(
00470                 &(nodeAt(track.askedRow, track.askedCol).node));
00471         track.node = *ask;
00472         if ( (! track.node.isUnspecified()) &&
00473                 (track.node != owner) )
00474             return;
00475     }
00476 
00477     do {
00478         // point to next possible position in routing table:
00479         track.askedCol++;
00480         if ((track.askedRow == track.failedRow) &&
00481                 (track.askedCol == track.failedCol)) track.askedCol++;
00482         if (track.askedCol == nodesPerRow) {
00483             if ((track.askedRow > track.askedCol) ||
00484                     (track.askedRow == (rows.size() - 1))) {
00485                 // no more nodes that could be asked, give up:
00486                 track.node = TransportAddress::UNSPECIFIED_NODE;
00487                 return;
00488             }
00489             track.askedRow++;
00490             track.askedCol = 0;
00491         }
00492 
00493         ask = static_cast<const TransportAddress*>(
00494                 &(nodeAt(track.askedRow, track.askedCol).node));
00495 
00496 //        if (!ask->isUnspecified() && !track.node.isUnspecified() && track.node == *ask)
00497 //            std::cout << "burp! " << owner.getKey() << " " << (static_cast<const NodeHandle*>(ask))->key << "\n("
00498 //            << track.failedRow << ", " << track.failedCol << ") -> ("
00499 //            << track.askedRow << ", " << track.askedCol << ")"
00500 //            << std::endl;
00501 
00502         if (track.node.isUnspecified() ||
00503             (!ask->isUnspecified() && track.node != *ask))
00504             track.node = *ask; //only happens if track.node == owner
00505         else track.node = TransportAddress::UNSPECIFIED_NODE;
00506     }
00507     while (track.node.isUnspecified() || (track.node == owner) );
00508 }
00509 
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3