Skip to content

Commit c177e77

Browse files
committed
more fixes for disteral to work correctly
Signed-off-by: Alejandro M. Ramallo <alejandro.ramallo@leapsight.com>
1 parent 5c962c6 commit c177e77

6 files changed

Lines changed: 117 additions & 26 deletions

src/partisan.erl

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@
182182
-export([nodes/0]).
183183
-export([nodes/1]).
184184
-export([nodestring/0]).
185+
-export([remote_ref_to_disterl/1]).
185186
-export([self/1]).
186187

187188

@@ -429,8 +430,18 @@ monitor(process, Term, Opts) when erlang:is_pid(Term) orelse is_atom(Term) ->
429430
erlang:monitor(process, Term, to_erl_monitor_opts(Opts));
430431

431432
monitor(process, RemoteRef, Opts) ->
432-
%% eqwalizer:ignore RemoteRef
433-
partisan_monitor:monitor(RemoteRef, Opts);
433+
%% When `connect_disterl' is true the test harness explicitly opted into
434+
%% disterl-only routing — decode the remote-ref and use `erlang:monitor'
435+
%% so DOWN messages fire promptly when the peer drops. Otherwise use the
436+
%% partisan transport's own monitor (the default behaviour).
437+
case partisan_config:get(connect_disterl, false)
438+
andalso remote_ref_to_disterl(RemoteRef) of
439+
{ok, {Name, _Node} = NN} when is_atom(Name) ->
440+
erlang:monitor(process, NN, to_erl_monitor_opts(Opts));
441+
_ ->
442+
%% eqwalizer:ignore RemoteRef
443+
partisan_monitor:monitor(RemoteRef, Opts)
444+
end;
434445

435446
monitor(Type, Term, Opts) when Type == port orelse Type == time_offset ->
436447
erlang:monitor(Type, Term, to_erl_monitor_opts(Opts)).
@@ -1762,4 +1773,39 @@ process_exit_reason(_) ->
17621773
noproc.
17631774

17641775

1776+
%% @private
1777+
%% True if the target lives on a node we already have a disterl connection
1778+
%% to (or is local). Caller uses this to prefer disterl-based monitoring,
1779+
%% which detects noconnection promptly.
1780+
is_disterl_connected(Pid) when erlang:is_pid(Pid) ->
1781+
Node = erlang:node(Pid),
1782+
Node =:= erlang:node()
1783+
orelse lists:member(Node, erlang:nodes());
1784+
is_disterl_connected({Name, Node}) when is_atom(Name), is_atom(Node) ->
1785+
Node =:= erlang:node()
1786+
orelse lists:member(Node, erlang:nodes());
1787+
is_disterl_connected(_) ->
1788+
false.
1789+
1790+
%% @private
1791+
%% When `connect_disterl' is set, convert a partisan_remote_ref to a
1792+
%% disterl-usable form: a foreign pid (via `list_to_pid/1') for encoded pids,
1793+
%% or `{Name, Node}' for encoded names. Returns `error' for refs we don't
1794+
%% know how to convert (the caller should fall back to partisan_monitor).
1795+
remote_ref_to_disterl(Ref) ->
1796+
try
1797+
Node = partisan_remote_ref:node(Ref),
1798+
case partisan_remote_ref:target(Ref) of
1799+
{encoded_pid, Str} ->
1800+
{ok, list_to_pid(Str)};
1801+
{encoded_name, Str} ->
1802+
{ok, {list_to_existing_atom(Str), Node}};
1803+
_ ->
1804+
error
1805+
end
1806+
catch
1807+
_:_ -> error
1808+
end.
1809+
1810+
17651811

src/partisan_otp_patches.erl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,11 @@ do_send_request_source() ->
184184
" do_send_request(LocalProcess, Label, Request);\n"
185185
" false ->\n"
186186
" Opts = partisan_gen:get_opts(),\n"
187-
" Mref = partisan:monitor(process, Process, Opts),\n"
187+
" %% Same `{alias, demonitor}' requirement as the {Name, Node}\n"
188+
" %% clause above — the receiver replies via `[alias|Mref]'.\n"
189+
" Mref = partisan:monitor(\n"
190+
" process, Process, [{alias, demonitor} | Opts]\n"
191+
" ),\n"
188192
" Message = {Label, {partisan:self(), [alias|Mref]}, Request},\n"
189193
" partisan:forward_message(Process, Message, Opts),\n"
190194
" Mref\n"

