This commit is contained in:
parent
47b02d37ec
commit
1d2db555be
19
lib/paxos.ex
19
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});
|
safecast(proc, {:prepared, inst, ballot, state.instmap[inst].accepted_ballot, state.instmap[inst].accepted_value});
|
||||||
|
|
||||||
set_instmap do
|
set_instmap do
|
||||||
%{ map
|
%{ map | ballot: ballot }
|
||||||
| ballot: ballot
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Ballot.compare(ballot, &>/2, state.instmap[inst].ballot) ->
|
Ballot.compare(ballot, &>/2, state.instmap[inst].ballot) ->
|
||||||
@ -240,9 +238,7 @@ defmodule Paxos do
|
|||||||
)
|
)
|
||||||
|
|
||||||
set_instmap do
|
set_instmap do
|
||||||
%{ map
|
%{ map | ballot: ballot }
|
||||||
| ballot: ballot
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
@ -257,7 +253,7 @@ defmodule Paxos do
|
|||||||
has_finished(state, inst) ->
|
has_finished(state, inst) ->
|
||||||
state
|
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
|
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})
|
send(state.instmap[inst].pid_to_inform, {:abort, inst})
|
||||||
end
|
end
|
||||||
@ -300,10 +296,9 @@ defmodule Paxos do
|
|||||||
has_finished(state, inst) ->
|
has_finished(state, inst) ->
|
||||||
state
|
state
|
||||||
|
|
||||||
Ballot.compare(ballot, &==/2, state.instmap[inst].ballot) ->
|
ballot == state.instmap[inst].ballot ->
|
||||||
set_instmap do
|
set_instmap do
|
||||||
%{
|
%{ map
|
||||||
map
|
|
||||||
| prepared_values: map.prepared_values ++ [{accepted_ballot, accepted_value}]
|
| prepared_values: map.prepared_values ++ [{accepted_ballot, accepted_value}]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -354,9 +349,7 @@ defmodule Paxos do
|
|||||||
|
|
||||||
state.leader == state.name and state.instmap[inst].ballot == ballot ->
|
state.leader == state.name and state.instmap[inst].ballot == ballot ->
|
||||||
set_instmap do
|
set_instmap do
|
||||||
%{ map |
|
%{ map | accepted: map.accepted + 1 }
|
||||||
accepted: map.accepted + 1
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
accepted( state, inst)
|
accepted( state, inst)
|
||||||
|
126
lib/server.ex
126
lib/server.ex
@ -8,15 +8,16 @@ defmodule ServerMacros do
|
|||||||
end
|
end
|
||||||
ast2 = quote do
|
ast2 = quote do
|
||||||
value ->
|
value ->
|
||||||
Process.send_after(self(), value, 100)
|
log("Got unexpected value: #{inspect(value)}")
|
||||||
unquote(function_name)(v)
|
Process.send_after(self(), value, t + 2000)
|
||||||
|
unquote(function_name)(v, t)
|
||||||
end
|
end
|
||||||
|
|
||||||
ast3 = ast1 ++ match_exp ++ ast2
|
ast3 = ast1 ++ match_exp ++ ast2
|
||||||
|
|
||||||
if after_exp != nil do
|
if after_exp != nil do
|
||||||
quote do
|
quote do
|
||||||
def unquote(function_name)(v) do
|
def unquote(function_name)(v, t) do
|
||||||
var!(v) = v
|
var!(v) = v
|
||||||
unquote(process_exp)
|
unquote(process_exp)
|
||||||
receive do
|
receive do
|
||||||
@ -28,11 +29,13 @@ defmodule ServerMacros do
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
quote do
|
quote do
|
||||||
def unquote(function_name)(v) do
|
def unquote(function_name)(v, t) do
|
||||||
var!(v) = v
|
var!(v) = v
|
||||||
unquote(process_exp)
|
unquote(process_exp)
|
||||||
receive do
|
receive do
|
||||||
unquote(ast3)
|
unquote(ast3)
|
||||||
|
after
|
||||||
|
t -> :timeout
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -63,7 +66,6 @@ defmodule ServerMacros do
|
|||||||
ast2 = quote do
|
ast2 = quote do
|
||||||
{:decision, v} ->
|
{:decision, v} ->
|
||||||
var!(state) = apply_game(var!(state), v)
|
var!(state) = apply_game(var!(state), v)
|
||||||
var!(res) = v
|
|
||||||
unquote(recal_do)
|
unquote(recal_do)
|
||||||
|
|
||||||
v ->
|
v ->
|
||||||
@ -88,7 +90,7 @@ defmodule Server do
|
|||||||
require Utils
|
require Utils
|
||||||
import Utils
|
import Utils
|
||||||
|
|
||||||
create_log 2
|
create_log 3
|
||||||
|
|
||||||
def start(name, participants) do
|
def start(name, participants) do
|
||||||
log("starting server")
|
log("starting server")
|
||||||
@ -115,56 +117,91 @@ defmodule Server do
|
|||||||
{state, game_id} = try_to_create_game(state, participants)
|
{state, game_id} = try_to_create_game(state, participants)
|
||||||
safecast(pid_to_inform, {:start_game_ans, game_id})
|
safecast(pid_to_inform, {:start_game_ans, game_id})
|
||||||
state
|
state
|
||||||
|
|
||||||
|
{:get_game_state, game_id, pid_to_inform} ->
|
||||||
|
get_game_state(state, game_id, pid_to_inform)
|
||||||
end
|
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
|
def try_to_create_game(state, participants) do
|
||||||
game_ids = Map.keys(state.games)
|
game_ids = Map.keys(state.games)
|
||||||
latest = Enum.at(Enum.sort(game_ids), length(game_ids) - 1)
|
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
|
new_game_id = if latest do latest else 0 end + 1
|
||||||
log("#{inspect(new_game_id)}")
|
|
||||||
|
|
||||||
# TODO: randomize game state
|
# TODO: randomize game state
|
||||||
new_game_state = [1, 1]
|
new_game_state = [1, 1]
|
||||||
# TODO: randomize Initial hand value
|
# TODO: randomize Initial hand value
|
||||||
hand = Enum.reduce(participants, %{}, fn p, acc -> Map.put(acc, p, 1) end)
|
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}
|
try_propose {:start_game, new_game_id, participants, new_game_state, hand}
|
||||||
do
|
do
|
||||||
{:decision, {:start_game, ^new_game_id, ^participants, ^new_game_state, ^hand}} ->
|
{: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 = apply_game(state, {:start_game, new_game_id, participants, new_game_state, hand})
|
||||||
{state, new_game_id}
|
{state, new_game_id}
|
||||||
else
|
else
|
||||||
log("HERE #{inspect(res)}")
|
|
||||||
try_to_create_game(state, participants)
|
try_to_create_game(state, participants)
|
||||||
end
|
end
|
||||||
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
|
# Apply Game States
|
||||||
#
|
#
|
||||||
|
|
||||||
def apply_game(state, {:start_game, game_id, participants, new_game_state, hand}) do
|
def apply_game(state, {:start_game, game_id, participants, new_game_state, hand}) do
|
||||||
if state.name in participants do
|
cond do
|
||||||
%{state |
|
state.games[game_id] ->
|
||||||
games: Map.put(state.games, game_id, %{
|
raise :game_already_exists
|
||||||
game_state: new_game_state,
|
state.name in participants ->
|
||||||
participants: participants,
|
%{state |
|
||||||
hand: hand[state.name],
|
games: Map.put(state.games, game_id, %{
|
||||||
}),
|
game_state: new_game_state,
|
||||||
instance: state.instance + 1
|
participants: participants,
|
||||||
}
|
hand: hand[state.name],
|
||||||
else
|
}),
|
||||||
%{state |
|
instance: state.instance + 1
|
||||||
games: Map.put(state.games, game_id, :not_playing_in_it),
|
}
|
||||||
instance: state.instance + 1,
|
true ->
|
||||||
}
|
%{state |
|
||||||
|
games: Map.put(state.games, game_id, :not_playing_in_game),
|
||||||
|
instance: state.instance + 1,
|
||||||
|
}
|
||||||
end
|
end
|
||||||
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
|
# Interface
|
||||||
@ -174,28 +211,31 @@ defmodule Server do
|
|||||||
{:start_game_ans, game_id} ->
|
{:start_game_ans, game_id} ->
|
||||||
log("Started a game #{game_id}")
|
log("Started a game #{game_id}")
|
||||||
{:start_game, game_id}
|
{:start_game, game_id}
|
||||||
after
|
|
||||||
1000 -> :timeout
|
|
||||||
end
|
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
|
def start_game(name, participants) do
|
||||||
safecast(name, {:start_game, participants, self()})
|
safecast(name, {:start_game, participants, self()})
|
||||||
start_game_loop(nil)
|
start_game_loop(nil, 1000)
|
||||||
end
|
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
|
# Debug
|
||||||
############
|
############
|
||||||
|
Reference in New Issue
Block a user