Skip to content

rabbit_peer_discovery: Compute start time once (backport #13490) #13497

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

Merged
merged 1 commit into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions deps/rabbit/src/rabbit_peer_discovery.erl
Original file line number Diff line number Diff line change
Expand Up @@ -627,8 +627,7 @@ query_node_props2([{Node, Members} | Rest], NodesAndProps, FromNode) ->
["Peer discovery: temporary hidden node '~ts' "
"queries properties from node '~ts'",
[node(), Node]], FromNode),
StartTime = get_node_start_time(
Node, microsecond, FromNode),
StartTime = get_node_start_time(Node, FromNode),
IsReady = is_node_db_ready(Node, FromNode),
NodeAndProps = {Node, Members, StartTime, IsReady},
NodesAndProps1 = [NodeAndProps | NodesAndProps],
Expand Down Expand Up @@ -656,9 +655,8 @@ query_node_props2([], NodesAndProps, _FromNode) ->
?assert(length(NodesAndProps1) =< length(nodes(hidden))),
NodesAndProps1.

-spec get_node_start_time(Node, Unit, FromNode) -> StartTime when
-spec get_node_start_time(Node, FromNode) -> StartTime when
Node :: node(),
Unit :: erlang:time_unit(),
FromNode :: node(),
StartTime :: non_neg_integer().
%% @doc Returns the start time of the given `Node' in `Unit'.
Expand All @@ -679,15 +677,21 @@ query_node_props2([], NodesAndProps, _FromNode) ->
%%
%% @private

get_node_start_time(Node, Unit, FromNode) ->
NativeStartTime = erpc_call(
Node, erlang, system_info, [start_time], FromNode),
TimeOffset = erpc_call(Node, erlang, time_offset, [], FromNode),
SystemStartTime = NativeStartTime + TimeOffset,
StartTime = erpc_call(
Node, erlang, convert_time_unit,
[SystemStartTime, native, Unit], FromNode),
StartTime.
get_node_start_time(Node, FromNode) ->
try
erpc_call(Node,rabbit_boot_state, get_start_time, [], FromNode)
catch
error:{exception, _, _} ->
NativeStartTime = erpc_call(
Node, erlang, system_info, [start_time],
FromNode),
TimeOffset = erpc_call(Node, erlang, time_offset, [], FromNode),
SystemStartTime = NativeStartTime + TimeOffset,
StartTime = erpc_call(
Node, erlang, convert_time_unit,
[SystemStartTime, native, microsecond], FromNode),
StartTime
end.

-spec is_node_db_ready(Node, FromNode) -> IsReady when
Node :: node(),
Expand Down
58 changes: 57 additions & 1 deletion deps/rabbitmq_prelaunch/src/rabbit_boot_state.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
set/1,
wait_for/2,
has_reached/1,
has_reached_and_is_active/1]).
has_reached_and_is_active/1,
get_start_time/0,
record_start_time/0]).

-define(PT_KEY_BOOT_STATE, {?MODULE, boot_state}).
-define(PT_KEY_START_TIME, {?MODULE, start_time}).

-type boot_state() :: stopped |
booting |
Expand Down Expand Up @@ -95,3 +98,56 @@ has_reached_and_is_active(TargetBootState) ->
andalso
not has_reached(CurrentBootState, stopping)
end.

-spec get_start_time() -> StartTime when
StartTime :: integer().
%% @doc Returns the start time of the Erlang VM.
%%
%% This time was recorded by {@link record_start_time/0} as early as possible
%% and is immutable.

get_start_time() ->
persistent_term:get(?PT_KEY_START_TIME).

-spec record_start_time() -> ok.
%% @doc Records the start time of the Erlang VM.
%%
%% The time is expressed in microseconds since Epoch. It can be compared to
%% other non-native times. This is used by the Peer Discovery subsystem to
%% sort nodes and select a seed node if the peer discovery backend did not
%% select one.
%%
%% This time is recorded once. Calling this function multiple times won't
%% overwrite the value.

record_start_time() ->
Key = ?PT_KEY_START_TIME,
try
%% Check if the start time was recorded.
_ = persistent_term:get(Key),
ok
catch
error:badarg ->
%% The start time was not recorded yet. Acquire a lock and check
%% again in case another process got the lock first and recorded
%% the start time.
Node = node(),
LockId = {?PT_KEY_START_TIME, self()},
true = global:set_lock(LockId, [Node]),
try
_ = persistent_term:get(Key),
ok
catch
error:badarg ->
%% We are really the first to get the lock and we can
%% record the start time.
NativeStartTime = erlang:system_info(start_time),
TimeOffset = erlang:time_offset(),
SystemStartTime = NativeStartTime + TimeOffset,
StartTime = erlang:convert_time_unit(
SystemStartTime, native, microsecond),
persistent_term:put(Key, StartTime)
after
global:del_lock(LockId, [Node])
end
end.
1 change: 1 addition & 0 deletions deps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ run_prelaunch_first_phase() ->
do_run() ->
%% Indicate RabbitMQ is booting.
clear_stop_reason(),
rabbit_boot_state:record_start_time(),
rabbit_boot_state:set(booting),

%% Configure dbg if requested.
Expand Down
Loading