Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add a timeout for out of order events

Some events may not be processed in sequence. Allow a time interval for
outstanding events to be caught.
  • Loading branch information...
commit b6f0a2d30e99659c8fadc4fa4e20c5871974bf0c 1 parent 2e6eb8a
@msantos authored
Showing with 49 additions and 28 deletions.
  1. +49 −28 src/pervon.erl
View
77 src/pervon.erl
@@ -39,37 +39,41 @@
-export([content/3, session/4]).
-export([filename/4]).
% States
--export([perving/2, perving/3]).
+-export([perving/2]).
% Behaviours
-export([init/1, handle_event/3, handle_sync_event/4,
handle_info/3, terminate/3, code_change/4]).
+
+-define(FILEPATH, "priv/files").
+-define(TRACEPATH, "priv/tmp/").
+
+-define(MAXHDRLEN, 8 * 1024). % 8K, mimic Apache
+-define(MAXCHUNKLEN, nolimit). % XXX
+-define(TIMEOUT, 5 * 1000 * 60). % 5 minutes, HTTP pipeline timeout
+-define(TIMEWAIT, 10 * 1000). % 10 seconds, allow for delayed
+ % packets when shutting down
+
-record(state, {
saddr,
sport,
daddr,
dport,
f = fun(_) -> ok end,
+ timeout = ?TIMEOUT,
debug = true,
data
}).
--define(FILEPATH, "priv/files").
--define(TRACEPATH, "priv/tmp/").
-
--define(MAXHDRLEN, 8 * 1024). % 8K, mimic Apache
--define(MAXCHUNKLEN, nolimit). % XXX
--define(TIMEOUT, 5 * 1000 * 60). % 5 minutes, HTTP pipeline timeout
-
%%--------------------------------------------------------------------
%%% Interface
%%--------------------------------------------------------------------
buf(Pid, SeqNo, Data) when is_binary(Data) ->
- gen_fsm:sync_send_event(Pid, {data, {SeqNo, Data}}).
+ gen_fsm:send_event(Pid, {data, {SeqNo, Data}}).
stop(Pid) ->
- gen_fsm:sync_send_event(Pid, stop).
+ gen_fsm:send_event(Pid, stop).
%%--------------------------------------------------------------------
@@ -127,30 +131,47 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%--------------------------------------------------------------------
%%% States
%%--------------------------------------------------------------------
-perving({data, {SeqNo, Data}}, _From, #state{data = Payload} = State) ->
+
+% There seems to be a race condition in receiving data/stopping
+% the fsm. Occasionally, data or stop events will be sent after
+% stop has been called.
+%
+% 1. Since events are delivered async, they may be received
+% out of order. The events could be sent synchronously,
+% but:
+%
+% 2. The closing FIN packet may be delivered out of order
+% (in which case the OS will not ACK it) or it may be
+% a duplicate.
+%
+% The TIME_WAIT interval should allow enough time for
+% additional events to be processed.
+%
+perving({data, {SeqNo, Data}}, #state{
+ data = Payload,
+ timeout = Timeout
+ } = State) ->
+
+ case Timeout of
+ ?TIMEOUT -> ok;
+ ?TIMEWAIT -> error_logger:info_report([{matched, ?TIMEWAIT}])
+ end,
+
case gb_trees:is_defined(SeqNo, Payload) of
true ->
- {reply, ok, perving, State#state{
+ {next_state, perving, State#state{
data = Payload
- }, ?TIMEOUT};
+ }, Timeout};
false ->
- {reply, ok, perving, State#state{
+ {next_state, perving, State#state{
data = gb_trees:enter(SeqNo, Data, Payload)
- }, ?TIMEOUT}
+ }, Timeout}
end;
-perving(stop, _From, State) ->
- {stop, normal, ok, State}.
-
-perving(timeout, #state{
- saddr = Saddr,
- sport = Sport,
- daddr = Daddr,
- dport = Dport
- } = State) ->
- error_logger:info_report([
- {session, {timeout, ?TIMEOUT}},
- {connection, session(Saddr, Sport, Daddr, Dport)}
- ]),
+perving(stop, State) ->
+ {next_state, perving, State#state{
+ timeout = ?TIMEWAIT
+ }, ?TIMEWAIT};
+perving(timeout, State) ->
{stop, normal, State}.
Please sign in to comment.
Something went wrong with that request. Please try again.