simplified paxos functions
This commit is contained in:
		
							parent
							
								
									bc89023c9b
								
							
						
					
					
						commit
						e00e07a057
					
				
							
								
								
									
										99
									
								
								lib/paxos.ex
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								lib/paxos.ex
									
									
									
									
									
								
							@ -26,10 +26,10 @@ defmodule Paxos do
 | 
			
		||||
    run(state)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def add_inst_map(state, inst, value, pid_to_inform, action) do
 | 
			
		||||
 | 
			
		||||
    IO.puts("#{state.name} SET BALLOT VALUE 3 nil")
 | 
			
		||||
 | 
			
		||||
  def has_or_create(state, inst, value \\ nil, pid_to_inform \\ nil, action \\ nil) do
 | 
			
		||||
    if Map.has_key?(state.instmap, inst) do
 | 
			
		||||
      state
 | 
			
		||||
    else
 | 
			
		||||
      instmap =
 | 
			
		||||
        Map.put(state.instmap, inst, %{
 | 
			
		||||
          value: value,
 | 
			
		||||
@ -46,13 +46,6 @@ defmodule Paxos do
 | 
			
		||||
 | 
			
		||||
      %{state | instmap: instmap}
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  def has_or_create(state, inst) do
 | 
			
		||||
    if Map.has_key?(state.instmap, inst) do
 | 
			
		||||
      state
 | 
			
		||||
    else
 | 
			
		||||
      add_inst_map(state, inst, nil, nil, nil)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def has_finished(state, inst) do
 | 
			
		||||
@ -81,7 +74,7 @@ defmodule Paxos do
 | 
			
		||||
 | 
			
		||||
            not Map.has_key?(state.instmap, inst) ->
 | 
			
		||||
              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)
 | 
			
		||||
              prepare(state, inst)
 | 
			
		||||
 | 
			
		||||
@ -90,12 +83,12 @@ defmodule Paxos do
 | 
			
		||||
              Process.send_after(self(), {:timeout, inst}, t)
 | 
			
		||||
 | 
			
		||||
              prepare(
 | 
			
		||||
                set_instmap(state, inst, %{
 | 
			
		||||
                  state.instmap[inst]
 | 
			
		||||
                set_instmap(state, inst, fn map -> %{
 | 
			
		||||
                  map
 | 
			
		||||
                  | value: value,
 | 
			
		||||
                    pid_to_inform: pid_to_inform,
 | 
			
		||||
                    action: action,
 | 
			
		||||
                }),
 | 
			
		||||
                } end),
 | 
			
		||||
                inst
 | 
			
		||||
              )
 | 
			
		||||
 | 
			
		||||
@ -127,7 +120,6 @@ defmodule Paxos do
 | 
			
		||||
              state
 | 
			
		||||
 | 
			
		||||
            not Map.has_key?(state.instmap, inst) ->
 | 
			
		||||
              IO.puts("I think that is the cause")
 | 
			
		||||
              state = has_or_create(state, inst)
 | 
			
		||||
 | 
			
		||||
              Utils.unicast(
 | 
			
		||||
@ -136,10 +128,10 @@ defmodule Paxos do
 | 
			
		||||
                proc
 | 
			
		||||
              )
 | 
			
		||||
              
 | 
			
		||||
              set_instmap(state, inst, %{
 | 
			
		||||
                state.instmap[inst]
 | 
			
		||||
              set_instmap(state, inst, fn map -> %{
 | 
			
		||||
                map
 | 
			
		||||
                | ballot: ballot
 | 
			
		||||
              })
 | 
			
		||||
              } end)
 | 
			
		||||
 | 
			
		||||
            ballot > state.instmap[inst].ballot ->
 | 
			
		||||
              Utils.unicast(
 | 
			
		||||
@ -148,10 +140,10 @@ defmodule Paxos do
 | 
			
		||||
                proc
 | 
			
		||||
              )
 | 
			
		||||
 | 
			
		||||
              set_instmap(state, inst, %{
 | 
			
		||||
                state.instmap[inst]
 | 
			
		||||
              set_instmap(state, inst, fn map -> %{
 | 
			
		||||
                map
 | 
			
		||||
                | ballot: ballot
 | 
			
		||||
              })
 | 
			
		||||
              } end)
 | 
			
		||||
 | 
			
		||||
            true ->
 | 
			
		||||
              Utils.unicast({:nack, inst, ballot}, proc)
 | 
			
		||||
@ -177,9 +169,9 @@ defmodule Paxos do
 | 
			
		||||
                send(state.instmap[inst].pid_to_inform, {:abort, inst})
 | 
			
		||||
              end
 | 
			
		||||
 | 
			
		||||
              set_instmap(state, inst, %{
 | 
			
		||||
                state.instmap[inst] | has_sent_accept: false
 | 
			
		||||
              })
 | 
			
		||||
              set_instmap(state, inst, fn map -> %{
 | 
			
		||||
                map | has_sent_accept: false
 | 
			
		||||
              } end)
 | 
			
		||||
 | 
			
		||||
            true ->
 | 
			
		||||
              state
 | 
			
		||||
@ -196,13 +188,10 @@ defmodule Paxos do
 | 
			
		||||
 | 
			
		||||
            ballot == state.instmap[inst].ballot ->
 | 
			
		||||
              state =
 | 
			
		||||
                set_instmap(state, inst, %{
 | 
			
		||||
                  state.instmap[inst]
 | 
			
		||||
                  | prepared_values:
 | 
			
		||||
                      state.instmap[inst].prepared_values ++ [{accepted_ballot, accepted_value}]
 | 
			
		||||
                })
 | 
			
		||||
 | 
			
		||||
              IO.puts("#{state.name} Try to run prepared")
 | 
			
		||||
                set_instmap(state, inst, fn map -> %{
 | 
			
		||||
                  map
 | 
			
		||||
                  | prepared_values: map.prepared_values ++ [{accepted_ballot, accepted_value}]
 | 
			
		||||
                } end)
 | 
			
		||||
 | 
			
		||||
              prepared(state, inst)
 | 
			
		||||
 | 
			
		||||
@ -228,12 +217,12 @@ defmodule Paxos do
 | 
			
		||||
            
 | 
			
		||||
                Utils.unicast({:accepted, inst, ballot}, proc)
 | 
			
		||||
 | 
			
		||||
                set_instmap(state, inst, %{
 | 
			
		||||
                  state.instmap[inst]
 | 
			
		||||
                set_instmap(state, inst, fn map -> %{
 | 
			
		||||
                  map
 | 
			
		||||
                  | ballot: ballot,
 | 
			
		||||
                    accepted_value: value,
 | 
			
		||||
                    accepted_ballot: ballot
 | 
			
		||||
                })
 | 
			
		||||
                } end)
 | 
			
		||||
              else
 | 
			
		||||
                IO.puts("#{state.name} -> #{proc} nack")
 | 
			
		||||
                Utils.unicast({:nack, inst, ballot}, proc)
 | 
			
		||||
@ -249,10 +238,10 @@ defmodule Paxos do
 | 
			
		||||
          else
 | 
			
		||||
            if state.leader == state.name and state.instmap[inst].ballot == ballot do
 | 
			
		||||
              accepted(
 | 
			
		||||
                set_instmap(state, inst, %{
 | 
			
		||||
                  state.instmap[inst]
 | 
			
		||||
                  | accepted: state.instmap[inst].accepted + 1
 | 
			
		||||
                }),
 | 
			
		||||
                set_instmap(state, inst, fn map -> %{
 | 
			
		||||
                  map
 | 
			
		||||
                  | accepted: map.accepted + 1
 | 
			
		||||
                } end),
 | 
			
		||||
                inst
 | 
			
		||||
              )
 | 
			
		||||
            else
 | 
			
		||||
@ -297,8 +286,8 @@ defmodule Paxos do
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_instmap(state, inst, instmap) do
 | 
			
		||||
    new_instmap = Map.put(state.instmap, inst, instmap)
 | 
			
		||||
  def set_instmap(state, inst, set_instmap) do
 | 
			
		||||
    new_instmap = Map.put(state.instmap, inst, set_instmap.(state.instmap[inst]))
 | 
			
		||||
    %{state | instmap: new_instmap}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -321,14 +310,13 @@ defmodule Paxos do
 | 
			
		||||
        IO.puts("#{state.name} sending all prepare #{inst} #{ballot}")
 | 
			
		||||
        EagerReliableBroadcast.broadcast(state.name, {:prepare, state.name, inst, ballot})
 | 
			
		||||
 | 
			
		||||
        IO.puts("#{state.name} SET BALLOT VALUE 2 nil")
 | 
			
		||||
        set_instmap(state, inst, %{
 | 
			
		||||
          state.instmap[inst]
 | 
			
		||||
        set_instmap(state, inst, fn map -> %{
 | 
			
		||||
          map
 | 
			
		||||
          |  prepared_values: [],
 | 
			
		||||
            accepted: 0,
 | 
			
		||||
            ballot_value: nil,
 | 
			
		||||
            has_sent_accept: false
 | 
			
		||||
        })
 | 
			
		||||
        } end)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -338,7 +326,6 @@ defmodule Paxos do
 | 
			
		||||
  def prepared(state, _) when state.leader != state.name, do: state
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
         not state.instmap[inst].has_sent_accept do
 | 
			
		||||
      {_, a_val} =
 | 
			
		||||
@ -367,13 +354,11 @@ defmodule Paxos do
 | 
			
		||||
        {:accept, inst, state.instmap[inst].ballot, a_val}
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      IO.puts("#{state.name} SET BALLOT VALUE #{inspect(a_val)}")
 | 
			
		||||
 | 
			
		||||
      set_instmap(state, inst, %{
 | 
			
		||||
        state.instmap[inst]
 | 
			
		||||
      set_instmap(state, inst, fn map -> %{
 | 
			
		||||
        map
 | 
			
		||||
        | ballot_value: a_val,
 | 
			
		||||
          has_sent_accept: true
 | 
			
		||||
      })
 | 
			
		||||
      } end)
 | 
			
		||||
    else
 | 
			
		||||
      state
 | 
			
		||||
    end
 | 
			
		||||
@ -412,22 +397,12 @@ defmodule Paxos do
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def propose_action(pid, inst, value, t, action) do
 | 
			
		||||
    # Utils.unicast({:propose, value}, name)
 | 
			
		||||
 | 
			
		||||
  def propose(pid, inst, value, t, action \\ nil) do
 | 
			
		||||
    send(pid, {:propose, inst, value, t, self(), action})
 | 
			
		||||
 | 
			
		||||
    propose_loop(inst)
 | 
			
		||||
  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
 | 
			
		||||
    receive do
 | 
			
		||||
      {:timeout, inst} ->
 | 
			
		||||
 | 
			
		||||
@ -15,10 +15,8 @@ defmodule PaxosTestAditional do
 | 
			
		||||
            [new_leader | _] = spare
 | 
			
		||||
 | 
			
		||||
            if name == leader do
 | 
			
		||||
              # Propose with action when passed with :kill_before_decision will die right before a decision is selected
 | 
			
		||||
              Paxos.propose_action(pid, 1, val, 1000, :kill_before_decision)
 | 
			
		||||
              # Process.sleep(Enum.random(1..5))
 | 
			
		||||
              # Process.exit(pid, :kill)
 | 
			
		||||
              # Propose  when passed with :kill_before_decision will die right before a decision is selected
 | 
			
		||||
              Paxos.propose(pid, 1, val, 1000, :kill_before_decision)
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            if name == new_leader do
 | 
			
		||||
 | 
			
		||||
@ -22,42 +22,42 @@ test_suite = [
 | 
			
		||||
  # Use TestUtil.get_local_config(n) to generate a single-node configuration 
 | 
			
		||||
  # consisting of n processes, all running on the same node.
 | 
			
		||||
 | 
			
		||||
  {&PaxosTest.run_simple/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
   "No failures, no concurrent ballots, 3 local procs"},
 | 
			
		||||
  {&PaxosTest.run_simple/3, TestUtil.get_dist_config(host, 3), 10,
 | 
			
		||||
   "No failures, no concurrent ballots, 3 nodes"},
 | 
			
		||||
  {&PaxosTest.run_simple/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
   "No failures, no concurrent ballots, 5 local procs"},
 | 
			
		||||
  {&PaxosTest.run_simple_2/3, TestUtil.get_dist_config(host, 3), 10,
 | 
			
		||||
   "No failures, 2 concurrent ballots, 3 nodes"},
 | 
			
		||||
  {&PaxosTest.run_simple_2/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
   "No failures, 2 concurrent ballots, 3 local procs"},
 | 
			
		||||
  {&PaxosTest.run_simple_3/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
   "No failures, 2 concurrent instances, 3 local procs"},
 | 
			
		||||
  {&PaxosTest.run_simple_many_1/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
   "No failures, many concurrent ballots 1, 5 nodes"},
 | 
			
		||||
  {&PaxosTest.run_simple_many_1/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
   "No failures, many concurrent ballots 1, 5 local procs"},
 | 
			
		||||
  {&PaxosTest.run_simple_many_2/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
   "No failures, many concurrent ballots 2, 5 nodes"},
 | 
			
		||||
  {&PaxosTest.run_simple_many_2/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
   "No failures, many concurrent ballots 2, 5 local procs"},
 | 
			
		||||
  {&PaxosTest.run_non_leader_crash/3, TestUtil.get_dist_config(host, 3), 10,
 | 
			
		||||
   "One non-leader crashes, no concurrent ballots, 3 nodes"},
 | 
			
		||||
  {&PaxosTest.run_non_leader_crash/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
   "One non-leader crashes, no concurrent ballots, 3 local procs"},
 | 
			
		||||
  {&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
   "Minority non-leader crashes, no concurrent ballots"},
 | 
			
		||||
  {&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
   "Minority non-leader crashes, no concurrent ballots"},
 | 
			
		||||
  {&PaxosTest.run_leader_crash_simple/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
   "Leader crashes, no concurrent ballots, 5 nodes"},
 | 
			
		||||
  {&PaxosTest.run_leader_crash_simple/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
   "Leader crashes, no concurrent ballots, 5 local procs"},
 | 
			
		||||
  {&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"},
 | 
			
		||||
  {&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"},
 | 
			
		||||
  # {&PaxosTest.run_simple/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
  #  "No failures, no concurrent ballots, 3 local procs"},
 | 
			
		||||
  # {&PaxosTest.run_simple/3, TestUtil.get_dist_config(host, 3), 10,
 | 
			
		||||
  #  "No failures, no concurrent ballots, 3 nodes"},
 | 
			
		||||
  # {&PaxosTest.run_simple/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
  #  "No failures, no concurrent ballots, 5 local procs"},
 | 
			
		||||
  # {&PaxosTest.run_simple_2/3, TestUtil.get_dist_config(host, 3), 10,
 | 
			
		||||
  #  "No failures, 2 concurrent ballots, 3 nodes"},
 | 
			
		||||
  # {&PaxosTest.run_simple_2/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
  #  "No failures, 2 concurrent ballots, 3 local procs"},
 | 
			
		||||
  # {&PaxosTest.run_simple_3/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
  #  "No failures, 2 concurrent instances, 3 local procs"},
 | 
			
		||||
  # {&PaxosTest.run_simple_many_1/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
  #  "No failures, many concurrent ballots 1, 5 nodes"},
 | 
			
		||||
  # {&PaxosTest.run_simple_many_1/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
  #  "No failures, many concurrent ballots 1, 5 local procs"},
 | 
			
		||||
  # {&PaxosTest.run_simple_many_2/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
  #  "No failures, many concurrent ballots 2, 5 nodes"},
 | 
			
		||||
  # {&PaxosTest.run_simple_many_2/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
  #  "No failures, many concurrent ballots 2, 5 local procs"},
 | 
			
		||||
  # {&PaxosTest.run_non_leader_crash/3, TestUtil.get_dist_config(host, 3), 10,
 | 
			
		||||
  #  "One non-leader crashes, no concurrent ballots, 3 nodes"},
 | 
			
		||||
  # {&PaxosTest.run_non_leader_crash/3, TestUtil.get_local_config(3), 10,
 | 
			
		||||
  #  "One non-leader crashes, no concurrent ballots, 3 local procs"},
 | 
			
		||||
  # {&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
  #  "Minority non-leader crashes, no concurrent ballots"},
 | 
			
		||||
  # {&PaxosTest.run_minority_non_leader_crash/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
  #  "Minority non-leader crashes, no concurrent ballots"},
 | 
			
		||||
  # {&PaxosTest.run_leader_crash_simple/3, TestUtil.get_dist_config(host, 5), 10,
 | 
			
		||||
  #  "Leader crashes, no concurrent ballots, 5 nodes"},
 | 
			
		||||
  # {&PaxosTest.run_leader_crash_simple/3, TestUtil.get_local_config(5), 10,
 | 
			
		||||
  #  "Leader crashes, no concurrent ballots, 5 local procs"},
 | 
			
		||||
  # {&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"},
 | 
			
		||||
  # {&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"},
 | 
			
		||||
  {&PaxosTest.run_leader_crash_complex/3, TestUtil.get_dist_config(host, 11), 10,
 | 
			
		||||
   "Cascading failures of leaders and non-leaders, 11 nodes"},
 | 
			
		||||
  {&PaxosTest.run_leader_crash_complex/3, TestUtil.get_local_config(11), 10,
 | 
			
		||||
@ -69,10 +69,10 @@ test_suite = [
 | 
			
		||||
 | 
			
		||||
  # Aditional Test functions
 | 
			
		||||
  
 | 
			
		||||
  {&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"},
 | 
			
		||||
  {&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"},
 | 
			
		||||
  # {&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"},
 | 
			
		||||
  # {&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"},
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
Node.stop()
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user