1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2019. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% Don't use the system rpc server since it may overload other 22%% applications when using a lot of dirty read operations. 23 24-module(mnesia_rpc). 25-behaviour(gen_server). 26 27-export([start/0, 28 call/4 29 ]). 30 31 32%% gen_server callbacks 33-export([init/1, 34 handle_call/3, 35 handle_cast/2, 36 handle_info/2, 37 terminate/2, 38 code_change/3 39 ]). 40 41-include("mnesia.hrl"). 42 43start() -> 44 gen_server:start_link({local, ?MODULE}, ?MODULE, [self()], 45 [{timeout, infinity} %%, {debug, [trace]} 46 ]). 47 48call(Node, M, F, Args) -> 49 case ?catch_val({protocol, Node}) of 50 {Ver, _} when Ver > {8,4} -> 51 try gen_server:call({?MODULE, Node}, {apply, M, F, Args}, infinity) 52 catch 53 _:Reason -> {badrpc, {'EXIT', Reason}} 54 end; 55 _ -> 56 rpc:call(Node, M, F, Args) 57 end. 58 59init([_Parent]) -> 60 {ok, #{}}. 61 62handle_call({apply, mnesia_lib, db_get=Func, Args}, From, State) -> 63 apply_lib(Func, Args, From, State); 64handle_call({apply, mnesia_lib, db_last=Func, Args}, From, State) -> 65 apply_lib(Func, Args, From, State); 66handle_call({apply, mnesia_lib, db_first=Func, Args}, From, State) -> 67 apply_lib(Func, Args, From, State); 68handle_call({apply, mnesia_lib, db_next_key=Func, Args}, From, State) -> 69 apply_lib(Func, Args, From, State); 70handle_call({apply, mnesia_lib, db_prev_key=Func, Args}, From, State) -> 71 apply_lib(Func, Args, From, State); 72handle_call({apply, Mod, Func, Args}, From, State) -> 73 Fun = apply_fun(Mod, Func, Args, From), 74 _Pid = spawn_link(Fun), 75 {noreply, State}; 76 77handle_call(Msg, _From, State) -> 78 mnesia_lib:error("~p got unexpected call: ~tp~n", [?MODULE, Msg]), 79 {reply, badop, State}. 80 81handle_cast(Msg, State) -> 82 mnesia_lib:error("~p got unexpected cast: ~tp~n", [?MODULE, Msg]), 83 {noreply, State}. 84 85handle_info(Msg, State) -> 86 mnesia_lib:error("~p got unexpected info: ~tp~n", [?MODULE, Msg]), 87 {noreply, State}. 88 89 90code_change(_OldVsn, State, _Extra) -> 91 {ok, State}. 92 93terminate(_Reason, _State) -> 94 ok. 95 96%%%% 97 98apply_lib(Func, [Tab|_] = Args, From, State) -> 99 try 100 Ram = ?catch_val({Tab, storage_type}), 101 if Ram =:= ram_copies; Ram =:= disc_copies -> 102 {reply, apply(mnesia_lib, Func, [Ram|Args]), State}; 103 true -> 104 Fun = apply_fun(mnesia_lib, Func, Args, From), 105 _Pid = spawn_link(Fun), 106 {noreply, State} 107 end 108 catch throw:Res -> {reply, Res, State}; 109 _:Reason -> {reply, {badrpc, {'EXIT', Reason}}, State} 110 end. 111 112apply_fun(Mod, Func, Args, From) -> 113 fun() -> 114 Result = try apply(Mod, Func, Args) 115 catch throw:Res -> Res; 116 _:Reason -> {badrpc, {'EXIT', Reason}} 117 end, 118 gen_server:reply(From, Result) 119 end. 120