diff options
Diffstat (limited to 'server/_build/default/lib/poolboy')
-rw-r--r-- | server/_build/default/lib/poolboy/LICENSE | 15 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/README.md | 171 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/ebin/poolboy.app | 9 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/ebin/poolboy.beam | bin | 0 -> 17524 bytes | |||
-rw-r--r-- | server/_build/default/lib/poolboy/ebin/poolboy_sup.beam | bin | 0 -> 1804 bytes | |||
-rw-r--r-- | server/_build/default/lib/poolboy/ebin/poolboy_worker.beam | bin | 0 -> 1560 bytes | |||
-rw-r--r-- | server/_build/default/lib/poolboy/hex_metadata.config | 15 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/rebar.config | 15 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/rebar.lock | 1 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/src/poolboy.app.src | 8 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/src/poolboy.erl | 357 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/src/poolboy_sup.erl | 14 | ||||
-rw-r--r-- | server/_build/default/lib/poolboy/src/poolboy_worker.erl | 10 |
13 files changed, 615 insertions, 0 deletions
diff --git a/server/_build/default/lib/poolboy/LICENSE b/server/_build/default/lib/poolboy/LICENSE new file mode 100644 index 0000000..ce34eab --- /dev/null +++ b/server/_build/default/lib/poolboy/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2014, Devin Alexander Torres <devin@devintorr.es> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/server/_build/default/lib/poolboy/README.md b/server/_build/default/lib/poolboy/README.md new file mode 100644 index 0000000..495d812 --- /dev/null +++ b/server/_build/default/lib/poolboy/README.md @@ -0,0 +1,171 @@ +# Poolboy - A hunky Erlang worker pool factory + +[](https://travis-ci.org/devinus/poolboy) + +[](https://gratipay.com/devinus/) + +Poolboy is a **lightweight**, **generic** pooling library for Erlang with a +focus on **simplicity**, **performance**, and **rock-solid** disaster recovery. + +## Usage + +```erl-sh +1> Worker = poolboy:checkout(PoolName). +<0.9001.0> +2> gen_server:call(Worker, Request). +ok +3> poolboy:checkin(PoolName, Worker). +ok +``` + +## Example + +This is an example application showcasing database connection pools using +Poolboy and [epgsql](https://github.com/epgsql/epgsql). + +### example.app + +```erlang +{application, example, [ + {description, "An example application"}, + {vsn, "0.1"}, + {applications, [kernel, stdlib, sasl, crypto, ssl]}, + {modules, [example, example_worker]}, + {registered, [example]}, + {mod, {example, []}}, + {env, [ + {pools, [ + {pool1, [ + {size, 10}, + {max_overflow, 20} + ], [ + {hostname, "127.0.0.1"}, + {database, "db1"}, + {username, "db1"}, + {password, "abc123"} + ]}, + {pool2, [ + {size, 5}, + {max_overflow, 10} + ], [ + {hostname, "127.0.0.1"}, + {database, "db2"}, + {username, "db2"}, + {password, "abc123"} + ]} + ]} + ]} +]}. +``` + +### example.erl + +```erlang +-module(example). +-behaviour(application). +-behaviour(supervisor). + +-export([start/0, stop/0, squery/2, equery/3]). +-export([start/2, stop/1]). +-export([init/1]). + +start() -> + application:start(?MODULE). + +stop() -> + application:stop(?MODULE). + +start(_Type, _Args) -> + supervisor:start_link({local, example_sup}, ?MODULE, []). + +stop(_State) -> + ok. + +init([]) -> + {ok, Pools} = application:get_env(example, pools), + PoolSpecs = lists:map(fun({Name, SizeArgs, WorkerArgs}) -> + PoolArgs = [{name, {local, Name}}, + {worker_module, example_worker}] ++ SizeArgs, + poolboy:child_spec(Name, PoolArgs, WorkerArgs) + end, Pools), + {ok, {{one_for_one, 10, 10}, PoolSpecs}}. + +squery(PoolName, Sql) -> + poolboy:transaction(PoolName, fun(Worker) -> + gen_server:call(Worker, {squery, Sql}) + end). + +equery(PoolName, Stmt, Params) -> + poolboy:transaction(PoolName, fun(Worker) -> + gen_server:call(Worker, {equery, Stmt, Params}) + end). +``` + +### example_worker.erl + +```erlang +-module(example_worker). +-behaviour(gen_server). +-behaviour(poolboy_worker). + +-export([start_link/1]). +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). + +-record(state, {conn}). + +start_link(Args) -> + gen_server:start_link(?MODULE, Args, []). + +init(Args) -> + process_flag(trap_exit, true), + Hostname = proplists:get_value(hostname, Args), + Database = proplists:get_value(database, Args), + Username = proplists:get_value(username, Args), + Password = proplists:get_value(password, Args), + {ok, Conn} = epgsql:connect(Hostname, Username, Password, [ + {database, Database} + ]), + {ok, #state{conn=Conn}}. + +handle_call({squery, Sql}, _From, #state{conn=Conn}=State) -> + {reply, epgsql:squery(Conn, Sql), State}; +handle_call({equery, Stmt, Params}, _From, #state{conn=Conn}=State) -> + {reply, epgsql:equery(Conn, Stmt, Params), State}; +handle_call(_Request, _From, State) -> + {reply, ok, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, #state{conn=Conn}) -> + ok = epgsql:close(Conn), + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +``` + +## Options + +- `name`: the pool name +- `worker_module`: the module that represents the workers +- `size`: maximum pool size +- `max_overflow`: maximum number of workers created if pool is empty +- `strategy`: `lifo` or `fifo`, determines whether checked in workers should be + placed first or last in the line of available workers. So, `lifo` operates like a traditional stack; `fifo` like a queue. Default is `lifo`. + +## Authors + +- Devin Torres (devinus) <devin@devintorres.com> +- Andrew Thompson (Vagabond) <andrew@hijacked.us> +- Kurt Williams (onkel-dirtus) <kurt.r.williams@gmail.com> + +## License + +Poolboy is available in the public domain (see `UNLICENSE`). +Poolboy is also optionally available under the ISC license (see `LICENSE`), +meant especially for jurisdictions that do not recognize public domain works. diff --git a/server/_build/default/lib/poolboy/ebin/poolboy.app b/server/_build/default/lib/poolboy/ebin/poolboy.app new file mode 100644 index 0000000..228edc3 --- /dev/null +++ b/server/_build/default/lib/poolboy/ebin/poolboy.app @@ -0,0 +1,9 @@ +{application,poolboy, + [{description,"A hunky Erlang worker pool factory"}, + {vsn,"1.5.2"}, + {applications,[kernel,stdlib]}, + {registered,[poolboy]}, + {maintainers,["Devin Torres","Andrew Thompson","Kurt Williams"]}, + {licenses,["Unlicense","Apache 2.0"]}, + {links,[{"GitHub","https://github.com/devinus/poolboy"}]}, + {modules,[poolboy,poolboy_sup,poolboy_worker]}]}. diff --git a/server/_build/default/lib/poolboy/ebin/poolboy.beam b/server/_build/default/lib/poolboy/ebin/poolboy.beam Binary files differnew file mode 100644 index 0000000..c6a0e49 --- /dev/null +++ b/server/_build/default/lib/poolboy/ebin/poolboy.beam diff --git a/server/_build/default/lib/poolboy/ebin/poolboy_sup.beam b/server/_build/default/lib/poolboy/ebin/poolboy_sup.beam Binary files differnew file mode 100644 index 0000000..76226d6 --- /dev/null +++ b/server/_build/default/lib/poolboy/ebin/poolboy_sup.beam diff --git a/server/_build/default/lib/poolboy/ebin/poolboy_worker.beam b/server/_build/default/lib/poolboy/ebin/poolboy_worker.beam Binary files differnew file mode 100644 index 0000000..c4f0656 --- /dev/null +++ b/server/_build/default/lib/poolboy/ebin/poolboy_worker.beam diff --git a/server/_build/default/lib/poolboy/hex_metadata.config b/server/_build/default/lib/poolboy/hex_metadata.config new file mode 100644 index 0000000..4b24846 --- /dev/null +++ b/server/_build/default/lib/poolboy/hex_metadata.config @@ -0,0 +1,15 @@ +{<<"name">>,<<"poolboy">>}. +{<<"version">>,<<"1.5.2">>}. +{<<"requirements">>,#{}}. +{<<"app">>,<<"poolboy">>}. +{<<"maintainers">>, + [<<"Devin Torres">>,<<"Andrew Thompson">>,<<"Kurt Williams">>]}. +{<<"precompiled">>,false}. +{<<"description">>,<<"A hunky Erlang worker pool factory">>}. +{<<"files">>, + [<<"src/poolboy.app.src">>,<<"LICENSE">>,<<"README.md">>,<<"rebar.config">>, + <<"rebar.lock">>,<<"src/poolboy.erl">>,<<"src/poolboy_sup.erl">>, + <<"src/poolboy_worker.erl">>]}. +{<<"licenses">>,[<<"Unlicense">>,<<"Apache 2.0">>]}. +{<<"links">>,[{<<"GitHub">>,<<"https://github.com/devinus/poolboy">>}]}. +{<<"build_tools">>,[<<"rebar3">>]}. diff --git a/server/_build/default/lib/poolboy/rebar.config b/server/_build/default/lib/poolboy/rebar.config new file mode 100644 index 0000000..1d494ca --- /dev/null +++ b/server/_build/default/lib/poolboy/rebar.config @@ -0,0 +1,15 @@ +{erl_opts, [ + debug_info, + {platform_define, "^R", pre17} +]}. + +{eunit_opts, [verbose]}. +{cover_enabled, true}. + +{profiles, [ + {test, [ + {plugins, [ + {rebar3_eqc, ".*", {git, "https://github.com/kellymclaughlin/rebar3-eqc-plugin.git", {tag, "0.1.0"}}} + ]} + ] +}]}. diff --git a/server/_build/default/lib/poolboy/rebar.lock b/server/_build/default/lib/poolboy/rebar.lock new file mode 100644 index 0000000..57afcca --- /dev/null +++ b/server/_build/default/lib/poolboy/rebar.lock @@ -0,0 +1 @@ +[]. diff --git a/server/_build/default/lib/poolboy/src/poolboy.app.src b/server/_build/default/lib/poolboy/src/poolboy.app.src new file mode 100644 index 0000000..5119212 --- /dev/null +++ b/server/_build/default/lib/poolboy/src/poolboy.app.src @@ -0,0 +1,8 @@ +{application,poolboy, + [{description,"A hunky Erlang worker pool factory"}, + {vsn,"1.5.2"}, + {applications,[kernel,stdlib]}, + {registered,[poolboy]}, + {maintainers,["Devin Torres","Andrew Thompson","Kurt Williams"]}, + {licenses,["Unlicense","Apache 2.0"]}, + {links,[{"GitHub","https://github.com/devinus/poolboy"}]}]}. diff --git a/server/_build/default/lib/poolboy/src/poolboy.erl b/server/_build/default/lib/poolboy/src/poolboy.erl new file mode 100644 index 0000000..0023412 --- /dev/null +++ b/server/_build/default/lib/poolboy/src/poolboy.erl @@ -0,0 +1,357 @@ +%% Poolboy - A hunky Erlang worker pool factory + +-module(poolboy). +-behaviour(gen_server). + +-export([checkout/1, checkout/2, checkout/3, checkin/2, transaction/2, + transaction/3, child_spec/2, child_spec/3, start/1, start/2, + start_link/1, start_link/2, stop/1, status/1]). +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). +-export_type([pool/0]). + +-define(TIMEOUT, 5000). + +-ifdef(pre17). +-type pid_queue() :: queue(). +-else. +-type pid_queue() :: queue:queue(). +-endif. + +-ifdef(OTP_RELEASE). %% this implies 21 or higher +-define(EXCEPTION(Class, Reason, Stacktrace), Class:Reason:Stacktrace). +-define(GET_STACK(Stacktrace), Stacktrace). +-else. +-define(EXCEPTION(Class, Reason, _), Class:Reason). +-define(GET_STACK(_), erlang:get_stacktrace()). +-endif. + +-type pool() :: + Name :: (atom() | pid()) | + {Name :: atom(), node()} | + {local, Name :: atom()} | + {global, GlobalName :: any()} | + {via, Module :: atom(), ViaName :: any()}. + +% Copied from gen:start_ret/0 +-type start_ret() :: {'ok', pid()} | 'ignore' | {'error', term()}. + +-record(state, { + supervisor :: undefined | pid(), + workers = [] :: [pid()], + waiting :: pid_queue(), + monitors :: ets:tid(), + size = 5 :: non_neg_integer(), + overflow = 0 :: non_neg_integer(), + max_overflow = 10 :: non_neg_integer(), + strategy = lifo :: lifo | fifo +}). + +-spec checkout(Pool :: pool()) -> pid(). +checkout(Pool) -> + checkout(Pool, true). + +-spec checkout(Pool :: pool(), Block :: boolean()) -> pid() | full. +checkout(Pool, Block) -> + checkout(Pool, Block, ?TIMEOUT). + +-spec checkout(Pool :: pool(), Block :: boolean(), Timeout :: timeout()) + -> pid() | full. +checkout(Pool, Block, Timeout) -> + CRef = make_ref(), + try + gen_server:call(Pool, {checkout, CRef, Block}, Timeout) + catch + ?EXCEPTION(Class, Reason, Stacktrace) -> + gen_server:cast(Pool, {cancel_waiting, CRef}), + erlang:raise(Class, Reason, ?GET_STACK(Stacktrace)) + end. + +-spec checkin(Pool :: pool(), Worker :: pid()) -> ok. +checkin(Pool, Worker) when is_pid(Worker) -> + gen_server:cast(Pool, {checkin, Worker}). + +-spec transaction(Pool :: pool(), Fun :: fun((Worker :: pid()) -> any())) + -> any(). +transaction(Pool, Fun) -> + transaction(Pool, Fun, ?TIMEOUT). + +-spec transaction(Pool :: pool(), Fun :: fun((Worker :: pid()) -> any()), + Timeout :: timeout()) -> any(). +transaction(Pool, Fun, Timeout) -> + Worker = poolboy:checkout(Pool, true, Timeout), + try + Fun(Worker) + after + ok = poolboy:checkin(Pool, Worker) + end. + +-spec child_spec(PoolId :: term(), PoolArgs :: proplists:proplist()) + -> supervisor:child_spec(). +child_spec(PoolId, PoolArgs) -> + child_spec(PoolId, PoolArgs, []). + +-spec child_spec(PoolId :: term(), + PoolArgs :: proplists:proplist(), + WorkerArgs :: proplists:proplist()) + -> supervisor:child_spec(). +child_spec(PoolId, PoolArgs, WorkerArgs) -> + {PoolId, {poolboy, start_link, [PoolArgs, WorkerArgs]}, + permanent, 5000, worker, [poolboy]}. + +-spec start(PoolArgs :: proplists:proplist()) + -> start_ret(). +start(PoolArgs) -> + start(PoolArgs, PoolArgs). + +-spec start(PoolArgs :: proplists:proplist(), + WorkerArgs:: proplists:proplist()) + -> start_ret(). +start(PoolArgs, WorkerArgs) -> + start_pool(start, PoolArgs, WorkerArgs). + +-spec start_link(PoolArgs :: proplists:proplist()) + -> start_ret(). +start_link(PoolArgs) -> + %% for backwards compatability, pass the pool args as the worker args as well + start_link(PoolArgs, PoolArgs). + +-spec start_link(PoolArgs :: proplists:proplist(), + WorkerArgs:: proplists:proplist()) + -> start_ret(). +start_link(PoolArgs, WorkerArgs) -> + start_pool(start_link, PoolArgs, WorkerArgs). + +-spec stop(Pool :: pool()) -> ok. +stop(Pool) -> + gen_server:call(Pool, stop). + +-spec status(Pool :: pool()) -> {atom(), integer(), integer(), integer()}. +status(Pool) -> + gen_server:call(Pool, status). + +init({PoolArgs, WorkerArgs}) -> + process_flag(trap_exit, true), + Waiting = queue:new(), + Monitors = ets:new(monitors, [private]), + init(PoolArgs, WorkerArgs, #state{waiting = Waiting, monitors = Monitors}). + +init([{worker_module, Mod} | Rest], WorkerArgs, State) when is_atom(Mod) -> + {ok, Sup} = poolboy_sup:start_link(Mod, WorkerArgs), + init(Rest, WorkerArgs, State#state{supervisor = Sup}); +init([{size, Size} | Rest], WorkerArgs, State) when is_integer(Size) -> + init(Rest, WorkerArgs, State#state{size = Size}); +init([{max_overflow, MaxOverflow} | Rest], WorkerArgs, State) when is_integer(MaxOverflow) -> + init(Rest, WorkerArgs, State#state{max_overflow = MaxOverflow}); +init([{strategy, lifo} | Rest], WorkerArgs, State) -> + init(Rest, WorkerArgs, State#state{strategy = lifo}); +init([{strategy, fifo} | Rest], WorkerArgs, State) -> + init(Rest, WorkerArgs, State#state{strategy = fifo}); +init([_ | Rest], WorkerArgs, State) -> + init(Rest, WorkerArgs, State); +init([], _WorkerArgs, #state{size = Size, supervisor = Sup} = State) -> + Workers = prepopulate(Size, Sup), + {ok, State#state{workers = Workers}}. + +handle_cast({checkin, Pid}, State = #state{monitors = Monitors}) -> + case ets:lookup(Monitors, Pid) of + [{Pid, _, MRef}] -> + true = erlang:demonitor(MRef), + true = ets:delete(Monitors, Pid), + NewState = handle_checkin(Pid, State), + {noreply, NewState}; + [] -> + {noreply, State} + end; + +handle_cast({cancel_waiting, CRef}, State) -> + case ets:match(State#state.monitors, {'$1', CRef, '$2'}) of + [[Pid, MRef]] -> + demonitor(MRef, [flush]), + true = ets:delete(State#state.monitors, Pid), + NewState = handle_checkin(Pid, State), + {noreply, NewState}; + [] -> + Cancel = fun({_, Ref, MRef}) when Ref =:= CRef -> + demonitor(MRef, [flush]), + false; + (_) -> + true + end, + Waiting = queue:filter(Cancel, State#state.waiting), + {noreply, State#state{waiting = Waiting}} + end; + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_call({checkout, CRef, Block}, {FromPid, _} = From, State) -> + #state{supervisor = Sup, + workers = Workers, + monitors = Monitors, + overflow = Overflow, + max_overflow = MaxOverflow} = State, + case Workers of + [Pid | Left] -> + MRef = erlang:monitor(process, FromPid), + true = ets:insert(Monitors, {Pid, CRef, MRef}), + {reply, Pid, State#state{workers = Left}}; + [] when MaxOverflow > 0, Overflow < MaxOverflow -> + {Pid, MRef} = new_worker(Sup, FromPid), + true = ets:insert(Monitors, {Pid, CRef, MRef}), + {reply, Pid, State#state{overflow = Overflow + 1}}; + [] when Block =:= false -> + {reply, full, State}; + [] -> + MRef = erlang:monitor(process, FromPid), + Waiting = queue:in({From, CRef, MRef}, State#state.waiting), + {noreply, State#state{waiting = Waiting}} + end; + +handle_call(status, _From, State) -> + #state{workers = Workers, + monitors = Monitors, + overflow = Overflow} = State, + StateName = state_name(State), + {reply, {StateName, length(Workers), Overflow, ets:info(Monitors, size)}, State}; +handle_call(get_avail_workers, _From, State) -> + Workers = State#state.workers, + {reply, Workers, State}; +handle_call(get_all_workers, _From, State) -> + Sup = State#state.supervisor, + WorkerList = supervisor:which_children(Sup), + {reply, WorkerList, State}; +handle_call(get_all_monitors, _From, State) -> + Monitors = ets:select(State#state.monitors, + [{{'$1', '_', '$2'}, [], [{{'$1', '$2'}}]}]), + {reply, Monitors, State}; +handle_call(stop, _From, State) -> + {stop, normal, ok, State}; +handle_call(_Msg, _From, State) -> + Reply = {error, invalid_message}, + {reply, Reply, State}. + +handle_info({'DOWN', MRef, _, _, _}, State) -> + case ets:match(State#state.monitors, {'$1', '_', MRef}) of + [[Pid]] -> + true = ets:delete(State#state.monitors, Pid), + NewState = handle_checkin(Pid, State), + {noreply, NewState}; + [] -> + Waiting = queue:filter(fun ({_, _, R}) -> R =/= MRef end, State#state.waiting), + {noreply, State#state{waiting = Waiting}} + end; +handle_info({'EXIT', Pid, _Reason}, State) -> + #state{supervisor = Sup, + monitors = Monitors} = State, + case ets:lookup(Monitors, Pid) of + [{Pid, _, MRef}] -> + true = erlang:demonitor(MRef), + true = ets:delete(Monitors, Pid), + NewState = handle_worker_exit(Pid, State), + {noreply, NewState}; + [] -> + case lists:member(Pid, State#state.workers) of + true -> + W = lists:filter(fun (P) -> P =/= Pid end, State#state.workers), + {noreply, State#state{workers = [new_worker(Sup) | W]}}; + false -> + {noreply, State} + end + end; + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, State) -> + ok = lists:foreach(fun (W) -> unlink(W) end, State#state.workers), + true = exit(State#state.supervisor, shutdown), + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +start_pool(StartFun, PoolArgs, WorkerArgs) -> + case proplists:get_value(name, PoolArgs) of + undefined -> + gen_server:StartFun(?MODULE, {PoolArgs, WorkerArgs}, []); + Name -> + gen_server:StartFun(Name, ?MODULE, {PoolArgs, WorkerArgs}, []) + end. + +new_worker(Sup) -> + {ok, Pid} = supervisor:start_child(Sup, []), + true = link(Pid), + Pid. + +new_worker(Sup, FromPid) -> + Pid = new_worker(Sup), + Ref = erlang:monitor(process, FromPid), + {Pid, Ref}. + +dismiss_worker(Sup, Pid) -> + true = unlink(Pid), + supervisor:terminate_child(Sup, Pid). + +prepopulate(N, _Sup) when N < 1 -> + []; +prepopulate(N, Sup) -> + prepopulate(N, Sup, []). + +prepopulate(0, _Sup, Workers) -> + Workers; +prepopulate(N, Sup, Workers) -> + prepopulate(N-1, Sup, [new_worker(Sup) | Workers]). + +handle_checkin(Pid, State) -> + #state{supervisor = Sup, + waiting = Waiting, + monitors = Monitors, + overflow = Overflow, + strategy = Strategy} = State, + case queue:out(Waiting) of + {{value, {From, CRef, MRef}}, Left} -> + true = ets:insert(Monitors, {Pid, CRef, MRef}), + gen_server:reply(From, Pid), + State#state{waiting = Left}; + {empty, Empty} when Overflow > 0 -> + ok = dismiss_worker(Sup, Pid), + State#state{waiting = Empty, overflow = Overflow - 1}; + {empty, Empty} -> + Workers = case Strategy of + lifo -> [Pid | State#state.workers]; + fifo -> State#state.workers ++ [Pid] + end, + State#state{workers = Workers, waiting = Empty, overflow = 0} + end. + +handle_worker_exit(Pid, State) -> + #state{supervisor = Sup, + monitors = Monitors, + overflow = Overflow} = State, + case queue:out(State#state.waiting) of + {{value, {From, CRef, MRef}}, LeftWaiting} -> + NewWorker = new_worker(State#state.supervisor), + true = ets:insert(Monitors, {NewWorker, CRef, MRef}), + gen_server:reply(From, NewWorker), + State#state{waiting = LeftWaiting}; + {empty, Empty} when Overflow > 0 -> + State#state{overflow = Overflow - 1, waiting = Empty}; + {empty, Empty} -> + Workers = + [new_worker(Sup) + | lists:filter(fun (P) -> P =/= Pid end, State#state.workers)], + State#state{workers = Workers, waiting = Empty} + end. + +state_name(State = #state{overflow = Overflow}) when Overflow < 1 -> + #state{max_overflow = MaxOverflow, workers = Workers} = State, + case length(Workers) == 0 of + true when MaxOverflow < 1 -> full; + true -> overflow; + false -> ready + end; +state_name(#state{overflow = MaxOverflow, max_overflow = MaxOverflow}) -> + full; +state_name(_State) -> + overflow. diff --git a/server/_build/default/lib/poolboy/src/poolboy_sup.erl b/server/_build/default/lib/poolboy/src/poolboy_sup.erl new file mode 100644 index 0000000..e6485a6 --- /dev/null +++ b/server/_build/default/lib/poolboy/src/poolboy_sup.erl @@ -0,0 +1,14 @@ +%% Poolboy - A hunky Erlang worker pool factory + +-module(poolboy_sup). +-behaviour(supervisor). + +-export([start_link/2, init/1]). + +start_link(Mod, Args) -> + supervisor:start_link(?MODULE, {Mod, Args}). + +init({Mod, Args}) -> + {ok, {{simple_one_for_one, 0, 1}, + [{Mod, {Mod, start_link, [Args]}, + temporary, 5000, worker, [Mod]}]}}. diff --git a/server/_build/default/lib/poolboy/src/poolboy_worker.erl b/server/_build/default/lib/poolboy/src/poolboy_worker.erl new file mode 100644 index 0000000..4a5bfae --- /dev/null +++ b/server/_build/default/lib/poolboy/src/poolboy_worker.erl @@ -0,0 +1,10 @@ +%% Poolboy - A hunky Erlang worker pool factory + +-module(poolboy_worker). + +-callback start_link(WorkerArgs) -> {ok, Pid} | + {error, {already_started, Pid}} | + {error, Reason} when + WorkerArgs :: proplists:proplist(), + Pid :: pid(), + Reason :: term(). |