Packages
ra
3.1.3
3.1.9
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.2
3.0.1
3.0.0
3.0.0-beta.1
2.17.3
2.17.2
2.17.1
2.17.0
2.16.13
2.16.12
2.16.11
2.16.10
2.16.9
2.16.8
2.16.7
2.16.6
2.16.5
2.16.4
2.16.3
2.16.2
2.16.1
2.16.0
2.16.0-pre.12
2.16.0-pre.11
2.16.0-pre.10
2.16.0-pre.9
2.16.0-pre.8
2.16.0-pre.7
2.16.0-pre.6
2.16.0-pre.5
2.16.0-pre.4
2.16.0-pre.3
2.16.0-pre.2
2.16.0-pre.1
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.0
2.13.6
2.13.5
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.13.0-pre.1
2.12.0
2.11.0
2.11.0-pre.1
2.10.2-pre.2
2.10.2-pre.1
2.10.1
2.10.0
2.10.0-pre.3
2.10.0-pre.2
2.10.0-pre.1
2.9.10-pre.1
2.9.1
2.9.1-pre.2
2.9.1-pre.1
2.9.0
2.8.0
retired
2.7.3
2.7.2
2.7.1
2.7.0
2.7.0-pre.3
2.7.0-pre.2
2.7.0-pre.1
2.6.3
2.6.2
2.6.1
2.6.0-pre.1
2.5.1
2.5.1-pre.1
2.5.0
2.4.9
2.4.8
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
retired
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.13
2.0.12
2.0.11
2.0.10
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.9.6
0.9.5
0.9.4
0.9.2
0.3.3
retired
0.3.2
retired
0.3.1
retired
Raft library
Current section
Files
Jump to
Current section
Files
src/ra_directory.erl
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
%%
%% Copyright (c) 2017-2025 Broadcom. All Rights Reserved. The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
%%
-module(ra_directory).
-export([
init/1,
init/2,
deinit/1,
register_name/6,
unregister_name/2,
where_is/2,
where_is_parent/2,
name_of/2,
cluster_name_of/2,
pid_of/2,
uid_of/2,
overview/1,
list_registered/1,
is_registered_uid/2
]).
-export_type([
]).
-include("ra.hrl").
% registry for ra servers' locally unique name
-spec init(atom()) -> ok | {error, system_not_started}.
init(System) when is_atom(System) ->
case ra_system:fetch(System) of
undefined ->
{error, system_not_started};
#{data_dir := Dir,
names := Names} ->
init(Dir, Names)
end.
-spec init(file:filename(), ra_system:names()) -> ok.
init(Dir, #{directory := Name,
directory_rev := NameRev}) ->
_ = ets:new(Name, [named_table,
public,
{read_concurrency, true}
]),
ok = ra_lib:make_dir(Dir),
Dets = filename:join(Dir, "names.dets"),
{ok, NameRev} = dets:open_file(NameRev,
[{file, Dets},
{auto_save, 500},
{access, read_write}]),
_ = dets:foldl(fun({ServerName, UId}, Acc) ->
true = ets:insert(Name, {UId, undefined, undefined,
ServerName, undefined}),
Acc
end, [], NameRev),
ok.
-spec deinit(atom() | ra_system:names()) -> ok.
deinit(System) when is_atom(System) ->
deinit(get_names(System));
deinit(#{directory := Name,
directory_rev := NameRev}) ->
_ = ets:delete(Name),
ok = dets:sync(NameRev),
_ = dets:close(NameRev),
ok.
-spec register_name(ra_system:names() | atom(), ra_uid(), pid(), option(pid()), atom(),
ra_cluster_name()) -> ok.
register_name(System, UId, Pid, ParentPid, ServerName, ClusterName)
when is_atom(System) ->
register_name(get_names(System), UId, Pid,
ParentPid, ServerName, ClusterName);
register_name(#{directory := Directory,
directory_rev := DirRev} = System, UId, Pid, ParentPid,
ServerName, ClusterName) ->
true = ets:insert(Directory, {UId, Pid, ParentPid, ServerName,
ClusterName}),
case uid_of(System, ServerName) of
undefined ->
ok = dets:insert(DirRev, {ServerName, UId});
UId ->
%% no need to insert into dets table if already there
ok;
OtherUId ->
ok = dets:insert(DirRev, {ServerName, UId}),
?WARN("ra server with name ~ts UId ~s replaces prior UId ~s",
[ServerName, UId, OtherUId]),
ok
end.
-spec unregister_name(atom() | ra_system:names(), ra_uid()) -> ra_uid().
unregister_name(System, UId) when is_atom(System) ->
unregister_name(get_names(System), UId);
unregister_name(#{directory := Directory,
directory_rev := DirRev}, UId) ->
case ets:take(Directory, UId) of
[{_, _, _, ServerName, _}] ->
ok = dets:delete(DirRev, ServerName),
UId;
[] ->
_ = dets:select_delete(DirRev, [{{'_', UId}, [], [true]}]),
UId
end.
-spec where_is(atom() | ra_system:names(), ra_uid() | atom()) ->
pid() | undefined.
where_is(System, ServerName) when is_atom(System) ->
where_is(get_names(System), ServerName);
where_is(#{directory_rev := DirRev} = Names, ServerName)
when is_atom(ServerName) ->
case dets:lookup(DirRev, ServerName) of
[] -> undefined;
[{_, UId}] ->
where_is(Names, UId)
end;
where_is(#{directory := Dir}, UId) when is_binary(UId) ->
case ets:lookup(Dir, UId) of
[{_, Pid, _, _, _}] when is_pid(Pid) ->
Pid;
_ -> undefined
end.
-spec where_is_parent(atom() | ra_system:names(), ra_uid() | atom()) ->
pid() | undefined.
where_is_parent(System, ServerName) when is_atom(System) ->
where_is_parent(get_names(System), ServerName);
where_is_parent(#{directory_rev := DirRev} = Names, ServerName)
when is_atom(ServerName) ->
case dets:lookup(DirRev, ServerName) of
[] -> undefined;
[{_, UId}] ->
where_is_parent(Names, UId)
end;
where_is_parent(#{directory := Dir}, UId) when is_binary(UId) ->
case ets:lookup(Dir, UId) of
[{_, _, Pid, _, _}] when is_pid(Pid) -> Pid;
_ -> undefined
end.
-spec name_of(atom() | ra_system:names(), ra_uid()) -> option(atom()).
name_of(SystemOrNames, UId) ->
Tbl = get_tbl(SystemOrNames),
case ets:lookup(Tbl, UId) of
[{_, _, _, ServerName, _}] -> ServerName;
[] ->
undefined
end.
-spec cluster_name_of(ra_system:names() | atom(), ra_uid()) ->
option(ra_cluster_name()).
cluster_name_of(SystemOrNames, UId) ->
Tbl = get_tbl(SystemOrNames),
case ets:lookup(Tbl, UId) of
[{_, _, _, _, ClusterName}]
when ClusterName /= undefined ->
ClusterName;
_ -> undefined
end.
-spec pid_of(atom() | ra_system:names(), ra_uid()) -> option(pid()).
pid_of(SystemOrNames, UId) ->
case ets:lookup(get_tbl(SystemOrNames), UId) of
[{_, Pid, _, _, _}] when is_pid(Pid) -> Pid;
_ -> undefined
end.
uid_of(System, ServerName) when is_atom(System) ->
uid_of(get_names(System), ServerName);
uid_of(#{directory_rev := Tbl}, ServerName) when is_atom(ServerName) ->
case dets:lookup(Tbl, ServerName) of
[] -> undefined;
[{_, UId}] ->
UId
end;
uid_of(SystemOrNames, {ServerName, _}) when is_atom(ServerName) ->
uid_of(SystemOrNames, ServerName).
overview(System) when is_atom(System) ->
#{directory := Tbl,
directory_rev := _TblRev} = get_names(System),
Dir = ets:tab2list(Tbl),
Rows = lists:map(fun({K, S, V}) ->
{K, {S, V}}
end,
ets:tab2list(ra_state)),
States = maps:from_list(Rows),
Snaps = lists:foldl(
fun (T, Acc) ->
Acc#{element(1, T) => erlang:delete_element(1, T)}
end, #{}, ets:tab2list(ra_log_snapshot_state)),
lists:foldl(fun ({UId, Pid, Parent, ServerName, ClusterName}, Acc) ->
{S, V} = maps:get(ServerName, States, {undefined, undefined}),
Acc#{ServerName =>
#{uid => UId,
pid => Pid,
parent => Parent,
state => S,
membership => V,
cluster_name => ClusterName,
snapshot_state => maps:get(UId, Snaps,
undefined)}}
end, #{}, Dir).
-spec list_registered(atom() | ra_system:names()) ->
[{atom(), ra_uid()}].
list_registered(SystemOrNames)
when is_atom(SystemOrNames) orelse
is_map(SystemOrNames) ->
Tbl = get_reverse(SystemOrNames),
dets:select(Tbl, [{'_', [], ['$_']}]).
-spec is_registered_uid(atom() | ra_system:names(), ra_uid()) -> boolean().
is_registered_uid(SystemOrNames, UId)
when (is_atom(SystemOrNames) orelse is_map(SystemOrNames)) andalso
is_binary(UId) ->
name_of(SystemOrNames, UId) =/= undefined.
get_tbl(#{directory := Tbl}) ->
Tbl;
get_tbl(System) when is_atom(System) ->
{ok, Tbl} = ra_system:lookup_name(System, directory),
Tbl.
get_reverse(System) when is_atom(System) ->
{ok, Tbl} = ra_system:lookup_name(System, directory_rev),
Tbl;
get_reverse(#{directory_rev := DirRev}) ->
DirRev.
get_names(System) when is_atom(System) ->
#{names := Names} = ra_system:fetch(System),
Names.