#include <PastryRoutingTable.h>
This module contains the routing table of the Chord implementation.
Public Member Functions | |
void | initializeTable (uint bitsPerDigit, double repairTimeout, const NodeHandle &owner) |
Initializes the routing table. | |
const NodeHandle & | lookupNextHop (const OverlayKey &destination) |
gets the next hop according to the Pastry routing scheme. | |
virtual const NodeHandle & | findCloserNode (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 TransportAddress & | failedNode (const TransportAddress &failed) |
tells the routing table that a node has failed | |
virtual const TransportAddress & | repair (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 | |
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. | |
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 PastryExtendedNode & | nodeAt (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 | |
uint | bitsPerDigit |
double | repairTimeout |
uint | nodesPerRow |
std::vector< PRTRow > | rows |
std::vector < PRTTrackRepair > | awaitingRepair |
void PastryRoutingTable::initializeTable | ( | uint | bitsPerDigit, | |
double | repairTimeout, | |||
const NodeHandle & | owner | |||
) |
Initializes the routing table.
This should be called on startup
bitsPerDigit | Pastry configuration parameter | |
repairTimeout | Pastry configuration parameter | |
owner | the node this table belongs to |
00041 { 00042 this->owner = owner; 00043 this->repairTimeout = repairTimeout; 00044 this->bitsPerDigit = bitsPerDigit; 00045 nodesPerRow = 1 << bitsPerDigit; // 2 ^ bitsPerDigit 00046 00047 // forget old routing table contents in case of restart: 00048 if (!rows.empty()) rows.clear(); 00049 00050 // clear pending repair requests: 00051 if (!awaitingRepair.empty()) awaitingRepair.clear(); 00052 00053 // Create first row in table: 00054 addRow(); 00055 }
const NodeHandle & PastryRoutingTable::lookupNextHop | ( | const OverlayKey & | destination | ) |
gets the next hop according to the Pastry routing scheme.
destination | the destination key |
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 { 00075 EV << "Pastry: Unable to find next hop for " << destination 00076 << ", row is empty." << endl; 00077 return NodeHandle::UNSPECIFIED_NODE; 00078 } 00079 00080 const PastryExtendedNode& next = nodeAt(shl, digit); 00081 00082 if (next.node.isUnspecified()) 00083 { 00084 EV << "Pastry: Unable to find next hop for " << destination << 00085 ", routing table entry is empty." << endl; 00086 } 00087 return next.node; 00088 }
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.
destination | the destination key | |
optimize | if set, check all nodes and return the best/closest one |
Implements PastryStateObject.
00092 { 00093 if (destination == owner.key) 00094 opp_error("trying to find closer node to own key!"); 00095 00096 const PastryExtendedNode* entry; 00097 00098 if (optimize) 00099 { 00100 // pointer to later return value, initialize to unspecified, so 00101 // the specialCloserCondition() check will be done against our own 00102 // node as long as no node closer to the destination than our own was 00103 // found. 00104 const NodeHandle* ret = &NodeHandle::UNSPECIFIED_NODE; 00105 00106 // a numerically closer node can only be found in the row containing 00107 // nodes with the same prefix length and in the row above. 00108 int shl = owner.key.sharedPrefixLength(destination) / bitsPerDigit; 00109 int digit = digitAt(shl, destination); 00110 int x = digitAt(shl, owner.key); // position index of own node 00111 00112 // first try the row with same prefix length: 00113 int n = nodesPerRow; 00114 int a = digit - 1; // position index of search to the left 00115 int b = digit + 1; // position index of search to the right 00116 00117 while ((a >= 0) || (b < n)) 00118 { 00119 // no need to continue search in one direction when own entry is 00120 // reached: 00121 if (a == x) a = -1; 00122 if (b == x) b = n; 00123 00124 if (a >= 0) 00125 { 00126 entry = &(nodeAt(shl, a)); 00127 if ((!entry->node.isUnspecified()) && 00128 specialCloserCondition(entry->node, destination, *ret)) 00129 ret = &(entry->node); 00130 a--; 00131 } 00132 if (b < n) 00133 { 00134 entry = &(nodeAt(shl, b)); 00135 if ((!entry->node.isUnspecified()) && 00136 specialCloserCondition(entry->node, destination, *ret)) 00137 ret = &(entry->node); 00138 b++; 00139 } 00140 } 00141 00142 // it this was not the first row, two more nodes to check: 00143 if (shl != 0) 00144 { 00145 // go up one row: 00146 x = digitAt(--shl, owner.key); 00147 00148 if (destination < owner.key) 00149 { 00150 entry = &(nodeAt(shl, digit - 1)); 00151 if ((!entry->node.isUnspecified()) && 00152 specialCloserCondition(entry->node, destination, *ret)) 00153 ret = &(entry->node); 00154 } 00155 else 00156 { 00157 entry = &(nodeAt(shl, digit + 1)); 00158 if ((!entry->node.isUnspecified()) && 00159 specialCloserCondition(entry->node, destination, *ret)) 00160 ret = &(entry->node); 00161 } 00162 } 00163 00164 return *ret; // still unspecified if no closer node was found 00165 } 00166 else 00167 { 00168 // no optimization, return the first closer node found 00169 for (uint y = 0; y < rows.size(); ++y) 00170 { 00171 for (uint x = 0; x < nodesPerRow; ++x) 00172 { 00173 entry = &(nodeAt(y, x)); 00174 if ((!entry->node.isUnspecified()) && 00175 specialCloserCondition(entry->node, destination)) 00176 return entry->node; 00177 } 00178 } 00179 00180 return NodeHandle::UNSPECIFIED_NODE; 00181 } 00182 }
void PastryRoutingTable::findCloserNodes | ( | const OverlayKey & | destination, | |
NodeVector * | nodes | |||
) | [virtual] |
Implements PastryStateObject.
00186 { 00187 //TODO 00188 const PastryExtendedNode* entry; 00189 00190 for (uint y = 0; y < rows.size(); ++y) { 00191 for (uint x = 0; x < nodesPerRow; ++x) { 00192 entry = &(nodeAt(y, x)); 00193 if (!entry->node.isUnspecified() 00194 /* && specialCloserCondition(entry->node, destination)*/) 00195 nodes->add(entry->node); 00196 } 00197 } 00198 }
const TransportAddress & PastryRoutingTable::failedNode | ( | const TransportAddress & | failed | ) | [virtual] |
tells the routing table that a node has failed
failed | the failed node |
Implements PastryStateObject.
00290 { 00291 std::vector<PRTRow>::iterator itRows; 00292 PRTRow::iterator itCols; 00293 PRTTrackRepair tmpTrack; 00294 00295 bool found = false; 00296 00297 // find node in table: 00298 for (itRows = rows.begin(); itRows != rows.end(); itRows++) 00299 { 00300 for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) 00301 { 00302 if ((! itCols->node.isUnspecified()) && 00303 (itCols->node.ip == failed.ip)) 00304 { 00305 itCols->node = NodeHandle::UNSPECIFIED_NODE; 00306 itCols->rtt = PASTRY_PROX_UNDEF; 00307 found = true; 00308 break; 00309 } 00310 } 00311 if (found) break; 00312 } 00313 00314 // not found, nothing to do: 00315 if (!found) return TransportAddress::UNSPECIFIED_NODE; 00316 00317 // else fill temporary record: 00318 tmpTrack.failedRow = itRows - rows.begin(); 00319 tmpTrack.failedCol = itCols - itRows->begin(); 00320 tmpTrack.node = TransportAddress::UNSPECIFIED_NODE; 00321 findNextNodeToAsk(tmpTrack); 00322 tmpTrack.timestamp = simTime(); 00323 00324 if (tmpTrack.node.isUnspecified()) 00325 return TransportAddress::UNSPECIFIED_NODE; 00326 awaitingRepair.push_back(tmpTrack); 00327 return awaitingRepair.back().node; 00328 }
const TransportAddress & PastryRoutingTable::repair | ( | const PastryStateMessage * | msg, | |
const PastryStateMsgProximity & | prox | |||
) | [virtual] |
attempt to repair the routing using a received REPAIR message
msg | the state message of type REPAIR | |
prox | record of proximity values matching the state message |
Reimplemented from PastryStateObject.
00332 { 00333 std::vector<PRTTrackRepair>::iterator it; 00334 simtime_t now = simTime(); 00335 00336 // first eliminate outdated entries in awaitingRepair: 00337 for (it = awaitingRepair.begin(); it != awaitingRepair.end();) 00338 { 00339 if (it->timestamp < (now - repairTimeout)) 00340 it = awaitingRepair.erase(it); 00341 else it++; 00342 } 00343 00344 // don't expect any more repair messages: 00345 if (awaitingRepair.empty()) return TransportAddress::UNSPECIFIED_NODE; 00346 00347 // look for source node in our list: 00348 for (it = awaitingRepair.begin(); it != awaitingRepair.end(); it++) 00349 if (it->node == msg->getSender()) break; 00350 00351 // if not found, return from function: 00352 if (it == awaitingRepair.end()) return TransportAddress::UNSPECIFIED_NODE; 00353 00354 // merge state: 00355 mergeState(msg, prox); 00356 00357 // repair not yet done? 00358 if (nodeAt(it->failedRow, it->failedCol).node.isUnspecified()) 00359 { 00360 // ask next node 00361 findNextNodeToAsk(*it); 00362 if (it->node.isUnspecified()) 00363 { 00364 // no more nodes to ask, give up: 00365 EV << "Pastry: RoutingTable giving up repair attempt." << endl; 00366 awaitingRepair.erase(it); 00367 return TransportAddress::UNSPECIFIED_NODE; 00368 } 00369 else return it->node; 00370 } 00371 00372 // repair done: clean up 00373 EV << "Pastry: RoutingTable repair was successful." << endl; 00374 awaitingRepair.erase(it); 00375 return TransportAddress::UNSPECIFIED_NODE; 00376 }
void PastryRoutingTable::dumpToStateMessage | ( | PastryStateMessage * | msg | ) | const [virtual] |
dump content of the table to a PastryStateMessage
msg | the PastryStateMessage to be filled with entries |
Implements PastryStateObject.
00201 { 00202 uint i = 0; 00203 std::vector<PRTRow>::const_iterator itRows; 00204 PRTRow::const_iterator itCols; 00205 00206 msg->setRoutingTableArraySize(rows.size() * nodesPerRow); 00207 00208 for (itRows = rows.begin(); itRows != rows.end(); itRows++) 00209 for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) 00210 msg->setRoutingTable(i++, itCols->node); 00211 }
bool PastryRoutingTable::mergeNode | ( | const NodeHandle & | node, | |
simtime_t | prox | |||
) | [virtual] |
merge a node in the RoutingTable
node | the node to merge | |
prox | proximity value of the node |
Implements PastryStateObject.
00214 { 00215 if (node.key == owner.key) 00216 opp_error("trying to merge node with same key!"); 00217 00218 uint shl; 00219 uint digit; 00220 PRTRow::iterator position; 00221 00222 shl = owner.key.sharedPrefixLength(node.key) / bitsPerDigit; 00223 digit = digitAt(shl, node.key); 00224 00225 while (rows.size() <= shl) addRow(); 00226 position = (rows.begin() + shl)->begin() + digit; 00227 if (position->node.isUnspecified() || (prox < position->rtt)) 00228 { 00229 EV << "Pastry: Node " << owner.key << endl; 00230 EV << " placing node " << node.key << "in row " 00231 << shl << ", col" << digit << endl; 00232 if (! position->node.isUnspecified()) 00233 { 00234 EV << " (replaced because of better proximity: " 00235 << prox << " < " << position->rtt << ")" << endl; 00236 } 00237 position->node = node; 00238 position->rtt = prox; 00239 return true; 00240 } 00241 return false; 00242 }
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
handles | the vector of PastryStateMsgHandles |
00246 { 00247 std::vector<PastryStateMsgHandle>::const_iterator it; 00248 int hopCheck = 0; 00249 00250 for (it = handles.begin(); it != handles.end(); ++it) 00251 { 00252 if (it->msg->getJoinHopCount() != ++hopCheck) return false; 00253 mergeState(it->msg, *(it->prox)); 00254 } 00255 return true; 00256 }
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.
affected | the vector to fill with routing table entries |
Implements PastryStateObject.
00260 { 00261 std::vector<PRTRow>::const_iterator itRows; 00262 PRTRow::const_iterator itCols; 00263 00264 for (itRows = rows.begin(); itRows != rows.end(); itRows++) 00265 for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) 00266 if (!itCols->node.isUnspecified()) 00267 affected.push_back(itCols->node); 00268 }
void PastryRoutingTable::earlyInit | ( | void | ) | [private, virtual] |
void PastryRoutingTable::addRow | ( | void | ) | [private] |
adds a new line to the routing table
00271 { 00272 PRTRow row(nodesPerRow, unspecNode); 00273 00274 // place own node at correct position: 00275 (row.begin() + digitAt(rows.size(), owner.key))->node = owner; 00276 rows.push_back(row); 00277 }
uint32_t PastryRoutingTable::digitAt | ( | uint | n, | |
const OverlayKey & | key | |||
) | const [private] |
returns n'th pastry digit from a key
n | which digit to return | |
key | extract digit from this key |
00030 { 00031 return key.get(OverlayKey::getLength() - ++n*bitsPerDigit, bitsPerDigit); 00032 }
const PastryExtendedNode & PastryRoutingTable::nodeAt | ( | uint | row, | |
uint | col | |||
) | const [private] |
returns routing table entry at specified position
row | the number of the row | |
col | the number of the column |
00058 { 00059 if (rows.size() <= row) return unspecNode; 00060 if (col >= nodesPerRow) return unspecNode; 00061 00062 return *((rows.begin()+row)->begin()+col); 00063 }
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
track | the PRTTrackRepair structure |
00379 { 00380 const TransportAddress* ask; 00381 00382 if (track.node.isUnspecified()) 00383 { 00384 track.askedRow = track.failedRow; 00385 if (track.failedCol == 0) 00386 track.askedCol = 1; 00387 else 00388 track.askedCol = 0; 00389 ask = static_cast<const TransportAddress*>( 00390 &(nodeAt(track.askedRow, track.askedCol).node)); 00391 track.node = *ask; 00392 if ( (! track.node.isUnspecified()) && 00393 (track.node != owner) ) 00394 return; 00395 } 00396 00397 do 00398 { 00399 // point to next possible position in routing table: 00400 track.askedCol++; 00401 if ((track.askedRow == track.failedRow) && 00402 (track.askedCol == track.failedCol)) track.askedCol++; 00403 if (track.askedCol == nodesPerRow) 00404 { 00405 if ((track.askedRow > track.askedCol) || 00406 (track.askedRow == (rows.size() - 1))) 00407 { 00408 // no more nodes that could be asked, give up: 00409 track.node = TransportAddress::UNSPECIFIED_NODE; 00410 return; 00411 } 00412 track.askedRow++; 00413 track.askedCol = 0; 00414 } 00415 00416 ask = static_cast<const TransportAddress*>( 00417 &(nodeAt(track.askedRow, track.askedCol).node)); 00418 00419 // if (!ask->isUnspecified() && !track.node.isUnspecified() && track.node == *ask) 00420 // std::cout << "burp! " << owner.key << " " << (static_cast<const NodeHandle*>(ask))->key << "\n(" 00421 // << track.failedRow << ", " << track.failedCol << ") -> (" 00422 // << track.askedRow << ", " << track.askedCol << ")" 00423 // << std::endl; 00424 00425 if(track.node.isUnspecified() || 00426 (!ask->isUnspecified() && track.node != *ask)) track.node = *ask; //only happens if track.node == owner 00427 else track.node = TransportAddress::UNSPECIFIED_NODE; 00428 } 00429 while (track.node.isUnspecified() || (track.node == owner) ); 00430 }
uint PastryRoutingTable::bitsPerDigit [private] |
double PastryRoutingTable::repairTimeout [private] |
uint PastryRoutingTable::nodesPerRow [private] |
std::vector<PRTRow> PastryRoutingTable::rows [private] |
std::vector<PRTTrackRepair> PastryRoutingTable::awaitingRepair [private] |