File: //usr/lib/erlang/lib/mnesia-4.21.1/src/mnesia_rpc.erl
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2019-2021. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%% Don't use the system rpc server since it may overload other
%% applications when using a lot of dirty read operations.
-module(mnesia_rpc).
-behaviour(gen_server).
-export([start/0,
call/4
]).
%% gen_server callbacks
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3
]).
-include("mnesia.hrl").
start() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [self()],
[{timeout, infinity} %%, {debug, [trace]}
]).
call(Node, M, F, Args) ->
case ?catch_val({protocol, Node}) of
{Ver, _} when Ver > {8,4} ->
try gen_server:call({?MODULE, Node}, {apply, M, F, Args}, infinity)
catch
_:Reason -> {badrpc, {'EXIT', Reason}}
end;
_ ->
rpc:call(Node, M, F, Args)
end.
init([_Parent]) ->
{ok, #{}}.
handle_call({apply, mnesia_lib, db_get=Func, Args}, From, State) ->
apply_lib(Func, Args, From, State);
handle_call({apply, mnesia_lib, db_last=Func, Args}, From, State) ->
apply_lib(Func, Args, From, State);
handle_call({apply, mnesia_lib, db_first=Func, Args}, From, State) ->
apply_lib(Func, Args, From, State);
handle_call({apply, mnesia_lib, db_next_key=Func, Args}, From, State) ->
apply_lib(Func, Args, From, State);
handle_call({apply, mnesia_lib, db_prev_key=Func, Args}, From, State) ->
apply_lib(Func, Args, From, State);
handle_call({apply, Mod, Func, Args}, From, State) ->
Fun = apply_fun(Mod, Func, Args, From),
_Pid = spawn_link(Fun),
{noreply, State};
handle_call(Msg, _From, State) ->
mnesia_lib:error("~p got unexpected call: ~tp~n", [?MODULE, Msg]),
{reply, badop, State}.
handle_cast(Msg, State) ->
mnesia_lib:error("~p got unexpected cast: ~tp~n", [?MODULE, Msg]),
{noreply, State}.
handle_info(Msg, State) ->
mnesia_lib:error("~p got unexpected info: ~tp~n", [?MODULE, Msg]),
{noreply, State}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
terminate(_Reason, _State) ->
ok.
%%%%
apply_lib(Func, [Tab|_] = Args, From, State) ->
try
Ram = ?catch_val({Tab, storage_type}),
if Ram =:= ram_copies; Ram =:= disc_copies ->
{reply, apply(mnesia_lib, Func, [Ram|Args]), State};
true ->
Fun = apply_fun(mnesia_lib, Func, Args, From),
_Pid = spawn_link(Fun),
{noreply, State}
end
catch throw:Res -> {reply, Res, State};
_:Reason -> {reply, {badrpc, {'EXIT', Reason}}, State}
end.
apply_fun(Mod, Func, Args, From) ->
fun() ->
Result = try apply(Mod, Func, Args)
catch throw:Res -> Res;
_:Reason -> {badrpc, {'EXIT', Reason}}
end,
gen_server:reply(From, Result)
end.