PastryRoutingTable Class Reference

#include <PastryRoutingTable.h>

Inheritance diagram for PastryRoutingTable:

PastryStateObject

List of all members.


Detailed Description

Routing table module.

This module contains the routing table of the Chord implementation.

Author:
Felix Palmen
See also:
Pastry

Public Member Functions

void initializeTable (uint bitsPerDigit, double repairTimeout, const NodeHandle &owner)
 Initializes the routing table.
const NodeHandlelookupNextHop (const OverlayKey &destination)
 gets the next hop according to the Pastry routing scheme.
virtual const NodeHandlefindCloserNode (const OverlayKey &destination, bool optimize=false)
 try to find a node numerically closer to a given key with the same shared prefix as the current node in the routing table.
void findCloserNodes (const OverlayKey &destination, NodeVector *nodes)
virtual const TransportAddressfailedNode (const TransportAddress &failed)
 tells the routing table that a node has failed
virtual const TransportAddressrepair (const PastryStateMessage *msg, const PastryStateMsgProximity &prox)
 attempt to repair the routing using a received REPAIR message
virtual void dumpToStateMessage (PastryStateMessage *msg) const
 dump content of the table to a PastryStateMessage
virtual void dumpRowToMessage (PastryRoutingRowMessage *msg, int row) const
 dump content of a single row of the routing table to a message
virtual void dumpRowToMessage (PastryStateMessage *msg, int row) const
 dump content of a single row of the routing table to a state message
int getLastRow ()
 gets the number of rows in the routing table
virtual const TransportAddressgetRandomNode (int row)
 returns a random node from the routing table
bool mergeNode (const NodeHandle &node, simtime_t prox)
 merge a node in the RoutingTable
bool initStateFromHandleVector (const std::vector< PastryStateMsgHandle > &handles)
 initialize table from vector of PastryStateMsgHandles with STATE messages received during JOIN phase.
virtual void dumpToVector (std::vector< TransportAddress > &affected) const
 appends all routing table entries to a given vector of TransportAddresses, needed to find all Nodes to be notified after joining.

Public Attributes

uint nodesPerRow

Private Member Functions

virtual void earlyInit (void)
 initialize watches etc.
void addRow (void)
 adds a new line to the routing table
uint32_t digitAt (uint n, const OverlayKey &key) const
 returns n'th pastry digit from a key
const PastryExtendedNodenodeAt (uint row, uint col) const
 returns routing table entry at specified position
void findNextNodeToAsk (PRTTrackRepair &track) const
 helper function, updates a PRTTrackRepair structure to point to the next node that can be asked for repair

Private Attributes

double repairTimeout
std::vector< PRTRowrows
std::vector< PRTTrackRepairawaitingRepair

Member Function Documentation

void PastryRoutingTable::initializeTable ( uint  bitsPerDigit,
double  repairTimeout,
const NodeHandle owner 
)

Initializes the routing table.

This should be called on startup

Parameters:
bitsPerDigit Pastry configuration parameter
repairTimeout Pastry configuration parameter
owner the node this table belongs to

Referenced by BasePastry::baseChangeState().

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 }

const NodeHandle & PastryRoutingTable::lookupNextHop ( const OverlayKey destination  ) 

gets the next hop according to the Pastry routing scheme.

Parameters:
destination the destination key
Returns:
the NodeHandle of the next Node or NodeHandle::UNSPECIFIED_NODE if no next hop could be determined

Referenced by BasePastry::findNode().

00067 {
00068     if (destination == owner.key) opp_error("trying to lookup own key!");
00069 
00070     uint shl = owner.key.sharedPrefixLength(destination) / bitsPerDigit;
00071     uint 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 }

const NodeHandle & PastryRoutingTable::findCloserNode ( const OverlayKey destination,
bool  optimize = false 
) [virtual]

try to find a node numerically closer to a given key with the same shared prefix as the current node in the routing table.

this method is to be called, when a regular next hop couldn't be found or wasn't reachable.

