1 /* Copyright (c) 2010. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
10 #include "xbt/asserts.h"
11 XBT_LOG_NEW_DEFAULT_CATEGORY(msg_chord,
12 "Messages specific for this msg example");
20 typedef struct finger {
23 } s_finger_t, *finger_t;
31 s_finger_t fingers[NB_BITS]; // finger table (fingers[0] is my successor)
32 int pred_id; // predecessor id
33 const char* pred_mailbox;
39 typedef struct task_data {
43 const char* answer_to;
44 } s_task_data_t, *task_data_t;
47 static int normalize(int id);
48 static int is_in_interval(int id, int start, int end);
49 static char* get_mailbox(int host_id);
52 static int node(int argc, char *argv[]);
53 static int sender(int argc,char *argv[]);
56 static void initialize_first_node(node_t node);
57 static void initialize_finger_table(node_t data, int known_id);
58 static void join(node_t node, int known_id);
61 static int find_successor(node_t node, int id);
62 static int remote_find_successor(node_t node, int ask_to_id, int id);
63 static int find_predecessor(node_t node, int id);
64 static int remote_find_predecessor(node_t node, int ask_to_id, int id);
65 static int closest_preceding_finger(node_t node, int id);
66 static int remote_closest_preceding_finger(int ask_to_id, int id);
67 static void notify(node_t);
68 static void remote_move_keys(node_t node, int take_from_id);
69 static void update_finger_table(node_t node, int candidate_id, int finger_index);
70 static void remote_update_finger_table(int ask_to_id, int candidate_id, int finger_index);
72 //static void find_successor_node(node_t my_data, m_task_t join_task);
75 * \brief Turns an id into an equivalent id in [0, NB_KEYS[
77 * \return the corresponding normalized id
79 static int normalize(int id) {
86 // make sure id < NB_KEYS
93 * \brief Returns whether a id belongs to the interval [start, end].
95 * The parameters are noramlized to make sure they are between 0 and CHORD_NB_KEYS - 1).
96 * 1 belongs to [62, 3]
97 * 1 does not belong to [3, 62]
98 * 63 belongs to [62, 3]
99 * 63 does not belong to [3, 62]
100 * 24 belongs to [21, 29]
101 * 24 does not belong to [29, 21]
103 * \param id id to check
104 * \param start lower bound
105 * \param end upper bound
106 * \return a non-zero value if id in in [start, end]
108 static int is_in_interval(int id, int start, int end) {
111 start = normalize(start);
112 end = normalize(end);
114 // make sure end >= start and id >= start
127 * \brief Gets the mailbox name of a host given its chord id.
128 * \param node_id id of a node
129 * \return the name of its mailbox
130 * FIXME: free the memory
132 static char* get_mailbox(int node_id) {
134 return bprintf("mailbox%d", node_id);
138 * \brief Node Function
141 * - the id of a guy I know in the system (except for the first node)
142 * - the time to sleep before I join (except for the first node)
144 int node(int argc, char *argv[])
146 xbt_assert0(argc == 2 || argc == 4, "Wrong number of arguments for this node");
148 // initialize my node
150 node.id = atoi(argv[1]);
151 node.mailbox = get_mailbox(node.id);
153 if (argc == 2) { // first ring
154 initialize_first_node(&node);
157 int known_id = atoi(argv[2]);
158 double sleep_time = atof(argv[3]);
160 // sleep before starting
161 INFO1("Let's sleep >>%f", sleep_time);
162 MSG_process_sleep(sleep_time);
163 INFO0("Hey! Let's join the system.");
165 join(&node, known_id);
170 m_task_t task = NULL;
171 MSG_error_t res = MSG_task_receive(&task, node.mailbox);
173 xbt_assert0(res == MSG_OK, "MSG_task_receive failed");
176 const char* task_name = MSG_task_get_name(task);
177 task_data_t task_data = (task_data_t) MSG_task_get_data(task);
179 if (!strcmp(task_name, "Find Successor")) {
181 // is my successor the successor?
182 if (is_in_interval(task_data->request_id, node.id + 1, node.fingers[0].id)) {
183 task_data->answer_id = node.fingers[0].id;
184 MSG_task_set_name(task, "Find Successor Answer");
185 MSG_task_send(task, task_data->answer_to);
188 // otherwise, forward the request to the closest preceding finger in my table
189 int closest = closest_preceding_finger(&node, task_data->request_id);
190 MSG_task_send(task, get_mailbox(closest));
194 else if (!strcmp(task_name, "Find Successor Answer")) {
198 else if (!strcmp(task_name, "Find Predecessor")) {
200 // am I the predecessor?
201 if (is_in_interval(task_data->request_id, node.id + 1, node.fingers[0].id)) {
202 task_data->answer_id = node.id;
203 MSG_task_set_name(task, "Find Predecessor Answer");
204 MSG_task_send(task, task_data->answer_to);
207 // otherwise, forward the request to the closest preceding finger in my table
208 int closest = closest_preceding_finger(&node, task_data->request_id);
209 MSG_task_send(task, get_mailbox(closest));
213 else if (!strcmp(task_name, "Find Predecessor Answer")) {
217 else if (!strcmp(task_name, "Update Finger")) {
218 update_finger_table(&node, task_data->request_id, task_data->request_finger);
221 else if (!strcmp(task_name, "Fix Fingers"))
224 for (i = KEY_BITS - 1 ; i >= 0; i--)
226 data->fingers[i] = find_finger_elem(data,(data->id)+pow(2,i-1));
234 * \brief Initializes the current node as the first one of the system.
235 * \param node the current node
237 static void initialize_first_node(node_t node)
239 INFO0("Create a new Chord ring...");
241 // I am my own successor and predecessor
243 for (i = 0; i < NB_BITS; i++) {
244 node->fingers[i].id = node->id;
245 node->fingers[i].mailbox = node->mailbox;
247 node->pred_id = node->id;
248 node->pred_mailbox = node->mailbox;
252 * \brief Makes the current node join the system, knowing the id of a node already in the system
253 * \param node the current node
254 * \param known_id id of a node already in the system
256 static void join(node_t node, int known_id)
258 initialize_finger_table(node, known_id); // determine my fingers, asking to known_id
259 notify(node); // tell others that I may have became their finger
260 remote_move_keys(node, node->fingers[0].id); // take some key-value pairs from my sucessor
264 * \brief Initializes my finger table, knowing the id of a node already in the system.
265 * \param node the current node
266 * \param known_id id of a node already in the system
268 static void initialize_finger_table(node_t node, int known_id)
270 int my_id = node->id;
274 // ask known_id who is my immediate successor
275 node->fingers[0].id = remote_find_successor(node, known_id, my_id + 1);
276 node->fingers[0].mailbox = get_mailbox(node->fingers[0].id);
278 // find all other fingers
279 for (i = 0; i < NB_BITS - 1; i++) {
281 pow = pow << 1; // equivalent to pow = pow * 2
282 if (is_in_interval(my_id + pow, my_id, node->fingers[i].id - 1)) {
283 // I already have the info for this finger
284 node->fingers[i + 1].id = node->fingers[i].id;
287 // I don't have the info, ask the only guy I know
288 node->fingers[i + 1].id = remote_find_successor(node, known_id, my_id + pow);
290 node->fingers[i + 1].mailbox = get_mailbox(node->fingers[i + 1].id);
295 * \brief Notifies some nodes that the current node may have became their finger.
296 * \param node the current node, which has just joined the system
298 static void notify(node_t node)
302 for (i = 0; i < NB_KEYS; i++) {
303 // find the closest node whose finger #i can be me
304 pred_id = find_predecessor(node, node->id - pow);
305 remote_update_finger_table(pred_id, node->id, i);
306 pow = pow << 1; // pow = pow * 2
311 * \brief Tells the current node that a node may have became its new finger.
312 * \param node the current node
313 * \param candidate_id id of the node that may be a new finger of the current node
314 * \param finger_index index of the finger to update
316 static void update_finger_table(node_t node, int candidate_id, int finger_index)
318 if (is_in_interval(candidate_id, node->id, node->fingers[finger_index].id - 1)) {
320 // candidate_id is my new finger
321 node->fingers[finger_index].id = candidate_id;
322 node->fingers[finger_index].mailbox = get_mailbox(candidate_id);
324 // my predecessor may be concerned too
325 remote_update_finger_table(node->pred_id, candidate_id, finger_index);
330 * \brief Tells a remote node that a node may have became its new finger.
331 * \param ask_to_id id of the remote node to update
332 * \param candidate_id id of the node that may be a new finger of the remote node
333 * \param finger_index index of the finger to update
335 static void remote_update_finger_table(int ask_to_id, int candidate_id, int finger_index)
337 s_task_data_t req_data;
338 req_data.request_id = candidate_id;
339 req_data.request_finger = finger_index;
341 // send a "Update Finger" request to ask_to_id
342 m_task_t task = MSG_task_create("Update Finger", 1000, 5000, &req_data);
343 MSG_task_send(task, get_mailbox(ask_to_id));
346 /* deprecated version where the remote host modifies the issuer's node data
347 static void find_successor_node(node_t n_data,m_task_t join_task) //use all data
350 node_t recv_data = (node_t)MSG_task_get_data(join_task);
351 INFO3("recv_data->id : %i , n_data->id :%i , successor->id :%i",recv_data->id,n_data->id,n_data->fingers[0].id);
352 //if ((recv_data->id >= n_data->id) && (recv_data->id <= n_data->fingers[0].id))
353 if (is_in_interval(recv_data->id,n_data->id,n_data->fingers[0].id))
355 INFO1("Successor Is %s",n_data->fingers[0].host_name);
356 //predecessor(recv_data) >>>> n_data
357 recv_data->pred_host_name = n_data->host_name;
358 recv_data->pred_id = n_data->id;
359 recv_data->pred_mailbox = n_data->pred_mailbox;
360 // successor(recv_data) >>>> n_data.finger[0]
361 recv_data->fingers_nb = 1;
362 recv_data->fingers[0].host_name = n_data->fingers[0].host_name;
363 recv_data->fingers[0].id = n_data->fingers[0].id;
364 recv_data->fingers[0].mailbox = n_data->fingers[0].mailbox;
365 // successor(n_data) >>>> recv_sucessor
366 n_data->fingers[0].id = recv_data->id;
367 n_data->fingers[0].host_name = recv_data->host_name;
368 n_data->fingers[0].mailbox = recv_data->mailbox;
370 INFO1("Sending back a Join Request to %s",recv_data->host_name);
371 MSG_task_set_name(join_task,"Join Response");
372 MSG_task_send(join_task,recv_data->mailbox);
377 const char* closest_preceding_mailbox = find_closest_preceding(n_data,recv_data->id);
378 INFO1("Forwarding Join Call to mailbox %s",closest_preceding_mailbox);
379 MSG_task_send(join_task,closest_preceding_mailbox);
385 * \brief Makes the current node find the successor node of an id.
386 * \param node the current node
387 * \param id the id to find
388 * \return the id of the successor node
390 static int find_successor(node_t node, int id)
392 // is my successor the successor?
393 if (is_in_interval(id, node->id + 1, node->fingers[0].id)) {
394 return node->fingers[0].id;
397 // otherwise, ask the closest preceding finger in my table
398 int closest = closest_preceding_finger(node, id);
399 return remote_find_successor(node, closest, id);
403 * \brief Asks another node the successor node of an id.
404 * \param node the current node
405 * \param ask_to the node to ask to
406 * \param id the id to find
407 * \return the id of the successor node
409 static int remote_find_successor(node_t node, int ask_to, int id)
411 s_task_data_t req_data;
412 req_data.request_id = id;
413 req_data.answer_to = node->mailbox;
415 // send a "Find Successor" request to ask_to_id
416 m_task_t task = MSG_task_create("Find Successor", 1000, 5000, &req_data);
417 MSG_task_send(task, get_mailbox(ask_to));
419 // receive the answer
421 MSG_task_receive(&task, node->mailbox); // FIXME: don't receive here other messages than the excepted one
422 task_data_t ans_data;
423 ans_data = MSG_task_get_data(task);
424 int successor = ans_data->answer_id;
430 * \brief Makes the current node find the predecessor node of an id.
431 * \param node the current node
432 * \param id the id to find
433 * \return the id of the predecessor node
435 static int find_predecessor(node_t node, int id)
437 if (node->id == node->fingers[0].id) {
438 // I am the only node in the system
442 if (is_in_interval(id, node->id + 1, node->fingers[0].id)) {
445 int ask_to = closest_preceding_finger(node, id);
446 return remote_find_predecessor(node, ask_to, id);
450 * \brief Asks another node the predecessor node of an id.
451 * \param node the current node
452 * \param ask_to the node to ask to
453 * \param id the id to find
454 * \return the id of the predecessor node
456 static int remote_find_predecessor(node_t node, int ask_to, int id)
458 s_task_data_t req_data;
459 req_data.request_id = id;
460 req_data.answer_to = node->mailbox;
462 // send a "Find Predecessor" request to ask_to
463 m_task_t task = MSG_task_create("Find Predecessor", 1000, 5000, &req_data);
464 MSG_task_send(task, get_mailbox(ask_to));
466 // receive the answer
468 MSG_task_receive(&task, node->mailbox); // FIXME: don't receive here other messages than the excepted one
469 task_data_t ans_data;
470 ans_data = MSG_task_get_data(task);
471 int predecessor = ans_data->answer_id;
477 * \brief Returns the closest preceding finger of an id
478 * with respect to the finger table of the current node.
479 * \param node the current node
480 * \param id the id to find
481 * \return the closest preceding finger of that id
483 int closest_preceding_finger(node_t node, int id)
486 for (i = NB_BITS - 1; i >= 0; i--) {
487 if (is_in_interval(node->fingers[i].id, node->id + 1, id - 1)) {
488 return node->fingers[i].id;
495 * \brief Asks a node to take some of its keys.
496 * \param node the current node, which has just joined the system
497 * \param take_from_id id of a node who may have keys to give to the current node
499 static void remote_move_keys(node_t node, int take_from_id) {
504 * \brief Main function.
506 int main(int argc, char *argv[])
509 printf("Usage: %s platform_file deployment_file\n", argv[0]);
510 printf("example: %s ../msg_platform.xml chord.xml\n", argv[0]);
514 MSG_global_init(&argc, argv);
516 const char* platform_file = argv[1];
517 const char* application_file = argv[2];
519 /* MSG_config("workstation/model","KCCFLN05"); */
520 MSG_set_channel_number(0);
521 MSG_create_environment(platform_file);
523 MSG_function_register("node", node);
524 MSG_launch_application(application_file);
526 MSG_error_t res = MSG_main();
527 INFO1("Simulation time: %g", MSG_get_clock());