Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
cleanups in java examples (2/2)
[simgrid.git] / examples / java / chord / Node.java
index 27cb63a..6456b6b 100644 (file)
 
 package chord;
 
+import org.simgrid.msg.Msg;
 import org.simgrid.msg.Comm;
 import org.simgrid.msg.Host;
-import org.simgrid.msg.Msg;
-import org.simgrid.msg.MsgException;
-import org.simgrid.msg.Process;
 import org.simgrid.msg.Task;
+import org.simgrid.msg.Process;
+import org.simgrid.msg.MsgException;
 import org.simgrid.msg.TimeoutException;
-/**
- * Node data
- */
 public class Node extends Process {
-       /**
-        * Node id
-        */
-       protected int id;
-       /**
-        * Node mailbox
-        */
-       protected String mailbox;
-       /**
-        * Predecessor id
-        */
-       protected int predId;
-       /**
-        * Predecessor mailbox
-        */
-       protected String predMailbox;
-       /**
-        * Index of the next finger to fix
-        */
-       protected int nextFingerToFix;
-       /**
-        * Current communication
-        */
-       protected Comm commReceive;
-       /**
-        * Last time I changed a finger or my predecessor
-        */
-       protected double lastChangeDate;
-       /**
-        * Node fingers
-        */
-       int fingers[];
-       /**
-        * Constructor
-        */
-       public Node(Host host, String name, String[] args) {
-               super(host,name,args);
-       }
-       @Override
-       public void main(String[] args) throws MsgException {
-               if (args.length != 2 && args.length != 4) {
-                       Msg.info("You need to provide 2 or 4 arguments.");
-                       return; 
-               }
-               double initTime = Msg.getClock();
-               int i;
-               boolean joinSuccess = false;
-               double deadline;
-               
-               double nextStabilizeDate = initTime + Common.PERIODIC_STABILIZE_DELAY;
-               double nextFixFingersDate = initTime + Common.PERIODIC_FIX_FINGERS_DELAY;
-               double nextCheckPredecessorDate = initTime + Common.PERIODIC_CHECK_PREDECESSOR_DELAY;
-               double nextLookupDate = initTime + Common.PERIODIC_LOOKUP_DELAY;
-               
-               id = Integer.valueOf(args[0]);
-               mailbox = Integer.toString(id);
-
-               fingers = new int[Common.NB_BITS];
-               for (i = 0; i < Common.NB_BITS; i++) {
-                       fingers[i] = -1;
-                       setFinger(i,this.id);
-               }
-               
-               //First node
-               if (args.length == 2) {
-                       deadline = Integer.valueOf(args[1]);
-                       create();
-                       joinSuccess = true;
-               }
-               else {
-                       int knownId = Integer.valueOf(args[1]);
-                       deadline = Integer.valueOf(args[3]);
-                       //Msg.info("Hey! Let's join the system with the id " + id + ".");
-                       
-                       joinSuccess = join(knownId);
-               }
-               if (joinSuccess) {
-                       double currentClock = Msg.getClock();
-                       while (currentClock < (initTime + deadline) && currentClock < Common.MAX_SIMULATION_TIME) {
-                               if (commReceive == null) {
-                                       commReceive = Task.irecv(this.mailbox);
-                               }
-                               try {
-                                       if (!commReceive.test()) {
-                                               if (currentClock >= nextStabilizeDate) {
-                                                       stabilize();
-                                                       nextStabilizeDate = Msg.getClock() + Common.PERIODIC_STABILIZE_DELAY;
-                                               }
-                                               else if (currentClock >= nextFixFingersDate) {
-                                                       fixFingers();
-                                                       nextFixFingersDate = Msg.getClock() + Common.PERIODIC_FIX_FINGERS_DELAY;
-                                               }
-                                               else if (currentClock >= nextCheckPredecessorDate) {
-                                                       this.checkPredecessor();
-                                                       nextCheckPredecessorDate = Msg.getClock() + Common.PERIODIC_CHECK_PREDECESSOR_DELAY;
-                                               }
-                                               else if (currentClock >= nextLookupDate) {
-                                                       this.randomLookup();
-                                                       nextLookupDate = Msg.getClock() + Common.PERIODIC_LOOKUP_DELAY;
-                                               }
-                                               else {
-                                                       waitFor(5);
-                                               }
-                                               currentClock = Msg.getClock();
-                                       }
-                                       else {
-                                               handleTask(commReceive.getTask());
-                                               currentClock = Msg.getClock();
-                                               commReceive = null;
-                                               
-                                       }
-                               }
-                               catch (Exception e) {
-                                       currentClock = Msg.getClock();
-                                       commReceive = null;
-                               }
-                               
-                       }
-                       leave();
-                       if (commReceive != null) {
-                               commReceive = null;
-                       }
-               }
-               else {
-                       Msg.info("I couldn't join the ring");
-               }
-       }
-       void handleTask(Task task) {
-               if (task instanceof FindSuccessorTask) {
-                       FindSuccessorTask fTask = (FindSuccessorTask)task;
-                       Msg.debug("Receiving a 'Find Successor' request from " + fTask.issuerHostName + " for id " + fTask.requestId);
-                       // is my successor the successor?
-                       if (isInInterval(fTask.requestId, this.id + 1, fingers[0])) {
-                               //Msg.info("Send the request to " + fTask.answerTo + " with answer " + fingers[0]);
-                               FindSuccessorAnswerTask answer = new FindSuccessorAnswerTask(host.getName(), mailbox, fingers[0]);
-                               answer.dsend(fTask.answerTo);
-                       }
-                       else {
-                       // otherwise, forward the request to the closest preceding finger in my table
-                               int closest = closestPrecedingNode(fTask.requestId);
-                               //Msg.info("Forward the request to " + closest);
-                               fTask.dsend(Integer.toString(closest));
-                       }
-               }
-               else if (task instanceof GetPredecessorTask) {
-                       GetPredecessorTask gTask = (GetPredecessorTask)(task);
-                       Msg.debug("Receiving a 'Get Predecessor' request from " + gTask.issuerHostName);
-                       GetPredecessorAnswerTask answer = new GetPredecessorAnswerTask(host.getName(), mailbox, predId);
-                       answer.dsend(gTask.answerTo);
-               }
-               else if (task instanceof NotifyTask) {
-                       NotifyTask nTask = (NotifyTask)task;
-                       notify(nTask.requestId);
-               }
-               else {
-                       Msg.debug("Ignoring unexpected task of type:" + task);
-               }
-       }
-       /**
-        * @brief Makes the current node quit the system
-        */
-       void leave() {
-               Msg.debug("Well Guys! I Think it's time for me to quit ;)");
-               quitNotify(1); //Notify my successor
-               quitNotify(-1); //Notify my predecessor.
-               // TODO ...
-       }
-       /**
-        * @brief Notifies the successor or the predecessor of the current node
-        * of the departure
-        * @param to 1 to notify the successor, -1 to notify the predecessor
-        */
-       static void quitNotify( int to) {
-               //TODO
-       }
-       /**
-      * @brief Initializes the current node as the first one of the system.
-        */
-       void create() {
-               Msg.debug("Create a new Chord ring...");
-               setPredecessor(-1);
-               
-       }
-       /**
-        * Makes the current node join the ring, knowing the id of a node
-        * already in the ring 
-        */
-       boolean join(int knownId) {
-               Msg.info("Joining the ring with id " + this.id + " knowing node " + knownId);
-               setPredecessor(-1);
-               int successorId = remoteFindSuccessor(knownId, this.id);
-               if (successorId == -1) {
-                       Msg.info("Cannot join the ring.");
-               }
-               else {
-                       setFinger(0, successorId);
-               }
-               return successorId != -1;
-       }
-       
-       /**
-        * Sets the node predecessor
-        */
-       void setPredecessor(int predecessorId) {
-               if (predecessorId != predId) {
-                       predId = predecessorId;
-                       if (predecessorId != -1) {
-                               predMailbox = Integer.toString(predId);
-                       }
-                       lastChangeDate = Msg.getClock();
-               }
-       }
-       /**
-        * @brief Asks another node its predecessor.
-        * @param askTo the node to ask to
-        * @return the id of its predecessor node, or -1 if the request failed
-        * (or if the node does not know its predecessor)
-        */
-       int remoteGetPredecessor(int askTo) {
-               int predecessorId = -1;
-               boolean stop = false;
-               Msg.debug("Sending a 'Get Predecessor' request to " + askTo);
-               String mailboxTo = Integer.toString(askTo);
-               GetPredecessorTask sendTask = new GetPredecessorTask(host.getName(), this.mailbox);
-               try {
-                       sendTask.send(mailboxTo, Common.TIMEOUT);                       
-                       try {
-                               do {
-                                       if (commReceive == null) {
-                                               commReceive = Task.irecv(this.mailbox);
-                                       }
-                                       commReceive.waitCompletion(Common.TIMEOUT);
-                                       Task taskReceived = commReceive.getTask();
-                                       if (taskReceived instanceof GetPredecessorAnswerTask) {
-                                               predecessorId = ((GetPredecessorAnswerTask) taskReceived).answerId;
-                                               stop = true;
-                                       }
-                                       else {
-                                               handleTask(taskReceived);
-                                       }
-                                       commReceive = null;                                     
-                               } while (!stop);
-               
-                       }
-                       catch (MsgException e) {
-                               commReceive = null;     
-                               stop = true;
-                       }
-               }
-               catch (MsgException e) {
-                       Msg.debug("Failed to send the Get Predecessor request");
-               }
-               
-               
-               return predecessorId;
-       }
-       /**
-        * @brief Makes the current node find the successor node of an id.
-        * @param node the current node
-        * @param id the id to find
-        * @return the id of the successor node, or -1 if the request failed
-        */
-       int findSuccessor(int id) {
-               if (isInInterval(id, this.id + 1, fingers[0])) {
-                       return fingers[0];
-               }
-               
-               int closest = this.closestPrecedingNode(id);
-               return remoteFindSuccessor(closest, id);
-       }
-       /**
-        * @brief Asks another node the successor node of an id.
-        */
-       int remoteFindSuccessor(int askTo, int id) {
-               int successor = -1;
-               boolean stop = false;
-               String mailbox = Integer.toString(askTo);
-               Task sendTask = new FindSuccessorTask(host.getName(), this.mailbox, id);
-               Msg.debug("Sending a 'Find Successor' request to " + mailbox + " for id " + id);
-               try {
-                       sendTask.send(mailbox, Common.TIMEOUT);
-                       do {
-                               if (commReceive == null) {
-                                       commReceive = Task.irecv(this.mailbox);
-                               }
-                               try {
-                                       commReceive.waitCompletion(Common.TIMEOUT);
-                                       Task task = commReceive.getTask();
-                                       if (task instanceof FindSuccessorAnswerTask) {
-                                               //TODO: Check if this this our answer.
-                                               FindSuccessorAnswerTask fTask = (FindSuccessorAnswerTask) task;
-                                               stop = true;
-                                               successor = fTask.answerId;
-                                       }
-                                       else {
-                                               handleTask(task);
-                                       }
-                                       commReceive = null;
-                               }
-                               catch (TimeoutException e) {
-                                       stop = true;
-                                       commReceive = null;
-                               }
-                       } while (!stop);
-               }
-               catch (TimeoutException e) {
-                       Msg.debug("Failed to send the 'Find Successor' request");
-               }
-               catch (MsgException e) {
-                       Msg.debug("Failed to receive Find Successor");
-               }
-               
-               return successor;
-
-       }
-       /**
-        * @brief This function is called periodically. It checks the immediate
-        * successor of the current node.
-        */
-       void stabilize() {
-               Msg.debug("Stabilizing node");
-               int candidateId;
-               int successorId = fingers[0];
-               if (successorId != this.id){
-                       candidateId = remoteGetPredecessor(successorId);
-               }
-               else {
-                       candidateId = predId;
-               }
-               //This node is a candidate to become my new successor
-               if (candidateId != -1 && isInInterval(candidateId, this.id + 1, successorId - 1)) {
-                       setFinger(0, candidateId);
-               }
-               if (successorId != this.id) {
-                       remoteNotify(successorId, this.id);
-               }
-               
-       }
-       /**
-        * \brief Notifies the current node that its predecessor may have changed.
-        * \param candidate_id the possible new predecessor
-        */
-       void notify(int predecessorCandidateId) {
-               if (predId == -1 || isInInterval(predecessorCandidateId, predId + 1, this.id - 1 )) {
-                       setPredecessor(predecessorCandidateId);
-               }
-               else {
-                       //Don't have to change the predecessor.
-               }
-       }
-       /**
-        * \brief Notifies a remote node that its predecessor may have changed.
-        * \param notify_id id of the node to notify
-        * \param candidate_id the possible new predecessor
-        */     
-       void remoteNotify(int notifyId, int predecessorCandidateId) {
-               Msg.debug("Sending a 'Notify' request to " + notifyId);
-               Task sentTask = new NotifyTask(host.getName(), this.mailbox, predecessorCandidateId);
-               sentTask.dsend(Integer.toString(notifyId));
-       }
-       /**
-        * \brief This function is called periodically.
-        * It refreshes the finger table of the current node.
-        */
-       void fixFingers() {
-               Msg.debug("Fixing fingers");
-               int i = this.nextFingerToFix;
-               int id = this.findSuccessor(this.id + (int)Math.pow(2,i)); //FIXME: SLOW
-               if (id != -1) {
-                       if (id != fingers[i]) {
-                               setFinger(i, id);
-                       }
-                       nextFingerToFix = (i + 1) % Common.NB_BITS;
-               }
-       }
-       /**
-        * \brief This function is called periodically.
-        * It checks whether the predecessor has failed
-        */
-       void checkPredecessor() {
-               //TODO
-       }
-       /**
-        * \brief Performs a find successor request to a random id.
-        */
-       void randomLookup() {
-               int id = 1337;
-               //Msg.info("Making a lookup request for id " + id);
-               findSuccessor(id);
-       }
-       
-       
-
-       /**
-        * @brief Returns the closest preceding finger of an id
-        * with respect to the finger table of the current node.
-        * @param id the id to find
-        * \return the closest preceding finger of that id
-        */
-       int closestPrecedingNode(int id) {
-               int i;
-               for (i = Common.NB_BITS - 1; i >= 0; i--) {
-                       if (isInInterval(fingers[i], this.id + 1, id - 1)) {
-                               return fingers[i];
-                       }
-               }               
-               return this.id;
-       }
-       /**
-        * @brief Returns whether an id belongs to the interval [start, end].
-        *
-        * The parameters are noramlized to make sure they are between 0 and nb_keys - 1).
-        * 1 belongs to [62, 3]
-        * 1 does not belong to [3, 62]
-        * 63 belongs to [62, 3]
-        * 63 does not belong to [3, 62]
-        * 24 belongs to [21, 29]
-        * 24 does not belong to [29, 21]
-        *
-        * \param id id to check
-        * \param start lower bound
-        * \param end upper bound
-        * \return a non-zero value if id in in [start, end]
-        */
-       static boolean isInInterval(int id, int start, int end) {
-               id = normalize(id);
-               start = normalize(start);
-               end = normalize(end);
-               
-               // make sure end >= start and id >= start
-               if (end < start) {
-                       end += Common.NB_KEYS;
-               }
-               if (id < start) {
-                       id += Common.NB_KEYS;
-               }
-               return (id <= end);
-       
-       }
-       /**
-        * @brief Turns an id into an equivalent id in [0, nb_keys).
-        * @param id an id
-        * @return the corresponding normalized id
-        */
-       static int normalize(int id) {
-               return id & (Common.NB_KEYS - 1);
-       }
-       /**
-        * \brief Sets a finger of the current node.
-        * \param finger_index index of the finger to set (0 to nb_bits - 1)
-        * \param id the id to set for this finger
-        */
-       void setFinger(int fingerIndex, int id) {
-               if (id != fingers[fingerIndex]) {
-                       fingers[fingerIndex] = id;
-                       lastChangeDate = Msg.getClock();
-               }
-       }
+  protected int id;
+  protected String mailbox;
+  protected int predId;
+  protected String predMailbox;
+  protected int nextFingerToFix;
+  protected Comm commReceive;
+  ///Last time I changed a finger or my predecessor
+  protected double lastChangeDate;
+  int fingers[];
+
+  public Node(Host host, String name, String[] args) {
+    super(host,name,args);
+  }
+
+  @Override
+  public void main(String[] args) throws MsgException {
+    if (args.length != 2 && args.length != 4) {
+      Msg.info("You need to provide 2 or 4 arguments.");
+      return;
+    }
+    double initTime = Msg.getClock();
+    int i;
+    boolean joinSuccess = false;
+    double deadline;
+
+    double nextStabilizeDate = initTime + Common.PERIODIC_STABILIZE_DELAY;
+    double nextFixFingersDate = initTime + Common.PERIODIC_FIX_FINGERS_DELAY;
+    double nextCheckPredecessorDate = initTime + Common.PERIODIC_CHECK_PREDECESSOR_DELAY;
+    double nextLookupDate = initTime + Common.PERIODIC_LOOKUP_DELAY;
+
+    id = Integer.valueOf(args[0]);
+    mailbox = Integer.toString(id);
+
+    fingers = new int[Common.NB_BITS];
+    for (i = 0; i < Common.NB_BITS; i++) {
+      fingers[i] = -1;
+      setFinger(i,this.id);
+    }
+
+    //First node
+    if (args.length == 2) {
+      deadline = Integer.valueOf(args[1]);
+      create();
+      joinSuccess = true;
+    } else {
+      int knownId = Integer.valueOf(args[1]);
+      deadline = Integer.valueOf(args[3]);
+      //Msg.info("Hey! Let's join the system with the id " + id + ".");
+
+      joinSuccess = join(knownId);
+    }
+    if (joinSuccess) {
+      double currentClock = Msg.getClock();
+      while (currentClock < (initTime + deadline) && currentClock < Common.MAX_SIMULATION_TIME) {
+        if (commReceive == null) {
+          commReceive = Task.irecv(this.mailbox);
+        }
+        try {
+          if (!commReceive.test()) {
+            if (currentClock >= nextStabilizeDate) {
+              stabilize();
+              nextStabilizeDate = Msg.getClock() + Common.PERIODIC_STABILIZE_DELAY;
+            } else if (currentClock >= nextFixFingersDate) {
+              fixFingers();
+              nextFixFingersDate = Msg.getClock() + Common.PERIODIC_FIX_FINGERS_DELAY;
+            } else if (currentClock >= nextCheckPredecessorDate) {
+              this.checkPredecessor();
+              nextCheckPredecessorDate = Msg.getClock() + Common.PERIODIC_CHECK_PREDECESSOR_DELAY;
+            } else if (currentClock >= nextLookupDate) {
+              this.randomLookup();
+              nextLookupDate = Msg.getClock() + Common.PERIODIC_LOOKUP_DELAY;
+            } else {
+              waitFor(5);
+            }
+            currentClock = Msg.getClock();
+          } else {
+            handleTask(commReceive.getTask());
+            currentClock = Msg.getClock();
+            commReceive = null;
+          }
+        }
+        catch (Exception e) {
+          currentClock = Msg.getClock();
+          commReceive = null;
+        }
+      }
+      leave();
+      if (commReceive != null) {
+        commReceive = null;
+      }
+    } else {
+      Msg.info("I couldn't join the ring");
+    }
+  }
+
+  void handleTask(Task task) {
+    if (task instanceof FindSuccessorTask) {
+      FindSuccessorTask fTask = (FindSuccessorTask)task;
+      Msg.debug("Receiving a 'Find Successor' request from " + fTask.issuerHostName + " for id " + fTask.requestId);
+      // is my successor the successor?
+      if (isInInterval(fTask.requestId, this.id + 1, fingers[0])) {
+        //Msg.info("Send the request to " + fTask.answerTo + " with answer " + fingers[0]);
+        FindSuccessorAnswerTask answer = new FindSuccessorAnswerTask(getHost().getName(), mailbox, fingers[0]);
+        answer.dsend(fTask.answerTo);
+      } else {
+        // otherwise, forward the request to the closest preceding finger in my table
+        int closest = closestPrecedingNode(fTask.requestId);
+        //Msg.info("Forward the request to " + closest);
+        fTask.dsend(Integer.toString(closest));
+      }
+    } else if (task instanceof GetPredecessorTask) {
+      GetPredecessorTask gTask = (GetPredecessorTask)(task);
+      Msg.debug("Receiving a 'Get Predecessor' request from " + gTask.issuerHostName);
+      GetPredecessorAnswerTask answer = new GetPredecessorAnswerTask(getHost().getName(), mailbox, predId);
+      answer.dsend(gTask.answerTo);
+    } else if (task instanceof NotifyTask) {
+      NotifyTask nTask = (NotifyTask)task;
+      notify(nTask.requestId);
+    } else {
+      Msg.debug("Ignoring unexpected task of type:" + task);
+    }
+  }
+
+  void leave() {
+    Msg.debug("Well Guys! I Think it's time for me to quit ;)");
+    quitNotify(1); //Notify my successor
+    quitNotify(-1); //Notify my predecessor.
+  }
+
+  /**
+   * @brief Notifies the successor or the predecessor of the current node of the departure
+   * @param to 1 to notify the successor, -1 to notify the predecessor
+   */
+  static void quitNotify( int to) {
+    //TODO
+  }
+
+  /**
+   * @brief Initializes the current node as the first one of the system.
+   */
+  void create() {
+    Msg.debug("Create a new Chord ring...");
+    setPredecessor(-1);
+  }
+
+  // Makes the current node join the ring, knowing the id of a node already in the ring 
+  boolean join(int knownId) {
+    Msg.info("Joining the ring with id " + this.id + " knowing node " + knownId);
+    setPredecessor(-1);
+    int successorId = remoteFindSuccessor(knownId, this.id);
+    if (successorId == -1) {
+      Msg.info("Cannot join the ring.");
+    } else {
+      setFinger(0, successorId);
+    }
+    return successorId != -1;
+  }
+
+  void setPredecessor(int predecessorId) {
+    if (predecessorId != predId) {
+      predId = predecessorId;
+      if (predecessorId != -1) {
+        predMailbox = Integer.toString(predId);
+      }
+      lastChangeDate = Msg.getClock();
+    }
+  }
+
+  /**
+   * @brief Asks another node its predecessor.
+   * @param askTo the node to ask to
+   * @return the id of its predecessor node, or -1 if the request failed(or if the node does not know its predecessor)
+   */
+  int remoteGetPredecessor(int askTo) {
+    int predecessorId = -1;
+    boolean stop = false;
+    Msg.debug("Sending a 'Get Predecessor' request to " + askTo);
+    String mailboxTo = Integer.toString(askTo);
+    GetPredecessorTask sendTask = new GetPredecessorTask(getHost().getName(), this.mailbox);
+    try {
+      sendTask.send(mailboxTo, Common.TIMEOUT);
+      try {
+        do {
+          if (commReceive == null) {
+            commReceive = Task.irecv(this.mailbox);
+          }
+          commReceive.waitCompletion(Common.TIMEOUT);
+          Task taskReceived = commReceive.getTask();
+          if (taskReceived instanceof GetPredecessorAnswerTask) {
+            predecessorId = ((GetPredecessorAnswerTask) taskReceived).answerId;
+            stop = true;
+          } else {
+            handleTask(taskReceived);
+          }
+          commReceive = null;
+        } while (!stop);
+      }
+      catch (MsgException e) {
+        commReceive = null;
+        stop = true;
+      }
+    }
+    catch (MsgException e) {
+      Msg.debug("Failed to send the Get Predecessor request");
+    }
+    return predecessorId;
+  }
+
+  /**
+   * @brief Makes the current node find the successor node of an id.
+   * @param node the current node
+   * @param id the id to find
+   * @return the id of the successor node, or -1 if the request failed
+   */
+  int findSuccessor(int id) {
+    if (isInInterval(id, this.id + 1, fingers[0])) {
+      return fingers[0];
+    }
+
+    int closest = this.closestPrecedingNode(id);
+    return remoteFindSuccessor(closest, id);
+  }
+
+  // Asks another node the successor node of an id.
+  int remoteFindSuccessor(int askTo, int id) {
+    int successor = -1;
+    boolean stop = false;
+    String mailbox = Integer.toString(askTo);
+    Task sendTask = new FindSuccessorTask(getHost().getName(), this.mailbox, id);
+    Msg.debug("Sending a 'Find Successor' request to " + mailbox + " for id " + id);
+    try {
+      sendTask.send(mailbox, Common.TIMEOUT);
+      do {
+        if (commReceive == null) {
+          commReceive = Task.irecv(this.mailbox);
+        }
+        try {
+          commReceive.waitCompletion(Common.TIMEOUT);
+          Task task = commReceive.getTask();
+          if (task instanceof FindSuccessorAnswerTask) {
+            //TODO: Check if this this our answer.
+            FindSuccessorAnswerTask fTask = (FindSuccessorAnswerTask) task;
+            stop = true;
+            successor = fTask.answerId;
+          } else {
+            handleTask(task);
+          }
+          commReceive = null;
+        }
+        catch (TimeoutException e) {
+          stop = true;
+          commReceive = null;
+        }
+      } while (!stop);
+    }
+    catch (TimeoutException e) {
+      Msg.debug("Failed to send the 'Find Successor' request");
+    }
+    catch (MsgException e) {
+      Msg.debug("Failed to receive Find Successor");
+    }
+
+    return successor;
+  }
+
+  // This function is called periodically. It checks the immediate successor of the current node.
+  void stabilize() {
+    Msg.debug("Stabilizing node");
+    int candidateId;
+    int successorId = fingers[0];
+    if (successorId != this.id){
+      candidateId = remoteGetPredecessor(successorId);
+    } else {
+      candidateId = predId;
+    }
+    //This node is a candidate to become my new successor
+    if (candidateId != -1 && isInInterval(candidateId, this.id + 1, successorId - 1)) {
+      setFinger(0, candidateId);
+    }
+    if (successorId != this.id) {
+      remoteNotify(successorId, this.id);
+    }
+  }
+
+  /**
+   * @brief Notifies the current node that its predecessor may have changed.
+   * @param candidate_id the possible new predecessor
+   */
+  void notify(int predecessorCandidateId) {
+    if (predId == -1 || isInInterval(predecessorCandidateId, predId + 1, this.id - 1 )) {
+      setPredecessor(predecessorCandidateId);
+    }
+  }
+
+  /**
+   * @brief Notifies a remote node that its predecessor may have changed.
+   * @param notify_id id of the node to notify
+   * @param candidate_id the possible new predecessor
+   */
+  void remoteNotify(int notifyId, int predecessorCandidateId) {
+    Msg.debug("Sending a 'Notify' request to " + notifyId);
+    Task sentTask = new NotifyTask(getHost().getName(), this.mailbox, predecessorCandidateId);
+    sentTask.dsend(Integer.toString(notifyId));
+  }
+
+  // This function is called periodically.
+  // It refreshes the finger table of the current node.
+  void fixFingers() {
+    Msg.debug("Fixing fingers");
+    int i = this.nextFingerToFix;
+    int id = this.findSuccessor(this.id + (int)Math.pow(2,i)); //FIXME: SLOW
+    if (id != -1) {
+      if (id != fingers[i]) {
+        setFinger(i, id);
+      }
+      nextFingerToFix = (i + 1) % Common.NB_BITS;
+    }
+  }
+
+  // This function is called periodically.
+  // It checks whether the predecessor has failed
+  void checkPredecessor() {
+    //TODO
+  }
+
+  // Performs a find successor request to a random id.
+  void randomLookup() {
+    int id = 1337;
+    //Msg.info("Making a lookup request for id " + id);
+    findSuccessor(id);
+  }
+
+  /**
+   * @brief Returns the closest preceding finger of an id with respect to the finger table of the current node.
+   * @param id the id to find
+   * @return the closest preceding finger of that id
+   */
+  int closestPrecedingNode(int id) {
+    int i;
+    for (i = Common.NB_BITS - 1; i >= 0; i--) {
+      if (isInInterval(fingers[i], this.id + 1, id - 1)) {
+        return fingers[i];
+      }
+    }
+    return this.id;
+  }
+
+  /**
+   * @brief Returns whether an id belongs to the interval [start, end].
+   *
+   * The parameters are noramlized to make sure they are between 0 and nb_keys - 1).
+   * 1 belongs to [62, 3]
+   * 1 does not belong to [3, 62]
+   * 63 belongs to [62, 3]
+   * 63 does not belong to [3, 62]
+   * 24 belongs to [21, 29]
+   * 24 does not belong to [29, 21]
+   *
+   * @param id id to check
+   * @param start lower bound
+   * @param end upper bound
+   * @return a non-zero value if id in in [start, end]
+   */
+  static boolean isInInterval(int id, int start, int end) {
+    id = normalize(id);
+    start = normalize(start);
+    end = normalize(end);
+
+    // make sure end >= start and id >= start
+    if (end < start) {
+      end += Common.NB_KEYS;
+    }
+    if (id < start) {
+      id += Common.NB_KEYS;
+    }
+    return (id <= end);
+  }
+
+  /**
+   * @brief Turns an id into an equivalent id in [0, nb_keys).
+   * @param id an id
+   * @return the corresponding normalized id
+   */
+  static int normalize(int id) {
+    return id & (Common.NB_KEYS - 1);
+  }
+
+  /**
+   * @brief Sets a finger of the current node.
+   * @param finger_index index of the finger to set (0 to nb_bits - 1)
+   * @param id the id to set for this finger
+   */
+  void setFinger(int fingerIndex, int id) {
+    if (id != fingers[fingerIndex]) {
+      fingers[fingerIndex] = id;
+      lastChangeDate = Msg.getClock();
+    }
+  }
 }