You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2015/07/29 17:55:12 UTC

[43/50] mochiweb commit: updated refs/heads/upstream to b66b68d

attempt to fix active_socket accounting #149


Project: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/commit/63947f4a
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/tree/63947f4a
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/diff/63947f4a

Branch: refs/heads/upstream
Commit: 63947f4a23010e0c7c810a23e01ac681c14b9f1e
Parents: 52ddb5d
Author: Bob Ippolito <bo...@redivi.com>
Authored: Sun Jan 25 22:07:50 2015 -0800
Committer: Bob Ippolito <bo...@redivi.com>
Committed: Sun Jan 25 22:07:50 2015 -0800

----------------------------------------------------------------------
 src/mochiweb_socket_server.erl | 106 ++++++++++++++++--------------------
 1 file changed, 46 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/63947f4a/src/mochiweb_socket_server.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_socket_server.erl b/src/mochiweb_socket_server.erl
index 7f8587e..fd7ab03 100644
--- a/src/mochiweb_socket_server.erl
+++ b/src/mochiweb_socket_server.erl
@@ -118,6 +118,15 @@ parse_options([{backlog, Backlog} | Rest], State) ->
 parse_options([{nodelay, NoDelay} | Rest], State) ->
     parse_options(Rest, State#mochiweb_socket_server{nodelay=NoDelay});
 parse_options([{recbuf, RecBuf} | Rest], State) when is_integer(RecBuf) ->
+    %% XXX: `recbuf' value which is passed to `gen_tcp'
+    %% and value reported by `inet:getopts(P, [recbuf])' may
+    %% differ. They depends on underlying OS. From linux mans:
+    %%
+    %% The kernel doubles this value (to allow space for
+    %% bookkeeping overhead) when it is set using setsockopt(2),
+    %% and this doubled value is returned by getsockopt(2).
+    %%
+    %% See: man 7 socket | grep SO_RCVBUF
     parse_options(Rest, State#mochiweb_socket_server{recbuf=RecBuf});
 parse_options([{acceptor_pool_size, Max} | Rest], State) ->
     MaxInt = ensure_int(Max),
@@ -190,40 +199,25 @@ init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog,
     end,
     listen(Port, Opts, State).
 
-new_acceptor_pool(Listen,
-                  State=#mochiweb_socket_server{acceptor_pool=Pool,
-                                                acceptor_pool_size=Size,
-                                                recbuf=RecBuf,
-                                                loop=Loop}) ->
+new_acceptor_pool(State=#mochiweb_socket_server{acceptor_pool_size=Size}) ->
+    lists:foldl(fun (_, S) -> new_acceptor(S) end, State, lists:seq(1, Size)).
+
+new_acceptor(State=#mochiweb_socket_server{acceptor_pool=Pool,
+                                           recbuf=RecBuf,
+                                           loop=Loop,
+                                           listen=Listen}) ->
     LoopOpts = [{recbuf, RecBuf}],
-    F = fun (_, S) ->
-                Pid = mochiweb_acceptor:start_link(
-                    self(), Listen, Loop, LoopOpts
-                ),
-                sets:add_element(Pid, S)
-        end,
-    Pool1 = lists:foldl(F, Pool, lists:seq(1, Size)),
-    State#mochiweb_socket_server{acceptor_pool=Pool1}.
-
-listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts,
-                                                 recbuf=RecBuf}) ->
+    Pid = mochiweb_acceptor:start_link(self(), Listen, Loop, LoopOpts),
+    State#mochiweb_socket_server{
+      acceptor_pool=sets:add_element(Pid, Pool)}.
+
+listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts}) ->
     case mochiweb_socket:listen(Ssl, Port, Opts, SslOpts) of
         {ok, Listen} ->
-            %% XXX: `recbuf' value which is passed to `gen_tcp'
-            %% and value reported by `inet:getopts(P, [recbuf])' may
-            %% differ. They depends on underlying OS. From linux mans:
-            %%
-            %% The kernel doubles this value (to allow space for
-            %% bookkeeping overhead) when it is set using setsockopt(2),
-            %% and this doubled value is returned by getsockopt(2).
-            %%
-            %% See: man 7 socket | grep SO_RCVBUF
             {ok, ListenPort} = mochiweb_socket:port(Listen),
-            {ok, new_acceptor_pool(
-                   Listen,
-                   State#mochiweb_socket_server{listen=Listen,
-                                                port=ListenPort,
-                                                recbuf=RecBuf})};
+            {ok, new_acceptor_pool(State#mochiweb_socket_server{
+                                     listen=Listen,
+                                     port=ListenPort})};
         {error, Reason} ->
             {stop, Reason}
     end.
@@ -300,38 +294,30 @@ code_change(_OldVsn, State, _Extra) ->
 recycle_acceptor(Pid, State=#mochiweb_socket_server{
                         acceptor_pool=Pool,
                         acceptor_pool_size=PoolSize,
-                        listen=Listen,
-                        loop=Loop,
                         max=Max,
-                        recbuf=RecBuf,
                         active_sockets=ActiveSockets}) ->
-    LoopOpts = [{recbuf, RecBuf}],
-    case sets:is_element(Pid, Pool) of
-        true ->
-            Pool1 = sets:del_element(Pid, Pool),
-            case ActiveSockets + sets:size(Pool1) < Max of
-                true ->
-                    Acceptor = mochiweb_acceptor:start_link(
-                        self(), Listen, Loop, LoopOpts
-                    ),
-                    Pool2 = sets:add_element(Acceptor, Pool1),
-                    State#mochiweb_socket_server{acceptor_pool=Pool2};
-                false ->
-                    State#mochiweb_socket_server{acceptor_pool=Pool1}
-            end;
-        false ->
-            case sets:size(Pool) < PoolSize of
-                true ->
-                    Acceptor = mochiweb_acceptor:start_link(
-                        self(), Listen, Loop, LoopOpts
-                    ),
-                    Pool1 = sets:add_element(Acceptor, Pool),
-                    State#mochiweb_socket_server{active_sockets=ActiveSockets,
-                                                 acceptor_pool=Pool1};
-                false ->
-                    State#mochiweb_socket_server{active_sockets=ActiveSockets - 1,
-                                                 acceptor_pool=Pool}
-            end
+    %% A socket is considered to be active from immediately after it
+    %% has been accepted (see the {accepted, Pid, Timing} cast above).
+    %% This function will be called when an acceptor is transitioning
+    %% to an active socket, or when either type of Pid dies. An acceptor
+    %% Pid will always be in the acceptor_pool set, and an active socket
+    %% will be in that set during the transition but not afterwards.
+    Pool1 = sets:del_element(Pid, Pool),
+    NewSize = sets:size(Pool1),
+    ActiveSockets1 = case NewSize =:= sets:size(Pool) of
+                         %% Pid has died and it is not in the acceptor set,
+                         %% it must be an active socket.
+                         true -> max(0, ActiveSockets - 1);
+                         false -> ActiveSockets
+                     end,
+    State1 = State#mochiweb_socket_server{
+               acceptor_pool=Pool1,
+               active_sockets=ActiveSockets1},
+    %% Spawn a new acceptor only if it will not overrun the maximum socket
+    %% count or the maximum pool size.
+    case NewSize + ActiveSockets1 < Max andalso NewSize < PoolSize of
+        true -> new_acceptor(State1);
+        false -> State1
     end.
 
 handle_info(Msg, State) when ?is_old_state(State) ->