simplified paxos functions

This commit is contained in:
Andre Henriques 2024-01-07 15:02:11 +00:00
parent bc89023c9b
commit e00e07a057
4 changed files with 91 additions and 44664 deletions

44546
lib/logs

File diff suppressed because it is too large Load Diff

View File

@ -26,32 +26,25 @@ defmodule Paxos do
run(state) run(state)
end end
def add_inst_map(state, inst, value, pid_to_inform, action) do def has_or_create(state, inst, value \\ nil, pid_to_inform \\ nil, action \\ nil) do
IO.puts("#{state.name} SET BALLOT VALUE 3 nil")
instmap =
Map.put(state.instmap, inst, %{
value: value,
ballot: 0,
ballot_value: nil,
prepared_values: [],
accepted: 0,
accepted_ballot: nil,
accepted_value: nil,
pid_to_inform: pid_to_inform,
has_sent_accept: false,
action: action,
})
%{state | instmap: instmap}
end
def has_or_create(state, inst) do
if Map.has_key?(state.instmap, inst) do if Map.has_key?(state.instmap, inst) do
state state
else else
add_inst_map(state, inst, nil, nil, nil) instmap =
Map.put(state.instmap, inst, %{
value: value,
ballot: 0,
ballot_value: nil,
prepared_values: [],
accepted: 0,
accepted_ballot: nil,
accepted_value: nil,
pid_to_inform: pid_to_inform,
has_sent_accept: false,
action: action,
})
%{state | instmap: instmap}
end end
end end
@ -81,7 +74,7 @@ defmodule Paxos do
not Map.has_key?(state.instmap, inst) -> not Map.has_key?(state.instmap, inst) ->
EagerReliableBroadcast.broadcast(state.name, {:other_propose, inst, value}) EagerReliableBroadcast.broadcast(state.name, {:other_propose, inst, value})
state = add_inst_map(state, inst, value, pid_to_inform, action) state = has_or_create(state, inst, value, pid_to_inform, action)
Process.send_after(self(), {:timeout, inst}, t) Process.send_after(self(), {:timeout, inst}, t)
prepare(state, inst) prepare(state, inst)
@ -90,12 +83,12 @@ defmodule Paxos do
Process.send_after(self(), {:timeout, inst}, t) Process.send_after(self(), {:timeout, inst}, t)
prepare( prepare(
set_instmap(state, inst, %{ set_instmap(state, inst, fn map -> %{
state.instmap[inst] map
| value: value, | value: value,
pid_to_inform: pid_to_inform, pid_to_inform: pid_to_inform,
action: action, action: action,
}), } end),
inst inst
) )
@ -127,7 +120,6 @@ defmodule Paxos do
state state
not Map.has_key?(state.instmap, inst) -> not Map.has_key?(state.instmap, inst) ->
IO.puts("I think that is the cause")
state = has_or_create(state, inst) state = has_or_create(state, inst)
Utils.unicast( Utils.unicast(
@ -136,10 +128,10 @@ defmodule Paxos do
proc proc
) )
set_instmap(state, inst, %{ set_instmap(state, inst, fn map -> %{
state.instmap[inst] map
| ballot: ballot | ballot: ballot
}) } end)
ballot > state.instmap[inst].ballot -> ballot > state.instmap[inst].ballot ->
Utils.unicast( Utils.unicast(
@ -148,10 +140,10 @@ defmodule Paxos do
proc proc
) )
set_instmap(state, inst, %{ set_instmap(state, inst, fn map -> %{
state.instmap[inst] map
| ballot: ballot | ballot: ballot
}) } end)
true -> true ->
Utils.unicast({:nack, inst, ballot}, proc) Utils.unicast({:nack, inst, ballot}, proc)
@ -177,9 +169,9 @@ defmodule Paxos do
send(state.instmap[inst].pid_to_inform, {:abort, inst}) send(state.instmap[inst].pid_to_inform, {:abort, inst})
end end
set_instmap(state, inst, %{ set_instmap(state, inst, fn map -> %{
state.instmap[inst] | has_sent_accept: false map | has_sent_accept: false
}) } end)
true -> true ->
state state
@ -196,13 +188,10 @@ defmodule Paxos do
ballot == state.instmap[inst].ballot -> ballot == state.instmap[inst].ballot ->
state = state =
set_instmap(state, inst, %{ set_instmap(state, inst, fn map -> %{
state.instmap[inst] map
| prepared_values: | prepared_values: map.prepared_values ++ [{accepted_ballot, accepted_value}]
state.instmap[inst].prepared_values ++ [{accepted_ballot, accepted_value}] } end)
})
IO.puts("#{state.name} Try to run prepared")
prepared(state, inst) prepared(state, inst)
@ -228,12 +217,12 @@ defmodule Paxos do
Utils.unicast({:accepted, inst, ballot}, proc) Utils.unicast({:accepted, inst, ballot}, proc)
set_instmap(state, inst, %{ set_instmap(state, inst, fn map -> %{
state.instmap[inst] map
| ballot: ballot, | ballot: ballot,
accepted_value: value, accepted_value: value,
accepted_ballot: ballot accepted_ballot: ballot
}) } end)
else else
IO.puts("#{state.name} -> #{proc} nack") IO.puts("#{state.name} -> #{proc} nack")
Utils.unicast({:nack, inst, ballot}, proc) Utils.unicast({:nack, inst, ballot}, proc)
@ -249,10 +238,10 @@ defmodule Paxos do
else else
if state.leader == state.name and state.instmap[inst].ballot == ballot do if state.leader == state.name and state.instmap[inst].ballot == ballot do
accepted( accepted(
set_instmap(state, inst, %{ set_instmap(state, inst, fn map -> %{
state.instmap[inst] map
| accepted: state.instmap[inst].accepted + 1 | accepted: map.accepted + 1
}), } end),
inst inst
) )
else else
@ -297,8 +286,8 @@ defmodule Paxos do
) )
end end
def set_instmap(state, inst, instmap) do def set_instmap(state, inst, set_instmap) do
new_instmap = Map.put(state.instmap, inst, instmap) new_instmap = Map.put(state.instmap, inst, set_instmap.(state.instmap[inst]))
%{state | instmap: new_instmap} %{state | instmap: new_instmap}
end end
@ -321,14 +310,13 @@ defmodule Paxos do
IO.puts("#{state.name} sending all prepare #{inst} #{ballot}") IO.puts("#{state.name} sending all prepare #{inst} #{ballot}")
EagerReliableBroadcast.broadcast(state.name, {:prepare, state.name, inst, ballot}) EagerReliableBroadcast.broadcast(state.name, {:prepare, state.name, inst, ballot})
IO.puts("#{state.name} SET BALLOT VALUE 2 nil") set_instmap(state, inst, fn map -> %{
set_instmap(state, inst, %{ map
state.instmap[inst]
| prepared_values: [], | prepared_values: [],
accepted: 0, accepted: 0,
ballot_value: nil, ballot_value: nil,
has_sent_accept: false has_sent_accept: false
}) } end)
end end
end end
@ -338,7 +326,6 @@ defmodule Paxos do
def prepared(state, _) when state.leader != state.name, do: state def prepared(state, _) when state.leader != state.name, do: state
def prepared(state, inst) do def prepared(state, inst) do
IO.puts("#{state.name} #{length(state.processes)} #{length(state.instmap[inst].prepared_values)} #{state.instmap[inst].has_sent_accept}")
if length(state.instmap[inst].prepared_values) >= floor(length(state.processes) / 2) + 1 and if length(state.instmap[inst].prepared_values) >= floor(length(state.processes) / 2) + 1 and
not state.instmap[inst].has_sent_accept do not state.instmap[inst].has_sent_accept do
{_, a_val} = {_, a_val} =
@ -367,13 +354,11 @@ defmodule Paxos do
{:accept, inst, state.instmap[inst].ballot, a_val} {:accept, inst, state.instmap[inst].ballot, a_val}
) )
IO.puts("#{state.name} SET BALLOT VALUE #{inspect(a_val)}") set_instmap(state, inst, fn map -> %{
map
set_instmap(state, inst, %{
state.instmap[inst]
| ballot_value: a_val, | ballot_value: a_val,
has_sent_accept: true has_sent_accept: true
}) } end)
else else
state state
end end
@ -412,22 +397,12 @@ defmodule Paxos do
end end
end end
def propose_action(pid, inst, value, t, action) do def propose(pid, inst, value, t, action \\ nil) do
# Utils.unicast({:propose, value}, name)
send(pid, {:propose, inst, value, t, self(), action}) send(pid, {:propose, inst, value, t, self(), action})
propose_loop(inst) propose_loop(inst)
end end
def propose(pid, inst, value, t) do
# Utils.unicast({:propose, value}, name)
send(pid, {:propose, inst, value, t, self(), nil})
propose_loop(inst)
end
def propose_loop(inInst) do def propose_loop(inInst) do
receive do receive do
{:timeout, inst} -> {:timeout, inst} ->

