chore: transaction without nnonymous function

This commit is contained in:
zhongwencool 2021-08-20 13:57:32 +08:00
parent 765c94152b
commit d55ba6b2e8
2 changed files with 44 additions and 50 deletions

View File

@ -92,37 +92,14 @@ multicall(M, F, A, Timeout) ->
-spec query(pos_integer()) -> {'atomic', map()} | {'aborted', Reason :: term()}. -spec query(pos_integer()) -> {'atomic', map()} | {'aborted', Reason :: term()}.
query(TnxId) -> query(TnxId) ->
transaction(fun do_query/1, [TnxId]). transaction(fun trans_query/1, [TnxId]).
do_query(TnxId) ->
case mnesia:read(?CLUSTER_MFA, TnxId) of
[] -> mnesia:abort(not_found);
[#cluster_rpc_mfa{mfa = MFA, initiator = InitNode, created_at = CreatedAt}] ->
#{tnx_id => TnxId, mfa => MFA, initiator => InitNode, created_at => CreatedAt}
end.
-spec reset() -> reset. -spec reset() -> reset.
reset() -> gen_statem:call(?MODULE, reset). reset() -> gen_statem:call(?MODULE, reset).
-spec status() -> {'atomic', [map()]} | {'aborted', Reason :: term()}. -spec status() -> {'atomic', [map()]} | {'aborted', Reason :: term()}.
status() -> status() ->
Fun = fun() -> transaction(fun trans_status/0, []).
mnesia:foldl(fun(Rec, Acc) ->
#cluster_rpc_commit{node = Node, tnx_id = TnxId} = Rec,
case mnesia:read(?CLUSTER_MFA, TnxId) of
[MFARec] ->
#cluster_rpc_mfa{mfa = MFA, initiator = InitNode, created_at = CreatedAt} = MFARec,
[#{
node => Node,
tnx_id => TnxId,
initiator => InitNode,
mfa => MFA,
created_at => CreatedAt
} | Acc];
[] -> Acc
end end, [], ?CLUSTER_COMMIT)
end,
transaction(Fun).
%%%=================================================================== %%%===================================================================
%%% gen_statem callbacks %%% gen_statem callbacks
@ -158,7 +135,7 @@ handle_event({call, From}, reset, _State, _Data) ->
{keep_state_and_data, [{reply, From, ok}, ?CATCH_UP_AFTER(0)]}; {keep_state_and_data, [{reply, From, ok}, ?CATCH_UP_AFTER(0)]};
handle_event({call, From}, {initiate, MFA}, ?REALTIME, Data = #{node := Node}) -> handle_event({call, From}, {initiate, MFA}, ?REALTIME, Data = #{node := Node}) ->
case transaction(fun() -> init_mfa(Node, MFA) end) of case transaction(fun init_mfa/2, [Node, MFA]) of
{atomic, {ok, TnxId}} -> {atomic, {ok, TnxId}} ->
{keep_state, Data, [{reply, From, {ok, TnxId}}]}; {keep_state, Data, [{reply, From, {ok, TnxId}}]};
{aborted, Reason} -> {aborted, Reason} ->
@ -188,12 +165,12 @@ code_change(_OldVsn, StateName, Data, _Extra) ->
%%% Internal functions %%% Internal functions
%%%=================================================================== %%%===================================================================
catch_up(#{node := Node, retry_interval := RetryMs} = Data) -> catch_up(#{node := Node, retry_interval := RetryMs} = Data) ->
case get_next_mfa(Node) of case transaction(fun get_next_mfa/1, [Node]) of
{atomic, caught_up} -> {next_state, ?REALTIME, Data}; {atomic, caught_up} -> {next_state, ?REALTIME, Data};
{atomic, {still_lagging, NextId, MFA}} -> {atomic, {still_lagging, NextId, MFA}} ->
case apply_mfa(NextId, MFA) of case apply_mfa(NextId, MFA) of
ok -> ok ->
case transaction(fun() -> commit(Node, NextId) end) of case transaction(fun commit/2, [Node, NextId]) of
{atomic, ok} -> catch_up(Data); {atomic, ok} -> catch_up(Data);
_ -> {next_state, ?CATCH_UP, Data, [?CATCH_UP_AFTER(RetryMs)]} _ -> {next_state, ?CATCH_UP, Data, [?CATCH_UP_AFTER(RetryMs)]}
end; end;
@ -203,24 +180,20 @@ catch_up(#{node := Node, retry_interval := RetryMs} = Data) ->
end. end.
get_next_mfa(Node) -> get_next_mfa(Node) ->
Fun = NextId =
fun() -> case mnesia:wread({?CLUSTER_COMMIT, Node}) of
NextId = [] ->
case mnesia:wread({?CLUSTER_COMMIT, Node}) of LatestId = get_latest_id(),
[] -> TnxId = max(LatestId - 1, 0),
LatestId = get_latest_id(), commit(Node, TnxId),
TnxId = max(LatestId - 1, 0), ?LOG(notice, "New node(~p) first catch up and start commit at ~p", [Node, TnxId]),
commit(Node, TnxId), TnxId;
?LOG(notice, "New node(~p) first catch up and start commit at ~p", [Node, TnxId]), [#cluster_rpc_commit{tnx_id = LastAppliedID}] -> LastAppliedID + 1
TnxId;
[#cluster_rpc_commit{tnx_id = LastAppliedID}] -> LastAppliedID + 1
end,
case mnesia:read(?CLUSTER_MFA, NextId) of
[] -> caught_up;
[#cluster_rpc_mfa{mfa = MFA}] -> {still_lagging, NextId, MFA}
end
end, end,
transaction(Fun). case mnesia:read(?CLUSTER_MFA, NextId) of
[] -> caught_up;
[#cluster_rpc_mfa{mfa = MFA}] -> {still_lagging, NextId, MFA}
end.
do_catch_up(ToTnxId, Node) -> do_catch_up(ToTnxId, Node) ->
case mnesia:wread({?CLUSTER_COMMIT, Node}) of case mnesia:wread({?CLUSTER_COMMIT, Node}) of
@ -255,11 +228,11 @@ get_latest_id() ->
handle_mfa_write_event(#cluster_rpc_mfa{tnx_id = EventId, mfa = MFA}, Data) -> handle_mfa_write_event(#cluster_rpc_mfa{tnx_id = EventId, mfa = MFA}, Data) ->
#{node := Node, retry_interval := RetryMs} = Data, #{node := Node, retry_interval := RetryMs} = Data,
{atomic, LastAppliedId} = transaction(fun() -> get_last_applied_id(Node, EventId - 1) end), {atomic, LastAppliedId} = transaction(fun get_last_applied_id/2, [Node, EventId - 1]),
if LastAppliedId + 1 =:= EventId -> if LastAppliedId + 1 =:= EventId ->
case apply_mfa(EventId, MFA) of case apply_mfa(EventId, MFA) of
ok -> ok ->
case transaction(fun() -> commit(Node, EventId) end) of case transaction(fun commit/2, [Node, EventId]) of
{atomic, ok} -> {atomic, ok} ->
{next_state, ?REALTIME, Data}; {next_state, ?REALTIME, Data};
_ -> {next_state, ?CATCH_UP, Data, [?CATCH_UP_AFTER(RetryMs)]} _ -> {next_state, ?CATCH_UP, Data, [?CATCH_UP_AFTER(RetryMs)]}
@ -306,8 +279,28 @@ do_catch_up_in_one_trans(LatestId, Node) ->
transaction(Func, Args) -> transaction(Func, Args) ->
ekka_mnesia:transaction(?COMMON_SHARD, Func, Args). ekka_mnesia:transaction(?COMMON_SHARD, Func, Args).
transaction(Func) -> trans_status() ->
ekka_mnesia:transaction(?COMMON_SHARD, Func). mnesia:foldl(fun(Rec, Acc) ->
#cluster_rpc_commit{node = Node, tnx_id = TnxId} = Rec,
case mnesia:read(?CLUSTER_MFA, TnxId) of
[MFARec] ->
#cluster_rpc_mfa{mfa = MFA, initiator = InitNode, created_at = CreatedAt} = MFARec,
[#{
node => Node,
tnx_id => TnxId,
initiator => InitNode,
mfa => MFA,
created_at => CreatedAt
} | Acc];
[] -> Acc
end end, [], ?CLUSTER_COMMIT).
trans_query(TnxId) ->
case mnesia:read(?CLUSTER_MFA, TnxId) of
[] -> mnesia:abort(not_found);
[#cluster_rpc_mfa{mfa = MFA, initiator = InitNode, created_at = CreatedAt}] ->
#{tnx_id => TnxId, mfa => MFA, initiator => InitNode, created_at => CreatedAt}
end.
apply_mfa(TnxId, {M, F, A} = MFA) -> apply_mfa(TnxId, {M, F, A} = MFA) ->
try try

View File

@ -136,7 +136,8 @@ t_commit_ok_apply_fail_on_other_node_then_recover(_Config) ->
{M, F, A} = {?MODULE, failed_on_other_recover_after_5_second, [erlang:whereis(?NODE1), Now]}, {M, F, A} = {?MODULE, failed_on_other_recover_after_5_second, [erlang:whereis(?NODE1), Now]},
{ok, _} = emqx_cluster_rpc:multicall(M, F, A), {ok, _} = emqx_cluster_rpc:multicall(M, F, A),
{ok, _} = emqx_cluster_rpc:multicall(io, format, ["test"]), {ok, _} = emqx_cluster_rpc:multicall(io, format, ["test"]),
{atomic, [Status]} = emqx_cluster_rpc:status(), {atomic, [Status|L]} = emqx_cluster_rpc:status(),
?assertEqual([], L),
?assertEqual({io, format, ["test"]}, maps:get(mfa, Status)), ?assertEqual({io, format, ["test"]}, maps:get(mfa, Status)),
?assertEqual(node(), maps:get(node, Status)), ?assertEqual(node(), maps:get(node, Status)),
?assertEqual(realtime, element(1, sys:get_state(?NODE1))), ?assertEqual(realtime, element(1, sys:get_state(?NODE1))),