feat(lts): inherit previous generation's lts when possible
This commit is contained in:
parent
75b08b525b
commit
db710c4be5
|
@ -18,7 +18,12 @@
|
||||||
|
|
||||||
%% API:
|
%% API:
|
||||||
-export([
|
-export([
|
||||||
trie_create/1, trie_create/0, trie_restore/2, topic_key/3, match_topics/2, lookup_topic_key/2
|
trie_create/1, trie_create/0,
|
||||||
|
trie_restore/2,
|
||||||
|
trie_restore_existing/2,
|
||||||
|
topic_key/3,
|
||||||
|
match_topics/2,
|
||||||
|
lookup_topic_key/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% Debug:
|
%% Debug:
|
||||||
|
@ -115,6 +120,10 @@ trie_create() ->
|
||||||
-spec trie_restore(options(), [{_Key, _Val}]) -> trie().
|
-spec trie_restore(options(), [{_Key, _Val}]) -> trie().
|
||||||
trie_restore(Options, Dump) ->
|
trie_restore(Options, Dump) ->
|
||||||
Trie = trie_create(Options),
|
Trie = trie_create(Options),
|
||||||
|
trie_restore_existing(Trie, Dump).
|
||||||
|
|
||||||
|
-spec trie_restore_existing(trie(), [{_Key, _Val}]) -> trie().
|
||||||
|
trie_restore_existing(Trie, Dump) ->
|
||||||
lists:foreach(
|
lists:foreach(
|
||||||
fun({{StateFrom, Token}, StateTo}) ->
|
fun({{StateFrom, Token}, StateTo}) ->
|
||||||
trie_insert(Trie, StateFrom, Token, StateTo)
|
trie_insert(Trie, StateFrom, Token, StateTo)
|
||||||
|
|
|
@ -32,7 +32,8 @@
|
||||||
get_streams/4,
|
get_streams/4,
|
||||||
make_iterator/5,
|
make_iterator/5,
|
||||||
update_iterator/4,
|
update_iterator/4,
|
||||||
next/4
|
next/4,
|
||||||
|
post_creation_actions/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% internal exports:
|
%% internal exports:
|
||||||
|
@ -200,6 +201,22 @@ open(_Shard, DBHandle, GenId, CFRefs, Schema) ->
|
||||||
ts_offset = TSOffsetBits
|
ts_offset = TSOffsetBits
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
-spec post_creation_actions(emqx_ds_storage_layer:post_creation_context()) ->
|
||||||
|
s().
|
||||||
|
post_creation_actions(
|
||||||
|
#{
|
||||||
|
db := DBHandle,
|
||||||
|
old_gen_id := OldGenId,
|
||||||
|
old_cf_refs := OldCFRefs,
|
||||||
|
new_gen_runtime_data := NewGenData0
|
||||||
|
}
|
||||||
|
) ->
|
||||||
|
{_, OldTrieCF} = lists:keyfind(trie_cf(OldGenId), 1, OldCFRefs),
|
||||||
|
#s{trie = NewTrie0} = NewGenData0,
|
||||||
|
NewTrie = copy_previous_trie(DBHandle, NewTrie0, OldTrieCF),
|
||||||
|
?tp(bitfield_lts_inherited_trie, #{}),
|
||||||
|
NewGenData0#s{trie = NewTrie}.
|
||||||
|
|
||||||
-spec drop(
|
-spec drop(
|
||||||
emqx_ds_storage_layer:shard_id(),
|
emqx_ds_storage_layer:shard_id(),
|
||||||
rocksdb:db_handle(),
|
rocksdb:db_handle(),
|
||||||
|
@ -516,6 +533,17 @@ restore_trie(TopicIndexBytes, DB, CF) ->
|
||||||
rocksdb:iterator_close(IT)
|
rocksdb:iterator_close(IT)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec copy_previous_trie(rocksdb:db_handle(), emqx_ds_lts:trie(), rocksdb:cf_handle()) ->
|
||||||
|
emqx_ds_lts:trie().
|
||||||
|
copy_previous_trie(DBHandle, NewTrie, OldCF) ->
|
||||||
|
{ok, IT} = rocksdb:iterator(DBHandle, OldCF, []),
|
||||||
|
try
|
||||||
|
OldDump = read_persisted_trie(IT, rocksdb:iterator_move(IT, first)),
|
||||||
|
emqx_ds_lts:trie_restore_existing(NewTrie, OldDump)
|
||||||
|
after
|
||||||
|
rocksdb:iterator_close(IT)
|
||||||
|
end.
|
||||||
|
|
||||||
read_persisted_trie(IT, {ok, KeyB, ValB}) ->
|
read_persisted_trie(IT, {ok, KeyB, ValB}) ->
|
||||||
[
|
[
|
||||||
{binary_to_term(KeyB), binary_to_term(ValB)}
|
{binary_to_term(KeyB), binary_to_term(ValB)}
|
||||||
|
|
|
@ -131,6 +131,39 @@ t_get_streams(_Config) ->
|
||||||
?assert(lists:member(A, AllStreams)),
|
?assert(lists:member(A, AllStreams)),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
t_new_generation_inherit_trie(_Config) ->
|
||||||
|
%% This test checks that we inherit the previous generation's LTS when creating a new
|
||||||
|
%% generation.
|
||||||
|
?check_trace(
|
||||||
|
begin
|
||||||
|
%% Create a bunch of topics to be learned in the first generation
|
||||||
|
Timestamps = lists:seq(1, 10_000, 100),
|
||||||
|
Batch = [
|
||||||
|
begin
|
||||||
|
B = integer_to_binary(I),
|
||||||
|
make_message(
|
||||||
|
TS,
|
||||||
|
<<"wildcard/", B/binary, "/suffix/", Suffix/binary>>,
|
||||||
|
integer_to_binary(TS)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|| I <- lists:seq(1, 200),
|
||||||
|
TS <- Timestamps,
|
||||||
|
Suffix <- [<<"foo">>, <<"bar">>]
|
||||||
|
],
|
||||||
|
ok = emqx_ds_storage_layer:store_batch(?SHARD, Batch, []),
|
||||||
|
%% Now we create a new generation with the same LTS module. It should inherit the
|
||||||
|
%% learned trie.
|
||||||
|
ok = emqx_ds_storage_layer:add_generation(?SHARD),
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
fun(Trace) ->
|
||||||
|
?assertMatch([_], ?of_kind(bitfield_lts_inherited_trie, Trace)),
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
),
|
||||||
|
ok.
|
||||||
|
|
||||||
t_replay(_Config) ->
|
t_replay(_Config) ->
|
||||||
%% Create concrete topics:
|
%% Create concrete topics:
|
||||||
Topics = [<<"foo/bar">>, <<"foo/bar/baz">>],
|
Topics = [<<"foo/bar">>, <<"foo/bar/baz">>],
|
||||||
|
|
Loading…
Reference in New Issue