simplified paxos functions
This commit is contained in:
parent
bc89023c9b
commit
e00e07a057
123
lib/paxos.ex
123
lib/paxos.ex
@ -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} ->
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
Reference in New Issue
Block a user