fix(ds): Move responsibility of returning end_of_stream to the CBM

This commit is contained in:
ieQu1 2024-05-19 23:12:46 +02:00
parent 0ff307e789
commit 60edf5e9b8
No known key found for this signature in database
GPG Key ID: 488654DF3FED6FDE
3 changed files with 41 additions and 24 deletions

View File

@ -35,7 +35,7 @@
make_iterator/5, make_iterator/5,
make_delete_iterator/5, make_delete_iterator/5,
update_iterator/4, update_iterator/4,
next/5, next/6,
delete_next/6, delete_next/6,
post_creation_actions/1, post_creation_actions/1,
@ -424,23 +424,21 @@ next(
Schema = #s{ts_offset = TSOffset, ts_bits = TSBits}, Schema = #s{ts_offset = TSOffset, ts_bits = TSBits},
It = #{?storage_key := Stream}, It = #{?storage_key := Stream},
BatchSize, BatchSize,
Now Now,
IsCurrent
) -> ) ->
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
%% complete epoch ends, so we need to know the current time to %% complete epoch ends, so we need to know the current time to
%% compute it. This is needed because new keys can be added before %% compute it. This is needed because new keys can be added before
%% the iterator. %% the iterator.
IsWildcard = %%
%% This is needed to avoid situations when the iterator advances
%% to position k1, and then a new message with k2, such that k2 <
%% k1 is inserted. k2 would be missed.
HasCutoff =
case Stream of case Stream of
{_StaticKey, []} -> false; {_StaticKey, []} ->
_ -> true
end,
SafeCutoffTime =
case IsWildcard of
true ->
(Now bsr TSOffset) bsl TSOffset;
false ->
%% Iterators scanning streams without varying topic %% Iterators scanning streams without varying topic
%% levels can operate on incomplete epochs, since new %% levels can operate on incomplete epochs, since new
%% matching keys for the single topic are added in %% matching keys for the single topic are added in
@ -450,10 +448,27 @@ next(
%% filters operating on streams with varying parts: %% filters operating on streams with varying parts:
%% iterator can jump to the next topic and then it %% iterator can jump to the next topic and then it
%% won't backtrack. %% won't backtrack.
false;
_ ->
%% New batches are only added to the current
%% generation. We can ignore cutoff time for old
%% generations:
IsCurrent
end,
SafeCutoffTime =
case HasCutoff of
true ->
(Now bsr TSOffset) bsl TSOffset;
false ->
1 bsl TSBits - 1 1 bsl TSBits - 1
end, end,
try try
next_until(Schema, It, SafeCutoffTime, BatchSize) case next_until(Schema, It, SafeCutoffTime, BatchSize) of
{ok, _, []} when not IsCurrent ->
{ok, end_of_stream};
Result ->
Result
end
after after
report_counters(Shard) report_counters(Shard)
end. end.

View File

@ -248,8 +248,8 @@
) -> ) ->
emqx_ds:make_delete_iterator_result(_Iterator). emqx_ds:make_delete_iterator_result(_Iterator).
-callback next(shard_id(), _Data, Iter, pos_integer(), emqx_ds:time()) -> -callback next(shard_id(), _Data, Iter, pos_integer(), emqx_ds:time(), _IsCurrent :: boolean()) ->
{ok, Iter, [emqx_types:message()]} | {error, _}. {ok, Iter, [emqx_types:message()]} | {ok, end_of_stream} | {error, _}.
-callback delete_next( -callback delete_next(
shard_id(), _Data, DeleteIterator, emqx_ds:delete_selector(), pos_integer(), emqx_ds:time() shard_id(), _Data, DeleteIterator, emqx_ds:delete_selector(), pos_integer(), emqx_ds:time()
@ -449,15 +449,12 @@ update_iterator(
next(Shard, Iter = #{?tag := ?IT, ?generation := GenId, ?enc := GenIter0}, BatchSize, Now) -> 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), IsCurrent = GenId =:= generation_current(Shard),
case Mod:next(Shard, GenData, GenIter0, BatchSize, Now) of case Mod:next(Shard, GenData, GenIter0, BatchSize, Now, IsCurrent) of
{ok, _GenIter, []} when GenId < Current ->
%% This is a past generation. Storage layer won't write
%% any more messages here. The iterator reached the end:
%% the stream has been fully replayed.
{ok, end_of_stream};
{ok, GenIter, Batch} -> {ok, GenIter, Batch} ->
{ok, Iter#{?enc := GenIter}, Batch}; {ok, Iter#{?enc := GenIter}, Batch};
{ok, end_of_stream} ->
{ok, end_of_stream};
Error = {error, _, _} -> Error = {error, _, _} ->
Error Error
end; end;

View File

@ -38,7 +38,7 @@
make_iterator/5, make_iterator/5,
make_delete_iterator/5, make_delete_iterator/5,
update_iterator/4, update_iterator/4,
next/5, next/6,
delete_next/6 delete_next/6
]). ]).
@ -148,7 +148,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, _Now) -> next(_Shard, #s{db = DB, cf = CF}, It0, BatchSize, _Now, IsCurrent) ->
#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 =
@ -162,7 +162,12 @@ next(_Shard, #s{db = DB, cf = CF}, It0, BatchSize, _Now) ->
{Key, Messages} = do_next(TopicFilter, StartTime, ITHandle, Action, BatchSize, Key0, []), {Key, Messages} = do_next(TopicFilter, StartTime, ITHandle, Action, BatchSize, Key0, []),
rocksdb:iterator_close(ITHandle), rocksdb:iterator_close(ITHandle),
It = It0#it{last_seen_message_key = Key}, It = It0#it{last_seen_message_key = Key},
{ok, It, lists:reverse(Messages)}. case Messages of
[] when not IsCurrent ->
{ok, end_of_stream};
_ ->
{ok, It, lists:reverse(Messages)}
end.
delete_next(_Shard, #s{db = DB, cf = CF}, It0, Selector, BatchSize, _Now) -> delete_next(_Shard, #s{db = DB, cf = CF}, It0, Selector, BatchSize, _Now) ->
#delete_it{ #delete_it{