Current section

Files

Jump to
pooler bench src consumer.erl
Raw

bench/src/consumer.erl

%% @doc A consumer of pool members used for perf testing pooler. The
%% consumer has a configurable think time for how long it keeps a
%% member checked out, how many take/return cycles it performs. Jitter
%% is added to think time. You can also request a consumer to crash or
%% trigger a member crash.
-module(consumer).
-behaviour(gen_server).
-define(SERVER, ?MODULE).
-export([start_link/0,
run/2
]).
-export([
code_change/3,
handle_call/3,
handle_cast/2,
handle_info/2,
init/1,
terminate/2
]).
%% ------------------------------------------------------------------
%% API Function Definitions
%% ------------------------------------------------------------------
start_link() ->
% not registered
gen_server:start_link(?MODULE, [], []).
run(S, Config) ->
SelfCrash = proplists:get_value(consumer_crash, Config) =:= true,
MemberCrash = proplists:get_value(member_crash, Config) =:= true,
TakeCycles = proplists:get_value(take_cycles, Config),
ThinkTime = proplists:get_value(think_time, Config),
PoolName = proplists:get_value(pool_name, Config),
gen_server:call(S, {run, PoolName, SelfCrash, MemberCrash,
TakeCycles, ThinkTime},
ThinkTime * 3 * TakeCycles).
%% ------------------------------------------------------------------
%% gen_server Function Definitions
%% ------------------------------------------------------------------
-record(state, {
id,
ping_count = 0
}).
init([]) ->
Now = os:timestamp(),
random:seed(Now),
{ok, #state{id = Now}}.
handle_call({run, PoolName, SelfCrash, MemberCrash,
TakeCycles, ThinkTime}, _From, State) ->
CrashData = crash_data(SelfCrash, MemberCrash, TakeCycles),
run_cycles(ThinkTime, TakeCycles, CrashData, PoolName),
{reply, ok, State};
handle_call(_Request, _From, State) ->
{noreply, ok, State}.
run_cycles(_ThinkTime, 0, _, _) ->
done;
run_cycles(_ThinkTime, CrashIdx, {CrashIdx, _}, _) ->
%% self crash
erlang:error({consumer, self_crash_requested});
run_cycles(ThinkTime, CrashIdx, {_, CrashIdx} = CrashData, PoolName) ->
%% member crash request
M = pooler:take_member(PoolName),
member:crash(M),
run_cycles(ThinkTime, CrashIdx - 1, CrashData, PoolName);
run_cycles(ThinkTime, Idx, CrashData, PoolName) ->
M = pooler:take_member(PoolName),
Think = ThinkTime + random:uniform(ThinkTime),
timer:sleep(Think),
pooler:return_member(PoolName, M),
run_cycles(ThinkTime, Idx - 1, CrashData, PoolName).
%% only support a single crash type. So if self crash is requested,
%% we'll never crash the member.
crash_data(false, false, _) ->
{never, never};
crash_data(true, _, TakeCycles) ->
{random:uniform(TakeCycles), never};
crash_data(false, true, TakeCycles) ->
{never, random:uniform(TakeCycles)}.
handle_cast(crash, _State) ->
erlang:error({member, requested_crash});
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.