+++ /dev/null
-/*
- * Copyright 2006-2012. The SimGrid Team. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the license (GNU LGPL) which comes with this package.
- */
-package chord;
-
-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.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();
- }
- }
-}