3 import org.simgrid.msg.Comm;
4 import org.simgrid.msg.Host;
5 import org.simgrid.msg.Msg;
6 import org.simgrid.msg.MsgException;
7 import org.simgrid.msg.Process;
8 import org.simgrid.msg.Task;
9 import org.simgrid.msg.TimeoutException;
13 public class Node extends Process {
21 protected String mailbox;
29 protected String predMailbox;
31 * Index of the next finger to fix
33 protected int nextFingerToFix;
35 * Current communication
37 protected Comm commReceive;
39 * Last time I changed a finger or my predecessor
41 protected double lastChangeDate;
49 public Node(Host host, String name, String[] args) {
50 super(host,name,args);
53 public void main(String[] args) throws MsgException {
54 if (args.length != 2 && args.length != 4) {
55 Msg.info("You need to provide 2 or 4 arguments.");
58 double initTime = Msg.getClock();
60 boolean joinSuccess = false;
63 double nextStabilizeDate = initTime + Common.PERIODIC_STABILIZE_DELAY;
64 double nextFixFingersDate = initTime + Common.PERIODIC_FIX_FINGERS_DELAY;
65 double nextCheckPredecessorDate = initTime + Common.PERIODIC_CHECK_PREDECESSOR_DELAY;
66 double nextLookupDate = initTime + Common.PERIODIC_LOOKUP_DELAY;
68 id = Integer.valueOf(args[0]);
69 mailbox = Integer.toString(id);
71 fingers = new int[Common.NB_BITS];
72 for (i = 0; i < Common.NB_BITS; i++) {
78 if (args.length == 2) {
79 deadline = Integer.valueOf(args[1]);
84 int knownId = Integer.valueOf(args[1]);
85 deadline = Integer.valueOf(args[3]);
86 //Msg.info("Hey! Let's join the system with the id " + id + ".");
88 joinSuccess = join(knownId);
91 double currentClock = Msg.getClock();
92 while (currentClock < (initTime + deadline) && currentClock < Common.MAX_SIMULATION_TIME) {
93 if (commReceive == null) {
94 commReceive = Task.irecv(this.mailbox);
97 if (!commReceive.test()) {
98 if (currentClock >= nextStabilizeDate) {
100 nextStabilizeDate = Msg.getClock() + Common.PERIODIC_STABILIZE_DELAY;
102 else if (currentClock >= nextFixFingersDate) {
104 nextFixFingersDate = Msg.getClock() + Common.PERIODIC_FIX_FINGERS_DELAY;
106 else if (currentClock >= nextCheckPredecessorDate) {
107 this.checkPredecessor();
108 nextCheckPredecessorDate = Msg.getClock() + Common.PERIODIC_CHECK_PREDECESSOR_DELAY;
110 else if (currentClock >= nextLookupDate) {
112 nextLookupDate = Msg.getClock() + Common.PERIODIC_LOOKUP_DELAY;
117 currentClock = Msg.getClock();
120 handleTask(commReceive.getTask());
121 currentClock = Msg.getClock();
126 catch (Exception e) {
127 currentClock = Msg.getClock();
133 if (commReceive != null) {
138 Msg.info("I couldn't join the ring");
141 void handleTask(Task task) {
142 if (task instanceof FindSuccessorTask) {
143 FindSuccessorTask fTask = (FindSuccessorTask)task;
144 Msg.debug("Receiving a 'Find Successor' request from " + fTask.issuerHostName + " for id " + fTask.requestId);
145 // is my successor the successor?
146 if (isInInterval(fTask.requestId, this.id + 1, fingers[0])) {
147 //Msg.info("Send the request to " + fTask.answerTo + " with answer " + fingers[0]);
148 FindSuccessorAnswerTask answer = new FindSuccessorAnswerTask(host.getName(), mailbox, fingers[0]);
149 answer.dsend(fTask.answerTo);
152 // otherwise, forward the request to the closest preceding finger in my table
153 int closest = closestPrecedingNode(fTask.requestId);
154 //Msg.info("Forward the request to " + closest);
155 fTask.dsend(Integer.toString(closest));
158 else if (task instanceof GetPredecessorTask) {
159 GetPredecessorTask gTask = (GetPredecessorTask)(task);
160 Msg.debug("Receiving a 'Get Predecessor' request from " + gTask.issuerHostName);
161 GetPredecessorAnswerTask answer = new GetPredecessorAnswerTask(host.getName(), mailbox, predId);
162 answer.dsend(gTask.answerTo);
164 else if (task instanceof NotifyTask) {
165 NotifyTask nTask = (NotifyTask)task;
166 notify(nTask.requestId);
169 Msg.debug("Ignoring unexpected task of type:" + task);
173 * @brief Makes the current node quit the system
176 Msg.debug("Well Guys! I Think it's time for me to quit ;)");
177 quitNotify(1); //Notify my successor
178 quitNotify(-1); //Notify my predecessor.
182 * @brief Notifies the successor or the predecessor of the current node
184 * @param to 1 to notify the successor, -1 to notify the predecessor
186 static void quitNotify( int to) {
190 * @brief Initializes the current node as the first one of the system.
193 Msg.debug("Create a new Chord ring...");
198 * Makes the current node join the ring, knowing the id of a node
199 * already in the ring
201 boolean join(int knownId) {
202 Msg.info("Joining the ring with id " + this.id + " knowing node " + knownId);
204 int successorId = remoteFindSuccessor(knownId, this.id);
205 if (successorId == -1) {
206 Msg.info("Cannot join the ring.");
209 setFinger(0, successorId);
211 return successorId != -1;
215 * Sets the node predecessor
217 void setPredecessor(int predecessorId) {
218 if (predecessorId != predId) {
219 predId = predecessorId;
220 if (predecessorId != -1) {
221 predMailbox = Integer.toString(predId);
223 lastChangeDate = Msg.getClock();
227 * @brief Asks another node its predecessor.
228 * @param askTo the node to ask to
229 * @return the id of its predecessor node, or -1 if the request failed
230 * (or if the node does not know its predecessor)
232 int remoteGetPredecessor(int askTo) {
233 int predecessorId = -1;
234 boolean stop = false;
235 Msg.debug("Sending a 'Get Predecessor' request to " + askTo);
236 String mailboxTo = Integer.toString(askTo);
237 GetPredecessorTask sendTask = new GetPredecessorTask(host.getName(), this.mailbox);
239 sendTask.send(mailboxTo, Common.TIMEOUT);
242 if (commReceive == null) {
243 commReceive = Task.irecv(this.mailbox);
245 commReceive.waitCompletion(Common.TIMEOUT);
246 Task taskReceived = commReceive.getTask();
247 if (taskReceived instanceof GetPredecessorAnswerTask) {
248 predecessorId = ((GetPredecessorAnswerTask) taskReceived).answerId;
252 handleTask(taskReceived);
258 catch (MsgException e) {
263 catch (MsgException e) {
264 Msg.debug("Failed to send the Get Predecessor request");
268 return predecessorId;
271 * @brief Makes the current node find the successor node of an id.
272 * @param node the current node
273 * @param id the id to find
274 * @return the id of the successor node, or -1 if the request failed
276 int findSuccessor(int id) {
277 if (isInInterval(id, this.id + 1, fingers[0])) {
281 int closest = this.closestPrecedingNode(id);
282 return remoteFindSuccessor(closest, id);
285 * @brief Asks another node the successor node of an id.
287 int remoteFindSuccessor(int askTo, int id) {
289 boolean stop = false;
290 String mailbox = Integer.toString(askTo);
291 Task sendTask = new FindSuccessorTask(host.getName(), this.mailbox, id);
292 Msg.debug("Sending a 'Find Successor' request to " + mailbox + " for id " + id);
294 sendTask.send(mailbox, Common.TIMEOUT);
296 if (commReceive == null) {
297 commReceive = Task.irecv(this.mailbox);
300 commReceive.waitCompletion(Common.TIMEOUT);
301 Task task = commReceive.getTask();
302 if (task instanceof FindSuccessorAnswerTask) {
303 //TODO: Check if this this our answer.
304 FindSuccessorAnswerTask fTask = (FindSuccessorAnswerTask) task;
306 successor = fTask.answerId;
313 catch (TimeoutException e) {
319 catch (TimeoutException e) {
320 Msg.debug("Failed to send the 'Find Successor' request");
322 catch (MsgException e) {
323 Msg.debug("Failed to receive Find Successor");
330 * @brief This function is called periodically. It checks the immediate
331 * successor of the current node.
334 Msg.debug("Stabilizing node");
336 int successorId = fingers[0];
337 if (successorId != this.id){
338 candidateId = remoteGetPredecessor(successorId);
341 candidateId = predId;
343 //This node is a candidate to become my new successor
344 if (candidateId != -1 && isInInterval(candidateId, this.id + 1, successorId - 1)) {
345 setFinger(0, candidateId);
347 if (successorId != this.id) {
348 remoteNotify(successorId, this.id);
353 * \brief Notifies the current node that its predecessor may have changed.
354 * \param candidate_id the possible new predecessor
356 void notify(int predecessorCandidateId) {
357 if (predId == -1 || isInInterval(predecessorCandidateId, predId + 1, this.id - 1 )) {
358 setPredecessor(predecessorCandidateId);
361 //Don't have to change the predecessor.
365 * \brief Notifies a remote node that its predecessor may have changed.
366 * \param notify_id id of the node to notify
367 * \param candidate_id the possible new predecessor
369 void remoteNotify(int notifyId, int predecessorCandidateId) {
370 Msg.debug("Sending a 'Notify' request to " + notifyId);
371 Task sentTask = new NotifyTask(host.getName(), this.mailbox, predecessorCandidateId);
372 sentTask.dsend(Integer.toString(notifyId));
375 * \brief This function is called periodically.
376 * It refreshes the finger table of the current node.
379 Msg.debug("Fixing fingers");
380 int i = this.nextFingerToFix;
381 int id = this.findSuccessor(this.id + (int)Math.pow(2,i)); //FIXME: SLOW
383 if (id != fingers[i]) {
386 nextFingerToFix = (i + 1) % Common.NB_BITS;
390 * \brief This function is called periodically.
391 * It checks whether the predecessor has failed
393 void checkPredecessor() {
397 * \brief Performs a find successor request to a random id.
399 void randomLookup() {
401 //Msg.info("Making a lookup request for id " + id);
408 * @brief Returns the closest preceding finger of an id
409 * with respect to the finger table of the current node.
410 * @param id the id to find
411 * \return the closest preceding finger of that id
413 int closestPrecedingNode(int id) {
415 for (i = Common.NB_BITS - 1; i >= 0; i--) {
416 if (isInInterval(fingers[i], this.id + 1, id - 1)) {
423 * @brief Returns whether an id belongs to the interval [start, end].
425 * The parameters are noramlized to make sure they are between 0 and nb_keys - 1).
426 * 1 belongs to [62, 3]
427 * 1 does not belong to [3, 62]
428 * 63 belongs to [62, 3]
429 * 63 does not belong to [3, 62]
430 * 24 belongs to [21, 29]
431 * 24 does not belong to [29, 21]
433 * \param id id to check
434 * \param start lower bound
435 * \param end upper bound
436 * \return a non-zero value if id in in [start, end]
438 static boolean isInInterval(int id, int start, int end) {
440 start = normalize(start);
441 end = normalize(end);
443 // make sure end >= start and id >= start
445 end += Common.NB_KEYS;
448 id += Common.NB_KEYS;
454 * @brief Turns an id into an equivalent id in [0, nb_keys).
456 * @return the corresponding normalized id
458 static int normalize(int id) {
459 return id & (Common.NB_KEYS - 1);
462 * \brief Sets a finger of the current node.
463 * \param finger_index index of the finger to set (0 to nb_bits - 1)
464 * \param id the id to set for this finger
466 void setFinger(int fingerIndex, int id) {
467 if (id != fingers[fingerIndex]) {
468 fingers[fingerIndex] = id;
469 lastChangeDate = Msg.getClock();