feat(ds): Pass current time to the storage layer via argument

This commit is contained in:
ieQu1 2024-04-23 02:36:33 +02:00
parent 8ac9700aab
commit 1ff2e02fd9
No known key found for this signature in database
GPG Key ID: 488654DF3FED6FDE
6 changed files with 61 additions and 34 deletions

View File

@ -491,7 +491,7 @@ do_next_v1(DB, Shard, Iter, BatchSize) ->
ShardId = {DB, Shard}, ShardId = {DB, Shard},
?IF_STORAGE_RUNNING( ?IF_STORAGE_RUNNING(
ShardId, ShardId,
emqx_ds_storage_layer:next(ShardId, Iter, BatchSize) emqx_ds_storage_layer:next(ShardId, Iter, BatchSize, emqx_ds:timestamp_us())
). ).
-spec do_delete_next_v4( -spec do_delete_next_v4(
@ -503,7 +503,9 @@ do_next_v1(DB, Shard, Iter, BatchSize) ->
) -> ) ->
emqx_ds:delete_next_result(emqx_ds_storage_layer:delete_iterator()). emqx_ds:delete_next_result(emqx_ds_storage_layer:delete_iterator()).
do_delete_next_v4(DB, Shard, Iter, Selector, BatchSize) -> do_delete_next_v4(DB, Shard, Iter, Selector, BatchSize) ->
emqx_ds_storage_layer:delete_next({DB, Shard}, Iter, Selector, BatchSize). emqx_ds_storage_layer:delete_next(
{DB, Shard}, Iter, Selector, BatchSize, emqx_ds:timestamp_us()
).
-spec do_add_generation_v2(emqx_ds:db()) -> no_return(). -spec do_add_generation_v2(emqx_ds:db()) -> no_return().
do_add_generation_v2(_DB) -> do_add_generation_v2(_DB) ->

View File

