fix(ft): respect checksum in `fin` packets
This commit is contained in:
parent
036f180c27
commit
0293b54211
|
@ -45,8 +45,8 @@ define(Term, _) ->
|
||||||
Term.
|
Term.
|
||||||
|
|
||||||
%% @doc Apply a function to a maybe argument.
|
%% @doc Apply a function to a maybe argument.
|
||||||
-spec apply(fun((A) -> maybe(A)), maybe(A)) ->
|
-spec apply(fun((A) -> B), maybe(A)) ->
|
||||||
maybe(A).
|
maybe(B).
|
||||||
apply(_Fun, undefined) ->
|
apply(_Fun, undefined) ->
|
||||||
undefined;
|
undefined;
|
||||||
apply(Fun, Term) when is_function(Fun) ->
|
apply(Fun, Term) when is_function(Fun) ->
|
||||||
|
|
|
@ -45,7 +45,8 @@
|
||||||
offset/0,
|
offset/0,
|
||||||
filemeta/0,
|
filemeta/0,
|
||||||
segment/0,
|
segment/0,
|
||||||
checksum/0
|
checksum/0,
|
||||||
|
finopts/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% Number of bytes
|
%% Number of bytes
|
||||||
|
@ -80,6 +81,10 @@
|
||||||
|
|
||||||
-type segment() :: {offset(), _Content :: binary()}.
|
-type segment() :: {offset(), _Content :: binary()}.
|
||||||
|
|
||||||
|
-type finopts() :: #{
|
||||||
|
checksum => checksum()
|
||||||
|
}.
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% API for app
|
%% API for app
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -170,8 +175,8 @@ on_file_command(PacketId, FileId, Msg, FileCommand) ->
|
||||||
ChecksumBin = emqx_maybe:from_list(MaybeChecksum),
|
ChecksumBin = emqx_maybe:from_list(MaybeChecksum),
|
||||||
validate(
|
validate(
|
||||||
[{size, FinalSizeBin}, {{maybe, checksum}, ChecksumBin}],
|
[{size, FinalSizeBin}, {{maybe, checksum}, ChecksumBin}],
|
||||||
fun([FinalSize, Checksum]) ->
|
fun([FinalSize, FinalChecksum]) ->
|
||||||
on_fin(PacketId, Msg, Transfer, FinalSize, Checksum)
|
on_fin(PacketId, Msg, Transfer, FinalSize, FinalChecksum)
|
||||||
end
|
end
|
||||||
);
|
);
|
||||||
[<<"abort">>] ->
|
[<<"abort">>] ->
|
||||||
|
@ -251,13 +256,13 @@ on_segment(PacketId, Msg, Transfer, Offset, Checksum) ->
|
||||||
end
|
end
|
||||||
end).
|
end).
|
||||||
|
|
||||||
on_fin(PacketId, Msg, Transfer, FinalSize, Checksum) ->
|
on_fin(PacketId, Msg, Transfer, FinalSize, FinalChecksum) ->
|
||||||
?tp(info, "file_transfer_fin", #{
|
?tp(info, "file_transfer_fin", #{
|
||||||
mqtt_msg => Msg,
|
mqtt_msg => Msg,
|
||||||
packet_id => PacketId,
|
packet_id => PacketId,
|
||||||
transfer => Transfer,
|
transfer => Transfer,
|
||||||
final_size => FinalSize,
|
final_size => FinalSize,
|
||||||
checksum => Checksum
|
checksum => FinalChecksum
|
||||||
}),
|
}),
|
||||||
%% TODO: handle checksum? Do we need it?
|
%% TODO: handle checksum? Do we need it?
|
||||||
FinPacketKey = {self(), PacketId},
|
FinPacketKey = {self(), PacketId},
|
||||||
|
@ -265,7 +270,7 @@ on_fin(PacketId, Msg, Transfer, FinalSize, Checksum) ->
|
||||||
?MODULE:on_complete("assemble", FinPacketKey, Transfer, Result)
|
?MODULE:on_complete("assemble", FinPacketKey, Transfer, Result)
|
||||||
end,
|
end,
|
||||||
with_responder(FinPacketKey, Callback, emqx_ft_conf:assemble_timeout(), fun() ->
|
with_responder(FinPacketKey, Callback, emqx_ft_conf:assemble_timeout(), fun() ->
|
||||||
case assemble(Transfer, FinalSize) of
|
case assemble(Transfer, FinalSize, FinalChecksum) of
|
||||||
%% Assembling completed, ack through the responder right away
|
%% Assembling completed, ack through the responder right away
|
||||||
ok ->
|
ok ->
|
||||||
emqx_ft_responder:ack(FinPacketKey, ok);
|
emqx_ft_responder:ack(FinPacketKey, ok);
|
||||||
|
@ -314,9 +319,10 @@ store_segment(Transfer, Segment) ->
|
||||||
{error, {internal_error, E}}
|
{error, {internal_error, E}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
assemble(Transfer, FinalSize) ->
|
assemble(Transfer, FinalSize, FinalChecksum) ->
|
||||||
try
|
try
|
||||||
emqx_ft_storage:assemble(Transfer, FinalSize)
|
FinOpts = [{checksum, FinalChecksum} || FinalChecksum /= undefined],
|
||||||
|
emqx_ft_storage:assemble(Transfer, FinalSize, maps:from_list(FinOpts))
|
||||||
catch
|
catch
|
||||||
C:E:S ->
|
C:E:S ->
|
||||||
?tp(error, "start_assemble_failed", #{
|
?tp(error, "start_assemble_failed", #{
|
||||||
|
@ -397,8 +403,8 @@ do_validate([{checksum, Checksum} | Rest], Parsed) ->
|
||||||
{error, _Reason} ->
|
{error, _Reason} ->
|
||||||
{error, {invalid_checksum, Checksum}}
|
{error, {invalid_checksum, Checksum}}
|
||||||
end;
|
end;
|
||||||
do_validate([{integrity, Payload, Checksum} | Rest], Parsed) ->
|
do_validate([{integrity, Payload, {Algo, Checksum}} | Rest], Parsed) ->
|
||||||
case crypto:hash(sha256, Payload) of
|
case crypto:hash(Algo, Payload) of
|
||||||
Checksum ->
|
Checksum ->
|
||||||
do_validate(Rest, [Payload | Parsed]);
|
do_validate(Rest, [Payload | Parsed]);
|
||||||
Mismatch ->
|
Mismatch ->
|
||||||
|
@ -411,7 +417,7 @@ do_validate([{{maybe, T}, Value} | Rest], Parsed) ->
|
||||||
|
|
||||||
parse_checksum(Checksum) when is_binary(Checksum) andalso byte_size(Checksum) =:= 64 ->
|
parse_checksum(Checksum) when is_binary(Checksum) andalso byte_size(Checksum) =:= 64 ->
|
||||||
try
|
try
|
||||||
{ok, binary:decode_hex(Checksum)}
|
{ok, {sha256, binary:decode_hex(Checksum)}}
|
||||||
catch
|
catch
|
||||||
error:badarg ->
|
error:badarg ->
|
||||||
{error, invalid_checksum}
|
{error, invalid_checksum}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
-module(emqx_ft_assembler).
|
-module(emqx_ft_assembler).
|
||||||
|
|
||||||
-export([start_link/3]).
|
-export([start_link/4]).
|
||||||
|
|
||||||
-behaviour(gen_statem).
|
-behaviour(gen_statem).
|
||||||
-export([callback_mode/0]).
|
-export([callback_mode/0]).
|
||||||
|
@ -29,6 +29,7 @@
|
||||||
-type stdata() :: #{
|
-type stdata() :: #{
|
||||||
storage := emqx_ft_storage_fs:storage(),
|
storage := emqx_ft_storage_fs:storage(),
|
||||||
transfer := emqx_ft:transfer(),
|
transfer := emqx_ft:transfer(),
|
||||||
|
finopts := emqx_ft:finopts(),
|
||||||
assembly := emqx_ft_assembly:t(),
|
assembly := emqx_ft_assembly:t(),
|
||||||
export => emqx_ft_storage_exporter:export()
|
export => emqx_ft_storage_exporter:export()
|
||||||
}.
|
}.
|
||||||
|
@ -38,8 +39,8 @@
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
start_link(Storage, Transfer, Size) ->
|
start_link(Storage, Transfer, Size, Opts) ->
|
||||||
gen_statem:start_link(?REF(Transfer), ?MODULE, {Storage, Transfer, Size}, []).
|
gen_statem:start_link(?REF(Transfer), ?MODULE, {Storage, Transfer, Size, Opts}, []).
|
||||||
|
|
||||||
where(Transfer) ->
|
where(Transfer) ->
|
||||||
gproc:where(?NAME(Transfer)).
|
gproc:where(?NAME(Transfer)).
|
||||||
|
@ -60,11 +61,12 @@ callback_mode() ->
|
||||||
handle_event_function.
|
handle_event_function.
|
||||||
|
|
||||||
-spec init(_Args) -> {ok, state(), stdata()}.
|
-spec init(_Args) -> {ok, state(), stdata()}.
|
||||||
init({Storage, Transfer, Size}) ->
|
init({Storage, Transfer, Size, Opts}) ->
|
||||||
_ = erlang:process_flag(trap_exit, true),
|
_ = erlang:process_flag(trap_exit, true),
|
||||||
St = #{
|
St = #{
|
||||||
storage => Storage,
|
storage => Storage,
|
||||||
transfer => Transfer,
|
transfer => Transfer,
|
||||||
|
finopts => Opts,
|
||||||
assembly => emqx_ft_assembly:new(Size)
|
assembly => emqx_ft_assembly:new(Size)
|
||||||
},
|
},
|
||||||
{ok, idle, St}.
|
{ok, idle, St}.
|
||||||
|
@ -164,8 +166,8 @@ handle_event(internal, _, {assemble, [{Node, Segment} | Rest]}, St = #{export :=
|
||||||
end;
|
end;
|
||||||
handle_event(internal, _, {assemble, []}, St = #{}) ->
|
handle_event(internal, _, {assemble, []}, St = #{}) ->
|
||||||
{next_state, complete, St, ?internal([])};
|
{next_state, complete, St, ?internal([])};
|
||||||
handle_event(internal, _, complete, St = #{export := Export}) ->
|
handle_event(internal, _, complete, St = #{export := Export, finopts := Opts}) ->
|
||||||
Result = emqx_ft_storage_exporter:complete(Export),
|
Result = emqx_ft_storage_exporter:complete(Export, Opts),
|
||||||
_ = maybe_garbage_collect(Result, St),
|
_ = maybe_garbage_collect(Result, St),
|
||||||
{stop, {shutdown, Result}, maps:remove(export, St)}.
|
{stop, {shutdown, Result}, maps:remove(export, St)}.
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
-module(emqx_ft_assembler_sup).
|
-module(emqx_ft_assembler_sup).
|
||||||
|
|
||||||
-export([start_link/0]).
|
-export([start_link/0]).
|
||||||
-export([ensure_child/3]).
|
-export([ensure_child/4]).
|
||||||
|
|
||||||
-behaviour(supervisor).
|
-behaviour(supervisor).
|
||||||
-export([init/1]).
|
-export([init/1]).
|
||||||
|
@ -25,10 +25,10 @@
|
||||||
start_link() ->
|
start_link() ->
|
||||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
ensure_child(Storage, Transfer, Size) ->
|
ensure_child(Storage, Transfer, Size, Opts) ->
|
||||||
Childspec = #{
|
Childspec = #{
|
||||||
id => Transfer,
|
id => Transfer,
|
||||||
start => {emqx_ft_assembler, start_link, [Storage, Transfer, Size]},
|
start => {emqx_ft_assembler, start_link, [Storage, Transfer, Size, Opts]},
|
||||||
restart => temporary
|
restart => temporary
|
||||||
},
|
},
|
||||||
case supervisor:start_child(?MODULE, Childspec) of
|
case supervisor:start_child(?MODULE, Childspec) of
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
[
|
[
|
||||||
store_filemeta/2,
|
store_filemeta/2,
|
||||||
store_segment/2,
|
store_segment/2,
|
||||||
assemble/2,
|
assemble/3,
|
||||||
|
|
||||||
files/0,
|
files/0,
|
||||||
files/1,
|
files/1,
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
ok | {async, pid()} | {error, term()}.
|
ok | {async, pid()} | {error, term()}.
|
||||||
-callback store_segment(storage(), emqx_ft:transfer(), emqx_ft:segment()) ->
|
-callback store_segment(storage(), emqx_ft:transfer(), emqx_ft:segment()) ->
|
||||||
ok | {async, pid()} | {error, term()}.
|
ok | {async, pid()} | {error, term()}.
|
||||||
-callback assemble(storage(), emqx_ft:transfer(), _Size :: emqx_ft:bytes()) ->
|
-callback assemble(storage(), emqx_ft:transfer(), _Size :: emqx_ft:bytes(), emqx_ft:finopts()) ->
|
||||||
ok | {async, pid()} | {error, term()}.
|
ok | {async, pid()} | {error, term()}.
|
||||||
|
|
||||||
-callback files(storage(), query(Cursor)) ->
|
-callback files(storage(), query(Cursor)) ->
|
||||||
|
@ -114,10 +114,10 @@ store_filemeta(Transfer, FileMeta) ->
|
||||||
store_segment(Transfer, Segment) ->
|
store_segment(Transfer, Segment) ->
|
||||||
dispatch(store_segment, [Transfer, Segment]).
|
dispatch(store_segment, [Transfer, Segment]).
|
||||||
|
|
||||||
-spec assemble(emqx_ft:transfer(), emqx_ft:bytes()) ->
|
-spec assemble(emqx_ft:transfer(), emqx_ft:bytes(), emqx_ft:finopts()) ->
|
||||||
ok | {async, pid()} | {error, term()}.
|
ok | {async, pid()} | {error, term()}.
|
||||||
assemble(Transfer, Size) ->
|
assemble(Transfer, Size, FinOpts) ->
|
||||||
dispatch(assemble, [Transfer, Size]).
|
dispatch(assemble, [Transfer, Size, FinOpts]).
|
||||||
|
|
||||||
-spec files() ->
|
-spec files() ->
|
||||||
{ok, page(file_info(), _)} | {error, term()}.
|
{ok, page(file_info(), _)} | {error, term()}.
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
%% Export API
|
%% Export API
|
||||||
-export([start_export/3]).
|
-export([start_export/3]).
|
||||||
-export([write/2]).
|
-export([write/2]).
|
||||||
-export([complete/1]).
|
-export([complete/2]).
|
||||||
-export([discard/1]).
|
-export([discard/1]).
|
||||||
|
|
||||||
%% Listing API
|
%% Listing API
|
||||||
|
@ -117,12 +117,19 @@ write(#{mod := ExporterMod, st := ExportSt, hash := Hash} = Export, Content) ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec complete(export()) ->
|
-spec complete(export(), emqx_ft:finopts()) ->
|
||||||
ok | {error, _Reason}.
|
ok | {error, _Reason}.
|
||||||
complete(#{mod := ExporterMod, st := ExportSt, hash := Hash, filemeta := Filemeta}) ->
|
complete(#{mod := ExporterMod, st := ExportSt, hash := Hash, filemeta := Filemeta}, Opts) ->
|
||||||
case verify_checksum(Hash, Filemeta) of
|
Checksum = emqx_maybe:define(
|
||||||
{ok, Checksum} ->
|
% NOTE
|
||||||
ExporterMod:complete(ExportSt, Checksum);
|
% Checksum in `Opts` takes precedence over one in `Filemeta` according to the spec.
|
||||||
|
% We do not care if they differ.
|
||||||
|
maps:get(checksum, Opts, undefined),
|
||||||
|
maps:get(checksum, Filemeta, undefined)
|
||||||
|
),
|
||||||
|
case verify_checksum(Hash, Checksum) of
|
||||||
|
{ok, ExportChecksum} ->
|
||||||
|
ExporterMod:complete(ExportSt, ExportChecksum);
|
||||||
{error, _} = Error ->
|
{error, _} = Error ->
|
||||||
_ = ExporterMod:discard(ExportSt),
|
_ = ExporterMod:discard(ExportSt),
|
||||||
Error
|
Error
|
||||||
|
@ -183,13 +190,13 @@ init_checksum(#{}) ->
|
||||||
update_checksum(Ctx, IoData) ->
|
update_checksum(Ctx, IoData) ->
|
||||||
crypto:hash_update(Ctx, IoData).
|
crypto:hash_update(Ctx, IoData).
|
||||||
|
|
||||||
verify_checksum(Ctx, #{checksum := {Algo, Digest} = Checksum}) ->
|
verify_checksum(Ctx, {Algo, Digest} = Checksum) ->
|
||||||
case crypto:hash_final(Ctx) of
|
case crypto:hash_final(Ctx) of
|
||||||
Digest ->
|
Digest ->
|
||||||
{ok, Checksum};
|
{ok, Checksum};
|
||||||
Mismatch ->
|
Mismatch ->
|
||||||
{error, {checksum, Algo, binary:encode_hex(Mismatch)}}
|
{error, {checksum, Algo, binary:encode_hex(Mismatch)}}
|
||||||
end;
|
end;
|
||||||
verify_checksum(Ctx, #{}) ->
|
verify_checksum(Ctx, undefined) ->
|
||||||
Digest = crypto:hash_final(Ctx),
|
Digest = crypto:hash_final(Ctx),
|
||||||
{ok, {sha256, Digest}}.
|
{ok, {sha256, Digest}}.
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
-export([list/3]).
|
-export([list/3]).
|
||||||
-export([pread/5]).
|
-export([pread/5]).
|
||||||
-export([lookup_local_assembler/1]).
|
-export([lookup_local_assembler/1]).
|
||||||
-export([assemble/3]).
|
-export([assemble/4]).
|
||||||
|
|
||||||
-export([transfers/1]).
|
-export([transfers/1]).
|
||||||
|
|
||||||
|
@ -211,14 +211,14 @@ pread(_Storage, _Transfer, Frag, Offset, Size) ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec assemble(storage(), transfer(), emqx_ft:bytes()) ->
|
-spec assemble(storage(), transfer(), emqx_ft:bytes(), emqx_ft:finopts()) ->
|
||||||
{async, _Assembler :: pid()} | ok | {error, _TODO}.
|
{async, _Assembler :: pid()} | ok | {error, _TODO}.
|
||||||
assemble(Storage, Transfer, Size) ->
|
assemble(Storage, Transfer, Size, Opts) ->
|
||||||
LookupSources = [
|
LookupSources = [
|
||||||
fun() -> lookup_local_assembler(Transfer) end,
|
fun() -> lookup_local_assembler(Transfer) end,
|
||||||
fun() -> lookup_remote_assembler(Transfer) end,
|
fun() -> lookup_remote_assembler(Transfer) end,
|
||||||
fun() -> check_if_already_exported(Storage, Transfer) end,
|
fun() -> check_if_already_exported(Storage, Transfer) end,
|
||||||
fun() -> ensure_local_assembler(Storage, Transfer, Size) end
|
fun() -> ensure_local_assembler(Storage, Transfer, Size, Opts) end
|
||||||
],
|
],
|
||||||
lookup_assembler(LookupSources).
|
lookup_assembler(LookupSources).
|
||||||
|
|
||||||
|
@ -295,8 +295,8 @@ lookup_remote_assembler(Transfer) ->
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
ensure_local_assembler(Storage, Transfer, Size) ->
|
ensure_local_assembler(Storage, Transfer, Size, Opts) ->
|
||||||
{ok, Pid} = emqx_ft_assembler_sup:ensure_child(Storage, Transfer, Size),
|
{ok, Pid} = emqx_ft_assembler_sup:ensure_child(Storage, Transfer, Size, Opts),
|
||||||
{async, Pid}.
|
{async, Pid}.
|
||||||
|
|
||||||
-spec transfers(storage()) ->
|
-spec transfers(storage()) ->
|
||||||
|
|
|
@ -159,6 +159,10 @@ t_invalid_topic_format(Config) ->
|
||||||
unspecified_error,
|
unspecified_error,
|
||||||
emqtt:publish(C, <<"$file/fileid/fin/offset">>, <<>>, 1)
|
emqtt:publish(C, <<"$file/fileid/fin/offset">>, <<>>, 1)
|
||||||
),
|
),
|
||||||
|
?assertRCName(
|
||||||
|
unspecified_error,
|
||||||
|
emqtt:publish(C, <<"$file/fileid/fin/42/xyz">>, <<>>, 1)
|
||||||
|
),
|
||||||
?assertRCName(
|
?assertRCName(
|
||||||
unspecified_error,
|
unspecified_error,
|
||||||
emqtt:publish(C, <<"$file/">>, <<>>, 1)
|
emqtt:publish(C, <<"$file/">>, <<>>, 1)
|
||||||
|
@ -390,9 +394,18 @@ t_invalid_checksum(Config) ->
|
||||||
with_offsets(Data)
|
with_offsets(Data)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
% Send `fin` w/o checksum, should fail since filemeta checksum is invalid
|
||||||
|
FinTopic = mk_fin_topic(FileId, Filesize),
|
||||||
?assertRCName(
|
?assertRCName(
|
||||||
unspecified_error,
|
unspecified_error,
|
||||||
emqtt:publish(C, mk_fin_topic(FileId, Filesize), <<>>, 1)
|
emqtt:publish(C, FinTopic, <<>>, 1)
|
||||||
|
),
|
||||||
|
|
||||||
|
% Send `fin` with the correct checksum
|
||||||
|
Checksum = binary:encode_hex(sha256(Data)),
|
||||||
|
?assertRCName(
|
||||||
|
success,
|
||||||
|
emqtt:publish(C, <<FinTopic/binary, "/", Checksum/binary>>, <<>>, 1)
|
||||||
).
|
).
|
||||||
|
|
||||||
t_corrupted_segment_retry(Config) ->
|
t_corrupted_segment_retry(Config) ->
|
||||||
|
@ -507,7 +520,7 @@ t_assemble_crash(Config) ->
|
||||||
C = ?config(client, Config),
|
C = ?config(client, Config),
|
||||||
|
|
||||||
meck:new(emqx_ft_storage_fs),
|
meck:new(emqx_ft_storage_fs),
|
||||||
meck:expect(emqx_ft_storage_fs, assemble, fun(_, _, _) -> meck:exception(error, oops) end),
|
meck:expect(emqx_ft_storage_fs, assemble, fun(_, _, _, _) -> meck:exception(error, oops) end),
|
||||||
|
|
||||||
?assertRCName(
|
?assertRCName(
|
||||||
unspecified_error,
|
unspecified_error,
|
||||||
|
|
|
@ -178,7 +178,7 @@ complete_assemble(Storage, Transfer, Size) ->
|
||||||
complete_assemble(Storage, Transfer, Size, 1000).
|
complete_assemble(Storage, Transfer, Size, 1000).
|
||||||
|
|
||||||
complete_assemble(Storage, Transfer, Size, Timeout) ->
|
complete_assemble(Storage, Transfer, Size, Timeout) ->
|
||||||
{async, Pid} = emqx_ft_storage_fs:assemble(Storage, Transfer, Size),
|
{async, Pid} = emqx_ft_storage_fs:assemble(Storage, Transfer, Size, #{}),
|
||||||
MRef = erlang:monitor(process, Pid),
|
MRef = erlang:monitor(process, Pid),
|
||||||
Pid ! kickoff,
|
Pid ! kickoff,
|
||||||
receive
|
receive
|
||||||
|
|
|
@ -381,7 +381,7 @@ complete_transfer(Storage, Transfer, Size) ->
|
||||||
complete_transfer(Storage, Transfer, Size, 100).
|
complete_transfer(Storage, Transfer, Size, 100).
|
||||||
|
|
||||||
complete_transfer(Storage, Transfer, Size, Timeout) ->
|
complete_transfer(Storage, Transfer, Size, Timeout) ->
|
||||||
case emqx_ft_storage_fs:assemble(Storage, Transfer, Size) of
|
case emqx_ft_storage_fs:assemble(Storage, Transfer, Size, #{}) of
|
||||||
ok ->
|
ok ->
|
||||||
ok;
|
ok;
|
||||||
{async, Pid} ->
|
{async, Pid} ->
|
||||||
|
|
Loading…
Reference in New Issue