-
Notifications
You must be signed in to change notification settings - Fork 428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simple MAM queries with complete result flag #3734
Changes from all commits
0c12a6d
6a5ac9b
cbe491d
22b77f0
f6ae3c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,7 +80,6 @@ | |
calculate_msg_id_borders/3, | ||
calculate_msg_id_borders/4, | ||
maybe_encode_compact_uuid/2, | ||
is_complete_result_page/4, | ||
wait_shaper/4, | ||
check_for_item_not_found/3]). | ||
|
||
|
@@ -90,7 +89,8 @@ | |
is_jid_in_user_roster/3]). | ||
|
||
%% Shared logic | ||
-export([check_result_for_policy_violation/2]). | ||
-export([check_result_for_policy_violation/2, | ||
lookup/3]). | ||
|
||
-callback extra_fin_element(mongooseim:host_type(), | ||
mam_iq:lookup_params(), | ||
|
@@ -1039,14 +1039,15 @@ maybe_previous_id(X) -> | |
%% It's the most efficient way to query archive, if the client side does | ||
%% not care about the total number of messages and if it's stateless | ||
%% (i.e. web interface). | ||
-spec is_complete_result_page(TotalCount, Offset, MessageRows, Params) -> | ||
%% Handles case when we have TotalCount and Offset as integers | ||
-spec is_complete_result_page_using_offset(Params, Result) -> | ||
boolean() when | ||
TotalCount :: non_neg_integer()|undefined, | ||
Offset :: non_neg_integer()|undefined, | ||
MessageRows :: list(), | ||
Params :: mam_iq:lookup_params(). | ||
is_complete_result_page(TotalCount, Offset, MessageRows, | ||
#{page_size := PageSize} = Params) -> | ||
Params :: mam_iq:lookup_params(), | ||
Result :: mod_mam:lookup_result_map(). | ||
is_complete_result_page_using_offset(#{page_size := PageSize} = Params, | ||
#{total_count := TotalCount, offset := Offset, | ||
messages := MessageRows}) | ||
when is_integer(TotalCount), is_integer(Offset) -> | ||
case maps:get(ordering_direction, Params, forward) of | ||
forward -> | ||
is_most_recent_page(PageSize, TotalCount, Offset, MessageRows); | ||
|
@@ -1155,19 +1156,75 @@ is_policy_violation(TotalCount, Offset, MaxResultLimit, LimitPassed) -> | |
LookupResult :: mod_mam:lookup_result(), | ||
R :: {ok, mod_mam:lookup_result()} | {error, item_not_found}. | ||
check_for_item_not_found(#rsm_in{direction = before, id = ID}, | ||
PageSize, {TotalCount, Offset, MessageRows}) -> | ||
_PageSize, {TotalCount, Offset, MessageRows}) -> | ||
case maybe_last(MessageRows) of | ||
{ok, #{id := ID}} = _IntervalEndpoint -> | ||
Page = lists:sublist(MessageRows, PageSize), | ||
{ok, {TotalCount, Offset, Page}}; | ||
{ok, #{id := ID}} -> | ||
{ok, {TotalCount, Offset, list_without_last(MessageRows)}}; | ||
undefined -> | ||
{error, item_not_found} | ||
end; | ||
check_for_item_not_found(#rsm_in{direction = aft, id = ID}, | ||
_PageSize, {TotalCount, Offset, MessageRows0}) -> | ||
case MessageRows0 of | ||
[#{id := ID} = _IntervalEndpoint | MessageRows] -> | ||
[#{id := ID} | MessageRows] -> | ||
{ok, {TotalCount, Offset, MessageRows}}; | ||
_ -> | ||
{error, item_not_found} | ||
end. | ||
|
||
-spec lookup(HostType :: mongooseim:host_type(), | ||
Params :: mam_iq:lookup_params(), | ||
F :: fun()) -> | ||
{ok, mod_mam:lookup_result_map()} | {error, Reason :: term()}. | ||
lookup(HostType, Params, F) -> | ||
F1 = patch_fun_to_make_result_as_map(F), | ||
process_lookup_with_complete_check(HostType, Params, F1). | ||
|
||
process_lookup_with_complete_check(HostType, Params = #{is_simple := true}, F) -> | ||
process_simple_lookup_with_complete_check(HostType, Params, F); | ||
process_lookup_with_complete_check(HostType, Params, F) -> | ||
case F(HostType, Params) of | ||
{ok, Result} -> | ||
IsComplete = is_complete_result_page_using_offset(Params, Result), | ||
{ok, Result#{is_complete => IsComplete}}; | ||
Other -> | ||
Other | ||
end. | ||
|
||
patch_fun_to_make_result_as_map(F) -> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh god, this is patching extreme dynamic typing 😱 anyway, for future major refactorings. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I knew you will love it! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I imagined 😱 |
||
fun(HostType, Params) -> result_to_map(F(HostType, Params)) end. | ||
|
||
result_to_map({ok, {TotalCount, Offset, MessageRows}}) -> | ||
{ok, #{total_count => TotalCount, offset => Offset, messages => MessageRows}}; | ||
result_to_map(Other) -> | ||
Other. | ||
|
||
%% We query an extra message by changing page_size. | ||
%% After that we remove this message from the result set when returning. | ||
process_simple_lookup_with_complete_check(HostType, Params = #{page_size := PageSize}, F) -> | ||
Params2 = Params#{page_size => PageSize + 1}, | ||
case F(HostType, Params2) of | ||
{ok, Result} -> | ||
{ok, set_complete_result_page_using_extra_message(PageSize, Params, Result)}; | ||
Other -> | ||
Other | ||
end. | ||
|
||
set_complete_result_page_using_extra_message(PageSize, Params, Result = #{messages := MessageRows}) -> | ||
case length(MessageRows) =:= (PageSize + 1) of | ||
true -> | ||
Result#{is_complete => false, messages => remove_extra_message(Params, MessageRows)}; | ||
false -> | ||
Result#{is_complete => true} | ||
end. | ||
|
||
remove_extra_message(Params, Messages) -> | ||
case maps:get(ordering_direction, Params, forward) of | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be pattern-matched on the function clause, it'll be even faster (see maps performance guide if curious). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, in case key exists - yea There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And in the case it does not, a second catch-all clause just throws the default. |
||
forward -> | ||
list_without_last(Messages); | ||
backward -> | ||
tl(Messages) | ||
end. | ||
|
||
list_without_last(List) -> | ||
lists:reverse(tl(lists:reverse(List))). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this parameter is not needed it can be removed, maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of course xd
Remained for compat/lazy.
Will get refactored with the tuple. And we probably wanna pass Params, instead of just RSM.