Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Fix bugs added by using the ETS table found by quickcheck #12

Merged
merged 1 commit into from Aug 8, 2012
Jump to file or symbol
Failed to load files and symbols.
+120 −83
Split
View
@@ -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
@@ -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)))).