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 + -
显示快捷键?