Skip to content

Commit

Permalink
Merge pull request #12 from devinus/adt-eqc-fixes
Browse files Browse the repository at this point in the history
Fix bugs added by using the ETS table found by quickcheck
  • Loading branch information
Devin Torres committed Aug 8, 2012
2 parents 4ca3e47 + 3a18d40 commit e6203be
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 83 deletions.
164 changes: 87 additions & 77 deletions src/poolboy.erl
Expand Up @@ -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;
Expand Down Expand Up @@ -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 ->
Expand Down Expand Up @@ -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.

39 changes: 33 additions & 6 deletions test/poolboy_eqc.erl
Expand Up @@ -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.

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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)))).

Expand Down

0 comments on commit e6203be

Please sign in to comment.