Permalink
Browse files

Use supervisors to manage crashes better.

Now crashing the FSM that manages the backend will cause the
connections to drop instead of just be orphaned.

closes #12

Change-Id: I99105f8ef9abf8949049ae0e9ea63cfe117f7cdc
  • Loading branch information...
1 parent 5c11902 commit db848a9c3047bc8b5d44ed5e2a93669e8b2469d5 @dustin committed Jun 14, 2011
Showing with 87 additions and 7 deletions.
  1. +1 −1 etc/couchdb/local.d/mccouch.ini
  2. +26 −0 src/mc_conn_sup.erl
  3. +9 −1 src/mc_connection.erl
  4. +2 −3 src/mc_daemon.erl
  5. +48 −0 src/mc_sup.erl
  6. +1 −2 src/mc_tcp_listener.erl
@@ -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]}
View
@@ -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}.
View
@@ -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).
@@ -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).
View
@@ -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)]).
View
@@ -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]}}.
View
@@ -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.