From 99242f3342f24f447e487aee6cbf909fcfce9fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 26 Nov 2013 14:22:10 +0100 Subject: Add accept_ack on all transports and ack_timeout transport option Doing this in the connection process allows us to free acceptors to start accepting more connections quicker, especially under load. --- manual/ranch_transport.md | 2 +- src/ranch.erl | 4 +++- src/ranch_conns_sup.erl | 26 +++++++++++++++----------- src/ranch_listener_sup.erl | 3 ++- src/ranch_ssl.erl | 32 +++++++++++--------------------- src/ranch_tcp.erl | 5 +++++ src/ranch_transport.erl | 5 ++++- test/sendfile_SUITE.erl | 1 + 8 files changed, 42 insertions(+), 36 deletions(-) diff --git a/manual/ranch_transport.md b/manual/ranch_transport.md index 7eb350d..291b0e4 100644 --- a/manual/ranch_transport.md +++ b/manual/ranch_transport.md @@ -17,7 +17,7 @@ Callbacks --------- ### accept(LSocket, Timeout) - -> {ok, CSocket} | {error, closed | timeout | atom() | tuple()} + -> {ok, CSocket} | {error, closed | timeout | atom()} > Types: > * LSocket = CSocket = any() diff --git a/src/ranch.erl b/src/ranch.erl index 2db4921..9bcd328 100644 --- a/src/ranch.erl +++ b/src/ranch.erl @@ -128,7 +128,9 @@ child_spec(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) %% the protocol process before starting to use it. -spec accept_ack(ref()) -> ok. accept_ack(Ref) -> - receive {shoot, Ref} -> ok end. + receive {shoot, Ref, Transport, Socket, AckTimeout} -> + Transport:accept_ack(Socket, AckTimeout) + end. %% @doc Remove the calling process' connection from the pool. %% diff --git a/src/ranch_conns_sup.erl b/src/ranch_conns_sup.erl index 245a5e0..f920919 100644 --- a/src/ranch_conns_sup.erl +++ b/src/ranch_conns_sup.erl @@ -20,12 +20,12 @@ -module(ranch_conns_sup). %% API. --export([start_link/4]). +-export([start_link/5]). -export([start_protocol/2]). -export([active_connections/1]). %% Supervisor internals. --export([init/5]). +-export([init/6]). -export([system_continue/3]). -export([system_terminate/4]). -export([system_code_change/4]). @@ -39,15 +39,17 @@ transport = undefined :: module(), protocol = undefined :: module(), opts :: any(), - max_conns = undefined :: non_neg_integer() | infinity + ack_timeout :: timeout(), + max_conns = undefined :: ranch:max_conns() }). %% API. --spec start_link(ranch:ref(), conn_type(), module(), module()) -> {ok, pid()}. -start_link(Ref, ConnType, Transport, Protocol) -> +-spec start_link(ranch:ref(), conn_type(), module(), timeout(), module()) + -> {ok, pid()}. +start_link(Ref, ConnType, Transport, AckTimeout, Protocol) -> proc_lib:start_link(?MODULE, init, - [self(), Ref, ConnType, Transport, Protocol]). + [self(), Ref, ConnType, Transport, AckTimeout, Protocol]). %% We can safely assume we are on the same node as the supervisor. %% @@ -92,8 +94,9 @@ active_connections(SupPid) -> %% Supervisor internals. --spec init(pid(), ranch:ref(), conn_type(), module(), module()) -> no_return(). -init(Parent, Ref, ConnType, Transport, Protocol) -> +-spec init(pid(), ranch:ref(), conn_type(), module(), timeout(), module()) + -> no_return(). +init(Parent, Ref, ConnType, Transport, AckTimeout, Protocol) -> process_flag(trap_exit, true), ok = ranch_server:set_connections_sup(Ref, self()), MaxConns = ranch_server:get_max_connections(Ref), @@ -101,17 +104,18 @@ init(Parent, Ref, ConnType, Transport, Protocol) -> ok = proc_lib:init_ack(Parent, {ok, self()}), loop(#state{parent=Parent, ref=Ref, conn_type=ConnType, transport=Transport, protocol=Protocol, opts=Opts, - max_conns=MaxConns}, 0, 0, []). + ack_timeout=AckTimeout, max_conns=MaxConns}, 0, 0, []). loop(State=#state{parent=Parent, ref=Ref, conn_type=ConnType, transport=Transport, protocol=Protocol, opts=Opts, - max_conns=MaxConns}, CurConns, NbChildren, Sleepers) -> + ack_timeout=AckTimeout, max_conns=MaxConns}, + CurConns, NbChildren, Sleepers) -> receive {?MODULE, start_protocol, To, Socket} -> case Protocol:start_link(Ref, Socket, Transport, Opts) of {ok, Pid} -> Transport:controlling_process(Socket, Pid), - Pid ! {shoot, Ref}, + Pid ! {shoot, Ref, Transport, Socket, AckTimeout}, put(Pid, true), CurConns2 = CurConns + 1, if CurConns2 < MaxConns -> diff --git a/src/ranch_listener_sup.erl b/src/ranch_listener_sup.erl index 56df6b7..b0a6bd5 100644 --- a/src/ranch_listener_sup.erl +++ b/src/ranch_listener_sup.erl @@ -36,10 +36,11 @@ start_link(Ref, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) -> %% supervisor. init({Ref, NbAcceptors, Transport, TransOpts, Protocol}) -> + AckTimeout = proplists:get_value(ack_timeout, TransOpts, 5000), ConnType = proplists:get_value(connection_type, TransOpts, worker), ChildSpecs = [ {ranch_conns_sup, {ranch_conns_sup, start_link, - [Ref, ConnType, Transport, Protocol]}, + [Ref, ConnType, Transport, AckTimeout, Protocol]}, permanent, infinity, supervisor, [ranch_conns_sup]}, {ranch_acceptors_sup, {ranch_acceptors_sup, start_link, [Ref, NbAcceptors, Transport, TransOpts]}, diff --git a/src/ranch_ssl.erl b/src/ranch_ssl.erl index 8fa7358..a6ceb4d 100644 --- a/src/ranch_ssl.erl +++ b/src/ranch_ssl.erl @@ -30,6 +30,7 @@ -export([messages/0]). -export([listen/1]). -export([accept/2]). +-export([accept_ack/2]). -export([connect/3]). -export([recv/3]). -export([send/2]). @@ -164,13 +165,18 @@ listen(Opts) -> %% @see ssl:transport_accept/2 %% @see ssl:ssl_accept/2 -spec accept(ssl:sslsocket(), timeout()) - -> {ok, ssl:sslsocket()} | {error, closed | timeout | atom() | tuple()}. + -> {ok, ssl:sslsocket()} | {error, closed | timeout | atom()}. accept(LSocket, Timeout) -> - case ssl:transport_accept(LSocket, Timeout) of - {ok, CSocket} -> - ssl_accept(CSocket, Timeout); + ssl:transport_accept(LSocket, Timeout). + +-spec accept_ack(ssl:sslsocket(), timeout()) -> ok. +accept_ack(CSocket, Timeout) -> + case ssl:ssl_accept(CSocket, Timeout) of + ok -> + ok; {error, Reason} -> - {error, Reason} + ok = close(CSocket), + error(Reason) end. %% @private Experimental. Open a connection to the given host and port number. @@ -263,22 +269,6 @@ close(Socket) -> %% Internal. -%% This call always times out, either because a numeric timeout value -%% was given, or because we've decided to use 5000ms instead of infinity. -%% This value should be reasonable enough for the moment. --spec ssl_accept(ssl:sslsocket(), timeout()) - -> {ok, ssl:sslsocket()} | {error, {ssl_accept, atom()}}. -ssl_accept(Socket, infinity) -> - ssl_accept(Socket, 5000); -ssl_accept(Socket, Timeout) -> - case ssl:ssl_accept(Socket, Timeout) of - ok -> - {ok, Socket}; - {error, Reason} -> - ok = close(Socket), - {error, {ssl_accept, Reason}} - end. - %% Unfortunately the implementation of elliptic-curve ciphers that has %% been introduced in R16B01 is incomplete. Depending on the particular %% client, this can cause the TLS handshake to break during key diff --git a/src/ranch_tcp.erl b/src/ranch_tcp.erl index 087cf09..86b1e35 100644 --- a/src/ranch_tcp.erl +++ b/src/ranch_tcp.erl @@ -24,6 +24,7 @@ -export([messages/0]). -export([listen/1]). -export([accept/2]). +-export([accept_ack/2]). -export([connect/3]). -export([recv/3]). -export([send/2]). @@ -89,6 +90,10 @@ listen(Opts) -> accept(LSocket, Timeout) -> gen_tcp:accept(LSocket, Timeout). +-spec accept_ack(inet:socket(), timeout()) -> ok. +accept_ack(_, _) -> + ok. + %% @private Experimental. Open a connection to the given host and port number. %% @see gen_tcp:connect/3 %% @todo Probably filter Opts? diff --git a/src/ranch_transport.erl b/src/ranch_transport.erl index d557594..5c1153c 100644 --- a/src/ranch_transport.erl +++ b/src/ranch_transport.erl @@ -46,7 +46,10 @@ %% Accept connections with the given listening socket. -callback accept(socket(), timeout()) - -> {ok, socket()} | {error, closed | timeout | atom() | tuple()}. + -> {ok, socket()} | {error, closed | timeout | atom()}. + +%% Perform post-accept operations on the socket. +-callback accept_ack(socket(), timeout()) -> ok. %% Experimental. Open a connection to the given host and port number. -callback connect(string(), inet:port_number(), opts()) diff --git a/test/sendfile_SUITE.erl b/test/sendfile_SUITE.erl index dc05fe6..c74659e 100644 --- a/test/sendfile_SUITE.erl +++ b/test/sendfile_SUITE.erl @@ -305,6 +305,7 @@ sockets(Config) -> end, _ = spawn_link(Fun), {ok, Server} = Transport:accept(LSocket, 500), + ok = Transport:accept_ack(Server, 500), receive {ok, Client} -> ok = Transport:close(LSocket), -- cgit v1.2.3