OverSim
Chord.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 <GlobalStatistics.h>
25 #include <Comparator.h>
26 #include <BootstrapList.h>
27 #include <GlobalParameters.h>
28 #include <NeighborCache.h>
29 
30 #include <ChordFingerTable.h>
31 #include <ChordSuccessorList.h>
32 
33 #include "Chord.h"
34 
35 namespace oversim {
36 
37 using namespace std;
38 
40 
42 {
43  stabilize_timer = fixfingers_timer = join_timer = NULL;
44  fingerTable = NULL;
45 }
46 
47 
48 void Chord::initializeOverlay(int stage)
49 {
50  // because of IPAddressResolver, we need to wait until interfaces
51  // are registered, address auto-assignment takes place etc.
52  if (stage != MIN_STAGE_OVERLAY)
53  return;
54 
55  if (iterativeLookupConfig.merge == true) {
56  throw cRuntimeError("Chord::initializeOverlay(): "
57  "Chord doesn't work with iterativeLookupConfig.merge = true!");
58  }
59 
60  // Chord provides KBR services
61  kbr = true;
62 
63  // fetch some parameters
64  useCommonAPIforward = par("useCommonAPIforward");
65  successorListSize = par("successorListSize");
66  joinRetry = par("joinRetry");
67  stabilizeRetry = par("stabilizeRetry");
68  joinDelay = par("joinDelay");
69  stabilizeDelay = par("stabilizeDelay");
70  fixfingersDelay = par("fixfingersDelay");
71  checkPredecessorDelay = par("checkPredecessorDelay");
72  aggressiveJoinMode = par("aggressiveJoinMode");
73  extendedFingerTable = par("extendedFingerTable");
74  numFingerCandidates = par("numFingerCandidates");
75  proximityRouting = par("proximityRouting");
76  memorizeFailedSuccessor = par("memorizeFailedSuccessor");
77 
78  // merging optimizations
79  mergeOptimizationL1 = par("mergeOptimizationL1");
80  mergeOptimizationL2 = par("mergeOptimizationL2");
81  mergeOptimizationL3 = par("mergeOptimizationL3");
82  mergeOptimizationL4 = par("mergeOptimizationL4");
83 
84  keyLength = OverlayKey::getLength();
85  missingPredecessorStabRequests = 0;
86 
87  // statistics
88  joinCount = 0;
89  stabilizeCount = 0;
90  fixfingersCount = 0;
91  notifyCount = 0;
92  newsuccessorhintCount = 0;
93  joinBytesSent = 0;
94  stabilizeBytesSent = 0;
95  notifyBytesSent = 0;
96  fixfingersBytesSent = 0;
97  newsuccessorhintBytesSent = 0;
98 
99  failedSuccessor = TransportAddress::UNSPECIFIED_NODE;
100 
101  // find friend modules
102  findFriendModules();
103 
104  // add some watches
105  WATCH(predecessorNode);
106  WATCH(thisNode);
107  WATCH(bootstrapNode);
108  WATCH(joinRetry);
109  WATCH(missingPredecessorStabRequests);
110 
111  // self-messages
112  join_timer = new cMessage("join_timer");
113  stabilize_timer = new cMessage("stabilize_timer");
114  fixfingers_timer = new cMessage("fixfingers_timer");
115  checkPredecessor_timer = new cMessage("checkPredecessor_timer");
116 }
117 
118 
120 {
121  // destroy self timer messages
122  cancelAndDelete(join_timer);
123  cancelAndDelete(stabilize_timer);
124  cancelAndDelete(fixfingers_timer);
125  cancelAndDelete(checkPredecessor_timer);
126 }
127 
128 
129 
131 {
132  changeState(INIT);
133  changeState(JOIN);
134 }
135 
136 
138 {
139  Enter_Method_Silent();
140 
141  // create a join call and sent to the bootstrap node.
142  JoinCall *call = new JoinCall("JoinCall");
143  call->setBitLength(JOINCALL_L(call));
144 
145  RoutingType routingType = (defaultRoutingType == FULL_RECURSIVE_ROUTING ||
146  defaultRoutingType == RECURSIVE_SOURCE_ROUTING) ?
147  SEMI_RECURSIVE_ROUTING : defaultRoutingType;
148 
149  sendRouteRpcCall(OVERLAY_COMP, node, thisNode.getKey(),
150  call, NULL, routingType, joinDelay);
151 }
152 
153 
154 void Chord::changeState(int toState)
155 {
156  //
157  // Defines tasks to be executed when a state change occurs.
158  //
159 
160  switch (toState) {
161  case INIT:
162  state = INIT;
163 
164  setOverlayReady(false);
165 
166  // initialize predecessor pointer
167  predecessorNode = NodeHandle::UNSPECIFIED_NODE;
168 
169  // initialize finger table and successor list
170  initializeFriendModules();
171 
172  updateTooltip();
173 
174  // debug message
175  if (debugOutput) {
176  EV << "[Chord::changeState() @ " << thisNode.getIp()
177  << " (" << thisNode.getKey().toString(16) << ")]\n"
178  << " Entered INIT stage"
179  << endl;
180  }
181 
182  getParentModule()->getParentModule()->bubble("Enter INIT state.");
183  break;
184 
185  case JOIN:
186  state = JOIN;
187 
188  // initiate join process
189  cancelEvent(join_timer);
190  // workaround: prevent notificationBoard from taking
191  // ownership of join_timer message
192  take(join_timer);
193  scheduleAt(simTime(), join_timer);
194 
195  // debug message
196  if (debugOutput) {
197  EV << "[Chord::changeState() @ " << thisNode.getIp()
198  << " (" << thisNode.getKey().toString(16) << ")]\n"
199  << " Entered JOIN stage"
200  << endl;
201  }
202  getParentModule()->getParentModule()->bubble("Enter JOIN state.");
203 
204  // find a new bootstrap node and enroll to the bootstrap list
205  bootstrapNode = bootstrapList->getBootstrapNode(overlayId);
206 
207  // is this the first node?
208  if (bootstrapNode.isUnspecified()) {
209  // create new cord ring
210  assert(predecessorNode.isUnspecified());
211  bootstrapNode = thisNode;
212  changeState(READY);
213  updateTooltip();
214  }
215  break;
216 
217  case READY:
218  state = READY;
219 
220  setOverlayReady(true);
221 
222  // initiate stabilization protocol
223  cancelEvent(stabilize_timer);
224  scheduleAt(simTime() + stabilizeDelay, stabilize_timer);
225 
226  // initiate finger repair protocol
227  cancelEvent(fixfingers_timer);
228  scheduleAt(simTime() + fixfingersDelay,
229  fixfingers_timer);
230 
231  // initiate predecessor check
232  cancelEvent(checkPredecessor_timer);
233  if (checkPredecessorDelay > 0) {
234  scheduleAt(simTime() + checkPredecessorDelay,
235  checkPredecessor_timer);
236  }
237 
238  // debug message
239  if (debugOutput) {
240  EV << "[Chord::changeState() @ " << thisNode.getIp()
241  << " (" << thisNode.getKey().toString(16) << ")]\n"
242  << " Entered READY stage"
243  << endl;
244  }
245  getParentModule()->getParentModule()->bubble("Enter READY state.");
246  break;
247  }
248 }
249 
250 
251 void Chord::handleTimerEvent(cMessage* msg)
252 {
253  // catch JOIN timer
254  if (msg == join_timer) {
255  handleJoinTimerExpired(msg);
256  }
257  // catch STABILIZE timer
258  else if (msg == stabilize_timer) {
259  handleStabilizeTimerExpired(msg);
260  }
261  // catch FIX_FINGERS timer
262  else if (msg == fixfingers_timer) {
263  handleFixFingersTimerExpired(msg);
264  }
265  // catch CHECK_PREDECESSOR timer
266  else if (msg == checkPredecessor_timer) {
267  cancelEvent(checkPredecessor_timer);
268  scheduleAt(simTime() + checkPredecessorDelay,
269  checkPredecessor_timer);
270  if (!predecessorNode.isUnspecified()) pingNode(predecessorNode);
271  }
272  // unknown self message
273  else {
274  error("Chord::handleTimerEvent(): received self message of "
275  "unknown type!");
276  }
277 }
278 
279 
281 {
282  ChordMessage* chordMsg = check_and_cast<ChordMessage*>(msg);
283  switch(chordMsg->getCommand()) {
284  case NEWSUCCESSORHINT:
285  handleNewSuccessorHint(chordMsg);
286  break;
287  default:
288  error("handleUDPMessage(): Unknown message type!");
289  break;
290  }
291 
292  delete chordMsg;
293 }
294 
295 
297 {
298  if (state != READY) {
299  EV << "[Chord::handleRpcCall() @ " << thisNode.getIp()
300  << " (" << thisNode.getKey().toString(16) << ")]\n"
301  << " Received RPC call and state != READY"
302  << endl;
303  return false;
304  }
305 
306  // delegate messages
307  RPC_SWITCH_START( msg )
308  // RPC_DELEGATE( <messageName>[Call|Response], <methodToCall> )
309  RPC_DELEGATE( Join, rpcJoin );
310  RPC_DELEGATE( Notify, rpcNotify );
311  RPC_DELEGATE( Stabilize, rpcStabilize );
312  RPC_DELEGATE( Fixfingers, rpcFixfingers );
313  RPC_SWITCH_END( )
314 
315  return RPC_HANDLED;
316 }
317 
319  cPolymorphic* context, int rpcId,
320  simtime_t rtt)
321 {
322  RPC_SWITCH_START(msg)
323  RPC_ON_RESPONSE( Join ) {
324  handleRpcJoinResponse(_JoinResponse);
325  EV << "[Chord::handleRpcResponse() @ " << thisNode.getIp()
326  << " (" << thisNode.getKey().toString(16) << ")]\n"
327  << " Received a Join RPC Response: id=" << rpcId << "\n"
328  << " msg=" << *_JoinResponse << " rtt=" << rtt
329  << endl;
330  break;
331  }
332  RPC_ON_RESPONSE( Notify ) {
333  handleRpcNotifyResponse(_NotifyResponse);
334  EV << "[Chord::handleRpcResponse() @ " << thisNode.getIp()
335  << " (" << thisNode.getKey().toString(16) << ")]\n"
336  << " Received a Notify RPC Response: id=" << rpcId << "\n"
337  << " msg=" << *_NotifyResponse << " rtt=" << rtt
338  << endl;
339  break;
340  }
341  RPC_ON_RESPONSE( Stabilize ) {
342  handleRpcStabilizeResponse(_StabilizeResponse);
343  EV << "[Chord::handleRpcResponse() @ " << thisNode.getIp()
344  << " (" << thisNode.getKey().toString(16) << ")]\n"
345  << " Received a Stabilize RPC Response: id=" << rpcId << "\n"
346  << " msg=" << *_StabilizeResponse << " rtt=" << rtt
347  << endl;
348  break;
349  }
350  RPC_ON_RESPONSE( Fixfingers ) {
351  handleRpcFixfingersResponse(_FixfingersResponse, SIMTIME_DBL(rtt));
352  EV << "[Chord::handleRpcResponse() @ " << thisNode.getIp()
353  << " (" << thisNode.getKey().toString(16) << ")]\n"
354  << " Received a Fixfingers RPC Response: id=" << rpcId << "\n"
355  << " msg=" << *_FixfingersResponse << " rtt=" << rtt
356  << endl;
357  break;
358  }
359  RPC_SWITCH_END( )
360 }
361 
363  const TransportAddress& dest,
364  cPolymorphic* context, int rpcId,
365  const OverlayKey&)
366 {
367  RPC_SWITCH_START(msg)
368  RPC_ON_CALL( FindNode ) {
369  EV << "[Chord::handleRpcTimeout() @ " << thisNode.getIp()
370  << " (" << thisNode.getKey().toString(16) << ")]\n"
371  << " FindNode RPC Call timed out: id=" << rpcId << "\n"
372  << " msg=" << *_FindNodeCall
373  << endl;
374  break;
375  }
376  RPC_ON_CALL( Join ) {
377  EV << "[Chord::handleRpcTimeout() @ " << thisNode.getIp()
378  << " (" << thisNode.getKey().toString(16) << ")]\n"
379  << " Join RPC Call timed out: id=" << rpcId << "\n"
380  << " msg=" << *_JoinCall
381  << endl;
382  break;
383  }
384  RPC_ON_CALL( Notify ) {
385  EV << "[Chord::handleRpcTimeout() @ " << thisNode.getIp()
386  << " (" << thisNode.getKey().toString(16) << ")]\n"
387  << " Notify RPC Call timed out: id=" << rpcId << "\n"
388  << " msg=" << *_NotifyCall
389  << endl;
390  if (!handleFailedNode(dest)) join();
391  break;
392  }
393  RPC_ON_CALL( Stabilize ) {
394  EV << "[Chord::handleRpcTimeout() @ " << thisNode.getIp()
395  << " (" << thisNode.getKey().toString(16) << ")]\n"
396  << " Stabilize RPC Call timed out: id=" << rpcId << "\n"
397  << " msg=" << *_StabilizeCall
398  << endl;
399  if (!handleFailedNode(dest)) join();
400  break;
401  }
402  RPC_ON_CALL( Fixfingers ) {
403  EV << "[Chord::handleRpcTimeout() @ " << thisNode.getIp()
404  << " (" << thisNode.getKey().toString(16) << ")]\n"
405  << " Fixfingers RPC Call timed out: id=" << rpcId << "\n"
406  << " msg=" << *_FixfingersCall
407  << endl;
408  break;
409  }
410  RPC_SWITCH_END( )
411 }
412 
414 {
415  return successorListSize;
416 }
417 
419 {
420  return extendedFingerTable ? numFingerCandidates : 1;
421 }
422 
423 
425  const OverlayKey& key,
426  int numSiblings,
427  bool* err)
428 {
429  if (key.isUnspecified())
430  error("Chord::isSiblingFor(): key is unspecified!");
431 
432  if (state != READY) {
433  *err = true;
434  return false;
435  }
436 
437  if (numSiblings > getMaxNumSiblings()) {
438  opp_error("Chord::isSiblingFor(): numSiblings too big!");
439  }
440  // set default number of siblings to consider
441  if (numSiblings == -1) numSiblings = getMaxNumSiblings();
442 
443  // if this is the first and only node on the ring, it is responsible
444  if ((predecessorNode.isUnspecified()) && (node == thisNode)) {
445  if (successorList->isEmpty() || (node.getKey() == key)) {
446  *err = false;
447  return true;
448  } else {
449  *err = true;
450  return false;
451  }
452  }
453 
454  if ((node == thisNode)
455  && (key.isBetweenR(predecessorNode.getKey(), thisNode.getKey()))) {
456 
457  *err = false;
458  return true;
459  }
460 
461  NodeHandle prevNode = predecessorNode;
462  NodeHandle curNode;
463 
464  for (int i = -1; i < (int)successorList->getSize();
465  i++, prevNode = curNode) {
466 
467  if (i < 0) {
468  curNode = thisNode;
469  } else {
470  curNode = successorList->getSuccessor(i);
471  }
472 
473  if (node == curNode) {
474  // is the message destined for curNode?
475  if (key.isBetweenR(prevNode.getKey(), curNode.getKey())) {
476  if (numSiblings <= ((int)successorList->getSize() - i)) {
477  *err = false;
478  return true;
479  } else {
480  *err = true;
481  return false;
482  }
483  } else {
484  // the key doesn't directly belong to this node, but
485  // the node could be a sibling for this key
486  if (numSiblings <= 1) {
487  *err = false;
488  return false;
489  } else {
490  // In Chord we don't know if we belong to the
491  // replicaSet of one of our predecessors
492  *err = true;
493  return false;
494  }
495  }
496  }
497  }
498 
499  // node is not in our neighborSet
500  *err = true;
501  return false;
502 }
503 
505 {
506  Enter_Method_Silent();
507 
508  if (!predecessorNode.isUnspecified() && failed == predecessorNode)
509  predecessorNode = NodeHandle::UNSPECIFIED_NODE;
510 
511  //TODO const reference -> trying to compare unspec NH
512  TransportAddress oldSuccessor = successorList->getSuccessor();
513 
514  if (successorList->handleFailedNode(failed))
515  updateTooltip();
516  // check pointer for koorde
517  if (fingerTable != NULL)
518  fingerTable->handleFailedNode(failed);
519 
520  // if we had a ring consisting of 2 nodes and our successor seems
521  // to be dead. Remove also predecessor because the successor
522  // and predecessor are the same node
523  if ((!predecessorNode.isUnspecified()) &&
524  oldSuccessor == predecessorNode) {
525  predecessorNode = NodeHandle::UNSPECIFIED_NODE;
526  callUpdate(predecessorNode, false);
527  }
528 
529  if (failed == oldSuccessor) {
530  // schedule next stabilization process
531  if (memorizeFailedSuccessor) {
532  failedSuccessor = oldSuccessor;
533  }
534  cancelEvent(stabilize_timer);
535  scheduleAt(simTime(), stabilize_timer);
536  }
537 
538  if (state != READY) return true;
539 
540  if (successorList->isEmpty()) {
541  // lost our last successor - cancel periodic stabilize tasks
542  // and wait for rejoin
543  cancelEvent(stabilize_timer);
544  cancelEvent(fixfingers_timer);
545  }
546 
547  return !(successorList->isEmpty());
548 }
549 
551  int numRedundantNodes,
552  int numSiblings,
553  BaseOverlayMessage* msg)
554 {
555  bool err;
556  NodeVector* nextHop;
557 
558  if (state != READY)
559  return new NodeVector();
560 
561  if (successorList->isEmpty() && !predecessorNode.isUnspecified()) {
562  throw new cRuntimeError("Chord: Node is READY, has a "
563  "predecessor but no successor!");
564  join();
565  return new NodeVector();
566  }
567 
568  // if key is unspecified, the message is for this node
569  if (key.isUnspecified()) {
570  nextHop = new NodeVector();
571  nextHop->push_back(thisNode);
572  }
573 
574  // the message is destined for this node
575  else if (isSiblingFor(thisNode, key, 1, &err)) {
576  nextHop = new NodeVector();
577  nextHop->push_back(thisNode);
578  for (uint32_t i = 0; i < successorList->getSize(); i++) {
579  nextHop->push_back(successorList->getSuccessor(i));
580  }
581  nextHop->downsizeTo(numSiblings);
582  }
583 
584  // the message destined for our successor
585  else if (key.isBetweenR(thisNode.getKey(),
586  successorList->getSuccessor().getKey())) {
587  nextHop = new NodeVector();
588  for (uint32_t i = 0; i < successorList->getSize(); i++) {
589  nextHop->push_back(successorList->getSuccessor(i));
590  }
591  nextHop->downsizeTo(numRedundantNodes);
592  }
593 
594  // find next hop with finger table and/or successor list
595  else {
596  nextHop = closestPreceedingNode(key);
597  nextHop->downsizeTo(numRedundantNodes);
598  }
599 
600  return nextHop;
601 }
602 
603 
605 {
607 
608  // find the closest preceding node in the successor list
609  for (int j = successorList->getSize() - 1; j >= 0; j--) {
610  // return a predecessor of the key, unless we know a node with an Id = destKey
611  if (successorList->getSuccessor(j).getKey().isBetweenR(thisNode.getKey(), key)) {
612  tempHandle = successorList->getSuccessor(j);
613  break;
614  }
615  }
616 
617  if(tempHandle.isUnspecified()) {
618  std::stringstream temp;
619  temp << "Chord::closestPreceedingNode(): Successor list broken "
620  << thisNode.getKey() << " " << key;
621  throw cRuntimeError(temp.str().c_str());
622  }
623 
624  NodeVector* nextHop = NULL;
625 
626  for (int i = fingerTable->getSize() - 1; i >= 0; i--) {
627  // return a predecessor of the key, unless we know a node with an Id = destKey
628  if (fingerTable->getFinger(i).getKey().isBetweenLR(tempHandle.getKey(), key)) {
629  if(!extendedFingerTable) {
630  nextHop = new NodeVector();
631  nextHop->push_back(fingerTable->getFinger(i));
632 
633  EV << "[Chord::closestPreceedingNode() @ " << thisNode.getIp()
634  << " (" << thisNode.getKey().toString(16) << ")]\n"
635  << " ClosestPreceedingNode: node " << thisNode
636  << " for key " << key << "\n"
637  << " finger " << fingerTable->getFinger(i).getKey()
638  << " better than \n"
639  << " " << tempHandle.getKey()
640  << endl;
641  return nextHop;
642  } else {
643  return fingerTable->getFinger(i, key);
644  }
645  }
646  }
647 
648  nextHop = new NodeVector();
649  EV << "[Chord::closestPreceedingNode() @ " << thisNode.getIp()
650  << " (" << thisNode.getKey().toString(16) << ")]\n"
651  << " No finger found"
652  << endl;
653 
654  // if no finger is found lookup the rest of the successor list
655  for (int i = successorList->getSize() - 1; i >= 0
656  && nextHop->size() <= numFingerCandidates ; i--) {
657  if (successorList->getSuccessor(i).getKey().isBetween(thisNode.getKey(), key)) {
658  nextHop->push_back(successorList->getSuccessor(i));
659  }
660  }
661 
662  if (nextHop->size() != 0) {
663  return nextHop;
664  }
665 
666  // if this is the first and only node on the ring, it is responsible
667  if ((predecessorNode.isUnspecified()) &&
668  (successorList->getSuccessor() == thisNode)) {
669  nextHop->push_back(thisNode);
670  return nextHop;
671  }
672 
673  // if there is still no node found throw an exception
674  throw cRuntimeError("Error in Chord::closestPreceedingNode()!");
675  return nextHop;
676 }
677 
679 {
680  BaseOverlayMessage* innerMsg = msg;
681  while (innerMsg->getType() != APPDATA &&
682  innerMsg->getEncapsulatedPacket() != NULL) {
683  innerMsg =
684  static_cast<BaseOverlayMessage*>(innerMsg->getEncapsulatedPacket());
685  }
686 
687  switch (innerMsg->getType()) {
688  case OVERLAYSIGNALING: {
689  ChordMessage* chordMsg = dynamic_cast<ChordMessage*>(innerMsg);
690  switch(chordMsg->getCommand()) {
691  case NEWSUCCESSORHINT:
692  RECORD_STATS(newsuccessorhintCount++;
693  newsuccessorhintBytesSent += msg->getByteLength());
694  break;
695  }
696  break;
697  }
698 
699  case RPC: {
700  if ((dynamic_cast<StabilizeCall*>(innerMsg) != NULL) ||
701  (dynamic_cast<StabilizeResponse*>(innerMsg) != NULL)) {
702  RECORD_STATS(stabilizeCount++; stabilizeBytesSent +=
703  msg->getByteLength());
704  } else if ((dynamic_cast<NotifyCall*>(innerMsg) != NULL) ||
705  (dynamic_cast<NotifyResponse*>(innerMsg) != NULL)) {
706  RECORD_STATS(notifyCount++; notifyBytesSent +=
707  msg->getByteLength());
708  } else if ((dynamic_cast<FixfingersCall*>(innerMsg) != NULL) ||
709  (dynamic_cast<FixfingersResponse*>(innerMsg) != NULL)) {
710  RECORD_STATS(fixfingersCount++; fixfingersBytesSent +=
711  msg->getByteLength());
712  } else if ((dynamic_cast<JoinCall*>(innerMsg) != NULL) ||
713  (dynamic_cast<JoinResponse*>(innerMsg) != NULL)) {
714  RECORD_STATS(joinCount++; joinBytesSent += msg->getByteLength());
715  }
716  break;
717  }
718 
719  case APPDATA:
720  break;
721 
722  default:
723  throw cRuntimeError("Unknown message type!");
724  }
725 }
726 
727 
729 {
730  // remove this node from the bootstrap list
731  bootstrapList->removeBootstrapNode(thisNode);
732 
733  simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
734  if (time < GlobalStatistics::MIN_MEASURED) return;
735 
736  globalStatistics->addStdDev("Chord: Sent JOIN Messages/s",
737  joinCount / time);
738  globalStatistics->addStdDev("Chord: Sent NEWSUCCESSORHINT Messages/s",
739  newsuccessorhintCount / time);
740  globalStatistics->addStdDev("Chord: Sent STABILIZE Messages/s",
741  stabilizeCount / time);
742  globalStatistics->addStdDev("Chord: Sent NOTIFY Messages/s",
743  notifyCount / time);
744  globalStatistics->addStdDev("Chord: Sent FIX_FINGERS Messages/s",
745  fixfingersCount / time);
746  globalStatistics->addStdDev("Chord: Sent JOIN Bytes/s",
747  joinBytesSent / time);
748  globalStatistics->addStdDev("Chord: Sent NEWSUCCESSORHINT Bytes/s",
749  newsuccessorhintBytesSent / time);
750  globalStatistics->addStdDev("Chord: Sent STABILIZE Bytes/s",
751  stabilizeBytesSent / time);
752  globalStatistics->addStdDev("Chord: Sent NOTIFY Bytes/s",
753  notifyBytesSent / time);
754  globalStatistics->addStdDev("Chord: Sent FIX_FINGERS Bytes/s",
755  fixfingersBytesSent / time);
756 }
757 
758 
759 
760 void Chord::handleJoinTimerExpired(cMessage* msg)
761 {
762  // only process timer, if node is not joined yet
763  if (state == READY)
764  return;
765 
766  // enter state JOIN
767  if (state != JOIN)
768  changeState(JOIN);
769 
770  // change bootstrap node from time to time
771  joinRetry--;
772  if (joinRetry == 0) {
773  joinRetry = par("joinRetry");
774  changeState(JOIN);
775  return;
776  }
777 
778  // call JOIN RPC
779  JoinCall* call = new JoinCall("JoinCall");
780  call->setBitLength(JOINCALL_L(call));
781 
782  RoutingType routingType = (defaultRoutingType == FULL_RECURSIVE_ROUTING ||
783  defaultRoutingType == RECURSIVE_SOURCE_ROUTING) ?
784  SEMI_RECURSIVE_ROUTING : defaultRoutingType;
785 
786  sendRouteRpcCall(OVERLAY_COMP, bootstrapNode, thisNode.getKey(),
787  call, NULL, routingType, joinDelay);
788 
789  // schedule next join process in the case this one fails
790  cancelEvent(join_timer);
791  scheduleAt(simTime() + joinDelay, msg);
792 }
793 
794 
796 {
797  if (state != READY)
798  return;
799 
800  // alternative predecessor check
801  if ((checkPredecessorDelay == 0) &&
802  (missingPredecessorStabRequests >= stabilizeRetry)) {
803  // predecessor node seems to be dead
804  // remove it from the predecessor / successor lists
805  //successorList->removeSuccessor(predecessorNode);
806  predecessorNode = NodeHandle::UNSPECIFIED_NODE;
807  missingPredecessorStabRequests = 0;
808  updateTooltip();
809  callUpdate(predecessorNode, false);
810  }
811 
812  if (!successorList->isEmpty()) {
813  // call STABILIZE RPC
814  StabilizeCall* call = new StabilizeCall("StabilizeCall");
815  call->setBitLength(STABILIZECALL_L(call));
816 
817  sendUdpRpcCall(successorList->getSuccessor(), call);
818 
819  missingPredecessorStabRequests++;
820  }
821 
822  // check if fingers are still alive and remove unreachable finger nodes
823  if (mergeOptimizationL4) {
824  OverlayKey offset;
825  for (uint32_t nextFinger = 0; nextFinger < thisNode.getKey().getLength();
826  nextFinger++) {
827  offset = OverlayKey::pow2(nextFinger);
828 
829  // send message only for non-trivial fingers
830  if (offset > successorList->getSuccessor().getKey() - thisNode.getKey()) {
831  if ((fingerTable->getFinger(nextFinger)).isUnspecified()) {
832  continue;
833  } else {
834  pingNode(fingerTable->getFinger(nextFinger), -1, 0, NULL,
835  NULL, NULL, nextFinger);
836  }
837  }
838  }
839  }
840 
841  // schedule next stabilization process
842  cancelEvent(stabilize_timer);
843  scheduleAt(simTime() + stabilizeDelay, msg);
844 }
845 
846 
848 {
849  if ((state != READY) || successorList->isEmpty())
850  return;
851 
852  OverlayKey offset, lookupKey;
853  for (uint32_t nextFinger = 0; nextFinger < thisNode.getKey().getLength();
854  nextFinger++) {
855  // calculate "n + 2^(i - 1)"
856  offset = OverlayKey::pow2(nextFinger);
857  lookupKey = thisNode.getKey() + offset;
858 
859  // send message only for non-trivial fingers
860  if (offset > successorList->getSuccessor().getKey() - thisNode.getKey()) {
861  // call FIXFINGER RPC
862  FixfingersCall* call = new FixfingersCall("FixfingersCall");
863  call->setFinger(nextFinger);
864  call->setBitLength(FIXFINGERSCALL_L(call));
865 
866  sendRouteRpcCall(OVERLAY_COMP, lookupKey, call, NULL,
867  DEFAULT_ROUTING, fixfingersDelay);
868  } else {
869  // delete trivial fingers (points to the successor node)
870  fingerTable->removeFinger(nextFinger);
871  }
872  }
873 
874  // schedule next finger repair process
875  cancelEvent(fixfingers_timer);
876  scheduleAt(simTime() + fixfingersDelay, msg);
877 }
878 
879 
881 {
882  NewSuccessorHintMessage* newSuccessorHintMsg =
883  check_and_cast<NewSuccessorHintMessage*>(chordMsg);
884 
885  // fetch the successor's predecessor
886  NodeHandle predecessor = newSuccessorHintMsg->getPreNode();
887 
888  // is the successor's predecessor a new successor for this node?
889  if (predecessor.getKey().isBetween(thisNode.getKey(),
890  successorList->getSuccessor().getKey())
891  || (thisNode.getKey() == successorList->getSuccessor().getKey())) {
892  // add the successor's predecessor to the successor list
893  successorList->addSuccessor(predecessor);
894  updateTooltip();
895  }
896 
897  // if the successor node reports a new successor, put it into the
898  // successor list and start stabilizing
899  if (mergeOptimizationL3) {
900  if (successorList->getSuccessor() == predecessor) {
901  StabilizeCall *call = new StabilizeCall("StabilizeCall");
902  call->setBitLength(STABILIZECALL_L(call));
903 
904  sendUdpRpcCall(predecessor, call);
905  } else {
906  if (successorList->getSuccessor() == newSuccessorHintMsg->
907  getSrcNode()) {
908 
909  StabilizeCall *call = new StabilizeCall("StabilizeCall");
910  call->setBitLength(STABILIZECALL_L(call));
911 
912  sendUdpRpcCall(predecessor, call);
913  }
914  }
915  }
916 }
917 
918 
919 void Chord::rpcJoin(JoinCall* joinCall)
920 {
921  NodeHandle requestor = joinCall->getSrcNode();
922 
923  // compile successor list
924  JoinResponse* joinResponse =
925  new JoinResponse("JoinResponse");
926 
927  int sucNum = successorList->getSize();
928  joinResponse->setSucNum(sucNum);
929  joinResponse->setSucNodeArraySize(sucNum);
930 
931  for (int k = 0; k < sucNum; k++) {
932  joinResponse->setSucNode(k, successorList->getSuccessor(k));
933  }
934 
935  // sent our predecessor as hint to the joining node
936  if (predecessorNode.isUnspecified() && successorList->isEmpty()) {
937  // we are the only node in the ring
938  joinResponse->setPreNode(thisNode);
939  } else {
940  joinResponse->setPreNode(predecessorNode);
941  }
942 
943  joinResponse->setBitLength(JOINRESPONSE_L(joinResponse));
944 
945  sendRpcResponse(joinCall, joinResponse);
946 
947  if (aggressiveJoinMode) {
948  // aggressiveJoinMode differs from standard join operations:
949  // 1. set our predecessor pointer to the joining node
950  // 2. send our old predecessor as hint in JoinResponse msgs
951  // 3. send a NEWSUCCESSORHINT to our old predecessor to update
952  // its successor pointer
953 
954  // send NEWSUCCESSORHINT to our old predecessor
955 
956  if (!predecessorNode.isUnspecified()) {
957  NewSuccessorHintMessage* newSuccessorHintMsg =
958  new NewSuccessorHintMessage("NEWSUCCESSORHINT");
959  newSuccessorHintMsg->setCommand(NEWSUCCESSORHINT);
960 
961  newSuccessorHintMsg->setSrcNode(thisNode);
962  newSuccessorHintMsg->setPreNode(requestor);
963  newSuccessorHintMsg->
964  setBitLength(NEWSUCCESSORHINT_L(newSuccessorHintMsg));
965 
966  sendMessageToUDP(predecessorNode, newSuccessorHintMsg);
967  }
968 
969  if (predecessorNode.isUnspecified() || (predecessorNode != requestor)) {
970  // the requestor is our new predecessor
971  NodeHandle oldPredecessor = predecessorNode;
972  predecessorNode = requestor;
973 
974  // send update to application if we've got a new predecessor
975  if (!oldPredecessor.isUnspecified()) {
976  callUpdate(oldPredecessor, false);
977  }
978  callUpdate(predecessorNode, true);
979 
980  }
981  }
982 
983  // if we don't have a successor, the requestor is also our new successor
984  if (successorList->isEmpty())
985  successorList->addSuccessor(requestor);
986 
987  updateTooltip();
988 }
989 
991 {
992  // determine the numer of successor nodes to add
993  int sucNum = successorListSize - 1;
994 
995  if (joinResponse->getSucNum() < successorListSize - 1) {
996  sucNum = joinResponse->getSucNum();
997  }
998 
999  // add successor getNode(s)
1000  for (int k = 0; k < sucNum; k++) {
1001  NodeHandle successor = joinResponse->getSucNode(k);
1002  successorList->addSuccessor(successor);
1003  }
1004 
1005  // the sender of this message is our new successor
1006  successorList->addSuccessor(joinResponse->getSrcNode());
1007 
1008  // in aggressiveJoinMode: use hint in JoinResponse
1009  // to set our new predecessor
1010  if (aggressiveJoinMode) {
1011  // it is possible that the joinResponse doesn't contain a valid
1012  // predecessor especially when merging two partitions
1013  if (!joinResponse->getPreNode().isUnspecified()) {
1014  if (!predecessorNode.isUnspecified()) {
1015 
1016 
1017  // inform the original predecessor about the new predecessor
1018  if (mergeOptimizationL2) {
1019  NewSuccessorHintMessage* newSuccessorHintMsg =
1020  new NewSuccessorHintMessage("NEWSUCCESSORHINT");
1021  newSuccessorHintMsg->setCommand(NEWSUCCESSORHINT);
1022  newSuccessorHintMsg->setSrcNode(thisNode);
1023  newSuccessorHintMsg->setPreNode(joinResponse->getPreNode());
1024  newSuccessorHintMsg->
1025  setBitLength(NEWSUCCESSORHINT_L(newSuccessorHintMsg));
1026 
1027  sendMessageToUDP(predecessorNode, newSuccessorHintMsg);
1028  }
1029  }
1030 
1031  NodeHandle oldPredecessor = predecessorNode;
1032  predecessorNode = joinResponse->getPreNode();
1033 
1034  if (!oldPredecessor.isUnspecified()
1035  && !joinResponse->getPreNode().isUnspecified()
1036  && oldPredecessor != joinResponse->getPreNode()) {
1037  callUpdate(oldPredecessor, false);
1038  }
1039  callUpdate(predecessorNode, true);
1040  }
1041  }
1042 
1043  updateTooltip();
1044 
1045  changeState(READY);
1046 
1047  // immediate stabilization protocol
1048  cancelEvent(stabilize_timer);
1049  scheduleAt(simTime(), stabilize_timer);
1050 
1051  // immediate finger repair protocol
1052  cancelEvent(fixfingers_timer);
1053  scheduleAt(simTime(), fixfingers_timer);
1054 }
1055 
1056 
1058 {
1059  // our predecessor seems to be alive
1060  if (!predecessorNode.isUnspecified() &&
1061  call->getSrcNode() == predecessorNode) {
1062  missingPredecessorStabRequests = 0;
1063  }
1064 
1065  // reply with StabilizeResponse message
1066  StabilizeResponse* stabilizeResponse =
1067  new StabilizeResponse("StabilizeResponse");
1068  stabilizeResponse->setPreNode(predecessorNode);
1069  stabilizeResponse->setBitLength(STABILIZERESPONSE_L(stabilizeResponse));
1070 
1071  sendRpcResponse(call, stabilizeResponse);
1072 }
1073 
1075 {
1076  if (state != READY) {
1077  return;
1078  }
1079 
1080  // fetch the successor's predecessor
1081  const NodeHandle& predecessor = stabilizeResponse->getPreNode();
1082 
1083  // is the successor's predecessor a new successor for this node?
1084  if ((successorList->isEmpty() ||
1085  predecessor.getKey().isBetween(thisNode.getKey(),
1086  successorList->getSuccessor().getKey())) &&
1087  (failedSuccessor.isUnspecified() || failedSuccessor != predecessor)) {
1088  if (successorList->isEmpty() && predecessor.isUnspecified()) {
1089  // successor is emptry and the sender of the response has
1090  // no predecessor => take the sender as new successor
1091  successorList->addSuccessor(stabilizeResponse->getSrcNode());
1092  } else {
1093  // add the successor's predecessor to the successor list
1094  successorList->addSuccessor(predecessor);
1095  }
1096  updateTooltip();
1097  }
1098 
1099  // compile NOTIFY RPC
1100  NotifyCall* notifyCall = new NotifyCall("NotifyCall");
1101  notifyCall->setBitLength(NOTIFYCALL_L(notifyCall));
1102  notifyCall->setFailed(failedSuccessor);
1103  failedSuccessor = TransportAddress::UNSPECIFIED_NODE;
1104 
1105  sendUdpRpcCall(successorList->getSuccessor(), notifyCall);
1106 }
1107 
1109 {
1110  // our predecessor seems to be alive
1111  if (!predecessorNode.isUnspecified() &&
1112  call->getSrcNode() == predecessorNode) {
1113  missingPredecessorStabRequests = 0;
1114  }
1115 
1116  bool newPredecessorSet = false;
1117 
1118  NodeHandle newPredecessor = call->getSrcNode();
1119 
1120  // is the new predecessor closer than the current one?
1121  if (predecessorNode.isUnspecified() ||
1122  newPredecessor.getKey().isBetween(predecessorNode.getKey(), thisNode.getKey()) ||
1123  (!call->getFailed().isUnspecified() &&
1124  call->getFailed() == predecessorNode)) {
1125 
1126  if ((predecessorNode.isUnspecified()) ||
1127  (newPredecessor != predecessorNode)) {
1128 
1129  // set up new predecessor
1130  NodeHandle oldPredecessor = predecessorNode;
1131  predecessorNode = newPredecessor;
1132 
1133  if (successorList->isEmpty()) {
1134  successorList->addSuccessor(newPredecessor);
1135  }
1136 
1137  newPredecessorSet = true;
1138  updateTooltip();
1139 
1140  // send update to application if we've got a new predecessor
1141  if (!oldPredecessor.isUnspecified()) {
1142  callUpdate(oldPredecessor, false);
1143  }
1144  callUpdate(predecessorNode, true);
1145 
1146  // inform the original predecessor about the new predecessor
1147  if (mergeOptimizationL1) {
1148  if (!oldPredecessor.isUnspecified()) {
1149  NewSuccessorHintMessage *newSuccessorHintMsg =
1150  new NewSuccessorHintMessage("NEWSUCCESSORHINT");
1151  newSuccessorHintMsg->setCommand(NEWSUCCESSORHINT);
1152 
1153  newSuccessorHintMsg->setSrcNode(thisNode);
1154  newSuccessorHintMsg->setPreNode(predecessorNode);
1155  newSuccessorHintMsg->
1156  setBitLength(NEWSUCCESSORHINT_L(newSuccessorHintMsg));
1157  sendMessageToUDP(oldPredecessor, newSuccessorHintMsg);
1158  }
1159  }
1160 
1161 
1162  }
1163  }
1164 
1165  // compile NOTIFY response
1166  NotifyResponse* notifyResponse = new NotifyResponse("NotifyResponse");
1167 
1168  int sucNum = successorList->getSize();
1169  notifyResponse->setSucNum(sucNum);
1170  notifyResponse->setSucNodeArraySize(sucNum);
1171 
1172  // can't accept the notify sender as predecessor,
1173  // tell it about my correct predecessor
1174  if (mergeOptimizationL3) {
1175  if (!newPredecessorSet && (predecessorNode != newPredecessor)) {
1176 
1177  notifyResponse->setPreNode(predecessorNode);
1178  notifyResponse->setPreNodeSet(false);
1179  } else {
1180  notifyResponse->setPreNodeSet(true);
1181  }
1182  }
1183 
1184  for (int k = 0; k < sucNum; k++) {
1185  notifyResponse->setSucNode(k, successorList->getSuccessor(k));
1186  }
1187 
1188  notifyResponse->setBitLength(NOTIFYRESPONSE_L(notifyResponse));
1189 
1190  sendRpcResponse(call, notifyResponse);
1191 }
1192 
1193 
1195 {
1196  if (state != READY) {
1197  return;
1198  }
1199 
1200  if (successorList->getSuccessor() != notifyResponse->getSrcNode()) {
1201  EV << "[Chord::handleRpcNotifyResponse() @ " << thisNode.getIp()
1202  << " (" << thisNode.getKey().toString(16) << ")]\n"
1203  << " The srcNode of the received NotifyResponse is not our "
1204  << " current successor"
1205  << endl;
1206  return;
1207  }
1208 
1209  // if the NotifyResponse sender couldn't accept me as predecessor,
1210  // put its predecessor into the successor list and starts stabilizing
1211  if (mergeOptimizationL3) {
1212  if (!notifyResponse->getPreNodeSet()) {
1213  StabilizeCall *call = new StabilizeCall("StabilizeCall");
1214  call->setBitLength(STABILIZECALL_L(call));
1215 
1216  successorList->addSuccessor(notifyResponse->getPreNode());
1217  if (successorList->getSuccessor() == notifyResponse->getPreNode())
1218  sendUdpRpcCall(notifyResponse->getPreNode(), call);
1219  return;
1220  }
1221  }
1222 
1223  // replace our successor list by our successor's successor list
1224  successorList->updateList(notifyResponse);
1225 
1226  updateTooltip();
1227 }
1228 
1229 
1231 {
1232  FixfingersResponse* fixfingersResponse =
1233  new FixfingersResponse("FixfingersResponse");
1234 
1235  fixfingersResponse->setSucNodeArraySize(1);
1236  fixfingersResponse->setSucNode(0, thisNode);
1237 
1238  if (extendedFingerTable) {
1239  fixfingersResponse->setSucNodeArraySize(((successorList->getSize() + 1
1240  < numFingerCandidates + 1)
1241  ? successorList->getSize() + 1
1242  : numFingerCandidates + 1));
1243  for (unsigned int i = 0;
1244  i < (((successorList->getSize()) < numFingerCandidates)
1245  ? (successorList->getSize()) : numFingerCandidates); i++) {
1246 
1247  assert(!successorList->getSuccessor(i).isUnspecified());
1248  fixfingersResponse->setSucNode(i + 1,
1249  successorList->getSuccessor(i));
1250  }
1251  }
1252  fixfingersResponse->setFinger(call->getFinger());
1253  fixfingersResponse->setBitLength(FIXFINGERSRESPONSE_L(fixfingersResponse));
1254 
1255  sendRpcResponse(call, fixfingersResponse);
1256 }
1257 
1258 
1260  double rtt)
1261 {
1262  /*
1263  OverlayCtrlInfo* ctrlInfo =
1264  check_and_cast<OverlayCtrlInfo*>(fixfingersResponse->getControlInfo());
1265 
1266  RECORD_STATS(globalStatistics->recordOutVector("Chord: FIX_FINGERS response Hop Count", ctrlInfo->getHopCount()));
1267  */
1268 
1269  // set new finger pointer#
1270  if (!extendedFingerTable) {
1271  fingerTable->setFinger(fixfingersResponse->getFinger(),
1272  fixfingersResponse->getSucNode(0));
1273  } else {
1274  Successors successors;
1275  for (unsigned int i = 0; i < fixfingersResponse->getSucNodeArraySize();
1276  i++) {
1277  if (fixfingersResponse->getSucNode(i).isUnspecified())
1278  continue;
1279  if (fixfingersResponse->getSucNode(i) == thisNode)
1280  break;
1281  successors.insert(std::make_pair(MAXTIME,
1282  fixfingersResponse->getSucNode(i)));
1283  }
1284 
1285  if (successors.size() == 0) {
1286  return;
1287  }
1288 
1289  fingerTable->setFinger(fixfingersResponse->getFinger(), successors);
1290 
1291 #if 0
1292  if (proximityRouting || globalParameters->getTopologyAdaptation()) {
1293 #else
1294  if (proximityRouting) {
1295 #endif
1296  for (unsigned int i = 0;
1297  i < fixfingersResponse->getSucNodeArraySize();
1298  i++) {
1299  if (fixfingersResponse->getSucNode(i).isUnspecified())
1300  continue;
1301  if (fixfingersResponse->getSucNode(i) == thisNode)
1302  break;
1303  //pingNode(fixfingersResponse->getSucNode(i), -1, 0, NULL,
1304  // NULL, NULL, fixfingersResponse->getFinger(),
1305  // INVALID_TRANSPORT);
1306  Prox prox =
1307  neighborCache->getProx(fixfingersResponse->getSucNode(i),
1309  fixfingersResponse->getFinger(),
1310  this, NULL);
1311  if (prox == Prox::PROX_TIMEOUT) {
1312  fingerTable->removeFinger(fixfingersResponse->getFinger());
1313  } else if (prox != Prox::PROX_UNKNOWN &&
1314  prox != Prox::PROX_WAITING &&
1315  prox != Prox::PROX_SELF) {
1316  fingerTable->updateFinger(fixfingersResponse->getFinger(),
1317  fixfingersResponse->getSucNode(i),
1318  prox.proximity);
1319  }
1320  }
1321  }
1322  }
1323 }
1324 
1325 void Chord::proxCallback(const TransportAddress &node, int rpcId,
1326  cPolymorphic *contextPointer, Prox prox)
1327 {
1328  if (prox == Prox::PROX_TIMEOUT) {
1329  // call join dependant on return value?
1330  handleFailedNode(node);
1331  return;
1332  }
1333 
1334  fingerTable->updateFinger(rpcId, (NodeHandle&)node, prox.proximity);
1335 }
1336 
1337 void Chord::pingResponse(PingResponse* pingResponse, cPolymorphic* context,
1338  int rpcId, simtime_t rtt)
1339 {
1340  EV << "[Chord::pingResponse() @ " << thisNode.getIp()
1341  << " (" << thisNode.getKey().toString(16) << ")]\n"
1342  << " Received a Ping RPC Response: id=" << rpcId << "\n"
1343  << " msg=" << *pingResponse << " rtt=" << rtt
1344  << endl;
1345 
1346  if (rpcId != -1)
1347  fingerTable->updateFinger(rpcId, pingResponse->getSrcNode(), rtt);
1348 }
1349 
1351  const TransportAddress& dest,
1352  cPolymorphic* context, int rpcId)
1353 {
1354  EV << "[Chord::pingTimeout() @ " << thisNode.getIp()
1355  << " (" << thisNode.getKey().toString(16) << ")]\n"
1356  << " Ping RPC timeout: id=" << rpcId << endl;
1357 
1358  // call join dependant on return value?
1359  handleFailedNode(dest);
1360 }
1361 
1363 {
1364  fingerTable = check_and_cast<ChordFingerTable*>
1365  (getParentModule()->getSubmodule("fingerTable"));
1366 
1367  successorList = check_and_cast<ChordSuccessorList*>
1368  (getParentModule()->getSubmodule("successorList"));
1369 }
1370 
1371 
1373 {
1374  // initialize finger table
1375  fingerTable->initializeTable(thisNode.getKey().getLength(), thisNode, this);
1376 
1377  // initialize successor list
1378  successorList->initializeList(par("successorListSize"), thisNode, this);
1379 }
1380 
1381 
1383 {
1384  if (ev.isGUI()) {
1385  std::stringstream ttString;
1386 
1387  // show our predecessor and successor in tooltip
1388  ttString << predecessorNode << endl << thisNode << endl
1389  << successorList->getSuccessor();
1390 
1391  getParentModule()->getParentModule()->getDisplayString().
1392  setTagArg("tt", 0, ttString.str().c_str());
1393  getParentModule()->getDisplayString().
1394  setTagArg("tt", 0, ttString.str().c_str());
1395  getDisplayString().setTagArg("tt", 0, ttString.str().c_str());
1396 
1397  // draw an arrow to our current successor
1398  showOverlayNeighborArrow(successorList->getSuccessor(), true,
1399  "m=m,50,0,50,0;ls=red,1");
1400  showOverlayNeighborArrow(predecessorNode, false,
1401  "m=m,50,100,50,100;ls=green,1");
1402  }
1403 }
1404 
1405 // TODO: The following should be removed, since Chord doesn't have a simple metric
1407  const OverlayKey& y,
1408  bool useAlternative) const
1409 {
1410  return KeyCwRingMetric().distance(x, y);
1411 }
1412 
1413 }; //namespace