Packages

An embedded, crash-safe key-value store for Gleam, inspired by CubDB

Current section

Files

Jump to
trove src trove@internal@db.erl
Raw

src/trove@internal@db.erl

-module(trove@internal@db).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/trove/internal/db.gleam").
-export([get/3, put/4, delete/3, has_key/3, put_multi/3, delete_multi/3, put_and_delete_multi/4, transaction/3, acquire_snapshot/2, compact/2, size/2, dirt_factor/2, file_sync/2, set_auto_compact/3, register_keyspace/4, list_keyspaces/2, put_in/5, get_in/4, delete_in/4, has_key_in/4, size_in/3, put_and_delete_multi_in/5, close/2, open/7]).
-export_type([open_error/0, file_sync/0, auto_compact/0, transaction_outcome/2, message/2, keyspace_state/0, state/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-type open_error() :: {directory_error, binary()} |
{store_error, binary()} |
{lock_error, binary()} |
actor_start_error.
-type file_sync() :: auto_sync | manual_sync.
-type auto_compact() :: {auto_compact, integer(), float()} | no_auto_compact.
-type transaction_outcome(KNK, KNL) :: {commit_outcome,
trove@internal@btree:btree(KNK, KNL),
gleam@dict:dict(binary(), trove@internal@tx:keyspace_entry())} |
cancel_outcome.
-type message(KNM, KNN) :: {get,
KNM,
gleam@erlang@process:subject({ok, KNN} | {error, nil})} |
{put, KNM, KNN, gleam@erlang@process:subject(nil)} |
{delete, KNM, gleam@erlang@process:subject(nil)} |
{has_key, KNM, gleam@erlang@process:subject(boolean())} |
{put_multi, list({KNM, KNN}), gleam@erlang@process:subject(nil)} |
{delete_multi, list(KNM), gleam@erlang@process:subject(nil)} |
{put_and_delete_multi,
list({KNM, KNN}),
list(KNM),
gleam@erlang@process:subject(nil)} |
{execute_transaction,
fun((trove@internal@tx:tx(KNM, KNN)) -> transaction_outcome(KNM, KNN)),
gleam@erlang@process:subject(nil)} |
{acquire_snapshot,
gleam@erlang@process:subject({ok,
trove@internal@snapshot:snapshot(KNM, KNN)} |
{error, binary()})} |
{compact, gleam@erlang@process:subject({ok, nil} | {error, binary()})} |
{size, gleam@erlang@process:subject(integer())} |
{dirt_factor, gleam@erlang@process:subject(float())} |
{sync_file, gleam@erlang@process:subject(nil)} |
{set_auto_compact, auto_compact(), gleam@erlang@process:subject(nil)} |
{register_keyspace,
binary(),
fun((bitstring(), bitstring()) -> gleam@order:order()),
gleam@erlang@process:subject(nil)} |
{list_keyspaces, gleam@erlang@process:subject(list(binary()))} |
{put_in,
binary(),
bitstring(),
bitstring(),
gleam@erlang@process:subject(nil)} |
{get_in,
binary(),
bitstring(),
gleam@erlang@process:subject({ok, bitstring()} | {error, nil})} |
{delete_in, binary(), bitstring(), gleam@erlang@process:subject(nil)} |
{has_key_in, binary(), bitstring(), gleam@erlang@process:subject(boolean())} |
{size_in, binary(), gleam@erlang@process:subject(integer())} |
{put_and_delete_multi_in,
binary(),
list({bitstring(), bitstring()}),
list(bitstring()),
gleam@erlang@process:subject(nil)} |
{close, gleam@erlang@process:subject(nil)}.
-type keyspace_state() :: {keyspace_state,
trove@internal@btree:btree(bitstring(), bitstring()),
fun((bitstring(), bitstring()) -> gleam@order:order())}.
-type state(KNO, KNP) :: {state,
trove@internal@btree:btree(KNO, KNP),
trove@internal@store:store(),
trove@codec:codec(KNO),
trove@codec:codec(KNP),
fun((KNO, KNO) -> gleam@order:order()),
file_sync(),
auto_compact(),
binary(),
integer(),
integer(),
gleam@dict:dict(binary(), keyspace_state())}.
-file("src/trove/internal/db.gleam", 124).
?DOC(false).
-spec unregistered_compare(binary()) -> fun((bitstring(), bitstring()) -> gleam@order:order()).
unregistered_compare(Name) ->
fun(_, _) -> erlang:error(#{gleam_error => panic,
message => (<<<<"keyspace '"/utf8, Name/binary>>/binary,
"' used before trove.keyspace(...) was called in this session"/utf8>>),
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"unregistered_compare"/utf8>>,
line => 126}) end.
-file("src/trove/internal/db.gleam", 136).
?DOC(false).
-spec store_path(binary(), integer()) -> binary().
store_path(Dir, File_number) ->
<<<<<<Dir/binary, "/"/utf8>>/binary,
(erlang:integer_to_binary(File_number))/binary>>/binary,
".trv"/utf8>>.
-file("src/trove/internal/db.gleam", 140).
?DOC(false).
-spec parse_trv_number(binary()) -> {ok, integer()} | {error, nil}.
parse_trv_number(Name) ->
gleam@bool:guard(
not gleam_stdlib:string_ends_with(Name, <<".trv"/utf8>>),
{error, nil},
fun() -> _pipe = Name,
_pipe@1 = gleam@string:drop_end(_pipe, 4),
gleam_stdlib:parse_int(_pipe@1) end
).
-file("src/trove/internal/db.gleam", 145).
?DOC(false).
-spec aggregate_counts(state(any(), any())) -> {integer(), integer()}.
aggregate_counts(State) ->
Default_size = trove@internal@btree:size(erlang:element(2, State)),
Default_dirt = trove@internal@btree:dirt(erlang:element(2, State)),
gleam@dict:fold(
erlang:element(12, State),
{Default_size, Default_dirt},
fun(Acc, _, Entry) ->
{erlang:element(1, Acc) + trove@internal@btree:size(
erlang:element(2, Entry)
),
erlang:element(2, Acc) + trove@internal@btree:dirt(
erlang:element(2, Entry)
)}
end
).
-file("src/trove/internal/db.gleam", 153).
?DOC(false).
-spec compute_dirt_factor(state(any(), any())) -> float().
compute_dirt_factor(State) ->
{Total_size, Total_dirt} = aggregate_counts(State),
case erlang:float((1 + Total_size) + Total_dirt) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(Total_dirt) / Gleam@denominator
end.
-file("src/trove/internal/db.gleam", 215).
?DOC(false).
-spec merge_compacted_keyspaces(
gleam@dict:dict(binary(), keyspace_state()),
list(trove@internal@compactor:compacted_keyspace())
) -> gleam@dict:dict(binary(), keyspace_state()).
merge_compacted_keyspaces(Old, Compacted) ->
gleam@list:fold(
Compacted,
maps:new(),
fun(Acc, Ks) ->
Byte_compare = case gleam_stdlib:map_get(Old, erlang:element(2, Ks)) of
{ok, Entry} ->
erlang:element(3, Entry);
{error, _} ->
unregistered_compare(erlang:element(2, Ks))
end,
gleam@dict:insert(
Acc,
erlang:element(2, Ks),
{keyspace_state, erlang:element(3, Ks), Byte_compare}
)
end
).
-file("src/trove/internal/db.gleam", 232).
?DOC(false).
-spec cleanup_old_store_files(binary(), integer()) -> nil.
cleanup_old_store_files(Path, Current_file_number) ->
case trove_file_ffi:list_dir(Path) of
{error, _} ->
nil;
{ok, Files} ->
Old_numbers = gleam@list:filter_map(
Files,
fun(Name) -> case parse_trv_number(Name) of
{ok, N} when N < Current_file_number ->
{ok, N};
_ ->
{error, nil}
end end
),
gleam@list:each(
Old_numbers,
fun(N@1) ->
Old_path = store_path(Path, N@1),
case trove_file_ffi:delete_file(Old_path) of
{ok, nil} ->
nil;
{error, Reason} ->
gleam_stdlib:println_error(
<<<<<<"[trove] failed to delete old store "/utf8,
Old_path/binary>>/binary,
": "/utf8>>/binary,
Reason/binary>>
)
end
end
)
end.
-file("src/trove/internal/db.gleam", 158).
?DOC(false).
-spec do_compact(state(KOA, KOB)) -> {ok, state(KOA, KOB)} |
{error, trove@internal@btree:error()}.
do_compact(State) ->
New_file_number = erlang:element(10, State) + 1,
New_path = store_path(erlang:element(9, State), New_file_number),
Old_path = store_path(erlang:element(9, State), erlang:element(10, State)),
_ = trove_file_ffi:delete_file(New_path),
Keyspaces_input = begin
_pipe = maps:to_list(erlang:element(12, State)),
gleam@list:map(
_pipe,
fun(Pair) ->
{Name, Entry} = Pair,
{keyspace_compaction,
Name,
erlang:element(2, Entry),
erlang:element(3, Entry)}
end
)
end,
gleam@result:'try'(
trove@internal@compactor:compact(
erlang:element(2, State),
Keyspaces_input,
erlang:element(3, State),
New_path,
trove@internal@btree:capacity(erlang:element(2, State)),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State)
),
fun(_use0) ->
{New_tree, New_keyspaces, New_store} = _use0,
gleam@result:'try'(
begin
_pipe@1 = trove_file_ffi:dir_fsync(erlang:element(9, State)),
gleam@result:map_error(
_pipe@1,
fun(S) -> {store_error, {io_error, S}} end
)
end,
fun(_) ->
case trove@internal@store:close(erlang:element(3, State)) of
{ok, nil} ->
nil;
{error, Reason} ->
gleam_stdlib:println_error(
<<"[trove] failed to close old store during compaction: "/utf8,
(trove@internal@store:error_to_string(
Reason
))/binary>>
)
end,
_ = trove_file_ffi:delete_file(Old_path),
cleanup_old_store_files(
erlang:element(9, State),
New_file_number
),
_ = trove_file_ffi:dir_fsync(erlang:element(9, State)),
{ok,
{state,
New_tree,
New_store,
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
erlang:element(9, State),
New_file_number,
erlang:element(11, State),
merge_compacted_keyspaces(
erlang:element(12, State),
New_keyspaces
)}}
end
)
end
).
-file("src/trove/internal/db.gleam", 260).
?DOC(false).
-spec maybe_auto_compact(state(KON, KOO)) -> state(KON, KOO).
maybe_auto_compact(State) ->
case erlang:element(8, State) of
no_auto_compact ->
State;
{auto_compact, Min_dirt, Min_dirt_factor} ->
{_, Total_dirt} = aggregate_counts(State),
Should_compact = (Total_dirt >= Min_dirt) andalso (compute_dirt_factor(
State
)
>= Min_dirt_factor),
gleam@bool:guard(
not Should_compact,
State,
fun() -> case do_compact(State) of
{ok, New_state} ->
New_state;
{error, Reason} ->
gleam_stdlib:println_error(
<<"[trove] auto-compact failed: "/utf8,
(trove@internal@btree:error_to_string(
Reason
))/binary>>
),
State
end end
)
end.
-file("src/trove/internal/db.gleam", 281).
?DOC(false).
-spec fold_inserts(
trove@internal@btree:btree(KOT, KOU),
list({KOT, KOU}),
state(KOT, KOU)
) -> trove@internal@btree:btree(KOT, KOU).
fold_inserts(Tree, Entries, State) ->
gleam@list:fold(
Entries,
Tree,
fun(Tree@1, Entry) ->
T@1 = case trove@internal@btree:insert(
Tree@1,
erlang:element(3, State),
erlang:element(1, Entry),
erlang:element(2, Entry),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State)
) of
{ok, T} -> T;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"fold_inserts"/utf8>>,
line => 287,
value => _assert_fail,
start => 8031,
'end' => 8283,
pattern_start => 8042,
pattern_end => 8047})
end,
T@1
end
).
-file("src/trove/internal/db.gleam", 301).
?DOC(false).
-spec fold_deletes(
trove@internal@btree:btree(KPC, KPD),
list(KPC),
state(KPC, KPD)
) -> trove@internal@btree:btree(KPC, KPD).
fold_deletes(Tree, Keys, State) ->
gleam@list:fold(
Keys,
Tree,
fun(Tree@1, Key) ->
T@1 = case trove@internal@btree:delete(
Tree@1,
erlang:element(3, State),
Key,
erlang:element(4, State),
erlang:element(6, State)
) of
{ok, T} -> T;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"fold_deletes"/utf8>>,
line => 307,
value => _assert_fail,
start => 8450,
'end' => 8634,
pattern_start => 8461,
pattern_end => 8466})
end,
T@1
end
).
-file("src/trove/internal/db.gleam", 346).
?DOC(false).
-spec tx_keyspaces(gleam@dict:dict(binary(), keyspace_state())) -> gleam@dict:dict(binary(), trove@internal@tx:keyspace_entry()).
tx_keyspaces(Keyspaces) ->
gleam@dict:map_values(
Keyspaces,
fun(_, Entry) ->
{keyspace_entry, erlang:element(2, Entry), erlang:element(3, Entry)}
end
).
-file("src/trove/internal/db.gleam", 381).
?DOC(false).
-spec merge_tx_keyspaces(
gleam@dict:dict(binary(), keyspace_state()),
gleam@dict:dict(binary(), trove@internal@tx:keyspace_entry())
) -> gleam@dict:dict(binary(), keyspace_state()).
merge_tx_keyspaces(Old, Updated) ->
gleam@dict:fold(
Updated,
Old,
fun(Acc, Name, Tx_entry) ->
gleam@dict:insert(
Acc,
Name,
{keyspace_state,
erlang:element(2, Tx_entry),
erlang:element(3, Tx_entry)}
)
end
).
-file("src/trove/internal/db.gleam", 409).
?DOC(false).
-spec keyspace_trees_match(
binary(),
keyspace_state(),
gleam@dict:dict(binary(), keyspace_state())
) -> boolean().
keyspace_trees_match(Name, Entry, Other) ->
case gleam_stdlib:map_get(Other, Name) of
{ok, Counterpart} ->
(trove@internal@btree:root(erlang:element(2, Entry)) =:= trove@internal@btree:root(
erlang:element(2, Counterpart)
))
andalso (trove@internal@btree:size(erlang:element(2, Entry)) =:= trove@internal@btree:size(
erlang:element(2, Counterpart)
));
{error, _} ->
false
end.
-file("src/trove/internal/db.gleam", 401).
?DOC(false).
-spec all_keyspaces_match(
gleam@dict:dict(binary(), keyspace_state()),
gleam@dict:dict(binary(), keyspace_state())
) -> boolean().
all_keyspaces_match(A, B) ->
_pipe = maps:to_list(A),
gleam@list:all(
_pipe,
fun(Pair) ->
keyspace_trees_match(
erlang:element(1, Pair),
erlang:element(2, Pair),
B
)
end
).
-file("src/trove/internal/db.gleam", 394).
?DOC(false).
-spec keyspaces_equal(
gleam@dict:dict(binary(), keyspace_state()),
gleam@dict:dict(binary(), keyspace_state())
) -> boolean().
keyspaces_equal(A, B) ->
(maps:size(A) =:= maps:size(B)) andalso all_keyspaces_match(A, B).
-file("src/trove/internal/db.gleam", 771).
?DOC(false).
-spec keyspace_views(gleam@dict:dict(binary(), keyspace_state())) -> gleam@dict:dict(binary(), trove@internal@snapshot:keyspace_view()).
keyspace_views(Keyspaces) ->
gleam@dict:map_values(
Keyspaces,
fun(_, Entry) ->
{keyspace_view, erlang:element(2, Entry), erlang:element(3, Entry)}
end
).
-file("src/trove/internal/db.gleam", 779).
?DOC(false).
-spec keyspace_headers(gleam@dict:dict(binary(), keyspace_state())) -> list(trove@internal@store:keyspace_header()).
keyspace_headers(Keyspaces) ->
_pipe = maps:to_list(Keyspaces),
_pipe@1 = gleam@list:sort(
_pipe,
fun(A, B) ->
gleam@string:compare(erlang:element(1, A), erlang:element(1, B))
end
),
gleam@list:map(
_pipe@1,
fun(Entry) ->
{Name, State} = Entry,
{keyspace_header,
Name,
trove@internal@btree:root(erlang:element(2, State)),
trove@internal@btree:size(erlang:element(2, State)),
trove@internal@btree:dirt(erlang:element(2, State))}
end
).
-file("src/trove/internal/db.gleam", 751).
?DOC(false).
-spec write_header(
trove@internal@store:store(),
trove@internal@btree:btree(any(), any()),
gleam@dict:dict(binary(), keyspace_state()),
file_sync()
) -> {ok, nil} | {error, trove@internal@store:error()}.
write_header(Store, Tree, Keyspaces, Auto_sync) ->
Header = {header,
trove@internal@btree:root(Tree),
trove@internal@btree:size(Tree),
trove@internal@btree:dirt(Tree),
keyspace_headers(Keyspaces)},
gleam@result:'try'(
trove@internal@store:put_header(Store, Header),
fun(_) -> case Auto_sync of
auto_sync ->
trove@internal@store:sync(Store);
manual_sync ->
{ok, nil}
end end
).
-file("src/trove/internal/db.gleam", 319).
?DOC(false).
-spec commit_tree(
state(KPL, KPM),
trove@internal@btree:btree(KPL, KPM),
gleam@erlang@process:subject(nil)
) -> gleam@otp@actor:next(state(KPL, KPM), message(KPL, KPM)).
commit_tree(State, New_tree, Reply) ->
case (trove@internal@btree:root(erlang:element(2, State)) =:= trove@internal@btree:root(
New_tree
))
andalso (trove@internal@btree:size(erlang:element(2, State)) =:= trove@internal@btree:size(
New_tree
)) of
true ->
gleam@otp@actor:send(Reply, nil),
gleam@otp@actor:continue(State);
false ->
case write_header(
erlang:element(3, State),
New_tree,
erlang:element(12, State),
erlang:element(7, State)
) of
{ok, nil} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"commit_tree"/utf8>>,
line => 333,
value => _assert_fail,
start => 9033,
'end' => 9187,
pattern_start => 9044,
pattern_end => 9051})
end,
gleam@otp@actor:send(Reply, nil),
gleam@otp@actor:continue(
maybe_auto_compact(
{state,
New_tree,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
erlang:element(12, State)}
)
)
end.
-file("src/trove/internal/db.gleam", 354).
?DOC(false).
-spec commit_transaction(
state(KQC, KQD),
trove@internal@btree:btree(KQC, KQD),
gleam@dict:dict(binary(), trove@internal@tx:keyspace_entry()),
gleam@erlang@process:subject(nil)
) -> gleam@otp@actor:next(state(KQC, KQD), message(KQC, KQD)).
commit_transaction(State, New_tree, New_other, Reply) ->
New_keyspaces = merge_tx_keyspaces(erlang:element(12, State), New_other),
case ((trove@internal@btree:root(erlang:element(2, State)) =:= trove@internal@btree:root(
New_tree
))
andalso (trove@internal@btree:size(erlang:element(2, State)) =:= trove@internal@btree:size(
New_tree
)))
andalso keyspaces_equal(erlang:element(12, State), New_keyspaces) of
true ->
gleam@otp@actor:send(Reply, nil),
gleam@otp@actor:continue(State);
false ->
case write_header(
erlang:element(3, State),
New_tree,
New_keyspaces,
erlang:element(7, State)
) of
{ok, nil} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"commit_transaction"/utf8>>,
line => 371,
value => _assert_fail,
start => 10100,
'end' => 10201,
pattern_start => 10111,
pattern_end => 10118})
end,
gleam@otp@actor:send(Reply, nil),
gleam@otp@actor:continue(
maybe_auto_compact(
{state,
New_tree,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
New_keyspaces}
)
)
end.
-file("src/trove/internal/db.gleam", 422).
?DOC(false).
-spec commit_keyspace_write(
state(KRH, KRI),
binary(),
keyspace_state(),
keyspace_state(),
gleam@erlang@process:subject(nil)
) -> gleam@otp@actor:next(state(KRH, KRI), message(KRH, KRI)).
commit_keyspace_write(State, Name, Old_entry, New_entry, Reply) ->
case (trove@internal@btree:root(erlang:element(2, Old_entry)) =:= trove@internal@btree:root(
erlang:element(2, New_entry)
))
andalso (trove@internal@btree:size(erlang:element(2, Old_entry)) =:= trove@internal@btree:size(
erlang:element(2, New_entry)
)) of
true ->
gleam@otp@actor:send(Reply, nil),
gleam@otp@actor:continue(State);
false ->
New_keyspaces = gleam@dict:insert(
erlang:element(12, State),
Name,
New_entry
),
case write_header(
erlang:element(3, State),
erlang:element(2, State),
New_keyspaces,
erlang:element(7, State)
) of
{ok, nil} -> nil;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"commit_keyspace_write"/utf8>>,
line => 439,
value => _assert_fail,
start => 11928,
'end' => 12082,
pattern_start => 11939,
pattern_end => 11946})
end,
gleam@otp@actor:send(Reply, nil),
gleam@otp@actor:continue(
maybe_auto_compact(
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
New_keyspaces}
)
)
end.
-file("src/trove/internal/db.gleam", 454).
?DOC(false).
-spec handle_message(state(KRS, KRT), message(KRS, KRT)) -> gleam@otp@actor:next(state(KRS, KRT), message(KRS, KRT)).
handle_message(State, Msg) ->
case Msg of
{get, Key, Reply} ->
Result@1 = case trove@internal@btree:lookup(
erlang:element(2, State),
erlang:element(3, State),
Key,
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State)
) of
{ok, Result} -> Result;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 460,
value => _assert_fail,
start => 12378,
'end' => 12629,
pattern_start => 12389,
pattern_end => 12399})
end,
gleam@otp@actor:send(Reply, gleam@option:to_result(Result@1, nil)),
gleam@otp@actor:continue(State);
{put, Key@1, Value, Reply@1} ->
New_tree@1 = case trove@internal@btree:insert(
erlang:element(2, State),
erlang:element(3, State),
Key@1,
Value,
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State)
) of
{ok, New_tree} -> New_tree;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 474,
value => _assert_fail@1,
start => 12758,
'end' => 13035,
pattern_start => 12769,
pattern_end => 12781})
end,
commit_tree(State, New_tree@1, Reply@1);
{delete, Key@2, Reply@2} ->
New_tree@3 = case trove@internal@btree:delete(
erlang:element(2, State),
erlang:element(3, State),
Key@2,
erlang:element(4, State),
erlang:element(6, State)
) of
{ok, New_tree@2} -> New_tree@2;
_assert_fail@2 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 488,
value => _assert_fail@2,
start => 13119,
'end' => 13330,
pattern_start => 13130,
pattern_end => 13142})
end,
commit_tree(State, New_tree@3, Reply@2);
{has_key, Key@3, Reply@3} ->
Result@3 = case trove@internal@btree:contains(
erlang:element(2, State),
erlang:element(3, State),
Key@3,
erlang:element(4, State),
erlang:element(6, State)
) of
{ok, Result@2} -> Result@2;
_assert_fail@3 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 500,
value => _assert_fail@3,
start => 13414,
'end' => 13625,
pattern_start => 13425,
pattern_end => 13435})
end,
gleam@otp@actor:send(Reply@3, Result@3),
gleam@otp@actor:continue(State);
{put_multi, Entries, Reply@4} ->
New_tree@4 = fold_inserts(erlang:element(2, State), Entries, State),
commit_tree(State, New_tree@4, Reply@4);
{delete_multi, Keys, Reply@5} ->
New_tree@5 = fold_deletes(erlang:element(2, State), Keys, State),
commit_tree(State, New_tree@5, Reply@5);
{put_and_delete_multi, Puts, Deletes, Reply@6} ->
New_tree@6 = begin
_pipe = fold_inserts(erlang:element(2, State), Puts, State),
fold_deletes(_pipe, Deletes, State)
end,
commit_tree(State, New_tree@6, Reply@6);
{execute_transaction, Run, Reply@7} ->
Offset_before@1 = case trove@internal@store:current_offset(
erlang:element(3, State)
) of
{ok, Offset_before} -> Offset_before;
_assert_fail@4 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 530,
value => _assert_fail@4,
start => 14231,
'end' => 14302,
pattern_start => 14242,
pattern_end => 14259})
end,
Transaction = trove@internal@tx:new(
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
tx_keyspaces(erlang:element(12, State))
),
case Run(Transaction) of
{commit_outcome, New_tree@7, New_other} ->
commit_transaction(State, New_tree@7, New_other, Reply@7);
cancel_outcome ->
Wasted = case trove@internal@store:current_offset(
erlang:element(3, State)
) of
{ok, Offset_after} ->
gleam@int:max(0, Offset_after - Offset_before@1);
{error, _} ->
0
end,
case Wasted > 0 of
true ->
Dirt_estimate = gleam@int:max(1, Wasted div 100),
New_tree@8 = trove@internal@btree:add_dirt(
erlang:element(2, State),
Dirt_estimate
),
case write_header(
erlang:element(3, State),
New_tree@8,
erlang:element(12, State),
erlang:element(7, State)
) of
{ok, nil} -> nil;
_assert_fail@5 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 553,
value => _assert_fail@5,
start => 15160,
'end' => 15362,
pattern_start => 15171,
pattern_end => 15178})
end,
New_state = {state,
New_tree@8,
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
erlang:element(12, State)},
gleam@otp@actor:send(Reply@7, nil),
gleam@otp@actor:continue(
maybe_auto_compact(New_state)
);
false ->
gleam@otp@actor:send(Reply@7, nil),
gleam@otp@actor:continue(State)
end
end;
{acquire_snapshot, Reply@8} ->
Snap_result = begin
_pipe@1 = trove@internal@store:open_reader(
erlang:element(3, State)
),
_pipe@2 = gleam@result:map(
_pipe@1,
fun(Reader) ->
trove@internal@snapshot:new(
erlang:element(2, State),
Reader,
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
keyspace_views(erlang:element(12, State))
)
end
),
gleam@result:map_error(
_pipe@2,
fun trove@internal@store:error_to_string/1
)
end,
gleam@otp@actor:send(Reply@8, Snap_result),
gleam@otp@actor:continue(State);
{compact, Reply@9} ->
case do_compact(State) of
{ok, Compacted} ->
gleam@otp@actor:send(Reply@9, {ok, nil}),
gleam@otp@actor:continue(Compacted);
{error, Reason} ->
gleam@otp@actor:send(
Reply@9,
{error, trove@internal@btree:error_to_string(Reason)}
),
gleam@otp@actor:continue(State)
end;
{size, Reply@10} ->
gleam@otp@actor:send(
Reply@10,
trove@internal@btree:size(erlang:element(2, State))
),
gleam@otp@actor:continue(State);
{dirt_factor, Reply@11} ->
gleam@otp@actor:send(Reply@11, compute_dirt_factor(State)),
gleam@otp@actor:continue(State);
{sync_file, Reply@12} ->
case trove@internal@store:sync(erlang:element(3, State)) of
{ok, nil} -> nil;
_assert_fail@6 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 615,
value => _assert_fail@6,
start => 16800,
'end' => 16851,
pattern_start => 16811,
pattern_end => 16818})
end,
gleam@otp@actor:send(Reply@12, nil),
gleam@otp@actor:continue(State);
{set_auto_compact, Setting, Reply@13} ->
gleam@otp@actor:send(Reply@13, nil),
gleam@otp@actor:continue(
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
Setting,
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
erlang:element(12, State)}
);
{register_keyspace, Name, Byte_compare, Reply@14} ->
Existing = begin
_pipe@3 = gleam_stdlib:map_get(erlang:element(12, State), Name),
gleam@result:unwrap(
_pipe@3,
{keyspace_state, trove@internal@btree:new(), Byte_compare}
)
end,
New_entry = {keyspace_state,
erlang:element(2, Existing),
Byte_compare},
New_keyspaces = gleam@dict:insert(
erlang:element(12, State),
Name,
New_entry
),
gleam@otp@actor:send(Reply@14, nil),
gleam@otp@actor:continue(
{state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
erlang:element(6, State),
erlang:element(7, State),
erlang:element(8, State),
erlang:element(9, State),
erlang:element(10, State),
erlang:element(11, State),
New_keyspaces}
);
{list_keyspaces, Reply@15} ->
Names = begin
_pipe@4 = maps:keys(erlang:element(12, State)),
gleam@list:sort(_pipe@4, fun gleam@string:compare/2)
end,
gleam@otp@actor:send(Reply@15, Names),
gleam@otp@actor:continue(State);
{put_in, Name@1, Key_bytes, Value_bytes, Reply@16} ->
Entry@1 = case gleam_stdlib:map_get(
erlang:element(12, State),
Name@1
) of
{ok, Entry} -> Entry;
_assert_fail@7 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 646,
value => _assert_fail@7,
start => 17776,
'end' => 17830,
pattern_start => 17787,
pattern_end => 17796})
end,
New_tree@10 = case trove@internal@btree:insert(
erlang:element(2, Entry@1),
erlang:element(3, State),
Key_bytes,
Value_bytes,
trove@codec:bit_array(),
trove@codec:bit_array(),
erlang:element(3, Entry@1)
) of
{ok, New_tree@9} -> New_tree@9;
_assert_fail@8 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 647,
value => _assert_fail@8,
start => 17837,
'end' => 18129,
pattern_start => 17848,
pattern_end => 17860})
end,
New_entry@1 = {keyspace_state,
New_tree@10,
erlang:element(3, Entry@1)},
commit_keyspace_write(State, Name@1, Entry@1, New_entry@1, Reply@16);
{get_in, Name@2, Key_bytes@1, Reply@17} ->
Entry@3 = case gleam_stdlib:map_get(
erlang:element(12, State),
Name@2
) of
{ok, Entry@2} -> Entry@2;
_assert_fail@9 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 662,
value => _assert_fail@9,
start => 18309,
'end' => 18363,
pattern_start => 18320,
pattern_end => 18329})
end,
Result@5 = case trove@internal@btree:lookup(
erlang:element(2, Entry@3),
erlang:element(3, State),
Key_bytes@1,
trove@codec:bit_array(),
trove@codec:bit_array(),
erlang:element(3, Entry@3)
) of
{ok, Result@4} -> Result@4;
_assert_fail@10 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 663,
value => _assert_fail@10,
start => 18370,
'end' => 18630,
pattern_start => 18381,
pattern_end => 18391})
end,
gleam@otp@actor:send(
Reply@17,
gleam@option:to_result(Result@5, nil)
),
gleam@otp@actor:continue(State);
{delete_in, Name@3, Key_bytes@2, Reply@18} ->
Entry@5 = case gleam_stdlib:map_get(
erlang:element(12, State),
Name@3
) of
{ok, Entry@4} -> Entry@4;
_assert_fail@11 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 677,
value => _assert_fail@11,
start => 18769,
'end' => 18823,
pattern_start => 18780,
pattern_end => 18789})
end,
New_tree@12 = case trove@internal@btree:delete(
erlang:element(2, Entry@5),
erlang:element(3, State),
Key_bytes@2,
trove@codec:bit_array(),
erlang:element(3, Entry@5)
) of
{ok, New_tree@11} -> New_tree@11;
_assert_fail@12 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 678,
value => _assert_fail@12,
start => 18830,
'end' => 19050,
pattern_start => 18841,
pattern_end => 18853})
end,
New_entry@2 = {keyspace_state,
New_tree@12,
erlang:element(3, Entry@5)},
commit_keyspace_write(State, Name@3, Entry@5, New_entry@2, Reply@18);
{has_key_in, Name@4, Key_bytes@3, Reply@19} ->
Entry@7 = case gleam_stdlib:map_get(
erlang:element(12, State),
Name@4
) of
{ok, Entry@6} -> Entry@6;
_assert_fail@13 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 691,
value => _assert_fail@13,
start => 19233,
'end' => 19287,
pattern_start => 19244,
pattern_end => 19253})
end,
Result@7 = case trove@internal@btree:contains(
erlang:element(2, Entry@7),
erlang:element(3, State),
Key_bytes@3,
trove@codec:bit_array(),
erlang:element(3, Entry@7)
) of
{ok, Result@6} -> Result@6;
_assert_fail@14 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 692,
value => _assert_fail@14,
start => 19294,
'end' => 19514,
pattern_start => 19305,
pattern_end => 19315})
end,
gleam@otp@actor:send(Reply@19, Result@7),
gleam@otp@actor:continue(State);
{size_in, Name@5, Reply@20} ->
Entry@9 = case gleam_stdlib:map_get(
erlang:element(12, State),
Name@5
) of
{ok, Entry@8} -> Entry@8;
_assert_fail@15 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 705,
value => _assert_fail@15,
start => 19617,
'end' => 19671,
pattern_start => 19628,
pattern_end => 19637})
end,
gleam@otp@actor:send(
Reply@20,
trove@internal@btree:size(erlang:element(2, Entry@9))
),
gleam@otp@actor:continue(State);
{put_and_delete_multi_in, Name@6, Puts@1, Deletes@1, Reply@21} ->
Entry@11 = case gleam_stdlib:map_get(
erlang:element(12, State),
Name@6
) of
{ok, Entry@10} -> Entry@10;
_assert_fail@16 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 711,
value => _assert_fail@16,
start => 19818,
'end' => 19872,
pattern_start => 19829,
pattern_end => 19838})
end,
Tree_with_puts = gleam@list:fold(
Puts@1,
erlang:element(2, Entry@11),
fun(Tree, Put) ->
T@1 = case trove@internal@btree:insert(
Tree,
erlang:element(3, State),
erlang:element(1, Put),
erlang:element(2, Put),
trove@codec:bit_array(),
trove@codec:bit_array(),
erlang:element(3, Entry@11)
) of
{ok, T} -> T;
_assert_fail@17 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 714,
value => _assert_fail@17,
start => 19962,
'end' => 20267,
pattern_start => 19973,
pattern_end => 19978})
end,
T@1
end
),
New_tree@13 = gleam@list:fold(
Deletes@1,
Tree_with_puts,
fun(Tree@1, Key@4) ->
T@3 = case trove@internal@btree:delete(
Tree@1,
erlang:element(3, State),
Key@4,
trove@codec:bit_array(),
erlang:element(3, Entry@11)
) of
{ok, T@2} -> T@2;
_assert_fail@18 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 728,
value => _assert_fail@18,
start => 20381,
'end' => 20610,
pattern_start => 20392,
pattern_end => 20397})
end,
T@3
end
),
New_entry@3 = {keyspace_state,
New_tree@13,
erlang:element(3, Entry@11)},
commit_keyspace_write(
State,
Name@6,
Entry@11,
New_entry@3,
Reply@21
);
{close, Reply@22} ->
case trove@internal@store:close(erlang:element(3, State)) of
{ok, nil} -> nil;
_assert_fail@19 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"trove/internal/db"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 743,
value => _assert_fail@19,
start => 20796,
'end' => 20848,
pattern_start => 20807,
pattern_end => 20814})
end,
_ = trove_file_ffi:unlock(erlang:element(9, State)),
gleam@otp@actor:send(Reply@22, nil),
gleam@otp@actor:stop()
end.
-file("src/trove/internal/db.gleam", 820).
?DOC(false).
-spec recover_keyspaces(list(trove@internal@store:keyspace_header())) -> {ok,
gleam@dict:dict(binary(), keyspace_state())} |
{error, trove@internal@btree:error()}.
recover_keyspaces(Entries) ->
gleam@list:try_fold(
Entries,
maps:new(),
fun(Acc, Entry) ->
gleam@result:'try'(
trove@internal@btree:from_header(
erlang:element(3, Entry),
erlang:element(4, Entry),
erlang:element(5, Entry),
32
),
fun(Tree) ->
{ok,
gleam@dict:insert(
Acc,
erlang:element(2, Entry),
{keyspace_state,
Tree,
unregistered_compare(erlang:element(2, Entry))}
)}
end
)
end
).
-file("src/trove/internal/db.gleam", 795).
?DOC(false).
-spec recover_state(trove@internal@store:store()) -> {ok,
{trove@internal@btree:btree(any(), any()),
gleam@dict:dict(binary(), keyspace_state())}} |
{error, trove@internal@btree:error()}.
recover_state(Store) ->
gleam@result:'try'(
begin
_pipe = trove@internal@store:blank(Store),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {store_error, Field@0} end
)
end,
fun(Is_blank) -> case Is_blank of
true ->
{ok, {trove@internal@btree:new(), maps:new()}};
false ->
gleam@result:'try'(
begin
_pipe@1 = trove@internal@store:get_latest_header(
Store
),
gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {store_error, Field@0} end
)
end,
fun(Header) ->
gleam@result:'try'(
trove@internal@btree:from_header(
erlang:element(2, Header),
erlang:element(3, Header),
erlang:element(4, Header),
32
),
fun(Tree) ->
gleam@result:'try'(
recover_keyspaces(
erlang:element(5, Header)
),
fun(Keyspaces) ->
{ok, {Tree, Keyspaces}}
end
)
end
)
end
)
end end
).
-file("src/trove/internal/db.gleam", 983).
?DOC(false).
-spec validate_tree_deep(trove@internal@store:store(), bitstring()) -> boolean().
validate_tree_deep(Store, Tree_data) ->
case trove@internal@btree@node:extract_locations(Tree_data) of
{error, _} ->
false;
{ok, Locations} ->
gleam@list:all(
Locations,
fun(Loc) -> case trove@internal@store:get_node(Store, Loc) of
{ok, Child_data} ->
case {trove@internal@btree@node:is_leaf(Tree_data),
trove@internal@btree@node:node_kind(Child_data)} of
{true, {ok, data_kind}} ->
true;
{false, {ok, tree_kind}} ->
trove@internal@btree@node:validate_structure(
Child_data
)
andalso validate_tree_deep(
Store,
Child_data
);
{_, _} ->
false
end;
{error, _} ->
false
end end
)
end.
-file("src/trove/internal/db.gleam", 962).
?DOC(false).
-spec validate_tree_header(
trove@internal@store:store(),
gleam@option:option(integer()),
integer(),
integer()
) -> boolean().
validate_tree_header(Store, Root, Size, Dirt) ->
case trove@internal@btree:from_header(Root, Size, Dirt, 32) of
{error, _} ->
false;
{ok, _} ->
case Root of
none ->
true;
{some, Offset} ->
case trove@internal@store:get_node(Store, Offset) of
{ok, Data} ->
trove@internal@btree@node:validate_structure(Data)
andalso validate_tree_deep(Store, Data);
{error, _} ->
false
end
end
end.
-file("src/trove/internal/db.gleam", 955).
?DOC(false).
-spec validate_root_readable(
trove@internal@store:store(),
trove@internal@store:header()
) -> boolean().
validate_root_readable(Store, Header) ->
validate_tree_header(
Store,
erlang:element(2, Header),
erlang:element(3, Header),
erlang:element(4, Header)
)
andalso gleam@list:all(
erlang:element(5, Header),
fun(Ks) ->
validate_tree_header(
Store,
erlang:element(3, Ks),
erlang:element(4, Ks),
erlang:element(5, Ks)
)
end
).
-file("src/trove/internal/db.gleam", 933).
?DOC(false).
-spec validate_store_file(binary(), boolean()) -> {ok, boolean()} |
{error, binary()}.
validate_store_file(File_path, Has_fallback) ->
case trove@internal@store:open(File_path) of
{error, Reason} ->
{error, trove@internal@store:error_to_string(Reason)};
{ok, Store} ->
Valid = case trove@internal@store:blank(Store) of
{ok, true} ->
not Has_fallback;
{ok, false} ->
case trove@internal@store:get_latest_header(Store) of
{ok, Header} ->
validate_root_readable(Store, Header);
{error, _} ->
false
end;
{error, _} ->
false
end,
_ = trove@internal@store:close(Store),
{ok, Valid}
end.
-file("src/trove/internal/db.gleam", 1008).
?DOC(false).
-spec find_valid_store_number(binary(), list(integer())) -> {ok, integer()} |
{error, binary()}.
find_valid_store_number(Path, Candidates) ->
case Candidates of
[] ->
{ok, 0};
[N] ->
File_path = store_path(Path, N),
case validate_store_file(File_path, false) of
{ok, true} ->
{ok, N};
{ok, false} ->
{error,
<<<<"store file "/utf8, File_path/binary>>/binary,
" is corrupt and no valid fallback exists"/utf8>>};
{error, Reason} ->
{error,
<<<<<<"unable to validate store "/utf8,
File_path/binary>>/binary,
": "/utf8>>/binary,
Reason/binary>>}
end;
[N@1 | Rest] ->
File_path@1 = store_path(Path, N@1),
case validate_store_file(File_path@1, true) of
{ok, true} ->
Older@1 = case Rest of
[_ | Older] ->
Older;
[] ->
[]
end,
gleam@list:each(
Older@1,
fun(Old_n) ->
Old_path = store_path(Path, Old_n),
case trove_file_ffi:delete_file(Old_path) of
{ok, nil} ->
nil;
{error, Reason@1} ->
gleam_stdlib:println_error(
<<<<<<"[trove] failed to delete old store "/utf8,
Old_path/binary>>/binary,
": "/utf8>>/binary,
Reason@1/binary>>
)
end
end
),
{ok, N@1};
{ok, false} ->
_ = trove_file_ffi:delete_file(File_path@1),
find_valid_store_number(Path, Rest);
{error, Reason@2} ->
gleam_stdlib:println_error(
<<<<<<"[trove] unable to validate store "/utf8,
File_path@1/binary>>/binary,
", trying fallback: "/utf8>>/binary,
Reason@2/binary>>
),
_ = trove_file_ffi:delete_file(File_path@1),
find_valid_store_number(Path, Rest)
end
end.
-file("src/trove/internal/db.gleam", 925).
?DOC(false).
-spec find_highest_store_number(binary()) -> {ok, integer()} | {error, binary()}.
find_highest_store_number(Path) ->
gleam@result:'try'(
trove_file_ffi:list_dir(Path),
fun(Files) ->
Numbers = begin
_pipe = gleam@list:filter_map(Files, fun parse_trv_number/1),
gleam@list:sort(_pipe, fun(A, B) -> gleam@int:compare(B, A) end)
end,
find_valid_store_number(Path, Numbers)
end
).
-file("src/trove/internal/db.gleam", 1071).
?DOC(false).
-spec get(gleam@erlang@process:subject(message(KTX, KTY)), KTX, integer()) -> {ok,
KTY} |
{error, nil}.
get(Subject, Key, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {get, Key, _capture} end
).
-file("src/trove/internal/db.gleam", 1079).
?DOC(false).
-spec put(gleam@erlang@process:subject(message(KUE, KUF)), KUE, KUF, integer()) -> nil.
put(Subject, Key, Value, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {put, Key, Value, _capture} end
).
-file("src/trove/internal/db.gleam", 1088).
?DOC(false).
-spec delete(gleam@erlang@process:subject(message(KUJ, any())), KUJ, integer()) -> nil.
delete(Subject, Key, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {delete, Key, _capture} end
).
-file("src/trove/internal/db.gleam", 1096).
?DOC(false).
-spec has_key(gleam@erlang@process:subject(message(KUO, any())), KUO, integer()) -> boolean().
has_key(Subject, Key, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {has_key, Key, _capture} end
).
-file("src/trove/internal/db.gleam", 1104).
?DOC(false).
-spec put_multi(
gleam@erlang@process:subject(message(KUT, KUU)),
list({KUT, KUU}),
integer()
) -> nil.
put_multi(Subject, Entries, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {put_multi, Entries, _capture} end
).
-file("src/trove/internal/db.gleam", 1112).
?DOC(false).
-spec delete_multi(
gleam@erlang@process:subject(message(KUZ, any())),
list(KUZ),
integer()
) -> nil.
delete_multi(Subject, Keys, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {delete_multi, Keys, _capture} end
).
-file("src/trove/internal/db.gleam", 1120).
?DOC(false).
-spec put_and_delete_multi(
gleam@erlang@process:subject(message(KVF, KVG)),
list({KVF, KVG}),
list(KVF),
integer()
) -> nil.
put_and_delete_multi(Subject, Puts, Deletes, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {put_and_delete_multi, Puts, Deletes, _capture} end
).
-file("src/trove/internal/db.gleam", 1133).
?DOC(false).
-spec transaction(
gleam@erlang@process:subject(message(KVM, KVN)),
integer(),
fun((trove@internal@tx:tx(KVM, KVN)) -> transaction_outcome(KVM, KVN))
) -> nil.
transaction(Subject, Timeout, Run) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {execute_transaction, Run, _capture} end
).
-file("src/trove/internal/db.gleam", 1141).
?DOC(false).
-spec acquire_snapshot(
gleam@erlang@process:subject(message(KVV, KVW)),
integer()
) -> {ok, trove@internal@snapshot:snapshot(KVV, KVW)} | {error, binary()}.
acquire_snapshot(Subject, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(Field@0) -> {acquire_snapshot, Field@0} end
).
-file("src/trove/internal/db.gleam", 1148).
?DOC(false).
-spec compact(gleam@erlang@process:subject(message(any(), any())), integer()) -> {ok,
nil} |
{error, binary()}.
compact(Subject, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(Field@0) -> {compact, Field@0} end
).
-file("src/trove/internal/db.gleam", 1155).
?DOC(false).
-spec size(gleam@erlang@process:subject(message(any(), any())), integer()) -> integer().
size(Subject, Timeout) ->
gleam@otp@actor:call(Subject, Timeout, fun(Field@0) -> {size, Field@0} end).
-file("src/trove/internal/db.gleam", 1162).
?DOC(false).
-spec dirt_factor(
gleam@erlang@process:subject(message(any(), any())),
integer()
) -> float().
dirt_factor(Subject, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(Field@0) -> {dirt_factor, Field@0} end
).
-file("src/trove/internal/db.gleam", 1169).
?DOC(false).
-spec file_sync(gleam@erlang@process:subject(message(any(), any())), integer()) -> nil.
file_sync(Subject, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(Field@0) -> {sync_file, Field@0} end
).
-file("src/trove/internal/db.gleam", 1176).
?DOC(false).
-spec set_auto_compact(
gleam@erlang@process:subject(message(any(), any())),
auto_compact(),
integer()
) -> nil.
set_auto_compact(Subject, Setting, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {set_auto_compact, Setting, _capture} end
).
-file("src/trove/internal/db.gleam", 1184).
?DOC(false).
-spec register_keyspace(
gleam@erlang@process:subject(message(any(), any())),
binary(),
fun((bitstring(), bitstring()) -> gleam@order:order()),
integer()
) -> nil.
register_keyspace(Subject, Name, Byte_compare, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {register_keyspace, Name, Byte_compare, _capture} end
).
-file("src/trove/internal/db.gleam", 1197).
?DOC(false).
-spec list_keyspaces(
gleam@erlang@process:subject(message(any(), any())),
integer()
) -> list(binary()).
list_keyspaces(Subject, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(Field@0) -> {list_keyspaces, Field@0} end
).
-file("src/trove/internal/db.gleam", 1204).
?DOC(false).
-spec put_in(
gleam@erlang@process:subject(message(any(), any())),
binary(),
bitstring(),
bitstring(),
integer()
) -> nil.
put_in(Subject, Name, Key_bytes, Value_bytes, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {put_in, Name, Key_bytes, Value_bytes, _capture} end
).
-file("src/trove/internal/db.gleam", 1219).
?DOC(false).
-spec get_in(
gleam@erlang@process:subject(message(any(), any())),
binary(),
bitstring(),
integer()
) -> {ok, bitstring()} | {error, nil}.
get_in(Subject, Name, Key_bytes, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {get_in, Name, Key_bytes, _capture} end
).
-file("src/trove/internal/db.gleam", 1228).
?DOC(false).
-spec delete_in(
gleam@erlang@process:subject(message(any(), any())),
binary(),
bitstring(),
integer()
) -> nil.
delete_in(Subject, Name, Key_bytes, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {delete_in, Name, Key_bytes, _capture} end
).
-file("src/trove/internal/db.gleam", 1237).
?DOC(false).
-spec has_key_in(
gleam@erlang@process:subject(message(any(), any())),
binary(),
bitstring(),
integer()
) -> boolean().
has_key_in(Subject, Name, Key_bytes, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {has_key_in, Name, Key_bytes, _capture} end
).
-file("src/trove/internal/db.gleam", 1246).
?DOC(false).
-spec size_in(
gleam@erlang@process:subject(message(any(), any())),
binary(),
integer()
) -> integer().
size_in(Subject, Name, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) -> {size_in, Name, _capture} end
).
-file("src/trove/internal/db.gleam", 1254).
?DOC(false).
-spec put_and_delete_multi_in(
gleam@erlang@process:subject(message(any(), any())),
binary(),
list({bitstring(), bitstring()}),
list(bitstring()),
integer()
) -> nil.
put_and_delete_multi_in(Subject, Name, Puts, Deletes, Timeout) ->
gleam@otp@actor:call(
Subject,
Timeout,
fun(_capture) ->
{put_and_delete_multi_in, Name, Puts, Deletes, _capture}
end
).
-file("src/trove/internal/db.gleam", 1269).
?DOC(false).
-spec close(gleam@erlang@process:subject(message(any(), any())), integer()) -> nil.
close(Subject, Timeout) ->
gleam@otp@actor:call(Subject, Timeout, fun(Field@0) -> {close, Field@0} end).
-file("src/trove/internal/db.gleam", 838).
?DOC(false).
-spec open(
binary(),
trove@codec:codec(KTG),
trove@codec:codec(KTI),
fun((KTG, KTG) -> gleam@order:order()),
file_sync(),
auto_compact(),
integer()
) -> {ok, gleam@erlang@process:subject(message(KTG, KTI))} |
{error, open_error()}.
open(
Path,
Key_codec,
Value_codec,
Key_compare,
Auto_file_sync,
Auto_compact,
Call_timeout
) ->
gleam@result:'try'(
begin
_pipe = trove_file_ffi:mkdir_p(Path),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {directory_error, Field@0} end
)
end,
fun(_) ->
Start_result = begin
_pipe@8 = gleam@otp@actor:new_with_initialiser(
Call_timeout,
fun(Subject) ->
gleam@result:'try'(
begin
_pipe@1 = trove_file_ffi:try_lock(Path),
gleam@result:map_error(
_pipe@1,
fun(Reason) ->
<<"lock:"/utf8, Reason/binary>>
end
)
end,
fun(_) ->
gleam@result:'try'(
begin
_pipe@2 = find_highest_store_number(
Path
),
gleam@result:map_error(
_pipe@2,
fun(Reason@1) ->
_ = trove_file_ffi:unlock(Path),
<<"failed to find store: "/utf8,
Reason@1/binary>>
end
)
end,
fun(File_number) ->
File_path = store_path(
Path,
File_number
),
gleam@result:'try'(
begin
_pipe@3 = trove@internal@store:open(
File_path
),
gleam@result:map_error(
_pipe@3,
fun(E) ->
_ = trove_file_ffi:unlock(
Path
),
<<"failed to open store: "/utf8,
(trove@internal@store:error_to_string(
E
))/binary>>
end
)
end,
fun(Store) ->
gleam@result:'try'(
begin
_pipe@4 = trove_file_ffi:dir_fsync(
Path
),
gleam@result:map_error(
_pipe@4,
fun(Reason@2) ->
_ = trove@internal@store:close(
Store
),
_ = trove_file_ffi:unlock(
Path
),
<<"failed to fsync directory: "/utf8,
Reason@2/binary>>
end
)
end,
fun(_) ->
gleam@result:'try'(
begin
_pipe@5 = recover_state(
Store
),
gleam@result:map_error(
_pipe@5,
fun(E@1) ->
_ = trove@internal@store:close(
Store
),
_ = trove_file_ffi:unlock(
Path
),
<<"failed to recover tree: "/utf8,
(trove@internal@btree:error_to_string(
E@1
))/binary>>
end
)
end,
fun(_use0) ->
{Tree,
Keyspaces} = _use0,
State = {state,
Tree,
Store,
Key_codec,
Value_codec,
Key_compare,
Auto_file_sync,
Auto_compact,
Path,
File_number,
Call_timeout,
Keyspaces},
_pipe@6 = gleam@otp@actor:initialised(
State
),
_pipe@7 = gleam@otp@actor:returning(
_pipe@6,
Subject
),
{ok, _pipe@7}
end
)
end
)
end
)
end
)
end
)
end
),
_pipe@9 = gleam@otp@actor:on_message(
_pipe@8,
fun handle_message/2
),
gleam@otp@actor:start(_pipe@9)
end,
case Start_result of
{ok, Started} ->
{ok, erlang:element(3, Started)};
{error, {init_failed, Reason@3}} ->
case gleam_stdlib:string_starts_with(
Reason@3,
<<"lock:"/utf8>>
) of
true ->
{error,
{lock_error,
gleam@string:drop_start(
Reason@3,
string:length(<<"lock:"/utf8>>)
)}};
false ->
{error, {store_error, Reason@3}}
end;
{error, init_timeout} ->
{error, actor_start_error};
{error, {init_exited, _}} ->
{error, actor_start_error}
end
end
).