-- A SimGrid Lua implementation of the Chord DHT require("simgrid") nb_bits = 24 nb_keys = 2^nb_bits comp_size = 0 comm_size = 10 timeout = 50 max_simulation_time = 1000 stabilize_delay = 20 fix_fingers_delay = 120 check_predecessor_delay = 120 lookup_delay = 10 -- current node (globals are duplicated in each process) my_node = { id = my_id, next_finger_to_fix = 1, fingers = {}, predecessor = nil comm_recv = nil } -- Main function of each Chord process -- Arguments: -- - my id -- - the id of a guy I know in the system (except for the first node) function node(my_id, known_id) simgrid.info("Hello, I'm a node") -- -- join the ring local success = false if known_id == nil then -- first node create() success = true else success = join(known_id) end -- main loop if join_success then local now = simgrid.get_clock() local next_stabilize_date = now + stabilize_delay local next_fix_fingers_date = now + fix_fingers_delay local next_check_predecessor_date = now + check_predecessor_delay local next_lookup_date = now + lookup_delay local task my_node.comm_recv = simgrid.task.irecv(my_node.id) while simgrid.get_clock() < max_simulation_time do task = simgrid.comm.test(node.comm_recv) if task then -- I received a task: answer it my_node.comm_recv = simgrid.task.irecv(my_node.id) handle_task(task) else -- no task was received: do periodic calls if simgrid.get_clock() >= next_fix_fingers_date then end end end leave() end end -- Returns whether an id belongs to the interval [a, b[. -- 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]. function is_in_interval(id, a, b) -- normalize the parameters id = id % nb_bits a = a % nb_bits b = b % nb_bits -- make sure a <= b and a <= id if b < a then b = b + nb_keys end if id < a then id = id + nb_keys end return id <= b end -- Finds the successor of an id -- id: the id to find -- return value: the id of the successor, or -1 if the request failed function find_successor(d) if is_in_interval(id, my_node.id + 1, my_node.fingers[1]) then -- my successor is the successor return my_node.fingers[1] end -- ask to the closest preceding finger in my table local ask_to = closest_preceding_node(id) return remote_find_successor(ask_to, id) end -- Asks a remote node the successor of an id. -- ask_to: id of a remote node to ask to -- id: the id to find -- return value: the id of the successor, or -1 if the request failed function remote_find_successor(ask_to, id) local successor local task = simgrid.task.new(comp_size, comm_size) task[type] = "find successor" task[request_id] = id task[issuer] = my_node.id if task:send(ask_to, timeout) then -- request successfully sent: wait for an answer local stop = false repeat task = simgrid.comm.wait(my_node.comm_recv, timeout) my_node.comm_recv = simgrid.task.irecv(my_node.id) if not task then -- failed to receiver the answer stop = true else -- a task was received: is it the expected answer? if task[type] ~= "find successor" or task[request_id] ~= id then -- this is not our anwser handle_task(task) else -- this is our answer successor = task[answer_id] stop = true end end until stop end return successor end -- Returns the closest preceding finger of an id with respect to the finger -- table of the current node. -- - id: the id to find -- - return value: the closest preceding finger of that id function closest_preceding_node(id) for i = nb_bits, 1, -1 do if is_in_interval(my_node.fingers[i].id, my_node.id + 1, id - 1) then -- finger i is the first one before id return my_node.fingers[i].id end end end simgrid.platform(arg[1] or "../../msg/msg_platform.xml") simgrid.application(arg[2] or "../../msg/chord/chord90.xml") simgrid.run()