mnesia_locker.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,176 行 · 第 1/3 页
ERL
1,176 行
Oid = {Tab, ?ALL}, Op = {self(), {write, Tid, Oid}}, get_wlocks_on_nodes(Ns, Ns, Store, Op, Oid).need_lock(Store, Tab, Key, LockPattern) -> TabL = ?ets_match_object(Store, {{locks, Tab, ?ALL}, LockPattern}), if TabL == [] -> KeyL = ?ets_match_object(Store, {{locks, Tab, Key}, LockPattern}), if KeyL == [] -> yes; true -> no end; true -> no end.add_debug(Nodes) -> % Use process dictionary for debug info put(mnesia_wlock_nodes, Nodes).del_debug() -> erase(mnesia_wlock_nodes).%% We first send lock request to the local node if it is part of the lockers%% then the first sorted node then to the rest of the lockmanagers on all %% nodes holding a copy of the tableget_wlocks_on_nodes([Node | Tail], Orig, Store, Request, Oid) -> {?MODULE, Node} ! Request, ?ets_insert(Store, {nodes, Node}), receive_wlocks([Node], undefined, Store, Oid), case node() of Node -> %% Local done try one more get_wlocks_on_nodes(Tail, Orig, Store, Request, Oid); _ -> %% The first succeded cont with the rest get_wlocks_on_nodes(Tail, Store, Request), receive_wlocks(Tail, Orig, Store, Oid) end;get_wlocks_on_nodes([], Orig, _Store, _Request, _Oid) -> Orig.get_wlocks_on_nodes([Node | Tail], Store, Request) -> {?MODULE, Node} ! Request, ?ets_insert(Store,{nodes, Node}), get_wlocks_on_nodes(Tail, Store, Request);get_wlocks_on_nodes([], _, _) -> ok.get_rwlocks_on_nodes([ReadNode|Tail], _Res, ReadNode, Store, Tid, Oid) -> Op = {self(), {read_write, Tid, Oid}}, {?MODULE, ReadNode} ! Op, ?ets_insert(Store, {nodes, ReadNode}), Res = receive_wlocks([ReadNode], undefined, Store, Oid), case node() of ReadNode -> get_rwlocks_on_nodes(Tail, Res, ReadNode, Store, Tid, Oid); _ -> get_wlocks_on_nodes(Tail, Store, {self(), {write, Tid, Oid}}), receive_wlocks(Tail, Res, Store, Oid) end;get_rwlocks_on_nodes([Node | Tail], Res, ReadNode, Store, Tid, Oid) -> Op = {self(), {write, Tid, Oid}}, {?MODULE, Node} ! Op, ?ets_insert(Store, {nodes, Node}), receive_wlocks([Node], undefined, Store, Oid), if node() == Node -> get_rwlocks_on_nodes(Tail, Res, ReadNode, Store, Tid, Oid); Res == rwlock -> %% Hmm Rest = lists:delete(ReadNode, Tail), Op2 = {self(), {read_write, Tid, Oid}}, {?MODULE, ReadNode} ! Op2, ?ets_insert(Store, {nodes, ReadNode}), get_wlocks_on_nodes(Rest, Store, {self(), {write, Tid, Oid}}), receive_wlocks([ReadNode|Rest], undefined, Store, Oid); true -> get_wlocks_on_nodes(Tail, Store, {self(), {write, Tid, Oid}}), receive_wlocks(Tail, Res, Store, Oid) end;get_rwlocks_on_nodes([],Res,_,_,_,_) -> Res.receive_wlocks([], Res, _Store, _Oid) -> del_debug(), Res;receive_wlocks(Nodes = [This|Ns], Res, Store, Oid) -> add_debug(Nodes), receive {?MODULE, Node, granted} -> receive_wlocks(lists:delete(Node,Nodes), Res, Store, Oid); {?MODULE, Node, {granted, Val}} -> %% for rwlocks case opt_lookup_in_client(Val, Oid, write) of C when record(C, cyclic) -> flush_remaining(Nodes, Node, {aborted, C}); Val2 -> receive_wlocks(lists:delete(Node,Nodes), Val2, Store, Oid) end; {?MODULE, Node, {not_granted, Reason}} -> Reason1 = {aborted, Reason}, flush_remaining(Nodes,Node,Reason1); {?MODULE, Node, {switch, Sticky, _Req}} -> %% for rwlocks Tail = lists:delete(Node,Nodes), Nonstuck = lists:delete(Sticky,Tail), [?ets_insert(Store, {nodes, NSNode}) || NSNode <- Nonstuck], case lists:member(Sticky,Tail) of true -> sticky_flush(Nonstuck,Store), receive_wlocks([Sticky], Res, Store, Oid); false -> sticky_flush(Nonstuck,Store), Res end; {mnesia_down, This} -> % Only look for down from Nodes in list Reason1 = {aborted, {node_not_running, This}}, flush_remaining(Ns, This, Reason1) end.sticky_flush([], _) -> del_debug(), ok;sticky_flush(Ns=[Node | Tail], Store) -> add_debug(Ns), receive {?MODULE, Node, _} -> sticky_flush(Tail, Store); {mnesia_down, Node} -> ?ets_delete(Store, {nodes, Node}), sticky_flush(Tail, Store) end.flush_remaining([], _SkipNode, Res) -> del_debug(), exit(Res);flush_remaining([SkipNode | Tail ], SkipNode, Res) -> flush_remaining(Tail, SkipNode, Res);flush_remaining(Ns=[Node | Tail], SkipNode, Res) -> add_debug(Ns), receive {?MODULE, Node, _} -> flush_remaining(Tail, SkipNode, Res); {mnesia_down, Node} -> flush_remaining(Tail, SkipNode, {aborted, {node_not_running, Node}}) end.opt_lookup_in_client(lookup_in_client, Oid, Lock) -> {Tab, Key} = Oid, case catch mnesia_lib:db_get(Tab, Key) of {'EXIT', _} -> %% Table has been deleted from this node, %% restart the transaction. #cyclic{op = read, lock = Lock, oid = Oid, lucky = nowhere}; Val -> Val end;opt_lookup_in_client(Val, _Oid, _Lock) -> Val.return_granted_or_nodes({_, ?ALL} , Nodes) -> Nodes;return_granted_or_nodes({?GLOBAL, _}, Nodes) -> Nodes;return_granted_or_nodes(_ , _Nodes) -> granted. %% We store a {Tab, read, From} item in the %% locks table on the node where we actually do pick up the object%% and we also store an item {lock, Oid, read} in our local store%% so that we can release any locks we hold when we commit.%% This function not only aquires a read lock, but also reads the object%% Oid's are always {Tab, Key} tuplesrlock(Tid, Store, Oid) -> {Tab, Key} = Oid, case val({Tab, where_to_read}) of nowhere -> mnesia:abort({no_exists, Tab}); Node -> case need_lock(Store, Tab, Key, '_') of yes -> R = l_request(Node, {read, Tid, Oid}, Store), rlock_get_reply(Node, Store, Oid, R); no -> if Key == ?ALL -> [Node]; Tab == ?GLOBAL -> [Node]; true -> dirty_rpc(Node, Tab, Key, read) end end end.dirty_rpc(nowhere, Tab, Key, _Lock) -> mnesia:abort({no_exists, {Tab, Key}});dirty_rpc(Node, _Tab, ?ALL, _Lock) -> [Node];dirty_rpc(Node, ?GLOBAL, _Key, _Lock) -> [Node];dirty_rpc(Node, Tab, Key, Lock) -> Args = [Tab, Key], case rpc:call(Node, mnesia_lib, db_get, Args) of {badrpc, Reason} -> case val({Tab, where_to_read}) of Node -> ErrorTag = mnesia_lib:dirty_rpc_error_tag(Reason), mnesia:abort({ErrorTag, Args}); _NewNode -> %% Table has been deleted from the node, %% restart the transaction. C = #cyclic{op = read, lock = Lock, oid = {Tab, Key}, lucky = nowhere}, exit({aborted, C}) end; Other -> Other end.rlock_get_reply(Node, Store, Oid, {granted, V}) -> {Tab, Key} = Oid, ?ets_insert(Store, {{locks, Tab, Key}, read}), ?ets_insert(Store, {nodes, Node}), case opt_lookup_in_client(V, Oid, read) of C when record(C, cyclic) -> mnesia:abort(C); Val -> Val end;rlock_get_reply(Node, Store, Oid, granted) -> {Tab, Key} = Oid, ?ets_insert(Store, {{locks, Tab, Key}, read}), ?ets_insert(Store, {nodes, Node}), return_granted_or_nodes(Oid, [Node]);rlock_get_reply(Node, Store, Tab, {granted, V, RealKeys}) -> L = fun(K) -> ?ets_insert(Store, {{locks, Tab, K}, read}) end, lists:foreach(L, RealKeys), ?ets_insert(Store, {nodes, Node}), V;rlock_get_reply(_Node, _Store, _Oid, {not_granted , Reason}) -> exit({aborted, Reason});rlock_get_reply(_Node, Store, Oid, {switch, N2, Req}) -> ?ets_insert(Store, {nodes, N2}), {?MODULE, N2} ! Req, rlock_get_reply(N2, Store, Oid, l_req_rec(N2, Store)).rlock_table(Tid, Store, Tab) -> rlock(Tid, Store, {Tab, ?ALL}).ixrlock(Tid, Store, Tab, IxKey, Pos) -> case val({Tab, where_to_read}) of nowhere -> mnesia:abort({no_exists, Tab}); Node -> R = l_request(Node, {ix_read, Tid, Tab, IxKey, Pos}, Store), rlock_get_reply(Node, Store, Tab, R) end.%% Grabs the locks or exitsglobal_lock(Tid, Store, Item, write, Ns) -> Oid = {?GLOBAL, Item}, Op = {self(), {write, Tid, Oid}}, get_wlocks_on_nodes(Ns, Ns, Store, Op, Oid);global_lock(Tid, Store, Item, read, Ns) -> Oid = {?GLOBAL, Item}, send_requests(Ns, {read, Tid, Oid}), rec_requests(Ns, Oid, Store), Ns.send_requests([Node | Nodes], X) -> {?MODULE, Node} ! {self(), X}, send_requests(Nodes, X);send_requests([], _X) -> ok.rec_requests([Node | Nodes], Oid, Store) -> Res = l_req_rec(Node, Store), case catch rlock_get_reply(Node, Store, Oid, Res) of {'EXIT', Reason} -> flush_remaining(Nodes, Node, Reason); _ -> rec_requests(Nodes, Oid, Store) end;rec_requests([], _Oid, _Store) -> ok.get_held_locks() -> ?ets_match_object(mnesia_held_locks, '_').get_lock_queue() -> Q = ?ets_match_object(mnesia_lock_queue, '_'), [{Oid, Op, Pid, Tid, WFT} || {queue, Oid, Tid, Op, Pid, WFT} <- Q].do_stop() -> exit(shutdown).%%%%%%%%%%%%%%%%%%%%%%%%%%%%% System upgradesystem_continue(_Parent, _Debug, State) -> loop(State).system_terminate(_Reason, _Parent, _Debug, _State) -> do_stop().system_code_change(State, _Module, _OldVsn, _Extra) -> {ok, State}.%%%%%%%%%%%%%%%%%%%%%%%%%%%%% AXD301 patch sort pids according to R9B sort order%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Om R9B == true, g鰎s j鋗f鰎elsen som i R9B plain.%% Om R9B == false, g鰎s j鋗f鰎elsen som i alla andra releaser.%% cmp_tid(T1, T2) returnerar -1 om T1 < T2, 0 om T1 = T2 och 1 om T1 > T2.-define(VERSION_MAGIC, 131).-define(ATOM_EXT, 100).-define(PID_EXT, 103).-record(pid_info, {serial, number, nodename, creation}).cmp_tid(R9B, #tid{} = T, #tid{} = T) when R9B == true; R9B == false -> 0;cmp_tid(R9B, #tid{counter = C, pid = Pid1}, #tid{counter = C, pid = Pid2}) when R9B == true; R9B == false -> cmp_pid_info(R9B, pid_to_pid_info(Pid1), pid_to_pid_info(Pid2));cmp_tid(R9B, #tid{counter = C1}, #tid{counter = C2}) when R9B == true; R9B == false -> cmp(C1, C2).cmp_pid_info(_, #pid_info{} = PI, #pid_info{} = PI) -> 0;cmp_pid_info(false, #pid_info{serial = S, number = N, nodename = NN, creation = C1}, #pid_info{serial = S, number = N, nodename = NN, creation = C2}) -> cmp(C1, C2);cmp_pid_info(false, #pid_info{serial = S, number = N, nodename = NN1}, #pid_info{serial = S, number = N, nodename = NN2}) -> cmp(NN1, NN2);cmp_pid_info(false, #pid_info{serial = S, number = N1}, #pid_info{serial = S, number = N2}) -> cmp(N1, N2);cmp_pid_info(false, #pid_info{serial = S1}, #pid_info{serial = S2}) -> cmp(S1, S2);cmp_pid_info(true, #pid_info{nodename = NN, creation = C, serial = S, number = N1}, #pid_info{nodename = NN, creation = C, serial = S, number = N2}) -> cmp(N1, N2);cmp_pid_info(true, #pid_info{nodename = NN, creation = C, serial = S1}, #pid_info{nodename = NN, creation = C, serial = S2}) -> cmp(S1, S2);cmp_pid_info(true, #pid_info{nodename = NN, creation = C1}, #pid_info{nodename = NN, creation = C2}) -> cmp(C1, C2);cmp_pid_info(true, #pid_info{nodename = NN1}, #pid_info{nodename = NN2}) -> cmp(NN1, NN2).cmp(X, X) -> 0;cmp(X1, X2) when X1 < X2 -> -1;cmp(_X1, _X2) -> 1.pid_to_pid_info(Pid) when pid(Pid) -> [?VERSION_MAGIC, ?PID_EXT, ?ATOM_EXT, NNL1, NNL0 | Rest] = binary_to_list(term_to_binary(Pid)), [N3, N2, N1, N0, S3, S2, S1, S0, Creation] = drop(bytes2int(NNL1, NNL0), Rest), #pid_info{serial = bytes2int(S3, S2, S1, S0), number = bytes2int(N3, N2, N1, N0), nodename = node(Pid), creation = Creation}.drop(0, L) -> L;drop(N, [_|L]) when integer(N), N > 0 -> drop(N-1, L);drop(N, []) when integer(N), N > 0 -> [].bytes2int(N1, N0) when 0 =< N1, N1 =< 255, 0 =< N0, N0 =< 255 -> (N1 bsl 8) bor N0.bytes2int(N3, N2, N1, N0) when 0 =< N3, N3 =< 255, 0 =< N2, N2 =< 255, 0 =< N1, N1 =< 255, 0 =< N0, N0 =< 255 -> (N3 bsl 24) bor (N2 bsl 16) bor (N1 bsl 8) bor N0.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?