Current section
Files
Jump to
Current section
Files
src/bath.erl
-module(bath).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/1, with_size/2, with_shutdown/2, with_checkout_strategy/2, with_creation_strategy/2, from_subject/1, apply/3, shutdown/3, child_spec/2, start/2]).
-export_type([checkout_strategy/0, creation_strategy/0, pool_config/2, start_error/1, apply_error/1, shutdown_error/0, pool/2, state/2, live_resource/1, msg/2]).
-type checkout_strategy() :: fifo | lifo.
-type creation_strategy() :: lazy | eager.
-opaque pool_config(HRG, HRH) :: {pool_config,
integer(),
fun(() -> {ok, HRG} | {error, HRH}),
fun((HRG) -> nil),
checkout_strategy(),
creation_strategy()}.
-type start_error(HRI) :: {pool_start_resource_create_error, HRI} |
{actor_start_error, gleam@otp@actor:start_error()}.
-type apply_error(HRJ) :: no_resources_available |
{check_out_resource_create_error, HRJ} |
check_out_timeout.
-type shutdown_error() :: resources_in_use |
shutdown_timeout |
{callee_down, gleam@dynamic:dynamic_()}.
-opaque pool(HRK, HRL) :: {pool, gleam@erlang@process:subject(msg(HRK, HRL))}.
-opaque state(HRM, HRN) :: {state,
checkout_strategy(),
creation_strategy(),
integer(),
fun(() -> {ok, HRM} | {error, HRN}),
fun((HRM) -> nil),
gleam@deque:deque(HRM),
integer(),
gleam@dict:dict(gleam@erlang@process:pid_(), live_resource(HRM)),
gleam@erlang@process:selector(msg(HRM, HRN))}.
-type live_resource(HRO) :: {live_resource,
HRO,
gleam@erlang@process:process_monitor()}.
-opaque msg(HRP, HRQ) :: {check_in, HRP, gleam@erlang@process:pid_()} |
{check_out,
gleam@erlang@process:subject({ok, HRP} | {error, apply_error(HRQ)}),
gleam@erlang@process:pid_()} |
{pool_exit, gleam@erlang@process:exit_message()} |
{caller_down, gleam@erlang@process:process_down()} |
{shutdown,
gleam@erlang@process:subject({ok, nil} | {error, shutdown_error()}),
boolean()}.
-file("/Users/isaac/repos/bath/src/bath.gleam", 62).
-spec new(fun(() -> {ok, HRV} | {error, HRW})) -> pool_config(HRV, HRW).
new(Create_resource) ->
{pool_config, 10, Create_resource, fun(_) -> nil end, fifo, lazy}.
-file("/Users/isaac/repos/bath/src/bath.gleam", 75).
-spec with_size(pool_config(HSB, HSC), integer()) -> pool_config(HSB, HSC).
with_size(Pool_config, Size) ->
erlang:setelement(2, Pool_config, Size).
-file("/Users/isaac/repos/bath/src/bath.gleam", 83).
-spec with_shutdown(pool_config(HSH, HSI), fun((HSH) -> nil)) -> pool_config(HSH, HSI).
with_shutdown(Pool_config, Shutdown_resource) ->
erlang:setelement(4, Pool_config, Shutdown_resource).
-file("/Users/isaac/repos/bath/src/bath.gleam", 91).
-spec with_checkout_strategy(pool_config(HSN, HSO), checkout_strategy()) -> pool_config(HSN, HSO).
with_checkout_strategy(Pool_config, Checkout_strategy) ->
erlang:setelement(5, Pool_config, Checkout_strategy).
-file("/Users/isaac/repos/bath/src/bath.gleam", 99).
-spec with_creation_strategy(pool_config(HST, HSU), creation_strategy()) -> pool_config(HST, HSU).
with_creation_strategy(Pool_config, Creation_strategy) ->
erlang:setelement(6, Pool_config, Creation_strategy).
-file("/Users/isaac/repos/bath/src/bath.gleam", 165).
-spec from_subject(gleam@erlang@process:subject(msg(HTM, HTN))) -> pool(HTM, HTN).
from_subject(Subject) ->
{pool, Subject}.
-file("/Users/isaac/repos/bath/src/bath.gleam", 190).
-spec check_out(pool(HUC, HUD), gleam@erlang@process:pid_(), integer()) -> {ok,
HUC} |
{error, apply_error(HUD)}.
check_out(Pool, Caller, Timeout) ->
_pipe = gleam@erlang@process:try_call(
erlang:element(2, Pool),
fun(_capture) -> {check_out, _capture, Caller} end,
Timeout
),
_pipe@1 = gleam@result:replace_error(_pipe, check_out_timeout),
gleam@result:flatten(_pipe@1).
-file("/Users/isaac/repos/bath/src/bath.gleam", 200).
-spec check_in(pool(HUJ, any()), HUJ, gleam@erlang@process:pid_()) -> nil.
check_in(Pool, Resource, Caller) ->
gleam@erlang@process:send(
erlang:element(2, Pool),
{check_in, Resource, Caller}
).
-file("/Users/isaac/repos/bath/src/bath.gleam", 219).
-spec apply(pool(HUO, HUP), integer(), fun((HUO) -> HUS)) -> {ok, HUS} |
{error, apply_error(HUP)}.
apply(Pool, Timeout, Next) ->
Self = erlang:self(),
gleam@result:'try'(
check_out(Pool, Self, Timeout),
fun(Resource) ->
Usage_result = Next(Resource),
check_in(Pool, Resource, Self),
{ok, Usage_result}
end
).
-file("/Users/isaac/repos/bath/src/bath.gleam", 241).
-spec shutdown(pool(any(), any()), boolean(), integer()) -> {ok, nil} |
{error, shutdown_error()}.
shutdown(Pool, Force, Timeout) ->
_pipe = gleam@erlang@process:try_call(
erlang:element(2, Pool),
fun(_capture) -> {shutdown, _capture, Force} end,
Timeout
),
_pipe@1 = gleam@result:map_error(_pipe, fun(Err) -> case Err of
call_timeout ->
shutdown_timeout;
{callee_down, Reason} ->
{callee_down, Reason}
end end),
gleam@result:flatten(_pipe@1).
-file("/Users/isaac/repos/bath/src/bath.gleam", 520).
-spec monitor_process(
gleam@erlang@process:selector(msg(HVT, HVU)),
gleam@erlang@process:pid_()
) -> {gleam@erlang@process:process_monitor(),
gleam@erlang@process:selector(msg(HVT, HVU))}.
monitor_process(Selector, Pid) ->
Monitor = gleam@erlang@process:monitor_process(Pid),
Selector@1 = begin
_pipe = Selector,
gleam@erlang@process:selecting_process_down(
_pipe,
Monitor,
fun(Field@0) -> {caller_down, Field@0} end
)
end,
{Monitor, Selector@1}.
-file("/Users/isaac/repos/bath/src/bath.gleam", 531).
-spec demonitor_process(
gleam@erlang@process:selector(msg(HVZ, HWA)),
gleam@erlang@process:process_monitor()
) -> gleam@erlang@process:selector(msg(HVZ, HWA)).
demonitor_process(Selector, Monitor) ->
Selector@1 = begin
_pipe = Selector,
gleam@erlang@process:deselecting_process_down(_pipe, Monitor)
end,
Selector@1.
-file("/Users/isaac/repos/bath/src/bath.gleam", 541).
-spec log_resource_creation_error(any()) -> nil.
log_resource_creation_error(Resource_create_error) ->
logging:log(
error,
<<"Bath: Resource creation failed: "/utf8,
(gleam@string:inspect(Resource_create_error))/binary>>
).
-file("/Users/isaac/repos/bath/src/bath.gleam", 299).
-spec handle_pool_message(msg(HVB, HVC), state(HVB, HVC)) -> gleam@otp@actor:next(msg(HVB, HVC), state(HVB, HVC)).
handle_pool_message(Msg, State) ->
case Msg of
{check_in, Resource, Caller} ->
Caller_live_resource = gleam_stdlib:map_get(
erlang:element(9, State),
Caller
),
Live_resources = gleam@dict:delete(erlang:element(9, State), Caller),
Selector = case Caller_live_resource of
{ok, Live_resource} ->
demonitor_process(
erlang:element(10, State),
erlang:element(3, Live_resource)
);
{error, _} ->
erlang:element(10, State)
end,
New_resources = gleam@deque:push_back(
erlang:element(7, State),
Resource
),
gleam@otp@actor:with_selector(
gleam@otp@actor:continue(
erlang:setelement(
10,
erlang:setelement(
9,
erlang:setelement(7, State, New_resources),
Live_resources
),
Selector
)
),
Selector
);
{check_out, Reply_to, Caller@1} ->
Get_result = case erlang:element(2, State) of
fifo ->
gleam@deque:pop_front(erlang:element(7, State));
lifo ->
gleam@deque:pop_back(erlang:element(7, State))
end,
Resource_result = case Get_result of
{ok, {Resource@1, New_resources@1}} ->
{ok,
{Resource@1, New_resources@1, erlang:element(8, State)}};
{error, _} ->
case erlang:element(8, State) < erlang:element(4, State) of
true ->
gleam@result:'try'(
begin
_pipe = (erlang:element(5, State))(),
gleam@result:map_error(
_pipe,
fun(Err) ->
log_resource_creation_error(Err),
{check_out_resource_create_error,
Err}
end
)
end,
fun(Resource@2) ->
{ok,
{Resource@2,
erlang:element(7, State),
erlang:element(8, State) + 1}}
end
);
false ->
{error, no_resources_available}
end
end,
case Resource_result of
{error, Err@1} ->
gleam@otp@actor:send(Reply_to, {error, Err@1}),
gleam@otp@actor:continue(State);
{ok, {Resource@3, New_resources@2, New_current_size}} ->
{Monitor, Selector@1} = monitor_process(
erlang:element(10, State),
Caller@1
),
Live_resources@1 = gleam@dict:insert(
erlang:element(9, State),
Caller@1,
{live_resource, Resource@3, Monitor}
),
gleam@otp@actor:send(Reply_to, {ok, Resource@3}),
gleam@otp@actor:with_selector(
gleam@otp@actor:continue(
erlang:setelement(
9,
erlang:setelement(
10,
erlang:setelement(
8,
erlang:setelement(
7,
State,
New_resources@2
),
New_current_size
),
Selector@1
),
Live_resources@1
)
),
Selector@1
)
end;
{pool_exit, Exit_message} ->
_pipe@1 = erlang:element(7, State),
_pipe@2 = gleam@deque:to_list(_pipe@1),
gleam@list:each(_pipe@2, erlang:element(6, State)),
{stop, erlang:element(3, Exit_message)};
{shutdown, Reply_to@1, Force} ->
case {maps:size(erlang:element(9, State)), Force} of
{0, _} ->
_pipe@3 = erlang:element(7, State),
_pipe@4 = gleam@deque:to_list(_pipe@3),
gleam@list:each(_pipe@4, erlang:element(6, State)),
gleam@otp@actor:send(Reply_to@1, {ok, nil}),
{stop, normal};
{_, true} ->
gleam@otp@actor:send(Reply_to@1, {ok, nil}),
{stop, normal};
{_, false} ->
gleam@otp@actor:send(Reply_to@1, {error, resources_in_use}),
gleam@otp@actor:continue(State)
end;
{caller_down, Process_down} ->
case gleam_stdlib:map_get(
erlang:element(9, State),
erlang:element(2, Process_down)
) of
{error, _} ->
gleam@otp@actor:continue(State);
{ok, Live_resource@1} ->
Selector@2 = demonitor_process(
erlang:element(10, State),
erlang:element(3, Live_resource@1)
),
(erlang:element(6, State))(
erlang:element(2, Live_resource@1)
),
{New_resources@3, New_current_size@1} = case erlang:element(
3,
State
) of
lazy ->
{erlang:element(7, State),
erlang:element(8, State) - 1};
eager ->
case (erlang:element(5, State))() of
{ok, Resource@4} ->
{gleam@deque:push_back(
erlang:element(7, State),
Resource@4
),
erlang:element(8, State)};
{error, Resource_create_error} ->
log_resource_creation_error(
Resource_create_error
),
{erlang:element(7, State),
erlang:element(8, State)}
end
end,
gleam@otp@actor:with_selector(
gleam@otp@actor:continue(
erlang:setelement(
9,
erlang:setelement(
10,
erlang:setelement(
8,
erlang:setelement(
7,
State,
New_resources@3
),
New_current_size@1
),
Selector@2
),
gleam@dict:delete(
erlang:element(9, State),
erlang:element(2, Process_down)
)
)
),
Selector@2
)
end
end.
-file("/Users/isaac/repos/bath/src/bath.gleam", 481).
-spec pool_spec(
pool_config(HVI, HVJ),
gleam@deque:deque(HVI),
integer(),
integer()
) -> gleam@otp@actor:spec(state(HVI, HVJ), msg(HVI, HVJ)).
pool_spec(Pool_config, Resources, Current_size, Init_timeout) ->
{spec,
fun() ->
Self = gleam@erlang@process:new_subject(),
gleam_erlang_ffi:trap_exits(true),
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
_pipe@1 = gleam@erlang@process:selecting(
_pipe,
Self,
fun gleam@function:identity/1
),
gleam@erlang@process:selecting_trapped_exits(
_pipe@1,
fun(Field@0) -> {pool_exit, Field@0} end
)
end,
State = {state,
erlang:element(5, Pool_config),
erlang:element(6, Pool_config),
erlang:element(2, Pool_config),
erlang:element(3, Pool_config),
erlang:element(4, Pool_config),
Resources,
Current_size,
maps:new(),
Selector},
{ready, State, Selector}
end,
Init_timeout,
fun handle_pool_message/2}.
-file("/Users/isaac/repos/bath/src/bath.gleam", 136).
-spec child_spec(pool_config(HSZ, HTA), integer()) -> {ok,
gleam@otp@actor:spec(state(HSZ, HTA), msg(HSZ, HTA))} |
{error, start_error(HTA)}.
child_spec(Pool_config, Init_timeout) ->
{Resources_result, Current_size} = case erlang:element(6, Pool_config) of
lazy ->
{{ok, gleam@deque:new()}, 0};
eager ->
{begin
_pipe = gleam@list:repeat(
<<""/utf8>>,
erlang:element(2, Pool_config)
),
_pipe@1 = gleam@list:try_map(
_pipe,
fun(_) -> (erlang:element(3, Pool_config))() end
),
_pipe@2 = gleam@result:map(
_pipe@1,
fun gleam@deque:from_list/1
),
gleam@result:map_error(
_pipe@2,
fun(Field@0) -> {pool_start_resource_create_error, Field@0} end
)
end,
erlang:element(2, Pool_config)}
end,
gleam@result:'try'(
Resources_result,
fun(Resources) ->
{ok, pool_spec(Pool_config, Resources, Current_size, Init_timeout)}
end
).
-file("/Users/isaac/repos/bath/src/bath.gleam", 173).
-spec start(pool_config(HTT, HTU), integer()) -> {ok, pool(HTT, HTU)} |
{error, start_error(HTU)}.
start(Pool_config, Init_timeout) ->
gleam@result:'try'(
child_spec(Pool_config, Init_timeout),
fun(Spec) -> _pipe = gleam@otp@actor:start_spec(Spec),
_pipe@1 = gleam@result:map(
_pipe,
fun(Subject) -> {pool, Subject} end
),
gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {actor_start_error, Field@0} end
) end
).