OverSim
PastryRoutingTable.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
24 #include "PastryRoutingTable.h"
25 
26 
28 
29 uint32_t PastryRoutingTable::digitAt(uint32_t n,
30  const OverlayKey& key) const
31 {
32  return key.getBitRange(OverlayKey::getLength() - ++n * bitsPerDigit,
33  bitsPerDigit);
34 }
35 
36 
38 {
39  WATCH_VECTOR(rows);
40 }
41 
42 
43 void PastryRoutingTable::initializeTable(uint32_t bitsPerDigit,
44  double repairTimeout,
45  const NodeHandle& owner)
46 {
47  this->owner = owner;
48  this->repairTimeout = repairTimeout;
49  this->bitsPerDigit = bitsPerDigit;
50  nodesPerRow = 1 << bitsPerDigit; // 2 ^ bitsPerDigit
51 
52  // forget old routing table contents in case of restart:
53  if (!rows.empty()) rows.clear();
54 
55  // clear pending repair requests:
56  if (!awaitingRepair.empty()) awaitingRepair.clear();
57 
58  // Create first row in table:
59  addRow();
60 }
61 
62 
64  uint32_t col) const
65 {
66  if (rows.size() <= row) return unspecNode();
67  if (col >= nodesPerRow) return unspecNode();
68 
69  return *((rows.begin()+row)->begin()+col);
70 }
71 
72 
74 {
75  if (destination == owner.getKey()) opp_error("trying to lookup own key!");
76 
77  uint32_t shl = owner.getKey().sharedPrefixLength(destination) / bitsPerDigit;
78  uint32_t digit = digitAt(shl, destination);
79 
80  if (shl >= rows.size()) {
81  EV << "Pastry: Unable to find next hop for " << destination
82  << ", row is empty." << endl;
84  }
85 
86  const PastryExtendedNode& next = nodeAt(shl, digit);
87 
88  if (next.node.isUnspecified()) {
89  EV << "Pastry: Unable to find next hop for " << destination
90  << ", routing table entry is empty." << endl;
91  }
92  return next.node;
93 }
94 
95 
97  bool optimize)
98 {
99  if (destination == owner.getKey())
100  opp_error("trying to find closer node to own key!");
101 
102  const PastryExtendedNode* entry;
103 
104  if (optimize) {
105  // pointer to later return value, initialize to unspecified, so
106  // the specialCloserCondition() check will be done against our own
107  // node as long as no node closer to the destination than our own was
108  // found.
110 
111  // a numerically closer node can only be found in the row containing
112  // nodes with the same prefix length and in the row above.
113  int shl = owner.getKey().sharedPrefixLength(destination) / bitsPerDigit;
114  int digit = digitAt(shl, destination);
115  int x = digitAt(shl, owner.getKey()); // position index of own node
116 
117  // first try the row with same prefix length:
118  int n = nodesPerRow;
119  int a = digit - 1; // position index of search to the left
120  int b = digit + 1; // position index of search to the right
121 
122  while ((a >= 0) || (b < n)) {
123  // no need to continue search in one direction when own entry is
124  // reached:
125  if (a == x) a = -1;
126  if (b == x) b = n;
127 
128  if (a >= 0) {
129  entry = &(nodeAt(shl, a));
130  if ((!entry->node.isUnspecified()) &&
131  specialCloserCondition(entry->node, destination, *ret))
132  ret = &(entry->node);
133  a--;
134  }
135  if (b < n) {
136  entry = &(nodeAt(shl, b));
137  if ((!entry->node.isUnspecified()) &&
138  specialCloserCondition(entry->node, destination, *ret))
139  ret = &(entry->node);
140  b++;
141  }
142  }
143 
144  // it this was not the first row, two more nodes to check:
145  if (shl != 0) {
146  // go up one row:
147  x = digitAt(--shl, owner.getKey());
148 
149  if (destination < owner.getKey()) {
150  entry = &(nodeAt(shl, digit - 1));
151  if ((!entry->node.isUnspecified()) &&
152  specialCloserCondition(entry->node, destination, *ret))
153  ret = &(entry->node);
154  } else {
155  entry = &(nodeAt(shl, digit + 1));
156  if ((!entry->node.isUnspecified()) &&
157  specialCloserCondition(entry->node, destination, *ret))
158  ret = &(entry->node);
159  }
160  }
161 
162  return *ret; // still unspecified if no closer node was found
163  } else {
164  // no optimization, return the first closer node found
165  for (uint32_t y = 0; y < rows.size(); ++y) {
166  for (uint32_t x = 0; x < nodesPerRow; ++x) {
167  entry = &(nodeAt(y, x));
168  if ((!entry->node.isUnspecified()) &&
169  specialCloserCondition(entry->node, destination))
170  return entry->node;
171  }
172  }
173 
175  }
176 }
177 
178 
180  NodeVector* nodes)
181 {
182  //TODO
183  const PastryExtendedNode* entry;
184 
185  for (uint32_t y = 0; y < rows.size(); ++y) {
186  for (uint32_t x = 0; x < nodesPerRow; ++x) {
187  entry = &(nodeAt(y, x));
188  if (!entry->node.isUnspecified()
189  /* && specialCloserCondition(entry->node, destination)*/)
190  nodes->add(entry->node);
191  }
192  }
193 }
194 
195 
197 {
198  uint32_t i = 0;
199  uint32_t size = 0;
200  std::vector<PRTRow>::const_iterator itRows;
201  PRTRow::const_iterator itCols;
202 
204 
205  for (itRows = rows.begin(); itRows != rows.end(); itRows++) {
206  for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
207  if (!itCols->node.isUnspecified()) {
208  ++size;
209  msg->setRoutingTable(i++, itCols->node);
210  }
211  }
212  }
213  msg->setRoutingTableArraySize(size);
214 }
215 
216 
218  int row) const
219 {
220  uint32_t i = 0;
221  uint32_t size = 0;
222  std::vector<PRTRow>::const_iterator itRows;
223  PRTRow::const_iterator itCols;
224 
226  if ((row == -1) || (row > (int)rows.size())) {
227  itRows = rows.end() - 1;
228  } else if (row > (int)rows.size()) {
229  EV << "asked for nonexistent row";
230  // TODO: verify this - added by ib
231  msg->setRoutingTableArraySize(0);
232  return;
233  } else {
234  itRows = rows.begin() + row - 1;
235  }
236  for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
237  if (!itCols->node.isUnspecified()) {
238  ++size;
239  msg->setRoutingTable(i++, itCols->node);
240  }
241  }
242  // TODO: verify this - added by ib
243  msg->setRoutingTableArraySize(size);
244 }
245 
246 
247 std::vector<TransportAddress>* PastryRoutingTable::getRow(uint8_t row) const
248 {
249  std::vector<TransportAddress>* temp = new std::vector<TransportAddress>;
250  if ((row < 1) || (row > (int)rows.size())) return temp;
251 
252  std::vector<PRTRow>::const_iterator itRows = rows.begin() + row - 1;
253 
254  for (PRTRow::const_iterator itCols = itRows->begin();
255  itCols != itRows->end(); ++itCols) {
256  if (itCols != itRows->end() && !itCols->node.isUnspecified()) {
257  temp->push_back(itCols->node);
258  }
259  }
260  return temp;
261 }
262 
263 
265 {
266  return rows.size();
267 }
268 
269 
271 {
272  std::vector<PRTRow>::const_iterator itRows;
273  PRTRow::const_iterator itCols;
274  uint32_t rnd;
275 
276  itRows = rows.begin() + row;
277  if (itRows >= rows.end()) {
278  EV << "[PastryRoutingTable::getRandomNode()]\n"
279  << " tried to get random Node from nonexistent row"
280  << endl;
281  }
282  rnd = intuniform(0, nodesPerRow - 1, 0);
283  itCols = itRows->begin() + rnd;
284  while (itCols != itRows->end()) {
285  if (!itCols->node.isUnspecified()) return itCols->node;
286  else itCols++;
287  }
288  itCols = itRows->begin() + rnd;
289  while (itCols >= itRows->begin()) {
290  if (!itCols->node.isUnspecified()) return itCols->node;
291  else itCols--;
292  }
294 }
295 
296 
297 bool PastryRoutingTable::mergeNode(const NodeHandle& node, simtime_t prox)
298 {
299  if (node.getKey() == owner.getKey())
300  opp_error("trying to merge node with same key!");
301 
302  uint32_t shl;
303  uint32_t digit;
304  PRTRow::iterator position;
305 
307  digit = digitAt(shl, node.getKey());
308 
309  while (rows.size() <= shl) addRow();
310  position = (rows.begin() + shl)->begin() + digit;
311  if (position->node.isUnspecified() || (prox < position->rtt)) {
312  EV << "[PastryRoutingTable::mergeNode()]\n"
313  << " Node " << owner.getKey()
314  << endl;
315  EV << " placing node " << node.getKey() << "in row "
316  << shl << ", col" << digit << endl;
317  if (! position->node.isUnspecified()) {
318  EV << " (replaced because of better proximity: "
319  << prox << " < " << position->rtt << ")" << endl;
320  }
321  position->node = node;
322  position->rtt = prox;
323  return true;
324  }
325  return false;
326 }
327 
328 
329 bool PastryRoutingTable::initStateFromHandleVector(const std::vector<PastryStateMsgHandle>& handles)
330 {
331  std::vector<PastryStateMsgHandle>::const_iterator it;
332  int hopCheck = 0;
333 
334  for (it = handles.begin(); it != handles.end(); ++it) {
335  if (it->msg->getRow() != ++hopCheck) return false;
336  mergeState(it->msg, it->prox);
337  }
338  return true;
339 }
340 
341 
342 void PastryRoutingTable::dumpToVector(std::vector<TransportAddress>& affected) const
343 {
344  std::vector<PRTRow>::const_iterator itRows;
345  PRTRow::const_iterator itCols;
346 
347  for (itRows = rows.begin(); itRows != rows.end(); ++itRows)
348  for (itCols = itRows->begin(); itCols != itRows->end(); ++itCols)
349  if (!itCols->node.isUnspecified())
350  affected.push_back(itCols->node);
351 }
352 
353 
355 {
356  PRTRow row(nodesPerRow, unspecNode());
357 
358  // place own node at correct position:
359  (row.begin() + digitAt(rows.size(), owner.getKey()))->node = owner;
360  rows.push_back(row);
361 }
362 
363 
364 std::ostream& operator<<(std::ostream& os, const PRTRow& row)
365 {
366  os << "Pastry IRoutingTable row {" << endl;
367  for (PRTRow::const_iterator i = row.begin(); i != row.end(); i++) {
368  os << " " << i->node << " ; Ping: ";
369  if (i->rtt != SimTime::getMaxTime())
370  os << i->rtt << endl;
371  else os << "<unknown>" << endl;
372  }
373  os << " }";
374  return os;
375 }
376 
377 
379 {
380  std::vector<PRTRow>::iterator itRows;
381  PRTRow::iterator itCols;
382  PRTTrackRepair tmpTrack;
383 
384  bool found = false;
385 
386  // find node in table:
387  for (itRows = rows.begin(); itRows != rows.end(); itRows++) {
388  for (itCols = itRows->begin(); itCols != itRows->end(); itCols++) {
389  if ((! itCols->node.isUnspecified()) &&
390  (itCols->node.getIp() == failed.getIp())) {
392  itCols->rtt = PASTRY_PROX_UNDEF;
393  found = true;
394  break;
395  }
396  }
397  if (found) break;
398  }
399 
400  // not found, nothing to do:
401  if (!found) return TransportAddress::UNSPECIFIED_NODE;
402 
403  // else fill temporary record:
404  tmpTrack.failedRow = itRows - rows.begin();
405  tmpTrack.failedCol = itCols - itRows->begin();
407  findNextNodeToAsk(tmpTrack);
408  tmpTrack.timestamp = simTime();
409 
410  if (tmpTrack.node.isUnspecified())
412  awaitingRepair.push_back(tmpTrack);
413  return awaitingRepair.back().node;
414 }
415 
416 
418  const PastryStateMsgProximity* prox)
419 {
420  std::vector<PRTTrackRepair>::iterator it;
421  simtime_t now = simTime();
422 
423  // first eliminate outdated entries in awaitingRepair:
424  for (it = awaitingRepair.begin(); it != awaitingRepair.end();) {
425  if (it->timestamp < (now - repairTimeout))
426  it = awaitingRepair.erase(it);
427  else it++;
428  }
429 
430  // don't expect any more repair messages:
432 
433  // look for source node in our list:
434  for (it = awaitingRepair.begin(); it != awaitingRepair.end(); it++)
435  if (it->node == msg->getSender()) break;
436 
437  // if not found, return from function:
438  if (it == awaitingRepair.end()) return TransportAddress::UNSPECIFIED_NODE;
439 
440  // merge state:
441  mergeState(msg, prox);
442 
443  // repair not yet done?
444  if (nodeAt(it->failedRow, it->failedCol).node.isUnspecified()) {
445  // ask next node
446  findNextNodeToAsk(*it);
447  if (it->node.isUnspecified()) {
448  // no more nodes to ask, give up:
449  EV << "[PastryRoutingTable::repair()]\n"
450  << " RoutingTable giving up repair attempt."
451  << endl;
452  awaitingRepair.erase(it);
454  }
455  else return it->node;
456  }
457 
458  // repair done: clean up
459  EV << "[PastryRoutingTable::repair()]\n"
460  << " RoutingTable repair was successful."
461  << endl;
463 }
464 
465 
467 {
468  const TransportAddress* ask;
469 
470  if (track.node.isUnspecified()) {
471  track.askedRow = track.failedRow;
472  if (track.failedCol == 0)
473  track.askedCol = 1;
474  else
475  track.askedCol = 0;
476  ask = static_cast<const TransportAddress*>(
477  &(nodeAt(track.askedRow, track.askedCol).node));
478  track.node = *ask;
479  if ( (! track.node.isUnspecified()) &&
480  (track.node != owner) )
481  return;
482  }
483 
484  do {
485  // point to next possible position in routing table:
486  track.askedCol++;
487  if ((track.askedRow == track.failedRow) &&
488  (track.askedCol == track.failedCol)) track.askedCol++;
489  if (track.askedCol == nodesPerRow) {
490  if ((track.askedRow > track.askedCol) ||
491  (track.askedRow == (rows.size() - 1))) {
492  // no more nodes that could be asked, give up:
494  return;
495  }
496  track.askedRow++;
497  track.askedCol = 0;
498  }
499 
500  ask = static_cast<const TransportAddress*>(
501  &(nodeAt(track.askedRow, track.askedCol).node));
502 
503  if (track.node.isUnspecified() ||
504  (!ask->isUnspecified() && track.node != *ask))
505  track.node = *ask; //only happens if track.node == owner
507  }
508  while (track.node.isUnspecified() || (track.node == owner) );
509 }