Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix bugs added by using the ETS table found by quickcheck

Additionally, fix some minor issues in the quickcheck test
  • Loading branch information...
commit 3a18d400d7cbcce5071a8944c27d92269793bd4c 1 parent 0e45be9
@Vagabond Vagabond authored
Showing with 120 additions and 83 deletions.
  1. +87 −77 src/poolboy.erl
  2. +33 −6 test/poolboy_eqc.erl
View
164 src/poolboy.erl
@@ -192,35 +192,12 @@ overflow(_Event, _From, State) ->
{reply, ok, overflow, State}.
full({checkin, Pid}, State) ->
- #state{supervisor = Sup,
- waiting = Waiting,
- monitors = Monitors,
- max_overflow = MaxOverflow,
- overflow = Overflow} = State,
+ #state{monitors = Monitors} = State,
case ets:lookup(Monitors, Pid) of
[{Pid, Ref}] ->
true = erlang:demonitor(Ref),
true = ets:delete(Monitors, Pid),
- case queue:out(Waiting) of
- {{value, {{FromPid, _}=From, Timeout, StartTime}}, Left} ->
- case wait_valid(StartTime, Timeout) of
- true ->
- Ref1 = erlang:monitor(process, FromPid),
- true = ets:insert(Monitors, {Pid, Ref1}),
- gen_fsm:reply(From, Pid),
- {next_state, full, State#state{waiting=Left}};
- false ->
- full({checkin, Pid}, State#state{waiting=Left})
- end;
- {empty, Empty} when MaxOverflow < 1 ->
- Workers = queue:in(Pid, State#state.workers),
- {next_state, ready, State#state{workers=Workers,
- waiting=Empty}};
- {empty, Empty} ->
- ok = dismiss_worker(Sup, Pid),
- {next_state, overflow, State#state{waiting=Empty,
- overflow=Overflow-1}}
- end;
+ checkin_while_full(Pid, State);
[] ->
{next_state, full, State}
end;
@@ -270,63 +247,14 @@ handle_info({'DOWN', Ref, _, _, _}, StateName, State) ->
[] ->
{next_state, StateName, State}
end;
-handle_info({'EXIT', Pid, Reason}, StateName, State) ->
+handle_info({'EXIT', Pid, _Reason}, StateName, State) ->
#state{supervisor = Sup,
- overflow = Overflow,
- waiting = Waiting,
- monitors = Monitors,
- max_overflow = MaxOverflow} = State,
+ monitors = Monitors} = State,
case ets:lookup(Monitors, Pid) of
[{Pid, Ref}] ->
true = erlang:demonitor(Ref),
true = ets:delete(Monitors, Pid),
- case StateName of
- ready ->
- W = queue:filter(fun (P) -> P =/= Pid end, State#state.workers),
- {next_state, ready, State#state{workers=queue:in(new_worker(Sup), W)}};
- overflow when Overflow =:= 0 ->
- W = queue:filter(fun (P) -> P =/= Pid end, State#state.workers),
- {next_state, ready, State#state{workers=queue:in(new_worker(Sup), W)}};
- overflow ->
- {next_state, overflow, State#state{overflow=Overflow-1}};
- full when MaxOverflow < 1 ->
- case queue:out(Waiting) of
- {{value, {{FromPid, _}=From, Timeout, StartTime}}, LeftWaiting} ->
- case wait_valid(StartTime, Timeout) of
- true ->
- MonitorRef = erlang:monitor(process, FromPid),
- NewWorker = new_worker(Sup),
- true = ets:insert(Monitors, {NewWorker, MonitorRef}),
- gen_fsm:reply(From, NewWorker),
- {next_state, full, State#state{waiting=LeftWaiting}};
- false ->
- handle_info({'EXIT', Pid, Reason}, StateName, State#state{waiting=LeftWaiting})
- end;
- {empty, Empty} ->
- Workers2 = queue:in(new_worker(Sup), State#state.workers),
- {next_state, ready, State#state{waiting=Empty,
- workers=Workers2}}
- end;
- full when Overflow =< MaxOverflow ->
- case queue:out(Waiting) of
- {{value, {{FromPid, _}=From, Timeout, StartTime}}, LeftWaiting} ->
- case wait_valid(StartTime, Timeout) of
- true ->
- MonitorRef = erlang:monitor(process, FromPid),
- NewWorker = new_worker(Sup),
- true = ets:insert(Monitors, {NewWorker, MonitorRef}),
- gen_fsm:reply(From, NewWorker),
- {next_state, full, State#state{waiting=LeftWaiting}};
- _ ->
- handle_info({'EXIT', Pid, Reason}, StateName, State#state{waiting=LeftWaiting})
- end;
- {empty, Empty} ->
- {next_state, overflow, State#state{overflow=Overflow-1,
- waiting=Empty}}
- end;
- full ->
- {next_state, full, State#state{overflow=Overflow-1}}
- end;
+ handle_worker_exit(Pid, StateName, State);
[] ->
case queue:member(Pid, State#state.workers) of
true ->
@@ -377,3 +305,85 @@ wait_valid(infinity, _) ->
wait_valid(StartTime, Timeout) ->
Waited = timer:now_diff(os:timestamp(), StartTime),
(Waited div 1000) < Timeout.
+
+handle_worker_exit(Pid, StateName, State) ->
+ #state{supervisor = Sup,
+ overflow = Overflow,
+ waiting = Waiting,
+ monitors = Monitors,
+ max_overflow = MaxOverflow} = State,
+ case StateName of
+ ready ->
+ W = queue:filter(fun (P) -> P =/= Pid end, State#state.workers),
+ {next_state, ready, State#state{workers=queue:in(new_worker(Sup), W)}};
+ overflow when Overflow =:= 0 ->
+ W = queue:filter(fun (P) -> P =/= Pid end, State#state.workers),
+ {next_state, ready, State#state{workers=queue:in(new_worker(Sup), W)}};
+ overflow ->
+ {next_state, overflow, State#state{overflow=Overflow-1}};
+ full when MaxOverflow < 1 ->
+ case queue:out(Waiting) of
+ {{value, {{FromPid, _}=From, Timeout, StartTime}}, LeftWaiting} ->
+ case wait_valid(StartTime, Timeout) of
+ true ->
+ MonitorRef = erlang:monitor(process, FromPid),
+ NewWorker = new_worker(Sup),
+ true = ets:insert(Monitors, {NewWorker, MonitorRef}),
+ gen_fsm:reply(From, NewWorker),
+ {next_state, full, State#state{waiting=LeftWaiting}};
+ false ->
+ handle_worker_exit(Pid, StateName, State#state{waiting=LeftWaiting})
+ end;
+ {empty, Empty} ->
+ Workers2 = queue:in(new_worker(Sup), State#state.workers),
+ {next_state, ready, State#state{waiting=Empty,
+ workers=Workers2}}
+ end;
+ full when Overflow =< MaxOverflow ->
+ case queue:out(Waiting) of
+ {{value, {{FromPid, _}=From, Timeout, StartTime}}, LeftWaiting} ->
+ case wait_valid(StartTime, Timeout) of
+ true ->
+ MonitorRef = erlang:monitor(process, FromPid),
+ NewWorker = new_worker(Sup),
+ true = ets:insert(Monitors, {NewWorker, MonitorRef}),
+ gen_fsm:reply(From, NewWorker),
+ {next_state, full, State#state{waiting=LeftWaiting}};
+ _ ->
+ handle_worker_exit(Pid, StateName, State#state{waiting=LeftWaiting})
+ end;
+ {empty, Empty} ->
+ {next_state, overflow, State#state{overflow=Overflow-1,
+ waiting=Empty}}
+ end;
+ full ->
+ {next_state, full, State#state{overflow=Overflow-1}}
+ end.
+
+checkin_while_full(Pid, State) ->
+ #state{supervisor = Sup,
+ waiting = Waiting,
+ monitors = Monitors,
+ max_overflow = MaxOverflow,
+ overflow = Overflow} = State,
+ case queue:out(Waiting) of
+ {{value, {{FromPid, _}=From, Timeout, StartTime}}, Left} ->
+ case wait_valid(StartTime, Timeout) of
+ true ->
+ Ref1 = erlang:monitor(process, FromPid),
+ true = ets:insert(Monitors, {Pid, Ref1}),
+ gen_fsm:reply(From, Pid),
+ {next_state, full, State#state{waiting=Left}};
+ false ->
+ checkin_while_full(Pid, State#state{waiting=Left})
+ end;
+ {empty, Empty} when MaxOverflow < 1 ->
+ Workers = queue:in(Pid, State#state.workers),
+ {next_state, ready, State#state{workers=Workers,
+ waiting=Empty}};
+ {empty, Empty} ->
+ ok = dismiss_worker(Sup, Pid),
+ {next_state, overflow, State#state{waiting=Empty,
+ overflow=Overflow-1}}
+ end.
+
View
39 test/poolboy_eqc.erl
@@ -110,6 +110,8 @@ precondition(S, {call, _, kill_worker, [Pid]}) ->
lists:member(Pid, S#state.checked_out);
precondition(S,{call,_,kill_idle_worker,[_Pool]}) ->
length(S#state.checked_out) < S#state.size;
+precondition(S,{call,_,checkin,[_Pool, Pid]}) ->
+ lists:member(Pid, S#state.checked_out);
precondition(_S,{call,_,_,_}) ->
true.
@@ -140,19 +142,44 @@ precondition(_S,{call,_,_,_}) ->
postcondition(S,{call,_,checkout_block,[_Pool]},R) ->
case R of
{{'EXIT', {timeout, _}}, _} ->
- length(S#state.checked_out) >= S#state.size + S#state.max_overflow;
+ case length(S#state.checked_out) >= S#state.size + S#state.max_overflow of
+ true ->
+ true;
+ _ ->
+ {checkout_block, R}
+ end;
_ ->
- length(S#state.checked_out) < S#state.size + S#state.max_overflow
+ case length(S#state.checked_out) < S#state.size + S#state.max_overflow of
+ true ->
+ true;
+ _ ->
+ {checkout_block, R}
+ end
end;
postcondition(S,{call,_,checkout_nonblock,[_Pool]},R) ->
case R of
{full, _} ->
- length(S#state.checked_out) >= S#state.size + S#state.max_overflow;
+ case length(S#state.checked_out) >= S#state.size + S#state.max_overflow of
+ true ->
+ true;
+ _ ->
+ {checkout_nonblock, R}
+ end;
_ ->
- length(S#state.checked_out) < S#state.size + S#state.max_overflow
+ case length(S#state.checked_out) < S#state.size + S#state.max_overflow of
+ true ->
+ true;
+ _ ->
+ {checkout_block, R}
+ end
end;
postcondition(_S, {call,_,checkin,_}, R) ->
- R == ok;
+ case R of
+ ok ->
+ true;
+ _ ->
+ {checkin, R}
+ end;
postcondition(_S,{call,_,_,_},_R) ->
true.
@@ -201,7 +228,7 @@ prop_sequential() ->
{H,S,Res} = run_commands(?MODULE,Cmds),
catch(stop_poolboy(whereis(poolboy_eqc))),
?WHENFAIL(io:format("History: ~p\nState: ~p\nRes: ~p\n~p\n",
- [H,S,Res, zip(tl(Cmds), [Y || {_, Y} <- H])]),
+ [H,S,Res, zip(Cmds, [Y || {_, Y} <- H])]),
Res == ok)
end)))).
Please sign in to comment.
Something went wrong with that request. Please try again.