diff --git a/lib/paxos.ex b/lib/paxos.ex index da869f9..8bf9474 100644 --- a/lib/paxos.ex +++ b/lib/paxos.ex @@ -228,9 +228,7 @@ defmodule Paxos do safecast(proc, {:prepared, inst, ballot, state.instmap[inst].accepted_ballot, state.instmap[inst].accepted_value}); set_instmap do - %{ map - | ballot: ballot - } + %{ map | ballot: ballot } end Ballot.compare(ballot, &>/2, state.instmap[inst].ballot) -> @@ -240,9 +238,7 @@ defmodule Paxos do ) set_instmap do - %{ map - | ballot: ballot - } + %{ map | ballot: ballot } end true -> @@ -257,7 +253,7 @@ defmodule Paxos do has_finished(state, inst) -> state - state.leader == state.name and Ballot.compare(state.instmap[inst].ballot, &==/2, ballot) -> + state.leader == state.name and state.instmap[inst].ballot == ballot -> if Map.has_key?(state.instmap, inst) and state.instmap[inst].pid_to_inform != nil do send(state.instmap[inst].pid_to_inform, {:abort, inst}) end @@ -300,10 +296,9 @@ defmodule Paxos do has_finished(state, inst) -> state - Ballot.compare(ballot, &==/2, state.instmap[inst].ballot) -> + ballot == state.instmap[inst].ballot -> set_instmap do - %{ - map + %{ map | prepared_values: map.prepared_values ++ [{accepted_ballot, accepted_value}] } end @@ -354,9 +349,7 @@ defmodule Paxos do state.leader == state.name and state.instmap[inst].ballot == ballot -> set_instmap do - %{ map | - accepted: map.accepted + 1 - } + %{ map | accepted: map.accepted + 1 } end accepted( state, inst) diff --git a/lib/server.ex b/lib/server.ex index 63d7564..d7c5d94 100644 --- a/lib/server.ex +++ b/lib/server.ex @@ -8,15 +8,16 @@ defmodule ServerMacros do end ast2 = quote do value -> - Process.send_after(self(), value, 100) - unquote(function_name)(v) + log("Got unexpected value: #{inspect(value)}") + Process.send_after(self(), value, t + 2000) + unquote(function_name)(v, t) end ast3 = ast1 ++ match_exp ++ ast2 if after_exp != nil do quote do - def unquote(function_name)(v) do + def unquote(function_name)(v, t) do var!(v) = v unquote(process_exp) receive do @@ -28,11 +29,13 @@ defmodule ServerMacros do end else quote do - def unquote(function_name)(v) do + def unquote(function_name)(v, t) do var!(v) = v unquote(process_exp) receive do unquote(ast3) + after + t -> :timeout end end end @@ -63,7 +66,6 @@ defmodule ServerMacros do ast2 = quote do {:decision, v} -> var!(state) = apply_game(var!(state), v) - var!(res) = v unquote(recal_do) v -> @@ -88,7 +90,7 @@ defmodule Server do require Utils import Utils - create_log 2 + create_log 3 def start(name, participants) do log("starting server") @@ -115,56 +117,91 @@ defmodule Server do {state, game_id} = try_to_create_game(state, participants) safecast(pid_to_inform, {:start_game_ans, game_id}) state + + {:get_game_state, game_id, pid_to_inform} -> + get_game_state(state, game_id, pid_to_inform) end + def get_game_state(state, game_id, pid_to_inform, repeat \\ false) do + cond do + state.games[game_id] == :not_playing_in_game -> + safecast(pid_to_inform, {:game_state, game_id, :not_playing}) + state + + state.games[game_id] == nil -> + if repeat do + safecast(pid_to_inform, {:game_state, game_id, :game_does_not_exist}) + state + else + state = qurey_status(state) + get_game_state(state, game_id, pid_to_inform, true) + end + + true -> + state = qurey_status(state) + safecast(pid_to_inform, {:game_state, game_id, state.games[game_id].game_state, state.games[game_id].hand}) + state + end + end + + def try_to_create_game(state, participants) do game_ids = Map.keys(state.games) latest = Enum.at(Enum.sort(game_ids), length(game_ids) - 1) - log("#{inspect(latest)}") new_game_id = if latest do latest else 0 end + 1 - log("#{inspect(new_game_id)}") # TODO: randomize game state new_game_state = [1, 1] # TODO: randomize Initial hand value hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, 1) end) - res = nil - try_propose {:start_game, new_game_id, participants, new_game_state, hand} do {:decision, {:start_game, ^new_game_id, ^participants, ^new_game_state, ^hand}} -> state = apply_game(state, {:start_game, new_game_id, participants, new_game_state, hand}) {state, new_game_id} else - log("HERE #{inspect(res)}") try_to_create_game(state, participants) end end + # + # Utils + # + + def qurey_status(state) do + v = Paxos.get_decision(state.paxos, state.instance, 100) + or_state v != nil do + state = apply_game(state, v) + qurey_status(state) + end + end + # # Apply Game States # - def apply_game(state, {:start_game, game_id, participants, new_game_state, hand}) do - if state.name in participants do - %{state | - games: Map.put(state.games, game_id, %{ - game_state: new_game_state, - participants: participants, - hand: hand[state.name], - }), - instance: state.instance + 1 - } - else - %{state | - games: Map.put(state.games, game_id, :not_playing_in_it), - instance: state.instance + 1, - } + cond do + state.games[game_id] -> + raise :game_already_exists + state.name in participants -> + %{state | + games: Map.put(state.games, game_id, %{ + game_state: new_game_state, + participants: participants, + hand: hand[state.name], + }), + instance: state.instance + 1 + } + true -> + %{state | + games: Map.put(state.games, game_id, :not_playing_in_game), + instance: state.instance + 1, + } end end - def apply_game(state, _), do: raise :do_not_know_how_to_apply_game_state + def apply_game(_, _), do: raise :do_not_know_how_to_apply_game_state ############ # Interface @@ -174,28 +211,31 @@ defmodule Server do {:start_game_ans, game_id} -> log("Started a game #{game_id}") {:start_game, game_id} - after - 1000 -> :timeout end - def start_game_loop() do - receive do - {:start_game_ans, game_id} -> - log("Started a game #{game_id}") - {:start_game, game_id} - v -> - Process.send_after(self(), v, 1000) - start_game_loop() - after - 1000 -> :timeout - end - end - def start_game(name, participants) do safecast(name, {:start_game, participants, self()}) - start_game_loop(nil) + start_game_loop(nil, 1000) end + create_loop :get_game_state do + {:game_state, ^v, :not_playing} -> + IO.puts("Not Playing in that game") + :not_playing + {:game_state, ^v, game_state, hand} -> + IO.puts("Got game state, #{inspect(game_state)}, hand: #{inspect(hand)}") + {game_state, hand} + {:game_state, ^v, :game_does_not_exist} -> + IO.puts("Got game does not exist") + nil + end + + def get_game_state(name, game_id) do + safecast(name, {:get_game_state, game_id, self()}) + get_game_state_loop(game_id, 1000) + end + + ############ # Debug ############