Skip to content

Commit

Permalink
Use supervisors to manage crashes better.
Browse files Browse the repository at this point in the history
Now crashing the FSM that manages the backend will cause the
connections to drop instead of just be orphaned.

closes dustin#12

Change-Id: I99105f8ef9abf8949049ae0e9ea63cfe117f7cdc
  • Loading branch information
dustin committed Jun 14, 2011
1 parent 5c11902 commit db848a9
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 7 deletions.
2 changes: 1 addition & 1 deletion etc/couchdb/local.d/mccouch.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
; Add this to etc/couchdb/local.d
[daemons]
mc_daemon={mc_daemon, start_link, ["kv", true]}
mc_daemon={mc_sup, start_link, ["kv", true]}
26 changes: 26 additions & 0 deletions src/mc_conn_sup.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
-module(mc_conn_sup).

-behaviour(supervisor).

-export([start_link/0]).

-export([init/1]).

-export([start_connection/1]).

-define(SERVER, ?MODULE).

start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).

init([]) ->
{ok, {{simple_one_for_one, 0, 1},
[{mc_connection, {mc_connection, start_link, [mc_daemon]},
temporary, brutal_kill, worker, [mc_connection]}]}}.

start_connection(NS) ->
{ok, Pid} = supervisor:start_child(?MODULE, [NS]),
gen_tcp:controlling_process(NS, Pid),
%% Tell this mc_connection it's the controlling process and ready to go.
Pid ! go,
{ok, Pid}.
10 changes: 9 additions & 1 deletion src/mc_connection.erl
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
-module (mc_connection).

-export([loop/2]).
-export([start_link/2, init/2]).
-export([respond/5, respond/4]).

-include("mc_constants.hrl").

start_link(Handler, Socket) ->
{ok, spawn_link(?MODULE, init, [Socket, Handler])}.

bin_size(undefined) -> 0;
bin_size(IoList) -> iolist_size(IoList).

Expand Down Expand Up @@ -90,6 +93,11 @@ process_message(Socket, StorageServer, {ok, <<?REQ_MAGIC:8, OpCode:8, KeyLen:16,
Res -> respond(Socket, OpCode, Opaque, Res)
end.

init(Socket, Handler) ->
%% The spawner will tell us when we are the controlling process.
receive go -> ok end,
loop(Socket, Handler).

loop(Socket, Handler) ->
process_message(Socket, Handler, gen_tcp:recv(Socket, ?HEADER_LEN)),
loop(Socket, Handler).
5 changes: 2 additions & 3 deletions src/mc_daemon.erl
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,15 @@
-include("couch_db.hrl").
-include("mc_constants.hrl").

-record(state, {mc_serv, db, json_mode, setqs=0, terminal_opaque=0}).
-record(state, {db, json_mode, setqs=0, terminal_opaque=0}).

start_link(DbName, JsonMode) ->
gen_fsm:start_link({local, ?SERVER}, ?MODULE, [DbName, JsonMode], []).

init([DbName, JsonMode]) ->
?LOG_INFO("MC daemon: starting: json_mode=~p.", [JsonMode]),
{ok, S} = mc_tcp_listener:start_link(11213, self()),
{ok, processing,
#state{mc_serv=S, db=list_to_binary(DbName), json_mode=JsonMode}}.
#state{db=list_to_binary(DbName), json_mode=JsonMode}}.

db_name(VBucket, State)->
iolist_to_binary([State#state.db, $/, integer_to_list(VBucket)]).
Expand Down
48 changes: 48 additions & 0 deletions src/mc_sup.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
-module(mc_sup).

-behaviour(supervisor).

-export([start_link/2]).

-export([init/1]).

-define(SERVER, ?MODULE).

start_link(DbName, JsonMode) ->
application:start(sasl),
supervisor:start_link({local, ?SERVER}, ?MODULE, [DbName, JsonMode]).

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Whenever a supervisor is started using supervisor:start_link/[2,3],
%% this function is called by the new process to find out about
%% restart strategy, maximum restart frequency and child
%% specifications.
%%
%% @spec init(Args) -> {ok, {SupFlags, [ChildSpec]}} |
%% ignore |
%% {error, Reason}
%% @end
%%--------------------------------------------------------------------
init([DbName, JsonMode]) ->
RestartStrategy = one_for_all,
MaxRestarts = 1000,
MaxSecondsBetweenRestarts = 3600,

SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},

Restart = permanent,
Shutdown = 2000,
Type = worker,

Daemon = {mc_daemon, {mc_daemon, start_link, [DbName, JsonMode]},
Restart, Shutdown, Type, [mc_daemon]},

TcpListener = {mc_tcp_listener, {mc_tcp_listener, start_link, [11213, mc_daemon]},
Restart, Shutdown, Type, [mc_tcp_listener, mc_daemon]},

ConnSup = {mc_conn_sup, {mc_conn_sup, start_link, []},
Restart, Shutdown, supervisor, dynamic},

{ok, {SupFlags, [Daemon, TcpListener, ConnSup]}}.
3 changes: 1 addition & 2 deletions src/mc_tcp_listener.erl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,5 @@ init(PortNum, StorageServer) ->
% Accept incoming connections
accept_loop(LS, StorageServer) ->
{ok, NS} = gen_tcp:accept(LS),
Pid = spawn(mc_connection, loop, [NS, StorageServer]),
gen_tcp:controlling_process(NS, Pid),
mc_conn_sup:start_connection(NS),
accept_loop(LS, StorageServer).

0 comments on commit db848a9

Please sign in to comment.