src/partisan_pluggable_peer_service_manager.erl

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,26 @@ forward_message(RemoteRef, Message, Opts) ->
479479
orelse error(badarg),
480480

481481
Node = partisan_remote_ref:node(RemoteRef),
482-
Target = partisan_remote_ref:target(RemoteRef),
483-
484-
forward_message(Node, Target, Message, Opts).
482+
%% When `connect_disterl' is true, prefer disterl: send directly to the
483+
%% native pid/name. Otherwise route through the encoded target so the
484+
%% partisan transport handles it.
485+
case partisan_config:get(connect_disterl, false) of
486+
true ->
487+
case partisan:remote_ref_to_disterl(RemoteRef) of
488+
{ok, Pid} when is_pid(Pid) ->
489+
_ = (catch erlang:send(Pid, Message, [noconnect])),
490+
ok;
491+
{ok, {Name, _Node} = NN} when is_atom(Name) ->
492+
_ = (catch erlang:send(NN, Message, [noconnect])),
493+
ok;
494+
_ ->
495+
Target = partisan_remote_ref:target(RemoteRef),
496+
forward_message(Node, Target, Message, Opts)
497+
end;
498+
false ->
499+
Target = partisan_remote_ref:target(RemoteRef),
500+
forward_message(Node, Target, Message, Opts)
501+
end.
485502

486503

487504
%% -----------------------------------------------------------------------------

test/partisan_gen_server_SUITE.erl

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,8 @@ hibernate(Config) when is_list(Config) ->
952952
erlang:process_info(Pid, current_function)),
953953
receive
954954
{result,R} ->
955-
{current_function,{erlang,hibernate,3}} = R
955+
{current_function, MFA0} = R,
956+
true = is_hibernating_mfa(MFA0)
956957
end,
957958

958959
true = partisan_gen_server:call(my_test_name_hibernate, hibernate),
@@ -1036,10 +1037,10 @@ is_in_erlang_hibernate_1(0, Pid) ->
10361037
ct:fail(not_in_erlang_hibernate_3);
10371038
is_in_erlang_hibernate_1(N, Pid) ->
10381039
{current_function,MFA} = erlang:process_info(Pid, current_function),
1039-
case MFA of
1040-
{erlang,hibernate,_Arity} ->
1040+
case is_hibernating_mfa(MFA) of
1041+
true ->
10411042
ok;
1042-
_ ->
1043+
false ->
10431044
receive after 10 -> ok end,
10441045
is_in_erlang_hibernate_1(N-1, Pid)
10451046
end.
@@ -1053,14 +1054,22 @@ is_not_in_erlang_hibernate_1(0, Pid) ->
10531054
ct:fail(not_in_erlang_hibernate_3);
10541055
is_not_in_erlang_hibernate_1(N, Pid) ->
10551056
{current_function,MFA} = erlang:process_info(Pid, current_function),
1056-
case MFA of
1057-
{erlang,hibernate,_Arity} ->
1057+
case is_hibernating_mfa(MFA) of
1058+
true ->
10581059
receive after 10 -> ok end,
10591060
is_not_in_erlang_hibernate_1(N-1, Pid);
1060-
_ ->
1061+
false ->
10611062
ok
10621063
end.
10631064

1065+
%% Recognize a hibernating-process current_function. OTP 28's gen_server
1066+
%% hibernation parks the process inside its own `loop_hibernate/4' rather than
1067+
%% inside `erlang:hibernate/_' (which the test was originally written for).
1068+
is_hibernating_mfa({erlang, hibernate, _}) -> true;
1069+
is_hibernating_mfa({partisan_gen_server, loop_hibernate, _}) -> true;
1070+
is_hibernating_mfa({gen_server, loop_hibernate, _}) -> true;
1071+
is_hibernating_mfa(_) -> false.
1072+
10641073
%% --------------------------------------
10651074
%% Test partisan_gen_server:abcast and handle_cast.
10661075
%% Test all different return values from
@@ -1609,20 +1618,21 @@ undef_terminate2(Config) when is_list(Config) ->
16091618
ok = partisan_gen_server:stop(Server, {error, test}, infinity),
16101619
ok = verify_down_reason(MRef, Server, {error, test}).
16111620

1612-
%% Start should return an undef error if init isn't implemented
1621+
%% Start should return an undef error if init isn't implemented.
1622+
%% OTP 28 catches the undef inside start_link and returns the error
1623+
%% synchronously without ever fully spawning the server, so no `{'EXIT', _, _}'
1624+
%% message is delivered to the trap_exit caller.
16131625
undef_init(_Config) ->
16141626
{error, {undef, [{oc_init_server, init, [_], _}|_]}} =
16151627
partisan_gen_server:start(oc_init_server, [], []),
16161628
process_flag(trap_exit, true),
16171629
{error, {undef, [{oc_init_server, init, [_], _}|_]}} =
16181630
(catch partisan_gen_server:start_link(oc_init_server, [], [])),
16191631
receive
1620-
{'EXIT', Server,
1621-
{undef, [{oc_init_server, init, [_], _}|_]}} when is_pid(Server) ->
1622-
partisan:is_pid(Server) orelse ct:fail({bad_pid, Server}),
1623-
ok
1624-
after 1000 ->
1625-
ct:fail(expected_exit_msg)
1632+
Msg ->
1633+
ct:fail({unexpected_msg, Msg})
1634+
after 500 ->
1635+
ok
16261636
end.
16271637

