1
%% ``The contents of this file are subject to the Erlang Public License,
4
%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
6
%% The contents of this file are subject to the Erlang Public License,
2
7
%% Version 1.1, (the "License"); you may not use this file except in
3
8
%% compliance with the License. You should have received a copy of the
4
9
%% Erlang Public License along with this software. If not, it can be
5
%% retrieved via the world wide web at http://www.erlang.org/.
10
%% retrieved online at http://www.erlang.org/.
7
12
%% Software distributed under the License is distributed on an "AS IS"
8
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
9
14
%% the License for the specific language governing rights and limitations
10
15
%% under the License.
12
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
13
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
14
%% AB. All Rights Reserved.''
19
20
-behaviour(gen_server).
72
73
%% Vsn 3 is enhanced with a tag in the synch messages to distinguish
73
74
%% different synch sessions from each other, see OTP-2766.
74
75
%% Vsn 4 uses a single, permanent, locker process, but works like vsn 3
75
%% when communicating with vsn 3 nodes. Current version of global does
76
%% not support vsn 3 nodes.
76
%% when communicating with vsn 3 nodes. (-R10B)
77
77
%% Vsn 5 uses an ordered list of self() and HisTheLocker when locking
78
%% nodes in the own partition.
78
%% nodes in the own partition. (R11B-)
80
%% Current version of global does not support vsn 4 or earlier.
114
116
%%% (the first position is the key):
116
118
%%% global_locks (set): {ResourceId, LockRequesterId, [{Pid,RPid,ref()]}
117
%%% pid() is locking ResourceId, ref() is the monitor ref.
119
%%% Pid is locking ResourceId, ref() is the monitor ref.
118
120
%%% RPid =/= Pid if there is an extra process calling erlang:monitor().
119
121
%%% global_names (set): {Name, Pid, Method, RPid, ref()}
120
122
%%% Registered names. ref() is the monitor ref.
810
812
S1#state.the_locker ! {nodeup, Node, MyTag},
812
814
%% In order to be compatible with unpatched R7 a locker
813
%% process was spawned. Vsn 5 is no longer comptabible with
815
%% process was spawned. Vsn 5 is no longer compatible with
814
816
%% vsn 3 nodes, so the locker process is no longer needed.
815
817
%% The permanent locker takes its place.
816
818
NotAPid = no_longer_a_pid,
977
979
{value, {Node, MyTag, _Resolver}} ->
978
980
MyTag = get({sync_tag_my, Node}), % assertion
980
{locker, HisLocker, HisKnown} -> %% before vsn 5
981
?trace({old_init_connect,{histhelocker,HisLocker}}),
982
HisLocker ! {his_locker_new, S#state.the_locker,
983
{HisKnown, S#state.known}};
985
{locker, _NoLongerAPid, HisKnown, HisTheLocker} -> %% vsn 5
982
{locker, _NoLongerAPid, _HisKnown0, HisTheLocker} ->
986
983
?trace({init_connect,{histhelocker,HisTheLocker}}),
987
985
S#state.the_locker ! {his_the_locker, HisTheLocker,
988
986
{Vsn,HisKnown}, S#state.known}
1512
1510
the_locker_message({his_the_locker, HisTheLocker, HisKnown0, _MyKnown}, S) ->
1513
1511
?trace({his_the_locker, HisTheLocker, {node,node(HisTheLocker)}}),
1516
{Vsn0, _} when Vsn0 > 4 ->
1518
_ when is_list(HisKnown0) ->
1512
{HisVsn, _HisKnown} = HisKnown0,
1522
1515
{nodeup, Node, MyTag} when node(HisTheLocker) =:= Node ->
1523
1516
?trace({the_locker_nodeup, {node,Node},{mytag,MyTag}}),
1618
1611
Him = random_element(Others2),
1619
1612
#him{locker = HisTheLocker, vsn = HisVsn,
1620
1613
node = Node, my_tag = MyTag} = Him,
1623
true -> [Node] % prevents deadlock; optimization
1625
1615
Us = [node() | HisNode],
1626
1616
LockId = locker_lock_id(HisTheLocker, HisVsn),
1627
1617
?trace({select_node, self(), {us, Us}}),
1618
%% HisNode = [Node] prevents deadlock:
1628
1619
{IsLockSet, S2} = lock_nodes_safely(LockId, HisNode, S1),
1629
1620
case IsLockSet of
1631
1622
Known1 = Us ++ S2#multi.known,
1632
1623
?trace({sending_lock_set, self(), {his,HisTheLocker}}),
1633
1624
HisTheLocker ! {lock_set, self(), true, S2#multi.known},
1635
S3 = lock_set_loop(S2, Him, MyTag, Known1, LockId),
1625
S3 = lock_is_set(S2, Him, MyTag, Known1, LockId),
1636
1626
loop_the_locker(S3);
1638
1628
loop_the_locker(S2)
1642
1632
%% Version 5: Both sides use the same requester id. Thereby the nodes
1643
1633
%% common to both sides are locked by both locker processes. This
1644
1634
%% means that the lock is still there when the 'new_nodes' message is
1645
%% received even if the other side has deleted the lock. Before R11 it
1646
%% could be that the lock had been deleted (by the other side) at the
1647
%% time 'new_nodes' was sent.
1648
locker_lock_id(Pid, 4) ->
1649
%% if node() > Node then Node locks common nodes with {global, Pid}
1635
%% received even if the other side has deleted the lock.
1651
1636
locker_lock_id(Pid, Vsn) when Vsn > 4 ->
1652
1637
{?GLOBAL_RID, lists:sort([self(), Pid])}.
1668
1653
Known = S#multi.known,
1669
1654
case set_lock(LockId, Known -- First, 0) of
1671
locker_trace(S, ok, {First, Known}),
1656
_ = locker_trace(S, ok, {First, Known}),
1674
%% Since the boss is locked we should have
1675
%% gotten the lock, at least if there are
1676
%% no version 4 nodes in the partition or
1677
%% someone else is locking 'global'.
1678
%% Calling set_lock with Retries > 0 does
1679
%% not seem to speed things up.
1659
%% Since the boss is locked we
1660
%% should have gotten the lock, at
1661
%% least if no one else is locking
1662
%% 'global'. Calling set_lock with
1663
%% Retries > 0 does not seem to
1680
1665
SoFar = First ++ Second,
1681
1666
del_lock(LockId, SoFar),
1682
locker_trace(S, not_ok, {Known,SoFar}),
1667
_ = locker_trace(S, not_ok, {Known,SoFar}),
1686
1671
del_lock(LockId, First),
1687
locker_trace(S, not_ok, {Second, First}),
1672
_ = locker_trace(S, not_ok, {Second, First}),
1691
locker_trace(S0, not_ok, {First, []}),
1676
_ = locker_trace(S0, not_ok, {First, []}),
1736
1721
exclude_known(Others, Known) ->
1737
1722
[N || N <- Others, not lists:member(N#him.node, Known)].
1739
lock_set_loop(S, Him, MyTag, Known1, LockId) ->
1724
lock_is_set(S, Him, MyTag, Known1, LockId) ->
1740
1725
Node = Him#him.node,
1742
Him#him.vsn < 5 -> 5000;
1746
1727
{lock_set, P, true, _} when node(P) =:= Node ->
1747
1728
gen_server:cast(global_name_server,
1762
1743
remote = lists:delete(Him, S#multi.remote)};
1763
1744
{lock_set, P, false, _} when node(P) =:= Node ->
1764
1745
?trace({not_both_set, {node,Node},{p, P},{known1,Known1}}),
1765
locker_trace(S, rejected, Known1),
1746
_ = locker_trace(S, rejected, Known1),
1766
1747
delete_global_lock(LockId, Known1),
1768
1749
{cancel, Node, _, Fun} ->
1769
1750
?trace({the_locker, cancel2, {node,Node}}),
1771
locker_trace(S, rejected, Known1),
1752
_ = locker_trace(S, rejected, Known1),
1772
1753
delete_global_lock(LockId, Known1),
1773
1754
remove_node(Node, S);
1774
1755
{'EXIT', _, _} ->
1775
1756
?trace({the_locker, exit, {node,Node}}),
1776
locker_trace(S, rejected, Known1),
1757
_ = locker_trace(S, rejected, Known1),
1777
1758
delete_global_lock(LockId, Known1),
1781
%% A cyclic deadlock could occur in rare cases where three or
1782
%% more nodes waited for a reply from each other.
1783
%% Therefore, reject lock_set attempts in this state from
1784
%% nodes < this node (its enough if at least one node in
1785
%% the cycle rejects and thus breaks the deadlock)
1760
%% There used to be an 'after' clause (OTP-4902), but it is
1761
%% no longer needed:
1787
1762
%% OTP-5770. Version 5 of the protocol. Deadlock can no longer
1788
1763
%% occur due to the fact that if a partition is locked, one
1789
1764
%% node in the other partition is also locked with the same
1790
1765
%% lock-id, which makes it impossible for any node in the
1791
1766
%% other partition to lock its partition unless it negotiates
1792
%% with the first partition. The OTP-4902 code can be removed
1793
%% when there is no need to support nodes running R10B.
1796
lock_set_loop(S, Him, MyTag, Known1, LockId)
1799
reject_lock_set() ->
1801
{lock_set, P, true, _} when node(P) < node() ->
1802
P ! {lock_set, self(), false, []},
1767
%% with the first partition.
1809
1770
%% The locker does the {new_nodes, ...} call before removing the lock.