From 21802d2767e48924186d173eb36b61994e990b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 31 Jan 2012 09:45:44 +0100 Subject: Use queue() for managing wait queues in cowboy_listener The previous solution was retrieving the last put connection and wasn't a real queue, so this solution should improve the overall latency under load. --- src/cowboy_listener.erl | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/cowboy_listener.erl b/src/cowboy_listener.erl index 51805b9..b12e059 100644 --- a/src/cowboy_listener.erl +++ b/src/cowboy_listener.erl @@ -27,7 +27,7 @@ -record(state, { req_pools = [] :: pools(), reqs_table :: ets:tid(), - queue = [] :: [{pid(), reference()}], + queue = undefined :: queue(), max_conns = undefined :: non_neg_integer(), proto_opts :: any(), proto_opts_vsn = 1 :: non_neg_integer() @@ -100,8 +100,9 @@ set_protocol_options(ServerPid, ProtoOpts) -> -spec init(list()) -> {ok, #state{}}. init([MaxConns, ProtoOpts]) -> ReqsTable = ets:new(requests_table, [set, private]), + Queue = queue:new(), {ok, #state{reqs_table=ReqsTable, max_conns=MaxConns, - proto_opts=ProtoOpts}}. + proto_opts=ProtoOpts, queue=Queue}}. %% @private -spec handle_call(_, _, State) @@ -115,7 +116,8 @@ handle_call({add_connection, Pool, ConnPid, AccOptsVsn}, From, State=#state{ if AccOptsVsn =/= LisOptsVsn -> {reply, {ugprade, ProtoOpts, LisOptsVsn}, State2}; NbConns > MaxConns -> - {noreply, State2#state{queue=[From|Queue]}}; + Queue2 = queue:in(From, Queue), + {noreply, State2#state{queue=Queue2}}; true -> {reply, ok, State2} end; @@ -193,18 +195,18 @@ move_pid(ConnPid, DestPool, Pools, ReqsTable) -> [{SrcPool, SrcNbConns - 1}, {DestPool, DestNbConns}|Pools2]. %% @private --spec remove_pid(pid(), pools(), ets:tid(), [{pid(), reference()}]) - -> {pools(), [{pid(), reference()}]}. +-spec remove_pid(pid(), pools(), ets:tid(), queue()) -> {pools(), queue()}. remove_pid(Pid, Pools, ReqsTable, Queue) -> {MonitorRef, Pool} = ets:lookup_element(ReqsTable, Pid, 2), erlang:demonitor(MonitorRef, [flush]), {Pool, NbConns} = lists:keyfind(Pool, 1, Pools), Pools2 = [{Pool, NbConns - 1}|lists:keydelete(Pool, 1, Pools)], ets:delete(ReqsTable, Pid), - case Queue of - [] -> + case queue:len(Queue) of + 0 -> {Pools2, Queue}; - [Client|Queue2] -> + _ -> + {{value, Client}, Queue2} = queue:out(Queue), gen_server:reply(Client, ok), {Pools2, Queue2} end. -- cgit v1.2.3