@ -34,8 +34,8 @@
make_iterator/5, make_iterator/5,
make_delete_iterator/5, make_delete_iterator/5,
update_iterator/4, update_iterator/4,
next/4, next/5,
delete_next/5, delete_next/6,
post_creation_actions/1 post_creation_actions/1
]). ]).
@ -354,8 +354,9 @@ update_iterator(
next( next(
Shard, Shard,
Schema = #s{ts_offset = TSOffset, ts_bits = TSBits}, Schema = #s{ts_offset = TSOffset, ts_bits = TSBits},
It = #{?topic_filter := TF, ?storage_key := Stream}, It = #{?storage_key := Stream},
BatchSize BatchSize,
Now
) -> ) ->
init_counters(), init_counters(),
%% Compute safe cutoff time. It's the point in time where the last %% Compute safe cutoff time. It's the point in time where the last
@ -370,7 +371,6 @@ next(
SafeCutoffTime = SafeCutoffTime =
case IsWildcard of case IsWildcard of
true -> true ->
Now = emqx_ds:timestamp_us(),
(Now bsr TSOffset) bsl TSOffset; (Now bsr TSOffset) bsl TSOffset;
false -> false ->
%% Iterators scanning streams without varying topic %% Iterators scanning streams without varying topic
@ -415,12 +415,11 @@ next_until(#s{db = DB, data = CF, keymappers = Keymappers}, It, SafeCutoffTime,
rocksdb:iterator_close(ITHandle) rocksdb:iterator_close(ITHandle)
end. end.
delete_next(Shard, Schema = #s{ts_offset = TSOffset}, It, Selector, BatchSize) -> delete_next(Shard, Schema = #s{ts_offset = TSOffset}, It, Selector, BatchSize, Now) ->
%% Compute safe cutoff time. %% Compute safe cutoff time.
%% It's the point in time where the last complete epoch ends, so we need to know %% It's the point in time where the last complete epoch ends, so we need to know
%% the current time to compute it. %% the current time to compute it.
init_counters(), init_counters(),
Now = emqx_message:timestamp_now(),
SafeCutoffTime = (Now bsr TSOffset) bsl TSOffset, SafeCutoffTime = (Now bsr TSOffset) bsl TSOffset,
try try
delete_next_until(Schema, It, SafeCutoffTime, Selector, BatchSize) delete_next_until(Schema, It, SafeCutoffTime, Selector, BatchSize)

View File

@ -31,8 +31,8 @@
make_iterator/4, make_iterator/4,
make_delete_iterator/4, make_delete_iterator/4,
update_iterator/3, update_iterator/3,
next/3, next/4,
delete_next/4, delete_next/5,
%% Generations %% Generations
update_config/3, update_config/3,
@ -223,9 +223,14 @@
) -> ) ->
emqx_ds:make_delete_iterator_result(_Iterator). emqx_ds:make_delete_iterator_result(_Iterator).
-callback next(shard_id(), _Data, Iter, pos_integer()) -> -callback next(shard_id(), _Data, Iter, pos_integer(), emqx_ds:time()) ->
{ok, Iter, [emqx_types:message()]} | {error, _}. {ok, Iter, [emqx_types:message()]} | {error, _}.
-callback delete_next(
shard_id(), _Data, DeleteIterator, emqx_ds:delete_selector(), pos_integer(), emqx_ds:time()
) ->
{ok, DeleteIterator, _NDeleted :: non_neg_integer(), _IteratedOver :: non_neg_integer()}.
-callback post_creation_actions(post_creation_context()) -> _Data. -callback post_creation_actions(post_creation_context()) -> _Data.
-optional_callbacks([post_creation_actions/1]). -optional_callbacks([post_creation_actions/1]).
@ -377,13 +382,13 @@ update_iterator(
{error, unrecoverable, generation_not_found} {error, unrecoverable, generation_not_found}
end. end.
-spec next(shard_id(), iterator(), pos_integer()) -> -spec next(shard_id(), iterator(), pos_integer(), emqx_ds:time()) ->
emqx_ds:next_result(iterator()). emqx_ds:next_result(iterator()).
next(Shard, Iter = #{?tag := ?IT, ?generation := GenId, ?enc := GenIter0}, BatchSize) -> next(Shard, Iter = #{?tag := ?IT, ?generation := GenId, ?enc := GenIter0}, BatchSize, Now) ->
case generation_get(Shard, GenId) of case generation_get(Shard, GenId) of
#{module := Mod, data := GenData} -> #{module := Mod, data := GenData} ->
Current = generation_current(Shard), Current = generation_current(Shard),
case Mod:next(Shard, GenData, GenIter0, BatchSize) of case Mod:next(Shard, GenData, GenIter0, BatchSize, Now) of
{ok, _GenIter, []} when GenId < Current -> {ok, _GenIter, []} when GenId < Current ->
%% This is a past generation. Storage layer won't write %% This is a past generation. Storage layer won't write
%% any more messages here. The iterator reached the end: %% any more messages here. The iterator reached the end:
@ -399,18 +404,21 @@ next(Shard, Iter = #{?tag := ?IT, ?generation := GenId, ?enc := GenIter0}, Batch
{error, unrecoverable, generation_not_found} {error, unrecoverable, generation_not_found}
end. end.
-spec delete_next(shard_id(), delete_iterator(), emqx_ds:delete_selector(), pos_integer()) -> -spec delete_next(
shard_id(), delete_iterator(), emqx_ds:delete_selector(), pos_integer(), emqx_ds:time()
) ->
emqx_ds:delete_next_result(delete_iterator()). emqx_ds:delete_next_result(delete_iterator()).
delete_next( delete_next(
Shard, Shard,
Iter = #{?tag := ?DELETE_IT, ?generation := GenId, ?enc := GenIter0}, Iter = #{?tag := ?DELETE_IT, ?generation := GenId, ?enc := GenIter0},
Selector, Selector,
BatchSize BatchSize,
Now
) -> ) ->
case generation_get(Shard, GenId) of case generation_get(Shard, GenId) of
#{module := Mod, data := GenData} -> #{module := Mod, data := GenData} ->
Current = generation_current(Shard), Current = generation_current(Shard),
case Mod:delete_next(Shard, GenData, GenIter0, Selector, BatchSize) of case Mod:delete_next(Shard, GenData, GenIter0, Selector, BatchSize, Now) of
{ok, _GenIter, _Deleted = 0, _IteratedOver = 0} when GenId < Current -> {ok, _GenIter, _Deleted = 0, _IteratedOver = 0} when GenId < Current ->
%% This is a past generation. Storage layer won't write %% This is a past generation. Storage layer won't write
%% any more messages here. The iterator reached the end: %% any more messages here. The iterator reached the end:

View File

@ -37,8 +37,8 @@
make_iterator/5, make_iterator/5,
make_delete_iterator/5, make_delete_iterator/5,
update_iterator/4, update_iterator/4,
next/4, next/5,
delete_next/5 delete_next/6
]). ]).
%% internal exports: %% internal exports:
@ -154,7 +154,7 @@ update_iterator(_Shard, _Data, OldIter, DSKey) ->
last_seen_message_key = DSKey last_seen_message_key = DSKey
}}. }}.
next(_Shard, #s{db = DB, cf = CF}, It0, BatchSize) -> next(_Shard, #s{db = DB, cf = CF}, It0, BatchSize, _Now) ->
#it{topic_filter = TopicFilter, start_time = StartTime, last_seen_message_key = Key0} = It0, #it{topic_filter = TopicFilter, start_time = StartTime, last_seen_message_key = Key0} = It0,
{ok, ITHandle} = rocksdb:iterator(DB, CF, []), {ok, ITHandle} = rocksdb:iterator(DB, CF, []),
Action = Action =
@ -170,7 +170,7 @@ next(_Shard, #s{db = DB, cf = CF}, It0, BatchSize) ->
It = It0#it{last_seen_message_key = Key}, It = It0#it{last_seen_message_key = Key},
{ok, It, lists:reverse(Messages)}. {ok, It, lists:reverse(Messages)}.
delete_next(_Shard, #s{db = DB, cf = CF}, It0, Selector, BatchSize) -> delete_next(_Shard, #s{db = DB, cf = CF}, It0, Selector, BatchSize, _Now) ->
#delete_it{ #delete_it{
topic_filter = TopicFilter, topic_filter = TopicFilter,
start_time = StartTime, start_time = StartTime,

View File

@ -73,13 +73,15 @@ t_iterate(_Config) ->
begin begin
[{_Rank, Stream}] = emqx_ds_storage_layer:get_streams(?SHARD, parse_topic(Topic), 0), [{_Rank, Stream}] = emqx_ds_storage_layer:get_streams(?SHARD, parse_topic(Topic), 0),
{ok, It} = emqx_ds_storage_layer:make_iterator(?SHARD, Stream, parse_topic(Topic), 0), {ok, It} = emqx_ds_storage_layer:make_iterator(?SHARD, Stream, parse_topic(Topic), 0),
{ok, NextIt, MessagesAndKeys} = emqx_ds_storage_layer:next(?SHARD, It, 100), {ok, NextIt, MessagesAndKeys} = emqx_ds_storage_layer:next(
?SHARD, It, 100, emqx_ds:timestamp_us()
),
Messages = [Msg || {_DSKey, Msg} <- MessagesAndKeys], Messages = [Msg || {_DSKey, Msg} <- MessagesAndKeys],
?assertEqual( ?assertEqual(
lists:map(fun integer_to_binary/1, Timestamps), lists:map(fun integer_to_binary/1, Timestamps),
payloads(Messages) payloads(Messages)
), ),
{ok, _, []} = emqx_ds_storage_layer:next(?SHARD, NextIt, 100) {ok, _, []} = emqx_ds_storage_layer:next(?SHARD, NextIt, 100, emqx_ds:timestamp_us())
end end
|| Topic <- Topics || Topic <- Topics
], ],
@ -370,7 +372,7 @@ dump_stream(Shard, Stream, TopicFilter, StartTime) ->
F(It, 0) -> F(It, 0) ->
error({too_many_iterations, It}); error({too_many_iterations, It});
F(It, N) -> F(It, N) ->
case emqx_ds_storage_layer:next(Shard, It, BatchSize) of case emqx_ds_storage_layer:next(Shard, It, BatchSize, emqx_ds:timestamp_us()) of
end_of_stream -> end_of_stream ->
[]; [];
{ok, _NextIt, []} -> {ok, _NextIt, []} ->
@ -542,7 +544,11 @@ delete(_Shard, [], _Selector) ->
delete(Shard, Iterators, Selector) -> delete(Shard, Iterators, Selector) ->
{NewIterators0, N} = lists:foldl( {NewIterators0, N} = lists:foldl(
fun(Iterator0, {AccIterators, NAcc}) -> fun(Iterator0, {AccIterators, NAcc}) ->
case emqx_ds_storage_layer:delete_next(Shard, Iterator0, Selector, 10) of case
emqx_ds_storage_layer:delete_next(
Shard, Iterator0, Selector, 10, emqx_ds:timestamp_us()
)
of
{ok, end_of_stream} -> {ok, end_of_stream} ->
{AccIterators, NAcc}; {AccIterators, NAcc};
{ok, _Iterator1, 0} -> {ok, _Iterator1, 0} ->
@ -573,7 +579,7 @@ replay(_Shard, []) ->
replay(Shard, Iterators) -> replay(Shard, Iterators) ->
{NewIterators0, Messages0} = lists:foldl( {NewIterators0, Messages0} = lists:foldl(
fun(Iterator0, {AccIterators, AccMessages}) -> fun(Iterator0, {AccIterators, AccMessages}) ->
case emqx_ds_storage_layer:next(Shard, Iterator0, 10) of case emqx_ds_storage_layer:next(Shard, Iterator0, 10, emqx_ds:timestamp_us()) of
{ok, end_of_stream} -> {ok, end_of_stream} ->
{AccIterators, AccMessages}; {AccIterators, AccMessages};
{ok, _Iterator1, []} -> {ok, _Iterator1, []} ->

View File

@ -85,8 +85,14 @@ consume_stream(DB, Stream, TopicFilter, StartTime) ->
consume_iter(DB, It) -> consume_iter(DB, It) ->
consume_iter(DB, It, #{}). consume_iter(DB, It, #{}).
consume_iter(DB, It, Opts) -> consume_iter(DB, It0, Opts) ->
consume_iter_with(fun emqx_ds:next/3, [DB], It, Opts). consume_iter_with(
fun(It, BatchSize) ->
emqx_ds:next(DB, It, BatchSize)
end,
It0,
Opts
).
storage_consume(ShardId, TopicFilter) -> storage_consume(ShardId, TopicFilter) ->
storage_consume(ShardId, TopicFilter, 0). storage_consume(ShardId, TopicFilter, 0).
@ -108,16 +114,22 @@ storage_consume_stream(ShardId, Stream, TopicFilter, StartTime) ->
storage_consume_iter(ShardId, It) -> storage_consume_iter(ShardId, It) ->
storage_consume_iter(ShardId, It, #{}). storage_consume_iter(ShardId, It, #{}).
storage_consume_iter(ShardId, It, Opts) -> storage_consume_iter(ShardId, It0, Opts) ->
consume_iter_with(fun emqx_ds_storage_layer:next/3, [ShardId], It, Opts). consume_iter_with(
fun(It, BatchSize) ->
emqx_ds_storage_layer:next(ShardId, It, BatchSize, emqx_ds:timestamp_us())
end,
It0,
Opts
).
consume_iter_with(NextFun, Args, It0, Opts) -> consume_iter_with(NextFun, It0, Opts) ->
BatchSize = maps:get(batch_size, Opts, 5), BatchSize = maps:get(batch_size, Opts, 5),
case erlang:apply(NextFun, Args ++ [It0, BatchSize]) of case NextFun(It0, BatchSize) of
{ok, It, _Msgs = []} -> {ok, It, _Msgs = []} ->
{ok, It, []}; {ok, It, []};
{ok, It1, Batch} -> {ok, It1, Batch} ->
{ok, It, Msgs} = consume_iter_with(NextFun, Args, It1, Opts), {ok, It, Msgs} = consume_iter_with(NextFun, It1, Opts),
{ok, It, [Msg || {_DSKey, Msg} <- Batch] ++ Msgs}; {ok, It, [Msg || {_DSKey, Msg} <- Batch] ++ Msgs};
{ok, Eos = end_of_stream} -> {ok, Eos = end_of_stream} ->
{ok, Eos, []}; {ok, Eos, []};