16281638
%% The upgrade should fail if code_change is expected in the callback module

test/partisan_gen_statem_SUITE.erl

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,10 +1644,10 @@ wait_erlang_hibernate_1(0, Pid) ->
16441644
ct:fail(should_be_in_erlang_hibernate_3);
16451645
wait_erlang_hibernate_1(N, Pid) ->
16461646
{current_function,MFA} = erlang:process_info(Pid, current_function),
1647-
case MFA of
1648-
{erlang,hibernate,_Arity} ->
1647+
case is_hibernating_mfa(MFA) of
1648+
true ->
16491649
ok;
1650-
_ ->
1650+
false ->
16511651
receive after 10 -> ok end,
16521652
wait_erlang_hibernate_1(N-1, Pid)
16531653
end.
@@ -1660,14 +1660,22 @@ is_not_in_erlang_hibernate_1(0, _Pid) ->
16601660
ct:fail(should_not_be_in_erlang_hibernate_3);
16611661
is_not_in_erlang_hibernate_1(N, Pid) ->
16621662
{current_function,MFA} = erlang:process_info(Pid, current_function),
1663-
case MFA of
1664-
{erlang,hibernate,_Arity} ->
1663+
case is_hibernating_mfa(MFA) of
1664+
true ->
16651665
receive after 10 -> ok end,
16661666
is_not_in_erlang_hibernate_1(N-1, Pid);
1667-
_ ->
1667+
false ->
16681668
ok
16691669
end.
16701670

1671+
%% OTP 28's gen_statem (and the rewritten partisan_gen_statem) parks a
1672+
%% hibernating process inside its own `loop_hibernate/4' rather than inside
1673+
%% `erlang:hibernate/_'. Match either form.
1674+
is_hibernating_mfa({erlang, hibernate, _}) -> true;
1675+
is_hibernating_mfa({partisan_gen_statem, loop_hibernate, _}) -> true;
1676+
is_hibernating_mfa({gen_statem, loop_hibernate, _}) -> true;
1677+
is_hibernating_mfa(_) -> false.
1678+
16711679

16721680
enter_loop(_Config) ->
16731681
OldFlag = process_flag(trap_exit, true),

test/partisan_support.erl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,12 @@ start_ct_node(Name, Opts) ->
597597
end.
598598

599599
stop_ct_node(Node) ->
600+
%% Ask the peer to leave the partisan cluster gracefully so the local
601+
%% partisan_monitor sees the disconnect (and fires `noconnection' DOWN
602+
%% messages on outstanding monitors). Without this, killing the peer via
603+
%% `peer:stop' alone makes the runner wait for partisan's heartbeat to
604+
%% time out, which exceeds CT's per-test budget.
605+
_ = (catch rpc:call(Node, partisan_peer_service, leave, [], 2000)),
600606
Key = {?MODULE, peer, Node},
601607
case persistent_term:get(Key, undefined) of
602608
undefined ->

0 commit comments

Comments
 (0)