This repository has been archived on 2024-01-29. You can view files and clone it, but cannot push or open issues or pull requests.
distributed_system_coursework/lib/leader_elector.ex

77 lines
1.9 KiB
Elixir
Raw Normal View History

2023-11-28 21:42:11 +00:00
#
# Emits {:ele_trust, proc }
#
defmodule EventualLeaderElector do
def getEleName(name) do
String.to_atom(Atom.to_string(name) <> "_ele")
end
def start(name, processes) do
new_name = getEleName(name)
pid = spawn(EventualLeaderElector, :init, [new_name, name, processes])
Utils.register_name(new_name, pid)
end
# Init event must be the first
# one after the component is created
def init(name, parent, processes) do
processes = Enum.map(processes, fn name -> getEleName(name) end)
state = %{
name: name,
parent: parent,
processes: processes,
timeout: 1000,
heard_back: MapSet.new(),
seq: 0,
last_trust: nil
}
run(request_heartbeats(state))
end
def request_heartbeats(state) do
state = %{state | heard_back: MapSet.new(), seq: state.seq + 1}
Utils.beb_broadcast({:heartbeat_request, state.name, state.seq}, state.processes)
Process.send_after(self(), {:timeout}, state.timeout)
state
end
def run(state) do
run(
receive do
{:heartbeat_request, name, seq} ->
2024-01-02 23:40:03 +00:00
Utils.unicast({:heartbeat, state.parent, seq}, name)
2023-11-28 21:42:11 +00:00
state
{:heartbeat, name, seq} ->
if seq == state.seq do
%{state | heard_back: MapSet.put(state.heard_back, name)}
else
state
end
{:timeout} ->
state =
if MapSet.size(state.heard_back) < floor(length(state.processes)/2) + 1 do
2023-11-28 21:42:11 +00:00
state
else
2024-01-02 23:40:03 +00:00
to_trust = Enum.at(Enum.sort(MapSet.to_list(state.heard_back)), 0)
2023-11-28 21:42:11 +00:00
if state.last_trust != to_trust do
Utils.unicast({:ele_trust, to_trust}, state.parent)
%{state | last_trust: to_trust}
else
state
end
end
request_heartbeats(state)
end
)
end
end