diff options
author | Loïc Hoguin <[email protected]> | 2018-10-10 16:22:19 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2018-10-10 16:22:19 +0200 |
commit | 7d3c65a6db5e267eb0a3f2503c9fa1264b559e73 (patch) | |
tree | 5552d175fb5e7838080a1029f1e3fe8d399cbf6b /src/ranch_server.erl | |
parent | 2b8ef9b606381f4e5912f815cdf0d5accf00409f (diff) | |
download | ranch-7d3c65a6db5e267eb0a3f2503c9fa1264b559e73.tar.gz ranch-7d3c65a6db5e267eb0a3f2503c9fa1264b559e73.tar.bz2 ranch-7d3c65a6db5e267eb0a3f2503c9fa1264b559e73.zip |
Fix a race condition on restart after listener_sup crash
The race condition occurs when the restart is faster than
the cleaning up. With this commit the restart will perform
the cleanup if it was not done beforehand.
Diffstat (limited to 'src/ranch_server.erl')
-rw-r--r-- | src/ranch_server.erl | 52 |
1 files changed, 28 insertions, 24 deletions
diff --git a/src/ranch_server.erl b/src/ranch_server.erl index 38eb0c6..a767cd8 100644 --- a/src/ranch_server.erl +++ b/src/ranch_server.erl @@ -82,8 +82,7 @@ cleanup_listener_opts(Ref) -> -spec set_connections_sup(ranch:ref(), pid()) -> ok. set_connections_sup(Ref, Pid) -> - true = gen_server:call(?MODULE, {set_connections_sup, Ref, Pid}), - ok. + gen_server:call(?MODULE, {set_connections_sup, Ref, Pid}). -spec get_connections_sup(ranch:ref()) -> pid(). get_connections_sup(Ref) -> @@ -95,8 +94,7 @@ get_connections_sups() -> -spec set_listener_sup(ranch:ref(), pid()) -> ok. set_listener_sup(Ref, Pid) -> - true = gen_server:call(?MODULE, {set_listener_sup, Ref, Pid}), - ok. + gen_server:call(?MODULE, {set_listener_sup, Ref, Pid}). -spec get_listener_sup(ranch:ref()) -> pid(). get_listener_sup(Ref) -> @@ -161,26 +159,12 @@ handle_call({set_new_listener_opts, Ref, MaxConns, TransOpts, ProtoOpts, StartAr ets:insert_new(?TAB, {{proto_opts, Ref}, ProtoOpts}), ets:insert_new(?TAB, {{listener_start_args, Ref}, StartArgs}), {reply, ok, State}; -handle_call({set_connections_sup, Ref, Pid}, _, - State=#state{monitors=Monitors}) -> - case ets:insert_new(?TAB, {{conns_sup, Ref}, Pid}) of - true -> - MonitorRef = erlang:monitor(process, Pid), - {reply, true, - State#state{monitors=[{{MonitorRef, Pid}, {conns_sup, Ref}}|Monitors]}}; - false -> - {reply, false, State} - end; -handle_call({set_listener_sup, Ref, Pid}, _, - State=#state{monitors=Monitors}) -> - case ets:insert_new(?TAB, {{listener_sup, Ref}, Pid}) of - true -> - MonitorRef = erlang:monitor(process, Pid), - {reply, true, - State#state{monitors=[{{MonitorRef, Pid}, {listener_sup, Ref}}|Monitors]}}; - false -> - {reply, false, State} - end; +handle_call({set_connections_sup, Ref, Pid}, _, State0) -> + State = set_monitored_process({conns_sup, Ref}, Pid, State0), + {reply, ok, State}; +handle_call({set_listener_sup, Ref, Pid}, _, State0) -> + State = set_monitored_process({listener_sup, Ref}, Pid, State0), + {reply, ok, State}; handle_call({set_addr, Ref, Addr}, _, State) -> true = ets:insert(?TAB, {{addr, Ref}, Addr}), {reply, ok, State}; @@ -227,3 +211,23 @@ terminate(_Reason, _State) -> code_change(_OldVsn, State, _Extra) -> {ok, State}. + +%% Internal. + +set_monitored_process(Key, Pid, State=#state{monitors=Monitors0}) -> + %% First we cleanup the monitor if a residual one exists. + %% This can happen during crashes when the restart is faster + %% than the cleanup. + Monitors = case lists:keytake(Key, 2, Monitors0) of + false -> + Monitors0; + {value, {{OldMonitorRef, _}, _}, Monitors1} -> + true = erlang:demonitor(OldMonitorRef, [flush]), + Monitors1 + end, + %% Then we unconditionally insert in the ets table. + %% If residual data is there, it will be overwritten. + true = ets:insert(?TAB, {Key, Pid}), + %% Finally we start monitoring this new process. + MonitorRef = erlang:monitor(process, Pid), + State#state{monitors=[{{MonitorRef, Pid}, Key}|Monitors]}. |