Parameters:
destination the destination key
optimize if set, check all nodes and return the best/closest one
Returns:
a closer NodeHandle or NodeHandle::UNSPECIFIED_NODE if none was found

Implements PastryStateObject.

Referenced by BasePastry::findNode().

00090 {
00091     if (destination == owner.key)
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.key.sharedPrefixLength(destination) / bitsPerDigit;
00106         int digit = digitAt(shl, destination);
00107         int x = digitAt(shl, owner.key); // 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.key);
00140 
00141             if (destination < owner.key) {
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 (uint y = 0; y < rows.size(); ++y) {
00158             for (uint 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 }

void PastryRoutingTable::findCloserNodes ( const OverlayKey destination,
NodeVector nodes 
) [virtual]

Implements PastryStateObject.

Referenced by BasePastry::findNode().

00172 {
00173     //TODO
00174     const PastryExtendedNode* entry;
00175 
00176     for (uint y = 0; y < rows.size(); ++y) {
00177         for (uint 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 }

const TransportAddress & PastryRoutingTable::failedNode ( const TransportAddress failed  )  [virtual]

tells the routing table that a node has failed

Parameters:
failed the failed node
Returns:
a node to ask for REPAIR or TransportAddress::UNSPECIFIED_NODE

Implements PastryStateObject.

Referenced by Pastry::handleFailedNode(), and Bamboo::handleFailedNode().

00333 {
00334     std::vector<PRTRow>::iterator itRows;
00335     PRTRow::iterator itCols;
00336     PRTTrackRepair tmpTrack;
00337 
00338     bool found = false;
00339 
00340     // find node in table:
00341     for (itRows = rows.begin(); itRows != rows.end(); itRows++) {
00342         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
00343             if ((! itCols->node.isUnspecified()) &&
00344                     (itCols->node.ip == failed.ip)) {
00345                 itCols->node = NodeHandle::UNSPECIFIED_NODE;
00346                 itCols->rtt = PASTRY_PROX_UNDEF;
00347                 found = true;
00348                 break;
00349             }
00350         }
00351         if (found) break;
00352     }
00353 
00354     // not found, nothing to do:
00355     if (!found) return TransportAddress::UNSPECIFIED_NODE;
00356 
00357     // else fill temporary record:
00358     tmpTrack.failedRow = itRows - rows.begin();
00359     tmpTrack.failedCol = itCols - itRows->begin();
00360     tmpTrack.node = TransportAddress::UNSPECIFIED_NODE;
00361     findNextNodeToAsk(tmpTrack);
00362     tmpTrack.timestamp = simTime();
00363 
00364     if (tmpTrack.node.isUnspecified())
00365         return TransportAddress::UNSPECIFIED_NODE;
00366     awaitingRepair.push_back(tmpTrack);
00367     return awaitingRepair.back().node;
00368 }

const TransportAddress & PastryRoutingTable::repair ( const PastryStateMessage *  msg,
const PastryStateMsgProximity prox 
) [virtual]

attempt to repair the routing using a received REPAIR message

Parameters:
msg the state message of type REPAIR
prox record of proximity values matching the state message
Returns:
another node to ask for REPAIR or TransportAddress::UNSPECIFIED_NODE

Reimplemented from PastryStateObject.

Referenced by Pastry::checkProxCache().

00372 {
00373     std::vector<PRTTrackRepair>::iterator it;
00374     simtime_t now = simTime();
00375 
00376     // first eliminate outdated entries in awaitingRepair:
00377     for (it = awaitingRepair.begin(); it != awaitingRepair.end();) {
00378         if (it->timestamp < (now - repairTimeout))
00379             it = awaitingRepair.erase(it);
00380         else it++;
00381     }
00382 
00383     // don't expect any more repair messages:
00384     if (awaitingRepair.empty()) return TransportAddress::UNSPECIFIED_NODE;
00385 
00386     // look for source node in our list:
00387     for (it = awaitingRepair.begin(); it != awaitingRepair.end(); it++)
00388         if (it->node == msg->getSender()) break;
00389 
00390     // if not found, return from function:
00391     if (it == awaitingRepair.end()) return TransportAddress::UNSPECIFIED_NODE;
00392 
00393     // merge state:
00394     mergeState(msg, prox);
00395 
00396     // repair not yet done?
00397     if (nodeAt(it->failedRow, it->failedCol).node.isUnspecified()) {
00398         // ask next node
00399         findNextNodeToAsk(*it);
00400         if (it->node.isUnspecified()) {
00401             // no more nodes to ask, give up:
00402             EV << "Pastry: RoutingTable giving up repair attempt." << endl;
00403             awaitingRepair.erase(it);
00404             return TransportAddress::UNSPECIFIED_NODE;
00405         }
00406         else return it->node;
00407     }
00408 
00409     // repair done: clean up
00410     EV << "Pastry: RoutingTable repair was successful." << endl;
00411     awaitingRepair.erase(it);
00412     return TransportAddress::UNSPECIFIED_NODE;
00413 }

void PastryRoutingTable::dumpToStateMessage ( PastryStateMessage *  msg  )  const [virtual]

dump content of the table to a PastryStateMessage

Parameters:
msg the PastryStateMessage to be filled with entries

Implements PastryStateObject.

Referenced by BasePastry::sendStateTables().

00187 {
00188     uint i = 0;
00189     std::vector<PRTRow>::const_iterator itRows;
00190     PRTRow::const_iterator itCols;
00191 
00192     msg->setRoutingTableArraySize(rows.size() * nodesPerRow);
00193 
00194     for (itRows = rows.begin(); itRows != rows.end(); itRows++)
00195         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++)
00196             msg->setRoutingTable(i++, itCols->node);
00197 }

void PastryRoutingTable::dumpRowToMessage ( PastryRoutingRowMessage *  msg,
int  row 
) const [virtual]

dump content of a single row of the routing table to a message

Parameters:
msg the message to be filled with entries
row the number of the row

Referenced by BasePastry::sendRoutingRow().

00200 {
00201     uint i = 0;
00202     std::vector<PRTRow>::const_iterator itRows;
00203     PRTRow::const_iterator itCols;
00204 
00205     msg->setRoutingTableArraySize(nodesPerRow);
00206     if (row == -1) 
00207         itRows = rows.end() - 1;
00208     else if (row > (int)rows.size()) {
00209         EV << "asked for nonexistent row";
00210         return;
00211     }
00212     else itRows = rows.begin() + row - 1;
00213     for (itCols = itRows->begin(); itCols != itRows->end(); itCols++)
00214         msg->setRoutingTable(i++, itCols->node);
00215 }

void PastryRoutingTable::dumpRowToMessage ( PastryStateMessage *  msg,
int  row 
) const [virtual]

dump content of a single row of the routing table to a state message

Parameters:
msg the state message to be filled with entries
row the number of the row
00219 {
00220     uint i = 0;
00221     std::vector<PRTRow>::const_iterator itRows;
00222     PRTRow::const_iterator itCols;
00223 
00224     msg->setRoutingTableArraySize(nodesPerRow);
00225     if ((row == -1) || (row > (int)rows.size())) 
00226         itRows = rows.end() - 1;
00227     else if (row > (int)rows.size()) {
00228         EV << "asked for nonexistent row";
00229         return;
00230     }
00231     else itRows = rows.begin() + row - 1;
00232     for (itCols = itRows->begin(); itCols != itRows->end(); itCols++)
00233         msg->setRoutingTable(i++, itCols->node);
00234 }

int PastryRoutingTable::getLastRow (  ) 

gets the number of rows in the routing table

Returns:
the number of rows in the routing table

Referenced by BasePastry::doRoutingTableMaintenance(), Pastry::handleUDPMessage(), and Bamboo::handleUDPMessage().

00237 {
00238     return rows.size();
00239 }

const TransportAddress & PastryRoutingTable::getRandomNode ( int  row  )  [virtual]

returns a random node from the routing table

Parameters:
row the row to choose a random node from
Returns:
a random node or TransportAddress::UNSPECIFIED_NODE

Referenced by BasePastry::doRoutingTableMaintenance().

00242 {
00243     std::vector<PRTRow>::const_iterator itRows;
00244     PRTRow::const_iterator itCols;
00245     uint rnd;
00246 
00247     itRows = rows.begin() + row;
00248     if (itRows >= rows.end()) {
00249         EV << "tried to get random Node from nonexistent row";
00250         return TransportAddress::UNSPECIFIED_NODE;
00251     }
00252           rnd = intuniform(0, nodesPerRow - 1, 0);
00253     itCols = itRows->begin() + rnd;
00254     while (itCols != itRows->end()) {
00255         if (!itCols->node.isUnspecified()) return itCols->node;
00256         else itCols++;
00257     }
00258     return TransportAddress::UNSPECIFIED_NODE;
00259 }

bool PastryRoutingTable::mergeNode ( const NodeHandle node,
simtime_t  prox 
) [virtual]

merge a node in the RoutingTable

Parameters:
node the node to merge
prox proximity value of the node
Returns:
true if node was merged

Implements PastryStateObject.

00262 {
00263     if (node.key == owner.key)
00264         opp_error("trying to merge node with same key!");
00265 
00266     uint shl;
00267     uint digit;
00268     PRTRow::iterator position;
00269 
00270     shl = owner.key.sharedPrefixLength(node.key) / bitsPerDigit;
00271     digit = digitAt(shl, node.key);
00272 
00273     while (rows.size() <= shl) addRow();
00274     position = (rows.begin() + shl)->begin() + digit;
00275     if (position->node.isUnspecified() || (prox < position->rtt)) {
00276         EV << "Pastry: Node " << owner.key << endl;
00277         EV << "        placing node " << node.key << "in row "
00278            << shl << ", col" << digit << endl;
00279         if (! position->node.isUnspecified()) {
00280             EV << "        (replaced because of better proximity: "
00281             << prox << " < " << position->rtt << ")" << endl;
00282         }
00283         position->node = node;
00284         position->rtt = prox;
00285         return true;
00286     }
00287     return false;
00288 }

bool PastryRoutingTable::initStateFromHandleVector ( const std::vector< PastryStateMsgHandle > &  handles  ) 

initialize table from vector of PastryStateMsgHandles with STATE messages received during JOIN phase.

The vector has to be sorted by JoinHopCount of the messages

Parameters:
handles the vector of PastryStateMsgHandles
Returns:
true on success

Referenced by Pastry::checkProxCache().

00291 {
00292     std::vector<PastryStateMsgHandle>::const_iterator it;
00293     int hopCheck = 0;
00294 
00295     for (it = handles.begin(); it != handles.end(); ++it) {
00296         if (it->msg->getJoinHopCount() != ++hopCheck) return false;
00297         mergeState(it->msg, *(it->prox));
00298     }
00299     return true;
00300 }

void PastryRoutingTable::dumpToVector ( std::vector< TransportAddress > &  affected  )  const [virtual]

appends all routing table entries to a given vector of TransportAddresses, needed to find all Nodes to be notified after joining.

Parameters:
affected the vector to fill with routing table entries

Implements PastryStateObject.

Referenced by Pastry::changeState(), and Pastry::doSecondStage().

00304 {
00305     std::vector<PRTRow>::const_iterator itRows;
00306     PRTRow::const_iterator itCols;
00307 
00308     for (itRows = rows.begin(); itRows != rows.end(); itRows++)
00309         for (itCols = itRows->begin(); itCols != itRows->end(); itCols++)
00310             if (!itCols->node.isUnspecified())
00311                 affected.push_back(itCols->node);
00312 }

void PastryRoutingTable::earlyInit ( void   )  [private, virtual]

initialize watches etc.

Implements PastryStateObject.

00035 {
00036     WATCH_VECTOR(rows);
00037 }

void PastryRoutingTable::addRow ( void   )  [private]

adds a new line to the routing table

Referenced by initializeTable(), and mergeNode().

00315 {
00316     PRTRow row(nodesPerRow, unspecNode);
00317 
00318     // place own node at correct position:
00319     (row.begin() + digitAt(rows.size(), owner.key))->node = owner;
00320     rows.push_back(row);
00321 }

uint32_t PastryRoutingTable::digitAt ( uint  n,
const OverlayKey key 
) const [private]

returns n'th pastry digit from a key

Parameters:
n which digit to return
key extract digit from this key
Returns:
a pastry digit

Referenced by addRow(), findCloserNode(), lookupNextHop(), and mergeNode().

00030 {
00031     return key.getBitRange(OverlayKey::getLength() - ++n * bitsPerDigit, bitsPerDigit);
00032 }

const PastryExtendedNode & PastryRoutingTable::nodeAt ( uint  row,
uint  col 
) const [private]

returns routing table entry at specified position

Parameters:
row the number of the row
col the number of the column

Referenced by findCloserNode(), findCloserNodes(), findNextNodeToAsk(), lookupNextHop(), and repair().

00059 {
00060     if (rows.size() <= row) return unspecNode;
00061     if (col >= nodesPerRow) return unspecNode;
00062 
00063     return *((rows.begin()+row)->begin()+col);
00064 }

void PastryRoutingTable::findNextNodeToAsk ( PRTTrackRepair track  )  const [private]

helper function, updates a PRTTrackRepair structure to point to the next node that can be asked for repair

Parameters:
track the PRTTrackRepair structure

Referenced by failedNode(), and repair().

00416 {
00417     const TransportAddress* ask;
00418 
00419     if (track.node.isUnspecified()) {
00420         track.askedRow = track.failedRow;
00421         if (track.failedCol == 0)
00422             track.askedCol = 1;
00423         else
00424             track.askedCol = 0;
00425         ask = static_cast<const TransportAddress*>(
00426                 &(nodeAt(track.askedRow, track.askedCol).node));
00427         track.node = *ask;
00428         if ( (! track.node.isUnspecified()) &&
00429                 (track.node != owner) )
00430             return;
00431     }
00432 
00433     do {
00434         // point to next possible position in routing table:
00435         track.askedCol++;
00436         if ((track.askedRow == track.failedRow) &&
00437                 (track.askedCol == track.failedCol)) track.askedCol++;
00438         if (track.askedCol == nodesPerRow) {
00439             if ((track.askedRow > track.askedCol) ||
00440                     (track.askedRow == (rows.size() - 1))) {
00441                 // no more nodes that could be asked, give up:
00442                 track.node = TransportAddress::UNSPECIFIED_NODE;
00443                 return;
00444             }
00445             track.askedRow++;
00446             track.askedCol = 0;
00447         }
00448 
00449         ask = static_cast<const TransportAddress*>(
00450                 &(nodeAt(track.askedRow, track.askedCol).node));
00451 
00452 //        if (!ask->isUnspecified() && !track.node.isUnspecified() && track.node == *ask)
00453 //            std::cout << "burp! " << owner.key << " " << (static_cast<const NodeHandle*>(ask))->key << "\n("
00454 //            << track.failedRow << ", " << track.failedCol << ") -> ("
00455 //            << track.askedRow << ", " << track.askedCol << ")"
00456 //            << std::endl;
00457 
00458         if (track.node.isUnspecified() ||
00459             (!ask->isUnspecified() && track.node != *ask))
00460             track.node = *ask; //only happens if track.node == owner
00461         else track.node = TransportAddress::UNSPECIFIED_NODE;
00462     }
00463     while (track.node.isUnspecified() || (track.node == owner) );
00464 }


Member Data Documentation

Referenced by repair().

std::vector<PRTRow> PastryRoutingTable::rows [private]

Referenced by failedNode(), initializeTable(), and repair().


The documentation for this class was generated from the following files:

Generated on Fri Sep 19 13:05:07 2008 for ITM OverSim by  doxygen 1.5.5