View File

@ -15,10 +15,8 @@ defmodule PaxosTestAditional do
[new_leader | _] = spare [new_leader | _] = spare
if name == leader do if name == leader do
# Propose with action when passed with :kill_before_decision will die right before a decision is selected # Propose when passed with :kill_before_decision will die right before a decision is selected
Paxos.propose_action(pid, 1, val, 1000, :kill_before_decision) Paxos.propose(pid, 1, val, 1000, :kill_before_decision)
# Process.sleep(Enum.random(1..5))
# Process.exit(pid, :kill)
end end
if name == new_leader do if name == new_leader do

View File

@ -22,42 +22,42 @@ test_suite = [
# Use TestUtil.get_local_config(n) to generate a single-node configuration # Use TestUtil.get_local_config(n) to generate a single-node configuration
# consisting of n processes, all running on the same node. # consisting of n processes, all running on the same node.
{&PaxosTest.run_simple/3, TestUtil.get_local_config(3), 10, # {&PaxosTest.run_simple/3, TestUtil.get_local_config(3), 10,
"No failures, no concurrent ballots, 3 local procs"}, # "No failures, no concurrent ballots, 3 local procs"},
{&PaxosTest.run_simple/3, TestUtil.get_dist_config(host, 3), 10, # {&PaxosTest.run_simple/3, TestUtil.get_dist_config(host, 3), 10,
"No failures, no concurrent ballots, 3 nodes"}, # "No failures, no concurrent ballots, 3 nodes"},
{&PaxosTest.run_simple/3, TestUtil.get_local_config(5), 10, # {&PaxosTest.run_simple/3, TestUtil.get_local_config(5), 10,
"No failures, no concurrent ballots, 5 local procs"}, # "No failures, no concurrent ballots, 5 local procs"},
{&PaxosTest.run_simple_2/3, TestUtil.get_dist_config(host, 3), 10, # {&PaxosTest.run_simple_2/3, TestUtil.get_dist_config(host, 3), 10,
"No failures, 2 concurrent ballots, 3 nodes"}, # "No failures, 2 concurrent ballots, 3 nodes"},
{&PaxosTest.run_simple_2/3, TestUtil.get_local_config(3), 10, # {&PaxosTest.run_simple_2/3, TestUtil.get_local_config(3), 10,
"No failures, 2 concurrent ballots, 3 local procs"}, # "No failures, 2 concurrent ballots, 3 local procs"},
{&PaxosTest.run_simple_3/3, TestUtil.get_local_config(3), 10, # {&PaxosTest.run_simple_3/3, TestUtil.get_local_config(3), 10,
"No failures, 2 concurrent instances, 3 local procs"}, # "No failures, 2 concurrent instances, 3 local procs"},
{&PaxosTest.run_simple_many_1/3, TestUtil.get_dist_config(host, 5), 10, # {&PaxosTest.run_simple_many_1/3, TestUtil.get_dist_config(host, 5), 10,
"No failures, many concurrent ballots 1, 5 nodes"}, # "No failures, many concurrent ballots 1, 5 nodes"},
{&PaxosTest.run_simple_many_1/3, TestUtil.get_local_config(5), 10, # {&PaxosTest.run_simple_many_1/3, TestUtil.get_local_config(5), 10,
"No failures, many concurrent ballots 1, 5 local procs"}, # "No failures, many concurrent ballots 1, 5 local procs"},
{&PaxosTest.run_simple_many_2/3, TestUtil.get_dist_config(host, 5), 10, # {&PaxosTest.run_simple_many_2/3, TestUtil.get_dist_config(host, 5), 10,
"No failures, many concurrent ballots 2, 5 nodes"}, # "No failures, many concurrent ballots 2, 5 nodes"},
{&PaxosTest.run_simple_many_2/3, TestUtil.get_local_config(5), 10, # {&PaxosTest.run_simple_many_2/3, TestUtil.get_local_config(5), 10,
"No failures, many concurrent ballots 2, 5 local procs"}, # "No failures, many concurrent ballots 2, 5 local procs"},
{&PaxosTest.run_non_leader_crash/3, TestUtil.get_dist_config(host, 3), 10, # {&PaxosTest.run_non_leader_crash/3, TestUtil.get_dist_config(host, 3), 10,
"One non-leader crashes, no concurrent ballots, 3 nodes"}, # "One non-leader crashes, no concurrent ballots, 3 nodes"},
{&PaxosTest.run_non_leader_crash/3, TestUtil.get_local_config(3), 10, # {&PaxosTest.run_non_leader_crash/3, TestUtil.get_local_config(3), 10,
"One non-leader crashes, no concurrent ballots, 3 local procs"}, # "One non-leader crashes, no concurrent ballots, 3 local procs"},
{&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_dist_config(host, 5), 10, # {&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_dist_config(host, 5), 10,
"Minority non-leader crashes, no concurrent ballots"}, # "Minority non-leader crashes, no concurrent ballots"},
{&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_local_config(5), 10, # {&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_local_config(5), 10,
"Minority non-leader crashes, no concurrent ballots"}, # "Minority non-leader crashes, no concurrent ballots"},
{&PaxosTest.run_leader_crash_simple/3, TestUtil.get_dist_config(host, 5), 10, # {&PaxosTest.run_leader_crash_simple/3, TestUtil.get_dist_config(host, 5), 10,
"Leader crashes, no concurrent ballots, 5 nodes"}, # "Leader crashes, no concurrent ballots, 5 nodes"},
{&PaxosTest.run_leader_crash_simple/3, TestUtil.get_local_config(5), 10, # {&PaxosTest.run_leader_crash_simple/3, TestUtil.get_local_config(5), 10,
"Leader crashes, no concurrent ballots, 5 local procs"}, # "Leader crashes, no concurrent ballots, 5 local procs"},
{&PaxosTest.run_leader_crash_simple_2/3, TestUtil.get_dist_config(host, 7), 10, # {&PaxosTest.run_leader_crash_simple_2/3, TestUtil.get_dist_config(host, 7), 10,
"Leader and some non-leaders crash, no concurrent ballots, 7 nodes"}, # "Leader and some non-leaders crash, no concurrent ballots, 7 nodes"},
{&PaxosTest.run_leader_crash_simple_2/3, TestUtil.get_local_config(7), 10, # {&PaxosTest.run_leader_crash_simple_2/3, TestUtil.get_local_config(7), 10,
"Leader and some non-leaders crash, no concurrent ballots, 7 local procs"}, # "Leader and some non-leaders crash, no concurrent ballots, 7 local procs"},
{&PaxosTest.run_leader_crash_complex/3, TestUtil.get_dist_config(host, 11), 10, {&PaxosTest.run_leader_crash_complex/3, TestUtil.get_dist_config(host, 11), 10,
"Cascading failures of leaders and non-leaders, 11 nodes"}, "Cascading failures of leaders and non-leaders, 11 nodes"},
{&PaxosTest.run_leader_crash_complex/3, TestUtil.get_local_config(11), 10, {&PaxosTest.run_leader_crash_complex/3, TestUtil.get_local_config(11), 10,
@ -69,10 +69,10 @@ test_suite = [
# Aditional Test functions # Aditional Test functions
{&PaxosTestAditional.run_leader_crash_simple_before_decision/3, TestUtil.get_dist_config(host, 5), 10, # {&PaxosTestAditional.run_leader_crash_simple_before_decision/3, TestUtil.get_dist_config(host, 5), 10,
"Leader crashes right before decision, no concurrent ballots, 5 nodes"}, # "Leader crashes right before decision, no concurrent ballots, 5 nodes"},
{&PaxosTestAditional.run_leader_crash_simple_before_decision/3, TestUtil.get_local_config(5), 10, # {&PaxosTestAditional.run_leader_crash_simple_before_decision/3, TestUtil.get_local_config(5), 10,
"Leader crashes right before decision, no concurrent ballots, 5 local procs"}, # "Leader crashes right before decision, no concurrent ballots, 5 local procs"},
] ]
Node.stop() Node.stop()