Now we can crash ggs_coordinator without it affecting the clients.

This commit is contained in:
Jonatan Pålsson 2011-02-24 22:22:32 +01:00
parent f6bb2328a1
commit 87df33fd47
4 changed files with 100 additions and 12 deletions

View file

@ -53,13 +53,26 @@ remove_player(_From, _Player) ->
%gen_server:cast(ggs_coordinator, {remove_player, Player}).
ggs_logger:not_implemented().
%% Just to shorten the name
back_up(State) ->
ggs_coordinator_backup:back_up(State),
State.
%% gen_server callbacks
init([]) ->
{ok, #co_state{}}.
% Restore old state from backup if there is old state stored there
case ggs_coordinator_backup:retrieve() of
no_state_stored ->
io:format("No old state stored.. Creating new!~n"),
{ok, #co_state{}};
State ->
{ok, State}
end.
handle_call(join_lobby, _From, State) ->
Token = helpers:get_new_token(),
back_up(State),
{reply, {ok, Token}, State};
handle_call({join_table, Table}, From, State) ->
@ -68,19 +81,23 @@ handle_call({join_table, Table}, From, State) ->
case lists:keyfind(Table, 1, Tables) of
{_TableID, TablePID} ->
ggs_table:add_player(TablePID, FromPlayer),
back_up(State),
{reply, {ok, TablePID}, State};
false ->
back_up(State),
{reply, {error, no_such_table}, State}
end;
handle_call({create_table, {force, TableID}}, From, State) ->
TableIDMap = State#co_state.player_table_map,
Tables = State#co_state.tables,
NewTableProc = ggs_table:start_link(),
{reply, {ok, TableID}, State#co_state{
player_table_map = [{From, TableID} | TableIDMap],
tables = [{TableID, NewTableProc} | Tables]
}};
NewTableProc = ggs_table:start(), % With start_link, the table dies with the coordinator
NewState = State#co_state{
player_table_map = [{From, TableID} | TableIDMap],
tables = [{TableID, NewTableProc} | Tables]
},
back_up(NewState),
{reply, {ok, TableID}, NewState};
handle_call(_Message, _From, State) ->
{noreply, State}.

View file

@ -0,0 +1,65 @@
-module(ggs_coordinator_backup).
-behaviour(gen_server).
%% API Exports
-export([start_link/0, stop/1]).
-export([back_up/1, retrieve/0]).
%% gen_server callback exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).
-define(SERVER, ?MODULE).
%% @doc This module is repsponsible for keeping a backup of the coodinator
%% at all times. At any point in time a backup can be restored from this
%% module.
%% This module is started by the root supervisor, and is restarted when it
%% crashes. Upon a crash, the backup state is lost in this module, and must
%% be filled in from the ggs_coordinator.
%% @doc Start a new ggs_coordinator backup instance, and register it under
%% this name. This means that there can only be one instance of this module
%% running.
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%% @doc Stops the server with the specified reason.
%% @spec stop(Reason) -> ok.
%% Reason = String
stop(_Reason) -> ggs_logger:not_implemented().
%% API
back_up(State) ->
gen_server:cast(?SERVER, State).
%% @doc Retrieve the state stored in this server. If there is a state stored
%% here, it is returned to the caller. If the backup server does not have a
%% state stored, it will return the no_state_stored atom.
retrieve() ->
gen_server:call(?SERVER, retrieve).
%% gen_server callbacks
%% @doc Initiate the server. This is called from gen_server
init([]) ->
{ok, no_state_stored}.
handle_call(retrieve, _From, State) ->
{reply, State, State}.
handle_cast(NewState, _State) ->
{noreply, NewState}.
handle_info(Msg, State) ->
io:format("Received out of bounds message! "),
erlang:display(Msg),
io:format("~n"),
{noreply, State}.
terminate(normal, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

View file

@ -26,7 +26,14 @@ init([Port]) ->
worker,
[ggs_coordinator]
},
Children = [Dispatcher, Coordinator],
Coordinator_backup = {ggs_coordinator_backup,
{ggs_coordinator_backup, start_link, []},
permanent,
2000,
worker,
[ggs_coordinator_backup]
},
Children = [Dispatcher, Coordinator_backup, Coordinator],
RestartStrategy = { one_for_one, % Restart only crashing child
10, % Allow ten crashes per..

View file

@ -11,7 +11,7 @@
-record(state, { players, game_vm } ).
%% API
-export([start_link/0,
-export([start/0,
add_player/2,
remove_player/2,
stop/1,
@ -24,8 +24,8 @@
% API implementation
% @doc returns a new table
start_link() ->
{ok, Pid} = gen_server:start_link(?MODULE, [], []),
start() ->
{ok, Pid} = gen_server:start(?MODULE, [], []),
Pid.
%% @private
@ -56,14 +56,13 @@ notify_all_players(Table, Message) ->
gen_server:cast(Table, {notify_all_players, Message}).
notify_game(Table, From, Message) ->
erlang:display(Table),
io:format("~n"),
gen_server:cast(Table, {notify_game, Message, From}).
%% ----------------------------------------------------------------------
%% @private
init([]) ->
process_flag(trap_exit, true),
GameVM = ggs_gamevm_e:start_link(self()), %% @TODO: Temporary erlang gamevm
{ok, #state {
game_vm = GameVM,