~rdoering/ubuntu/intrepid/erlang/fix-535090

« back to all changes in this revision

Viewing changes to lib/kernel/src/global.erl

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2007-05-01 16:57:10 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070501165710-2sapk0hp2gf3o0ip
Tags: 1:11.b.4-2ubuntu1
* Merge with Debian Unstable. Remaining changes:
  - Add -fno-stack-protector to fix broken crypto_drv.
* DebianMaintainerField update.

Show diffs side-by-side

added added

removed removed

Lines of Context:
102
102
%% {prot_vsn, Node}    = Vsn - the exchange protocol version (not used now)
103
103
%% {sync_tag_my, Node} =  My tag, used at synchronization with Node
104
104
%% {sync_tag_his, Node} = The Node's tag, used at synchronization
 
105
%% {lock_id, Node} = The resource locking the partitions
105
106
%%-----------------------------------------------------------------
106
107
-record(state, {connect_all, known = [], synced = [],
107
108
                resolvers = [], syncers = [], node_name = node(),
108
 
                the_locker, the_deleter}).
 
109
                the_locker, the_deleter, the_registrar, trace,
 
110
                global_lock_down = false
 
111
               }).
109
112
 
110
113
%%% There are also ETS tables used for bookkeeping of locks and names
111
114
%%% (the first position is the key):
112
115
%%%
113
 
%%% global_locks (set): {ResourceId, LockRequesterId, Pids}
114
 
%%%   Pids is a list of all pids locking ResourceId.
115
 
%%% global_names (set):  {Name, Pid, Method}
116
 
%%%   Registered names.
 
116
%%% global_locks (set): {ResourceId, LockRequesterId, [{Pid,RPid,ref()]}
 
117
%%%   pid() is locking ResourceId, ref() is the monitor ref.
 
118
%%%   RPid =/= Pid if there is an extra process calling erlang:monitor().
 
119
%%% global_names (set):  {Name, Pid, Method, RPid, ref()}
 
120
%%%   Registered names. ref() is the monitor ref.
 
121
%%%   RPid =/= Pid if there is an extra process calling erlang:monitor().
117
122
%%% global_names_ext (set): {Name, Pid, RegNode}
118
123
%%%   External registered names (C-nodes).
 
124
%%%   (The RPid:s can be removed when/if erlang:monitor() returns before 
 
125
%%%    trying to connect to the other node.)
119
126
%%% 
120
127
%%% Helper tables:
121
 
%%% global_pid_names (bag): {Pid, Name}
 
128
%%% global_pid_names (bag): {Pid, Name} | {ref(), Name}
122
129
%%%   Name(s) registered for Pid.
123
 
%%% global_pid_ids (bag): {Pid, ResourceId}
 
130
%%%   There is one {Pid, Name} and one {ref(), Name} for every Pid.
 
131
%%%   ref() is the same ref() as in global_names.
 
132
%%% global_pid_ids (bag): {Pid, ResourceId} | {ref(), ResourceId}
124
133
%%%   Resources locked by Pid.
125
 
%%% global_node_pids (duplicated_bag): {{lock, node(Pid)}, Pid} or 
126
 
%%%                                    {{name, Node},Pid}, 
127
 
%%%                     where Node is a node where some name is registered
128
 
%%%   Pids affected by a nodedown.
 
134
%%%   ref() is the same ref() as in global_locks.
129
135
%%%
130
136
%%% global_pid_names is a 'bag' for backward compatibility.
131
 
%%% global_node_pids is a 'duplicate_bag' for the same reason.
132
137
%%% (Before vsn 5 more than one name could be registered for a process.)
 
138
%%%
 
139
%%% R11B-3 (OTP-6341): The list of pids in the table 'global_locks'
 
140
%%% was replaced by a list of {Pid, Ref}, where Ref is a monitor ref.
 
141
%%% It was necessary to use monitors to fix bugs regarding locks that
 
142
%%% were never removed. The signal {async_del_lock, ...} has been
 
143
%%% kept for backward compatibility. It can be removed later.
 
144
%%% 
 
145
%%% R11B-4 (OTP-6428): Monitors are used for registered names.
 
146
%%% The signal {delete_name, ...} has been kept for backward compatibility.
 
147
%%% It can be removed later as can the deleter process.
 
148
%%% An extra process calling erlang:monitor() is sometimes created.
 
149
%%% The new_nodes messages has been augmented with the global lock id.
133
150
 
134
151
start() -> 
135
152
    gen_server:start({local, global_name_server}, ?MODULE, [], []).
192
209
    register_name(Name, Pid, {?MODULE, random_exit_name}).
193
210
 
194
211
register_name(Name, Pid, Method) when is_pid(Pid) ->
195
 
    trans_all_known(fun(Nodes) ->
 
212
    Fun = fun(Nodes) ->
196
213
        case (where(Name) =:= undefined) andalso check_dupname(Name, Pid) of
197
214
            true ->
198
215
                gen_server:multi_call(Nodes,
202
219
            _ ->
203
220
                no
204
221
        end
205
 
    end).
 
222
    end,
 
223
    ?trace({register_name, self(), Name, Pid, Method}),
 
224
    gen_server:call(global_name_server, {registrar, Fun}, infinity).
206
225
 
207
226
check_dupname(Name, Pid) ->
208
227
    case ets:lookup(global_pid_names, Pid) of
225
244
        undefined ->
226
245
            ok;
227
246
        _ ->
228
 
            trans_all_known(fun(Nodes) ->
 
247
            Fun = fun(Nodes) ->
229
248
                          gen_server:multi_call(Nodes,
230
249
                                                global_name_server,
231
250
                                                {unregister, Name}),
232
251
                          ok
233
 
                  end)
 
252
                  end,
 
253
            ?trace({unregister_name, self(), Name}),
 
254
            gen_server:call(global_name_server, {registrar, Fun}, infinity)
234
255
    end.
235
256
 
236
257
re_register_name(Name, Pid) when is_pid(Pid) ->
237
258
    re_register_name(Name, Pid, {?MODULE, random_exit_name}).
238
259
 
239
260
re_register_name(Name, Pid, Method) when is_pid(Pid) ->
240
 
    trans_all_known(fun(Nodes) ->
 
261
    Fun = fun(Nodes) ->
241
262
                  gen_server:multi_call(Nodes,
242
263
                                        global_name_server,
243
264
                                        {register, Name, Pid, Method}),
244
265
                  yes
245
 
          end).
 
266
          end,
 
267
    ?trace({re_register_name, self(), Name, Pid, Method}),
 
268
    gen_server:call(global_name_server, {registrar, Fun}, infinity).
246
269
 
247
270
registered_names() ->
248
 
    ets:select(global_names, ets:fun2ms(fun({Name,_Pid,_Meth}) -> Name end)).
 
271
    MS = ets:fun2ms(fun({Name,_Pid,_M,_RP,_R}) -> Name end),
 
272
    ets:select(global_names, MS).
249
273
 
250
274
%%-----------------------------------------------------------------
251
275
%% The external node (e.g. a C-node) registers the name on an Erlang
259
283
%%
260
284
%% Note: if the Erlang node dies an EXIT signal is also sent to the
261
285
%% C-node due to the link between the global_name_server and the
262
 
%% registered process.
 
286
%% registered process. [This is why the link has been kept despite
 
287
%% the fact that monitors do the job now.]
263
288
%%-----------------------------------------------------------------
264
289
register_name_external(Name, Pid) when is_pid(Pid) ->
265
290
    register_name_external(Name, Pid, {?MODULE, random_exit_name}).
266
291
 
267
292
register_name_external(Name, Pid, Method) when is_pid(Pid) ->
268
 
    trans_all_known(fun(Nodes) ->
 
293
    Fun = fun(Nodes) ->
269
294
                  case where(Name) of
270
295
                      undefined ->
271
296
                          gen_server:multi_call(Nodes,
275
300
                          yes;
276
301
                      _Pid -> no
277
302
                  end
278
 
          end).
 
303
          end,
 
304
    ?trace({register_name_external, self(), Name, Pid, Method}),
 
305
    gen_server:call(global_name_server, {registrar, Fun}, infinity).
279
306
 
280
307
unregister_name_external(Name) ->
281
308
    unregister_name(Name).
347
374
 
348
375
    _ = ets:new(global_pid_names, [bag, named_table, protected]),
349
376
    _ = ets:new(global_pid_ids, [bag, named_table, protected]),
350
 
    _ = ets:new(global_node_pids, [duplicate_bag, named_table, protected]),
351
 
 
352
 
    S = #state{the_locker = start_the_locker(),
353
 
               the_deleter = start_the_deleter(self())},
 
377
 
 
378
    %% This is for troubleshooting only.
 
379
    DoTrace = os:getenv("GLOBAL_HIGH_LEVEL_TRACE") =:= "TRUE",
 
380
    T0 = case DoTrace of
 
381
             true -> 
 
382
                 send_high_level_trace(),
 
383
                 [];
 
384
             false -> 
 
385
                 no_trace
 
386
         end,
 
387
 
 
388
    S = #state{the_locker = start_the_locker(DoTrace),
 
389
               trace = T0,
 
390
               the_deleter = start_the_deleter(self()),
 
391
               the_registrar = start_the_registrar()},
 
392
    S1 = trace_message(S, {init, node()}, []),
354
393
 
355
394
    case init:get_argument(connect_all) of
356
395
        {ok, [["false"]]} ->
357
 
            {ok, S#state{connect_all = false}};
 
396
            {ok, S1#state{connect_all = false}};
358
397
        _ ->
359
 
            {ok, S#state{connect_all = true}}
 
398
            {ok, S1#state{connect_all = true}}
360
399
    end.
361
400
 
362
401
%%-----------------------------------------------------------------
462
501
%%          then send to global_name_server {lock_is_set, Node, Tag}
463
502
%% 3. Connecting node's global_name_server informs other nodes in the same 
464
503
%%    partition about hitherto unknown nodes in the other partition
465
 
%%    {new_nodes, _Node, Ops, ListOfNamesExt, NewNodes, _Unused}
 
504
%%    {new_nodes, Node, Ops, ListOfNamesExt, NewNodes, ExtraInfo}
466
505
%% 4. Between global_name_server and resolver
467
506
%%    {resolve, NameList, Node} to resolver
468
507
%%    {exchange_ops, Node, Tag, Ops, Resolved} from resolver
475
514
    do_whereis(Name, From),
476
515
    {noreply, S};
477
516
 
478
 
handle_call({register, Name, Pid, Method}, _From, S) ->
479
 
    ins_name(Name, Pid, Method),
 
517
handle_call({registrar, Fun}, From, S) ->
 
518
    S#state.the_registrar ! {trans_all_known, Fun, From},
 
519
    {noreply, S};
 
520
 
 
521
%% The pattern {register,'_','_','_'} is traced by the inviso
 
522
%% application. Do not change.
 
523
handle_call({register, Name, Pid, Method}, {FromPid, _Tag}, S0) ->
 
524
    S = ins_name(Name, Pid, Method, FromPid, [], S0),
480
525
    {reply, yes, S};
481
526
 
482
 
handle_call({unregister, Name}, _From, S) ->
483
 
    delete_global_name(Name),
 
527
handle_call({unregister, Name}, _From, S0) ->
 
528
    S = delete_global_name2(Name, S0),
484
529
    {reply, ok, S};
485
530
 
486
 
handle_call({register_ext, Name, Pid, Method, RegNode}, _F, S) ->
487
 
    ins_name_ext(Name, Pid, Method, RegNode),
 
531
handle_call({register_ext, Name, Pid, Method, RegNode}, {FromPid,_Tag}, S0) ->
 
532
    S = ins_name_ext(Name, Pid, Method, RegNode, FromPid, [], S0),
488
533
    {reply, yes, S};
489
534
 
490
 
handle_call({set_lock, Lock}, {Pid, _Tag}, S) ->
491
 
    Reply = handle_set_lock(Lock, Pid),
 
535
handle_call({set_lock, Lock}, {Pid, _Tag}, S0) ->
 
536
    {Reply, S} = handle_set_lock(Lock, Pid, S0),
492
537
    {reply, Reply, S};
493
538
 
494
 
handle_call({del_lock, Lock}, {Pid, _Tag}, S) ->
495
 
    handle_del_lock(Lock, Pid),
 
539
handle_call({del_lock, Lock}, {Pid, _Tag}, S0) ->
 
540
    S = handle_del_lock(Lock, Pid, S0),
496
541
    {reply, true, S};
497
542
 
498
543
handle_call(get_known, _From, S) ->
517
562
handle_call(info, _From, S) ->
518
563
    {reply, S, S};
519
564
 
 
565
%% "High level trace". For troubleshooting only.
 
566
handle_call(high_level_trace_start, _From, S) ->
 
567
    S#state.the_locker ! {do_trace, true},
 
568
    send_high_level_trace(),
 
569
    {reply, ok, trace_message(S#state{trace = []}, {init, node()}, [])};
 
570
handle_call(high_level_trace_stop, _From, S) ->
 
571
    #state{the_locker = TheLocker, trace = Trace} = S,
 
572
    TheLocker ! {do_trace, false},
 
573
    wait_high_level_trace(),
 
574
    {reply, Trace, S#state{trace = no_trace}};
 
575
handle_call(high_level_trace_get, _From, #state{trace = Trace}=S) ->
 
576
    {reply, Trace, S#state{trace = []}};
 
577
 
520
578
handle_call(stop, _From, S) ->
521
 
    {stop, normal, stopped, S}.
 
579
    {stop, normal, stopped, S};
 
580
 
 
581
handle_call(Request, From, S) ->
 
582
    error_logger:warning_msg("The global_name_server "
 
583
                             "received an unexpected message:\n"
 
584
                             "handle_call(~p, ~p, _)\n", 
 
585
                             [Request, From]),
 
586
    {noreply, S}.
522
587
 
523
588
%%========================================================================
524
589
%% init_connect
552
617
%%
553
618
%% Ok, the lock is now set on both partitions. Send our names to other node.
554
619
%%=======================================================================
555
 
handle_cast({lock_is_set, Node, MyTag}, S) ->
 
620
handle_cast({lock_is_set, Node, MyTag, LockId}, S) ->
556
621
    %% Sent from the_locker at node().
557
622
    ?trace({'####', lock_is_set , {node,Node}}),
558
623
    case get({sync_tag_my, Node}) of
559
624
        MyTag ->
560
 
            lock_is_set(Node, S#state.resolvers),
 
625
            lock_is_set(Node, S#state.resolvers, LockId),
561
626
            {noreply, S};
562
627
        _ -> %% Illegal tag, delete the old sync session.
563
628
            NewS = cancel_locker(Node, S, MyTag),
586
651
%% resolve operations. Otherwise we have to save the operations and
587
652
%% wait for {resolve, ...}. This is very much like {lock_is_set, ...}
588
653
%% and {exchange, ...}.
589
 
handle_cast({exchange_ops, Node, MyTag, Ops, Resolved}, S) ->
 
654
handle_cast({exchange_ops, Node, MyTag, Ops, Resolved}, S0) ->
590
655
    %% Sent from the resolver for Node at node().
591
656
    ?trace({exchange_ops, {node,Node}, {ops,Ops},{resolved,Resolved},
592
657
            {mytag,MyTag}}),
 
658
    S = trace_message(S0, {exit_resolver, Node}, [MyTag]),
593
659
    case get({sync_tag_my, Node}) of
594
660
        MyTag ->
595
661
            Known = S#state.known,
641
707
%%
642
708
%% We get to know the other node's known nodes.
643
709
%%========================================================================
644
 
handle_cast({new_nodes, _Node, Ops, Names_ext, Nodes, _Nodes_v2}, S) ->
645
 
    %% Sent from global_name_server at _Node.
646
 
    ?trace({new_nodes, {node,_Node}, {ops,Ops}, {nodes,Nodes}}),
647
 
    NewS = new_nodes(Ops, Names_ext, Nodes, S),
 
710
handle_cast({new_nodes, Node, Ops, Names_ext, Nodes, ExtraInfo}, S) ->
 
711
    %% Sent from global_name_server at Node.
 
712
    ?trace({new_nodes, {node,Node},{ops,Ops},{nodes,Nodes},{x,ExtraInfo}}),
 
713
    NewS = new_nodes(Ops, Node, Names_ext, Nodes, ExtraInfo, S),
648
714
    {noreply, NewS};
649
715
 
650
716
%%========================================================================
665
731
    {noreply, NewS#state{synced = NSynced}};
666
732
 
667
733
%% Called when Pid on other node crashed
668
 
handle_cast({async_del_name, Name, Pid}, S) ->
 
734
handle_cast({async_del_name, _Name, _Pid}, S) ->
669
735
    %% Sent from the_deleter at some node in the partition but node().
670
 
    case ets:lookup(global_names, Name) of
671
 
        [{Name, Pid, _}] ->
672
 
            delete_global_name(Name, Pid);
673
 
        _ -> ok
674
 
    end,
 
736
    %% The DOWN message deletes the name.
675
737
    {noreply, S};
676
738
 
677
 
handle_cast({async_del_lock, _ResourceId, Pid}, S) ->
 
739
handle_cast({async_del_lock, _ResourceId, _Pid}, S) ->
678
740
    %% Sent from global_name_server at some node in the partition but node().
679
 
    async_del_lock(Pid),
 
741
    %% The DOWN message deletes the lock.
 
742
    {noreply, S};
 
743
 
 
744
handle_cast(Request, S) ->
 
745
    error_logger:warning_msg("The global_name_server "
 
746
                             "received an unexpected message:\n"
 
747
                             "handle_cast(~p, _)\n", [Request]),
680
748
    {noreply, S}.
681
749
 
682
750
handle_info({'EXIT', Deleter, _Reason}=Exit, #state{the_deleter=Deleter}=S) ->
683
751
    {stop, {deleter_died,Exit}, S#state{the_deleter=undefined}};
 
752
handle_info({'EXIT', Locker, _Reason}=Exit, #state{the_locker=Locker}=S) ->
 
753
    {stop, {locker_died,Exit}, S#state{the_locker=undefined}};
 
754
handle_info({'EXIT', Registrar, _}=Exit, #state{the_registrar=Registrar}=S) ->
 
755
    {stop, {registrar_died,Exit}, S#state{the_registrar=undefined}};
684
756
handle_info({'EXIT', Pid, _Reason}, S) when is_pid(Pid) ->
685
 
    ?trace({global_EXIT,Pid}),
686
 
    %% The process that died was either a synch process started by
687
 
    %% start_sync or a registered process.
688
 
    #state{the_deleter=Deleter, known = Known} = S,
689
 
    check_exit(Deleter, Pid, Known),
 
757
    ?trace({global_EXIT,_Reason,Pid}),
 
758
    %% The process that died was a synch process started by start_sync
 
759
    %% or a registered process running on an external node (C-node).
 
760
    %% Links to external names are ignored here (there are also DOWN
 
761
    %% signals).
690
762
    Syncers = lists:delete(Pid, S#state.syncers),
691
763
    {noreply, S#state{syncers = Syncers}};
692
764
 
695
767
    %% references to old node name (Node) to new node name ('nonode@nohost')
696
768
    {noreply, change_our_node_name(node(), S)};
697
769
 
698
 
handle_info({nodedown, Node}, S) ->
 
770
handle_info({nodedown, Node}, S0) ->
699
771
    ?trace({'####', nodedown, {node,Node}}),
700
 
    do_node_down(Node),
701
 
    #state{known = Known, synced = Syncs} = S,
702
 
    NewS = cancel_locker(Node, S, get({sync_tag_my, Node})),
703
 
    NewS#state.the_locker ! {remove_from_known, Node},
704
 
    reset_node_state(Node),
705
 
    {noreply, NewS#state{known = lists:delete(Node, Known),
706
 
                         synced = lists:delete(Node, Syncs)}};
 
772
    S1 = trace_message(S0, {nodedown, Node}, []),
 
773
    S = handle_nodedown(Node, S1),
 
774
    {noreply, S};
 
775
 
 
776
handle_info({extra_nodedown, Node}, S0) ->
 
777
    ?trace({'####', extra_nodedown, {node,Node}}),
 
778
    S1 = trace_message(S0, {extra_nodedown, Node}, []),
 
779
    S = handle_nodedown(Node, S1),
 
780
    {noreply, S};
707
781
 
708
782
handle_info({nodeup, Node}, S) when Node =:= node() ->
709
783
    ?trace({'####', local_nodeup, {node, Node}}),
711
785
    %% references to old node name ('nonode@nohost') to Node.
712
786
    {noreply, change_our_node_name(Node, S)};
713
787
 
714
 
handle_info({nodeup, Node}, S) when S#state.connect_all ->
715
 
    IsKnown = lists:member(Node, S#state.known) or
 
788
handle_info({nodeup, Node}, S0) when S0#state.connect_all ->
 
789
    IsKnown = lists:member(Node, S0#state.known) or
716
790
              %% This one is only for double nodeups (shouldn't occur!)
717
 
              lists:keymember(Node, 1, S#state.resolvers),
 
791
              lists:keymember(Node, 1, S0#state.resolvers),
718
792
    ?trace({'####', nodeup, {node,Node}, {isknown,IsKnown}}),
 
793
    S1 = trace_message(S0, {nodeup, Node}, []),
719
794
    case IsKnown of
720
795
        true ->
721
 
            {noreply, S};
 
796
            {noreply, S1};
722
797
        false ->
723
798
            resend_pre_connect(Node),
724
799
 
729
804
            MyTag = now(),
730
805
            put({sync_tag_my, Node}, MyTag),
731
806
            ?trace({sending_nodeup_to_locker, {node,Node},{mytag,MyTag}}),
732
 
            S#state.the_locker ! {nodeup, Node, MyTag},
 
807
            S1#state.the_locker ! {nodeup, Node, MyTag},
733
808
 
734
809
            %% In order to be compatible with unpatched R7 a locker
735
810
            %% process was spawned. Vsn 5 is no longer comptabible with
736
811
            %% vsn 3 nodes, so the locker process is no longer needed.
737
812
            %% The permanent locker takes its place.
738
813
            NotAPid = no_longer_a_pid,
739
 
            Locker = {locker, NotAPid, S#state.known, S#state.the_locker},
 
814
            Locker = {locker, NotAPid, S1#state.known, S1#state.the_locker},
740
815
            InitC = {init_connect, {?vsn, MyTag}, node(), Locker},
741
 
            Rs = S#state.resolvers,
 
816
            Rs = S1#state.resolvers,
742
817
            ?trace({casting_init_connect, {node,Node},{initmessage,InitC},
743
818
                    {resolvers,Rs}}),
744
819
            gen_server:cast({global_name_server, Node}, InitC),
745
820
            Resolver = start_resolver(Node, MyTag),
 
821
            S = trace_message(S1, {new_resolver, Node}, [MyTag, Resolver]),
746
822
            {noreply, S#state{resolvers = [{Node, MyTag, Resolver} | Rs]}}
747
823
    end;
748
824
 
754
830
    io:format(">>>> ~p\n",[S#state.known]),
755
831
    {noreply, S};
756
832
 
757
 
handle_info(_Message, S) ->
 
833
%% "High level trace". For troubleshooting only.
 
834
handle_info(high_level_trace, S) ->
 
835
    case S of 
 
836
        #state{trace = [{Node, _Time, _M, Nodes, _X} | _]} ->
 
837
            send_high_level_trace(),
 
838
            CNode = node(),
 
839
            CNodes = nodes(),
 
840
            case {CNode, CNodes} of
 
841
                {Node, Nodes} ->
 
842
                    {noreply, S};
 
843
                _ ->
 
844
                    {New, _, Old} = 
 
845
                        sofs:symmetric_partition(sofs:set([CNode|CNodes]),
 
846
                                                 sofs:set([Node|Nodes])),
 
847
                    M = {nodes_changed, {sofs:to_external(New),
 
848
                                         sofs:to_external(Old)}},
 
849
                    {noreply, trace_message(S, M, [])}
 
850
            end;
 
851
        _ ->
 
852
            {noreply, S}
 
853
    end;
 
854
handle_info({trace_message, M}, S) ->
 
855
    {noreply, trace_message(S, M, [])};
 
856
handle_info({trace_message, M, X}, S) ->
 
857
    {noreply, trace_message(S, M, X)};
 
858
 
 
859
handle_info({'DOWN', MonitorRef, process, _Pid, _Info}, S0) ->
 
860
    S1 = delete_lock(MonitorRef, S0),
 
861
    S = del_name(MonitorRef, S1),
 
862
    {noreply, S};
 
863
 
 
864
handle_info(Message, S) ->
 
865
    error_logger:warning_msg("The global_name_server "
 
866
                             "received an unexpected message:\n"
 
867
                             "handle_info(~p, _)\n", [Message]),
758
868
    {noreply, S}.
759
869
 
 
870
 
760
871
%%========================================================================
761
872
%%========================================================================
762
873
%%=============================== Internal Functions =====================
763
874
%%========================================================================
764
875
%%========================================================================
765
876
 
 
877
-define(HIGH_LEVEL_TRACE_INTERVAL, 500). % ms
 
878
 
 
879
wait_high_level_trace() ->
 
880
    receive
 
881
        high_level_trace ->
 
882
            ok
 
883
    after ?HIGH_LEVEL_TRACE_INTERVAL+1 ->
 
884
            ok
 
885
    end.
 
886
 
 
887
send_high_level_trace() ->
 
888
    erlang:send_after(?HIGH_LEVEL_TRACE_INTERVAL, self(), high_level_trace).
 
889
 
766
890
-define(GLOBAL_RID, global).
767
891
 
768
892
%% Similar to trans(Id, Fun), but always uses global's own lock
774
898
    try
775
899
        Fun(Nodes)
776
900
    after
777
 
        del_lock(Id, Nodes)
 
901
        delete_global_lock(Id, Nodes)
778
902
    end.
779
903
 
780
904
set_lock_known(Id, Times) -> 
781
905
    Known = get_known(),
782
906
    Nodes = [node() | Known],
783
 
    Boss = lists:max(Nodes),
 
907
    Boss = the_boss(Nodes),
784
908
    %% Use the  same convention (a boss) as lock_nodes_safely. Optimization.
785
909
    case set_lock_on_nodes(Id, [Boss]) of
786
910
        true ->
876
1000
%% the exchange instead. In the lock_is_set we must first check if
877
1001
%% exchange info is stored, in that case we take care of it.
878
1002
%%========================================================================
879
 
lock_is_set(Node, Resolvers) ->
 
1003
lock_is_set(Node, Resolvers, LockId) ->
880
1004
    gen_server:cast({global_name_server, Node},
881
1005
                    {exchange, node(), get_names(), _ExtNames = [],
882
1006
                     get({sync_tag_his, Node})}),
 
1007
    put({lock_id, Node}, LockId),
883
1008
    %% If both have the lock, continue with exchange.
884
1009
    case get({wait_lock, Node}) of
885
1010
        {exchange, NameList} ->
904
1029
            put({wait_lock, Node}, {exchange, NameList})
905
1030
    end.
906
1031
 
907
 
resolved(Node, HisResolved, HisKnown, Names_ext, S) ->
 
1032
resolved(Node, HisResolved, HisKnown, Names_ext, S0) ->
908
1033
    Ops = erase({save_ops, Node}) ++ HisResolved,
909
1034
    %% Known may have shrunk since the lock was taken (due to nodedowns).
910
 
    Known = S#state.known,
911
 
    Synced = S#state.synced,
 
1035
    Known = S0#state.known,
 
1036
    Synced = S0#state.synced,
912
1037
    NewNodes = [Node | HisKnown],
913
1038
    sync_others(HisKnown),
914
 
    do_ops(Ops, Names_ext),
915
 
    gen_server:abcast(Known, global_name_server,
916
 
                      {new_nodes, node(), Ops, Names_ext, NewNodes,NewNodes}),
 
1039
    ExtraInfo = [{vsn,get({prot_vsn, Node})}, {lock, get({lock_id, Node})}],
 
1040
    S = do_ops(Ops, node(), Names_ext, ExtraInfo, S0),
917
1041
    %% I am synced with Node, but not with HisKnown yet
918
1042
    lists:foreach(fun(Pid) -> Pid ! {synced, [Node]} end, S#state.syncers),
919
 
    NewS = lists:foldl(fun(Node1, S1) -> 
920
 
                               Tag1 = get({sync_tag_my, Node1}),
921
 
                               ?trace({calling_cancel_locker,Tag1,get()}),
922
 
                               S2 = cancel_locker(Node1, S1, Tag1),
923
 
                               reset_node_state(Node1),
924
 
                               S2
925
 
                       end, S, NewNodes),
 
1043
    S3 = lists:foldl(fun(Node1, S1) -> 
 
1044
                             F = fun(Tag) -> cancel_locker(Node1,S1,Tag) end,
 
1045
                             cancel_resolved_locker(Node1, F)
 
1046
                     end, S, HisKnown),
 
1047
    %% The locker that took the lock is asked to send 
 
1048
    %% the {new_nodes, ...} message. This ensures that
 
1049
    %% {del_lock, ...} is received after {new_nodes, ...} 
 
1050
    %% (except when abcast spawns process(es)...).
 
1051
    NewNodesF = fun() ->
 
1052
                        gen_server:abcast(Known, global_name_server,
 
1053
                                          {new_nodes, node(), Ops, Names_ext,
 
1054
                                           NewNodes, ExtraInfo})
 
1055
                end,
 
1056
    F = fun(Tag) -> cancel_locker(Node, S3, Tag, NewNodesF) end,
 
1057
    S4 = cancel_resolved_locker(Node, F),
926
1058
    %% See (*) below... we're node b in that description
927
1059
    AddedNodes = (NewNodes -- Known),
928
1060
    NewKnown = Known ++ AddedNodes,
929
 
    NewS#state.the_locker ! {add_to_known, AddedNodes},
 
1061
    S4#state.the_locker ! {add_to_known, AddedNodes},
 
1062
    NewS = trace_message(S4, {added, AddedNodes}, 
 
1063
                         [{new_nodes, NewNodes}, {abcast, Known}, {ops,Ops}]),
930
1064
    NewS#state{known = NewKnown, synced = [Node | Synced]}.
931
1065
 
932
 
new_nodes(Ops, Names_ext, Nodes, S) ->
933
 
    Known = S#state.known,
 
1066
cancel_resolved_locker(Node, CancelFun) ->
 
1067
    Tag = get({sync_tag_my, Node}),
 
1068
    ?trace({calling_cancel_locker,Tag,get()}),
 
1069
    S = CancelFun(Tag),
 
1070
    reset_node_state(Node),
 
1071
    S.
 
1072
 
 
1073
new_nodes(Ops, ConnNode, Names_ext, Nodes, ExtraInfo, S0) ->
 
1074
    Known = S0#state.known,
934
1075
    %% (*) This one requires some thought...
935
1076
    %% We're node a, other nodes b and c:
936
1077
    %% The problem is that {in_sync, a} may arrive before {resolved, [a]} to
937
1078
    %% b from c, leading to b sending {new_nodes, [a]} to us (node a).
938
1079
    %% Therefore, we make sure we never get duplicates in Known.
939
 
    NewNodes = lists:delete(node(), Nodes -- Known),
940
 
    sync_others(NewNodes),
941
 
    do_ops(Ops, Names_ext),
942
 
    ?trace({new_nodes_in_sync,{new_nodes,NewNodes}}),
943
 
    S#state.the_locker ! {add_to_known, NewNodes},
944
 
    S#state{known = Known ++ NewNodes}.
 
1080
    AddedNodes = lists:delete(node(), Nodes -- Known),
 
1081
    sync_others(AddedNodes),
 
1082
    S = do_ops(Ops, ConnNode, Names_ext, ExtraInfo, S0),
 
1083
    ?trace({added_nodes_in_sync,{added_nodes,AddedNodes}}),
 
1084
    S#state.the_locker ! {add_to_known, AddedNodes},
 
1085
    S1 = trace_message(S, {added, AddedNodes}, [{ops,Ops}]),
 
1086
    S1#state{known = Known ++ AddedNodes}.
945
1087
 
946
1088
do_whereis(Name, From) ->
947
 
    case is_lock_set(?GLOBAL_RID) of
 
1089
    case is_global_lock_set() of
948
1090
        false ->
949
1091
            gen_server:reply(From, where(Name));
950
1092
        true ->
956
1098
    true = ets:delete(global_names_ext),
957
1099
    true = ets:delete(global_locks),
958
1100
    true = ets:delete(global_pid_names),
959
 
    true = ets:delete(global_pid_ids),
960
 
    true = ets:delete(global_node_pids).
 
1101
    true = ets:delete(global_pid_ids).
961
1102
 
962
1103
code_change(_OldVsn, S, _Extra) ->
963
1104
    {ok, S}.
989
1130
            ok
990
1131
    end.
991
1132
 
992
 
ins_name(Name, Pid, Method) ->
 
1133
ins_name(Name, Pid, Method, FromPidOrNode, ExtraInfo, S0) ->
993
1134
    ?trace({ins_name,insert,{name,Name},{pid,Pid}}),
994
 
    delete_global_name(Name),
995
 
    dolink(Pid),
996
 
    insert_global_name(Name, Pid, Method, node(Pid)).
 
1135
    S1 = delete_global_name_keep_pid(Name, S0),
 
1136
    S = trace_message(S1, {ins_name, node(Pid)}, [Name, Pid]),
 
1137
    insert_global_name(Name, Pid, Method, FromPidOrNode, ExtraInfo, S).
997
1138
 
998
 
ins_name_ext(Name, Pid, Method, RegNode) ->
 
1139
ins_name_ext(Name, Pid, Method, RegNode, FromPidOrNode, ExtraInfo, S0) ->
999
1140
    ?trace({ins_name_ext, {name,Name}, {pid,Pid}}),
1000
 
    delete_global_name(Name),
 
1141
    S1 = delete_global_name_keep_pid(Name, S0),
1001
1142
    dolink_ext(Pid, RegNode),
1002
 
    insert_global_name(Name, Pid, Method, RegNode),
1003
 
    true = ets:insert(global_names_ext, {Name, Pid, RegNode}).
 
1143
    S = trace_message(S1, {ins_name_ext, node(Pid)}, [Name, Pid]),
 
1144
    true = ets:insert(global_names_ext, {Name, Pid, RegNode}),
 
1145
    insert_global_name(Name, Pid, Method, FromPidOrNode, ExtraInfo, S).
1004
1146
 
1005
1147
where(Name) ->
1006
1148
    case ets:lookup(global_names, Name) of
1007
 
        [{_, Pid, _}] -> Pid;
 
1149
        [{_Name, Pid, _Method, _RPid, _Ref}] -> Pid;
1008
1150
        [] -> undefined
1009
1151
    end.
1010
1152
 
1011
 
handle_set_lock(Id, Pid) ->
 
1153
handle_set_lock(Id, Pid, S) ->
1012
1154
    ?trace({handle_set_lock, Id, Pid}),
1013
1155
    case can_set_lock(Id) of
1014
 
        {true, Pids} ->
1015
 
            case lists:member(Pid, Pids) of
1016
 
                true -> true;
1017
 
                false -> insert_lock(Id, Pid, Pids)
 
1156
        {true, PidRefs} ->
 
1157
            case pid_is_locking(Pid, PidRefs) of
 
1158
                true -> 
 
1159
                    {true, S};
 
1160
                false -> 
 
1161
                    {true, insert_lock(Id, Pid, PidRefs, S)}
1018
1162
            end;
1019
1163
        false=Reply ->
1020
 
            Reply
 
1164
            {Reply, S}
1021
1165
    end.
1022
1166
 
1023
1167
can_set_lock({ResourceId, LockRequesterId}) ->
1024
1168
    case ets:lookup(global_locks, ResourceId) of
1025
 
        [{ResourceId, LockRequesterId, Pids}] ->
1026
 
            {true, Pids};
1027
 
        [{ResourceId, _LockRequesterId2, _Pids}] ->
 
1169
        [{ResourceId, LockRequesterId, PidRefs}] ->
 
1170
            {true, PidRefs};
 
1171
        [{ResourceId, _LockRequesterId2, _PidRefs}] ->
1028
1172
            false;
1029
1173
        [] ->
1030
1174
            {true, []}
1031
1175
    end.
1032
1176
 
1033
 
insert_lock({ResourceId, LockRequesterId}, Pid, Pids) ->
1034
 
    dolink(Pid),
 
1177
insert_lock({ResourceId, LockRequesterId}=Id, Pid, PidRefs, S) ->
 
1178
    {RPid, Ref} = do_monitor(Pid),
1035
1179
    true = ets:insert(global_pid_ids, {Pid, ResourceId}),
1036
 
    true = ets:insert(global_node_pids, {{lock,node(Pid)}, Pid}),
1037
 
    Lock = {ResourceId, LockRequesterId, [Pid | Pids]},
1038
 
    true = ets:insert(global_locks, Lock).
 
1180
    true = ets:insert(global_pid_ids, {Ref, ResourceId}),
 
1181
    Lock = {ResourceId, LockRequesterId, [{Pid,RPid,Ref} | PidRefs]},
 
1182
    true = ets:insert(global_locks, Lock),
 
1183
    trace_message(S, {ins_lock, node(Pid)}, [Id, Pid]).
 
1184
 
 
1185
is_global_lock_set() ->
 
1186
    is_lock_set(?GLOBAL_RID).
1039
1187
 
1040
1188
is_lock_set(ResourceId) ->
1041
1189
    ets:member(global_locks, ResourceId).
1042
1190
 
1043
 
handle_del_lock({ResourceId, LockRequesterId}, Pid) ->
1044
 
    ?trace({handle_del_lock, {pid,Pid},{id,{ResourceId, LockRequesterId}}}),
 
1191
handle_del_lock({ResourceId, LockReqId}, Pid, S0) ->
 
1192
    ?trace({handle_del_lock, {pid,Pid},{id,{ResourceId, LockReqId}}}),
1045
1193
    case ets:lookup(global_locks, ResourceId) of
1046
 
        [{ResourceId, LockRequesterId, Pids}]->
1047
 
            remove_lock(ResourceId, LockRequesterId, Pid, Pids),
1048
 
            dounlink(Pid);
1049
 
        _ -> ok
 
1194
        [{ResourceId, LockReqId, PidRefs}]->
 
1195
            remove_lock(ResourceId, LockReqId, Pid, PidRefs, false, S0);
 
1196
        _ -> S0
1050
1197
    end.
1051
1198
 
1052
 
remove_lock(ResourceId, _LockRequesterId, Pid, [Pid]) ->
 
1199
remove_lock(ResourceId, LockRequesterId, Pid, [{Pid,RPid,Ref}], Down, S0) ->
1053
1200
    ?trace({remove_lock_1, {id,ResourceId},{pid,Pid}}),
 
1201
    true = erlang:demonitor(Ref, [flush]),
 
1202
    kill_monitor_proc(RPid, Pid),
1054
1203
    true = ets:delete(global_locks, ResourceId),
1055
 
    true = ets:delete_object(global_node_pids, {{lock,node(Pid)}, Pid}),
1056
 
    true = ets:delete_object(global_pid_ids, {Pid, ResourceId});
1057
 
remove_lock(ResourceId, LockRequesterId, Pid, Pids) ->
 
1204
    true = ets:delete_object(global_pid_ids, {Pid, ResourceId}),
 
1205
    true = ets:delete_object(global_pid_ids, {Ref, ResourceId}),
 
1206
    S = case ResourceId of
 
1207
            ?GLOBAL_RID -> S0#state{global_lock_down = Down};
 
1208
            _ -> S0
 
1209
        end,
 
1210
    trace_message(S, {rem_lock, node(Pid)}, 
 
1211
                  [{ResourceId, LockRequesterId}, Pid]);
 
1212
remove_lock(ResourceId, LockRequesterId, Pid, PidRefs0, _Down, S) ->
1058
1213
    ?trace({remove_lock_2, {id,ResourceId},{pid,Pid}}),
1059
 
    Lock = {ResourceId, LockRequesterId, lists:delete(Pid, Pids)},
 
1214
    PidRefs = case lists:keysearch(Pid, 1, PidRefs0) of
 
1215
                  {value, {Pid, RPid, Ref}} ->
 
1216
                      true = erlang:demonitor(Ref, [flush]),
 
1217
                      kill_monitor_proc(RPid, Pid),
 
1218
                      true = ets:delete_object(global_pid_ids, 
 
1219
                                               {Ref, ResourceId}),
 
1220
                      lists:keydelete(Pid, 1, PidRefs0);
 
1221
                  false ->
 
1222
                      PidRefs0
 
1223
              end,
 
1224
    Lock = {ResourceId, LockRequesterId, PidRefs},
1060
1225
    true = ets:insert(global_locks, Lock),
1061
 
    true = ets:delete_object(global_node_pids, {{lock,node(Pid)}, Pid}),
1062
 
    true = ets:delete_object(global_pid_ids, {Pid, ResourceId}).
1063
 
 
1064
 
do_ops(Ops, Names_ext) ->
 
1226
    true = ets:delete_object(global_pid_ids, {Pid, ResourceId}),
 
1227
    trace_message(S, {rem_lock, node(Pid)}, 
 
1228
                  [{ResourceId, LockRequesterId}, Pid]).
 
1229
 
 
1230
kill_monitor_proc(Pid, Pid) ->
 
1231
    ok;
 
1232
kill_monitor_proc(RPid, _Pid) ->
 
1233
    exit(RPid, kill).
 
1234
 
 
1235
do_ops(Ops, ConnNode, Names_ext, ExtraInfo, S0) ->
1065
1236
    ?trace({do_ops, {ops,Ops}}),
1066
1237
 
1067
1238
    XInserts = [{Name, Pid, RegNode, Method} || 
1068
1239
                   {Name2, Pid2, RegNode} <- Names_ext,
1069
1240
                   {insert, {Name, Pid, Method}} <- Ops,
1070
1241
                   Name =:= Name2, Pid =:= Pid2],
1071
 
    lists:foreach(fun({Name, Pid, RegNode, Method}) ->
1072
 
                     ins_name_ext(Name, Pid, Method, RegNode)
1073
 
                  end, XInserts),
 
1242
    S1 = lists:foldl(fun({Name, Pid, RegNode, Method}, S1) ->
 
1243
                             ins_name_ext(Name, Pid, Method, RegNode, 
 
1244
                                          ConnNode, ExtraInfo, S1)
 
1245
                     end, S0, XInserts),
1074
1246
 
1075
1247
    XNames = [Name || {Name, _Pid, _RegNode, _Method} <- XInserts],
1076
1248
    Inserts = [{Name, Pid, node(Pid), Method} || 
1077
1249
                  {insert, {Name, Pid, Method}} <- Ops,
1078
1250
                  not lists:member(Name, XNames)],
1079
 
    lists:foreach(fun({Name, Pid, _RegNode, Method}) ->
1080
 
                     ins_name(Name, Pid, Method)
1081
 
                  end, Inserts),
 
1251
    S2 = lists:foldl(fun({Name, Pid, _RegNode, Method}, S2) ->
 
1252
                            ins_name(Name, Pid, Method, ConnNode, 
 
1253
                                     ExtraInfo, S2)
 
1254
                    end, S1, Inserts),
1082
1255
 
1083
1256
    DelNames = [Name || {delete, Name} <- Ops],
1084
 
    lists:foreach(fun(Name) -> delete_global_name(Name) end, DelNames).
 
1257
    lists:foldl(fun(Name, S) -> delete_global_name2(Name, S) 
 
1258
                end, S2, DelNames).
1085
1259
 
1086
1260
%% It is possible that a node that was up and running when the
1087
1261
%% operations were assembled has since died. The final {in_sync,...}
1116
1290
            ?trace({missing_nodedown, {node, Node}}),
1117
1291
            error_logger:warning_msg("global: ~w failed to connect to ~w\n",
1118
1292
                                     [node(), Node]),
1119
 
            global_name_server ! {nodedown, Node}
 
1293
            global_name_server ! {extra_nodedown, Node}
1120
1294
    after 0 ->
1121
1295
            gen_server:cast({global_name_server,Node}, {in_sync,node(),true})
1122
1296
    end.
1123
1297
    % monitor_node(Node, false),
1124
1298
    % exit(normal).
1125
1299
 
1126
 
insert_global_name(Name, Pid, Method, Node) ->
 
1300
insert_global_name(Name, Pid, Method, FromPidOrNode, ExtraInfo, S) ->
 
1301
    {RPid, Ref} = do_monitor(Pid),
 
1302
    true = ets:insert(global_names, {Name, Pid, Method, RPid, Ref}),
1127
1303
    true = ets:insert(global_pid_names, {Pid, Name}),
1128
 
    true = ets:insert(global_names, {Name, Pid, Method}),
1129
 
    true = ets:insert(global_node_pids, {{name,Node}, Pid}).
1130
 
 
1131
 
delete_global_name(Name) ->
1132
 
    case ets:lookup(global_names, Name) of
1133
 
        [{Name, Pid, _}] ->
1134
 
            delete_global_name(Name, Pid);
1135
 
        [] ->
 
1304
    true = ets:insert(global_pid_names, {Ref, Name}),
 
1305
    case lock_still_set(FromPidOrNode, ExtraInfo, S) of
 
1306
        true -> 
 
1307
            S;
 
1308
        false ->
 
1309
            %% The node that took the lock has gone down and then up
 
1310
            %% again. The {register, ...} or {new_nodes, ...} message
 
1311
            %% was delayed and arrived after nodeup (maybe it caused
 
1312
            %% the nodeup). The DOWN signal from the monitor of the
 
1313
            %% lock has removed the lock. 
 
1314
            %% Note: it is assumed here that the DOWN signal arrives
 
1315
            %% _before_ nodeup and any message that caused nodeup.
 
1316
            %% This is true of Erlang/OTP.
 
1317
            delete_global_name2(Name, S)
 
1318
    end.
 
1319
 
 
1320
lock_still_set(PidOrNode, ExtraInfo, S) ->
 
1321
    case ets:lookup(global_locks, ?GLOBAL_RID) of
 
1322
        [{?GLOBAL_RID, _LockReqId, PidRefs}] when is_pid(PidOrNode) -> 
 
1323
            %% Name registration.
 
1324
            lists:keymember(PidOrNode, 1, PidRefs);
 
1325
        [{?GLOBAL_RID, LockReqId, PidRefs}] when is_atom(PidOrNode) ->
 
1326
            case extra_info(lock, ExtraInfo) of
 
1327
                {?GLOBAL_RID, LockId} -> % R11B-4 or later
 
1328
                    LockReqId =:= LockId;
 
1329
                undefined ->
 
1330
                    lock_still_set_old(PidOrNode, LockReqId, PidRefs)
 
1331
            end;
 
1332
        [] ->
 
1333
            %% If the global lock was not removed by a DOWN message
 
1334
            %% then we have a node that do not monitor locking pids
 
1335
            %% (pre R11B-3), or an R11B-3 node (which does not ensure
 
1336
            %% that {new_nodes, ...} arrives before {del_lock, ...}).
 
1337
            not S#state.global_lock_down
 
1338
    end.
 
1339
 
 
1340
%%% The following is probably overkill. It is possible that this node
 
1341
%%% has been locked again, but it is a rare occasion.
 
1342
lock_still_set_old(_Node, ReqId, _PidRefs) when is_pid(ReqId) ->
 
1343
    %% Cannot do better than return true.
 
1344
    true;
 
1345
lock_still_set_old(Node, ReqId, PidRefs) when is_list(ReqId) ->
 
1346
    %% Connection, version > 4, but before R11B-4.
 
1347
    [P || {P, _RPid, _Ref} <- PidRefs, node(P) =:= Node] =/= [].
 
1348
 
 
1349
extra_info(Tag, ExtraInfo) ->
 
1350
    %% ExtraInfo used to be a list of nodes (vsn 2).
 
1351
    case catch lists:keysearch(Tag, 1, ExtraInfo) of
 
1352
        {value, {Tag, Info}} ->
 
1353
            Info;
 
1354
        _ ->
 
1355
            undefined
 
1356
    end.
 
1357
 
 
1358
del_name(Ref, S) ->
 
1359
    NameL = [{Name, Pid} || 
 
1360
                {_, Name} <- ets:lookup(global_pid_names, Ref),
 
1361
                {_, Pid, _Method, _RPid, Ref1} <- 
 
1362
                    ets:lookup(global_names, Name),
 
1363
                Ref1 =:= Ref],
 
1364
    ?trace({async_del_name, self(), NameL, Ref}),
 
1365
    case NameL of
 
1366
        [{Name, Pid}] ->
 
1367
            del_names(Name, Pid, S),
 
1368
            delete_global_name2(Name, S);
 
1369
        [] ->
 
1370
            S
 
1371
    end.
 
1372
 
 
1373
%% Send {async_del_name, ...} to old nodes (pre R11B-3).
 
1374
del_names(Name, Pid, S) ->
 
1375
    Send = case ets:lookup(global_names_ext, Name) of
 
1376
               [{Name, Pid, RegNode}] ->
 
1377
                   RegNode =:= node();
 
1378
               [] ->
 
1379
                   node(Pid) =:= node()
 
1380
           end,
 
1381
    if 
 
1382
        Send ->
 
1383
            ?trace({del_names, {pid,Pid}, {name,Name}}),
 
1384
            S#state.the_deleter ! {delete_name, self(), Name, Pid};
 
1385
        true ->
1136
1386
            ok
1137
1387
    end.
1138
1388
 
1139
 
delete_global_name(Name, Pid) ->
 
1389
%% Keeps the entry in global_names for whereis_name/1.
 
1390
delete_global_name_keep_pid(Name, S) ->
 
1391
    case ets:lookup(global_names, Name) of
 
1392
        [{Name, Pid, _Method, RPid, Ref}] ->
 
1393
            delete_global_name2(Name, Pid, RPid, Ref, S);
 
1394
        [] ->
 
1395
            S
 
1396
    end.
 
1397
 
 
1398
delete_global_name2(Name, S) ->
 
1399
    case ets:lookup(global_names, Name) of
 
1400
        [{Name, Pid, _Method, RPid, Ref}] ->
 
1401
            true = ets:delete(global_names, Name),
 
1402
            delete_global_name2(Name, Pid, RPid, Ref, S);
 
1403
        [] ->
 
1404
            S
 
1405
    end.
 
1406
 
 
1407
delete_global_name2(Name, Pid, RPid, Ref, S) ->
 
1408
    true = erlang:demonitor(Ref, [flush]),
 
1409
    kill_monitor_proc(RPid, Pid),
 
1410
    delete_global_name(Name, Pid),
1140
1411
    ?trace({delete_global_name,{item,Name},{pid,Pid}}),
1141
 
    true = ets:delete(global_names, Name),
1142
1412
    true = ets:delete_object(global_pid_names, {Pid, Name}),
 
1413
    true = ets:delete_object(global_pid_names, {Ref, Name}),
1143
1414
    case ets:lookup(global_names_ext, Name) of
1144
1415
        [{Name, Pid, RegNode}] ->
1145
1416
            true = ets:delete(global_names_ext, Name),
1146
1417
            ?trace({delete_global_name, {name,Name,{pid,Pid},{RegNode,Pid}}}),
1147
 
            true = ets:delete_object(global_node_pids, {{name,RegNode}, Pid}),
1148
1418
            dounlink_ext(Pid, RegNode);
1149
1419
        [] ->
1150
1420
            ?trace({delete_global_name,{name,Name,{pid,Pid},{node(Pid),Pid}}}),
1151
 
            true = ets:delete_object(global_node_pids,{{name,node(Pid)},Pid}),
1152
 
            dounlink(Pid)
1153
 
    end.
 
1421
            ok
 
1422
    end,
 
1423
    trace_message(S, {del_name, node(Pid)}, [Name, Pid]).
 
1424
 
 
1425
%% delete_global_name/2 is traced by the inviso application. 
 
1426
%% Do not change.
 
1427
delete_global_name(_Name, _Pid) ->
 
1428
    ok.
1154
1429
 
1155
1430
%%-----------------------------------------------------------------
1156
1431
%% The locker is a satellite process to global_name_server. When a
1170
1445
-define(locker_vsn, 2).
1171
1446
 
1172
1447
-record(multi, 
1173
 
        {local = [],         % Requests from nodes on the local host.
1174
 
         remote = [],        % Other requests.
1175
 
         known = [],         % Copy of global_name_server's known nodes. It's
1176
 
                             % faster to keep a copy of known than to asking 
1177
 
                             % for it when needed.
1178
 
         the_boss,           % max([node() | 'known'])
1179
 
         just_synced = false % true if node() synced just a moment ago
 
1448
        {local = [],          % Requests from nodes on the local host.
 
1449
         remote = [],         % Other requests.
 
1450
         known = [],          % Copy of global_name_server's known nodes. It's
 
1451
                              % faster to keep a copy of known than asking 
 
1452
                              % for it when needed.
 
1453
         the_boss,            % max([node() | 'known'])
 
1454
         just_synced = false, % true if node() synced just a moment ago
 
1455
                              %% Statistics:
 
1456
         do_trace             % bool()
1180
1457
        }).
1181
1458
 
1182
1459
-record(him, {node, locker, vsn, my_tag}).
1183
1460
 
1184
 
start_the_locker() ->
1185
 
    spawn_link(fun() -> init_the_locker() end).
 
1461
start_the_locker(DoTrace) ->
 
1462
    spawn_link(fun() -> init_the_locker(DoTrace) end).
1186
1463
 
1187
 
init_the_locker() ->
 
1464
init_the_locker(DoTrace) ->
1188
1465
    process_flag(trap_exit, true),    % needed?
1189
 
    S1 = update_locker_known({add, get_known()}, #multi{}),
 
1466
    S0 = #multi{do_trace = DoTrace},
 
1467
    S1 = update_locker_known({add, get_known()}, S0),
1190
1468
    loop_the_locker(S1),
1191
1469
    erlang:error(locker_exited).
1192
1470
 
1220
1498
                Message when element(1, Message) =/= nodeup ->
1221
1499
                    the_locker_message(Message, S1)
1222
1500
            after Timeout ->
1223
 
                    case is_lock_set(?GLOBAL_RID) of
 
1501
                    case is_global_lock_set() of
1224
1502
                        true -> 
1225
1503
                            loop_the_locker(S1);
1226
1504
                        false -> 
1244
1522
            Him = #him{node = node(HisTheLocker), my_tag = MyTag,
1245
1523
                       locker = HisTheLocker, vsn = HisVsn},
1246
1524
            loop_the_locker(add_node(Him, S));
1247
 
        {cancel, Node, _Tag} when node(HisTheLocker) =:= Node ->
 
1525
        {cancel, Node, _Tag, no_fun} when node(HisTheLocker) =:= Node ->
1248
1526
            loop_the_locker(S)
1249
1527
    after 60000 ->
1250
1528
            ?trace({nodeupnevercame, node(HisTheLocker)}),
1252
1530
                                   [node(), node(HisTheLocker)]),
1253
1531
            loop_the_locker(S#multi{just_synced = false})
1254
1532
    end;
1255
 
the_locker_message({cancel, _Node, undefined}, S) ->
 
1533
the_locker_message({cancel, _Node, undefined, no_fun}, S) ->
1256
1534
    ?trace({cancel_the_locker, undefined, {node,_Node}}),
1257
1535
    %% If we actually cancel something when a cancel message with the
1258
1536
    %% tag 'undefined' arrives, we may be acting on an old nodedown,
1259
1537
    %% to cancel a new nodeup, so we can't do that.
1260
1538
    loop_the_locker(S);
1261
 
the_locker_message({cancel, Node, Tag}, S) ->
 
1539
the_locker_message({cancel, Node, Tag, no_fun}, S) ->
1262
1540
    ?trace({the_locker, cancel, {multi,S}, {tag,Tag},{node,Node}}),
1263
1541
    receive
1264
1542
        {nodeup, Node, Tag} ->
1285
1563
            case IsLockSet of
1286
1564
                true ->
1287
1565
                    gen_server:cast(global_name_server, 
1288
 
                                    {lock_is_set, Node, MyTag}),
 
1566
                                    {lock_is_set, Node, MyTag, LockId}),
1289
1567
                    ?trace({lock_sync_done, {pid,Pid}, 
1290
1568
                            {node,node(Pid)}, {me,self()}}),
1291
1569
                    %% Wait for global to tell us to remove lock.
1293
1571
                    %% global_name_server will receive nodedown, and
1294
1572
                    %% then send {cancel, Node, Tag}.
1295
1573
                    receive
1296
 
                        {cancel, Node, _Tag} ->
 
1574
                        {cancel, Node, _Tag, Fun} ->
1297
1575
                            ?trace({cancel_the_lock,{node,Node}}),
1298
 
                            del_lock(LockId, Known2)
 
1576
                            call_fun(Fun),
 
1577
                            delete_global_lock(LockId, Known2)
1299
1578
                    end,
1300
1579
                    S2 = S1#multi{just_synced = true},
1301
1580
                    loop_the_locker(remove_node(Node, S2));
1313
1592
the_locker_message({remove_from_known, Node}, S) ->
1314
1593
    S1 = update_locker_known({remove, Node}, S),
1315
1594
    loop_the_locker(S1);
1316
 
the_locker_message(_Other, S) ->
1317
 
    ?trace({the_locker, {other_msg, _Other}}),
 
1595
the_locker_message({do_trace, DoTrace}, S) ->
 
1596
    loop_the_locker(S#multi{do_trace = DoTrace});
 
1597
the_locker_message(Other, S) ->
 
1598
    unexpected_message(Other, locker),
 
1599
    ?trace({the_locker, {other_msg, Other}}),
1318
1600
    loop_the_locker(S).
1319
1601
 
1320
1602
%% Requests from nodes on the local host are chosen before requests
1368
1650
    {?GLOBAL_RID, lists:sort([self(), Pid])}.
1369
1651
 
1370
1652
lock_nodes_safely(LockId, Extra, S0) ->
1371
 
    %% Locking the boss first is an optimization.
1372
 
    First = lists:usort([node(), S0#multi.the_boss]) -- [nonode@nohost],
1373
 
    case set_lock(LockId, First, 0) of
 
1653
    %% Locking node() could stop some node that has already locked the
 
1654
    %% boss, so just check if it is possible to lock node().
 
1655
    First = delete_nonode([S0#multi.the_boss]),
 
1656
    case ([node()] =:= First) orelse (can_set_lock(LockId) =/= false) of
1374
1657
        true ->
1375
 
            S = update_locker_known(S0),
1376
 
            %% The boss may have changed, but don't bother.
1377
 
            case set_lock(LockId, Extra, 0) of
 
1658
            %% Locking the boss first is an optimization.
 
1659
            case set_lock(LockId, First, 0) of
1378
1660
                true ->
1379
 
                    case set_lock(LockId, S#multi.known, 0) of
 
1661
                    S = update_locker_known(S0),
 
1662
                    %% The boss may have changed, but don't bother.
 
1663
                    Second = delete_nonode([node() | Extra] -- First),
 
1664
                    case set_lock(LockId, Second, 0) of
1380
1665
                        true ->
1381
 
                            {true, S};
 
1666
                            Known = S#multi.known,
 
1667
                            case set_lock(LockId, Known -- First, 0) of
 
1668
                                true ->
 
1669
                                    locker_trace(S, ok, {First, Known}),
 
1670
                                    {true, S};
 
1671
                                false ->
 
1672
                                    %% Since the boss is locked we should have
 
1673
                                    %% gotten the lock, at least if there are
 
1674
                                    %% no version 4 nodes in the partition or
 
1675
                                    %% someone else is locking 'global'. 
 
1676
                                    %% Calling set_lock with Retries > 0 does
 
1677
                                    %% not seem to speed things up.
 
1678
                                    SoFar = First ++ Second,
 
1679
                                    del_lock(LockId, SoFar),
 
1680
                                    locker_trace(S, not_ok, {Known,SoFar}),
 
1681
                                    {false, S}
 
1682
                            end;
1382
1683
                        false ->
1383
 
                            %% Since the boss is locked we should have
1384
 
                            %% gotten the lock, at least if there are
1385
 
                            %% no version 4 nodes in the partition or
1386
 
                            %% someone else is locking 'global'. 
1387
 
                            %% Calling set_lock with Retries > 0 does
1388
 
                            %% not seem to speed things up.
1389
 
                            del_lock(LockId, Extra ++ First),
 
1684
                            del_lock(LockId, First),
 
1685
                            locker_trace(S, not_ok, {Second, First}),
1390
1686
                            {false, S}
1391
1687
                    end;
1392
1688
                false ->
1393
 
                    del_lock(LockId, First),
1394
 
                    {false, S}
 
1689
                    locker_trace(S0, not_ok, {First, []}),
 
1690
                    {false, S0}
1395
1691
            end;
1396
1692
        false ->
1397
1693
            {false, S0}
1398
1694
    end.
1399
1695
 
 
1696
delete_nonode(L) ->
 
1697
    lists:delete(nonode@nohost, L).
 
1698
 
 
1699
%% Let the server add timestamp.
 
1700
locker_trace(#multi{do_trace = false}, _, _Nodes) ->
 
1701
    ok;
 
1702
locker_trace(#multi{do_trace = true}, ok, Ns) ->
 
1703
    global_name_server ! {trace_message, {locker_succeeded, node()}, Ns};
 
1704
locker_trace(#multi{do_trace = true}, not_ok, Ns) ->
 
1705
    global_name_server ! {trace_message, {locker_failed, node()}, Ns};
 
1706
locker_trace(#multi{do_trace = true}, rejected, Ns) ->
 
1707
    global_name_server ! {trace_message, {lock_rejected, node()}, Ns}.
 
1708
 
1400
1709
update_locker_known(S) ->
1401
1710
    receive
1402
1711
        {add_to_known, Nodes} ->
1414
1723
                {add, Nodes} -> Nodes ++ S#multi.known;
1415
1724
                {remove, Node} -> lists:delete(Node, S#multi.known)
1416
1725
            end,
1417
 
    TheBoss = lists:max([node() | Known]), 
 
1726
    TheBoss = the_boss([node() | Known]), 
1418
1727
    S#multi{known = Known, the_boss = TheBoss}.
1419
1728
 
1420
1729
random_element(L) ->
1433
1742
              end,
1434
1743
    receive
1435
1744
        {lock_set, P, true, _} when node(P) =:= Node ->
1436
 
            gen_server:cast(global_name_server, {lock_is_set, Node, MyTag}),
 
1745
            gen_server:cast(global_name_server, 
 
1746
                            {lock_is_set, Node, MyTag, LockId}),
1437
1747
            ?trace({lock_sync_done, {p,P, node(P)}, {me,self()}}),
1438
1748
 
1439
1749
            %% Wait for global to tell us to remove lock. Should the
1440
1750
            %% other locker's node die, global_name_server will
1441
 
            %% receive nodedown, and then send {cancel, Node, Tag}.
 
1751
            %% receive nodedown, and then send {cancel, Node, Tag, Fun}.
1442
1752
            receive
1443
 
                {cancel, Node, _} ->
 
1753
                {cancel, Node, _, Fun} ->
1444
1754
                    ?trace({lock_set_loop, {known1,Known1}}),
1445
 
                    del_lock(LockId, Known1)
 
1755
                    call_fun(Fun),
 
1756
                    delete_global_lock(LockId, Known1)
1446
1757
            end,
1447
1758
            S#multi{just_synced = true,
1448
1759
                    local = lists:delete(Him, S#multi.local),
1449
1760
                    remote = lists:delete(Him, S#multi.remote)};
1450
1761
        {lock_set, P, false, _} when node(P) =:= Node ->
1451
1762
            ?trace({not_both_set, {node,Node},{p, P},{known1,Known1}}),
1452
 
            del_lock(LockId, Known1),
 
1763
            locker_trace(S, rejected, Known1),
 
1764
            delete_global_lock(LockId, Known1),
1453
1765
            S;
1454
 
        {cancel, Node, _} ->
 
1766
        {cancel, Node, _, Fun} ->
1455
1767
            ?trace({the_locker, cancel2, {node,Node}}),
1456
 
            del_lock(LockId, Known1),
 
1768
            call_fun(Fun),
 
1769
            locker_trace(S, rejected, Known1),
 
1770
            delete_global_lock(LockId, Known1),
1457
1771
            remove_node(Node, S);
1458
1772
        {'EXIT', _, _} ->
1459
1773
            ?trace({the_locker, exit, {node,Node}}),
1460
 
            del_lock(LockId, Known1),
 
1774
            locker_trace(S, rejected, Known1),
 
1775
            delete_global_lock(LockId, Known1),
1461
1776
            S
1462
1777
    after
1463
1778
        %% OTP-4902
1472
1787
        %% node in the other partition is also locked with the same
1473
1788
        %% lock-id, which makes it impossible for any node in the
1474
1789
        %% other partition to lock its partition unless it negotiates
1475
 
        %% with the first partition.
 
1790
        %% with the first partition. The OTP-4902 code can be removed
 
1791
        %% when there is no need to support nodes running R10B.
1476
1792
        Timeout -> 
1477
1793
            reject_lock_set(),
1478
1794
            lock_set_loop(S, Him, MyTag, Known1, LockId)
1488
1804
            true
1489
1805
    end.
1490
1806
 
 
1807
%% The locker does the {new_nodes, ...} call before removing the lock.
 
1808
call_fun(no_fun) ->
 
1809
    ok;
 
1810
call_fun(Fun) ->
 
1811
    Fun().
 
1812
 
 
1813
%% The lock on the boss is removed last. The purpose is to reduce the
 
1814
%% risk of failing to lock the known nodes after having locked the
 
1815
%% boss. (Assumes the boss occurs only once.)
 
1816
delete_global_lock(LockId, Nodes) ->
 
1817
    TheBoss = the_boss(Nodes),
 
1818
    del_lock(LockId, lists:delete(TheBoss, Nodes)),
 
1819
    del_lock(LockId, [TheBoss]).
 
1820
 
 
1821
the_boss(Nodes) ->
 
1822
    lists:max(Nodes).
 
1823
 
1491
1824
find_node_tag(Node, S) ->
1492
1825
    case find_node_tag2(Node, S#multi.local) of
1493
1826
        false -> 
1536
1869
split_node([], _, Ack)        -> [lists:reverse(Ack)].
1537
1870
 
1538
1871
cancel_locker(Node, S, Tag) ->
1539
 
    S#state.the_locker ! {cancel, Node, Tag},
 
1872
    cancel_locker(Node, S, Tag, no_fun).
 
1873
 
 
1874
cancel_locker(Node, S, Tag, ToBeRunOnLockerF) ->
 
1875
    S#state.the_locker ! {cancel, Node, Tag, ToBeRunOnLockerF},
1540
1876
    Resolvers = S#state.resolvers,
1541
1877
    ?trace({cancel_locker, {node,Node},{tag,Tag},
1542
1878
            {sync_tag_my, get({sync_tag_my, Node})},{resolvers,Resolvers}}),
1544
1880
        {value, {_, Tag, Resolver}} ->
1545
1881
            ?trace({{resolver, Resolver}}),
1546
1882
            exit(Resolver, kill),
1547
 
            S#state{resolvers = lists:keydelete(Node, 1, Resolvers)};
 
1883
            S1 = trace_message(S, {kill_resolver, Node}, [Tag, Resolver]),
 
1884
            S1#state{resolvers = lists:keydelete(Node, 1, Resolvers)};
1548
1885
        _ ->
1549
1886
            S
1550
1887
    end.
1556
1893
    erase({pre_connect, Node}),
1557
1894
    erase({prot_vsn, Node}),
1558
1895
    erase({sync_tag_my, Node}),
1559
 
    erase({sync_tag_his, Node}).
 
1896
    erase({sync_tag_his, Node}),
 
1897
    erase({lock_id, Node}).
1560
1898
 
1561
1899
%% Some node sent us his names. When a name clash is found, the resolve
1562
1900
%% function is called from the smaller node => all resolve funcs are called
1563
1901
%% from the same partition.
1564
1902
exchange_names([{Name, Pid, Method} | Tail], Node, Ops, Res) ->
1565
1903
    case ets:lookup(global_names, Name) of
1566
 
        [{Name, Pid, _}] ->
 
1904
        [{Name, Pid, _Method, _RPid2, _Ref2}] ->
1567
1905
            exchange_names(Tail, Node, Ops, Res);
1568
 
        [{Name, Pid2, Method2}] when node() < Node ->
 
1906
        [{Name, Pid2, Method2, _RPid2, _Ref2}] when node() < Node ->
1569
1907
            %% Name clash!  Add the result of resolving to Res(olved).
1570
1908
            %% We know that node(Pid) =/= node(), so we don't
1571
1909
            %% need to link/unlink to Pid.
1594
1932
                    Op = {delete, Name},
1595
1933
                    exchange_names(Tail, Node, [Op | Ops], [Op | Res])
1596
1934
            end;
1597
 
        [{Name, _Pid2, _}] ->
 
1935
        [{Name, _Pid2, _Method, _RPid, _Ref}] ->
1598
1936
            %% The other node will solve the conflict.
1599
1937
            exchange_names(Tail, Node, Ops, Res);
1600
1938
        _ ->
1629
1967
    Pid2 ! {global_name_conflict, Name, Pid},
1630
1968
    none.
1631
1969
 
1632
 
%% Only link to pids on our own node
1633
 
dolink(Pid) when node(Pid) =:= node() ->
1634
 
    link(Pid);
1635
 
dolink(_) -> ok.
1636
 
 
1637
 
%% Only link to pids on our own node
1638
1970
dolink_ext(Pid, RegNode) when RegNode =:= node() -> 
1639
1971
    link(Pid);
1640
1972
dolink_ext(_, _) -> 
1641
1973
    ok.
1642
1974
 
1643
 
dounlink(Pid) when node(Pid) =:= node() ->
1644
 
    unlink_pid(Pid);
1645
 
dounlink(_Pid) ->
1646
 
    ok.
1647
 
 
1648
1975
dounlink_ext(Pid, RegNode) when RegNode =:= node() ->
1649
1976
    unlink_pid(Pid);
1650
1977
dounlink_ext(_Pid, _RegNode) ->
1663
1990
            ok
1664
1991
    end.
1665
1992
 
1666
 
%% check_exit/3 removes the Pid from affected tables.
1667
 
%% This function needs to abcast the thingie since only the local
1668
 
%% server is linked to the registered process (or the owner of the
1669
 
%% lock). All the other servers rely on the nodedown mechanism.
1670
 
check_exit(Deleter, Pid, KnownNodes) ->
1671
 
    del_names(Deleter, Pid),
1672
 
    del_locks(pid_locks(Pid), Pid, KnownNodes).
1673
 
 
1674
 
del_names(Deleter, Pid) ->
1675
 
    lists:foreach(fun({_Pid,Name}) ->
1676
 
                          %% The local name is deleted immediately,
1677
 
                          %% before the lock is taken. It is not known
1678
 
                          %% exactly why, but it may have something to
1679
 
                          %% do with supervisors...
1680
 
                          ?trace({del_names, {pid,Pid}, {name,Name}}),
1681
 
                          delete_global_name(Name, Pid),
1682
 
                          Deleter ! {delete_name, self(), Name, Pid}
1683
 
                  end, ets:lookup(global_pid_names, Pid)).
1684
 
 
1685
 
pid_locks(Pid) ->
1686
 
    L = lists:flatmap(fun({_Pid, ResourceId}) ->
 
1993
pid_is_locking(Pid, PidRefs) ->
 
1994
    lists:keysearch(Pid, 1, PidRefs) =/= false.
 
1995
 
 
1996
delete_lock(Ref, S0) ->
 
1997
    Locks = pid_locks(Ref),
 
1998
    del_locks(Locks, Ref, S0#state.known),
 
1999
    F = fun({ResourceId, LockRequesterId, PidRefs}, S) -> 
 
2000
                {value, {Pid, _RPid, Ref}} = 
 
2001
                    lists:keysearch(Ref, 3, PidRefs),
 
2002
                remove_lock(ResourceId, LockRequesterId, Pid, PidRefs, true,S)
 
2003
        end,
 
2004
    lists:foldl(F, S0, Locks).
 
2005
 
 
2006
pid_locks(Ref) ->
 
2007
    L = lists:flatmap(fun({_, ResourceId}) ->
1687
2008
                              ets:lookup(global_locks, ResourceId)
1688
 
                      end, ets:lookup(global_pid_ids, Pid)),
1689
 
    [Lock || Lock = {_Id, _Req, Pids} <- L, lists:member(Pid, Pids)].
1690
 
 
1691
 
del_locks([{ResourceId, LockReqId, Pids} | Tail], Pid, KnownNodes) ->
1692
 
    remove_lock(ResourceId, LockReqId, Pid, Pids),
1693
 
    gen_server:abcast(KnownNodes, global_name_server,
1694
 
                      {async_del_lock, ResourceId, Pid}),
1695
 
    del_locks(Tail, Pid, KnownNodes);
1696
 
del_locks([], _Pid, _KnownNodes) -> done.
1697
 
 
1698
 
%% Unregister all Name/Pid pairs such that node(Pid) =:= Node
1699
 
%% and delete all locks where node(Pid) =:= Node
1700
 
do_node_down(Node) ->
1701
 
    ?trace({do_node_down, Node}),
1702
 
    do_node_down_names(Node),
1703
 
    do_node_down_locks(Node).
1704
 
 
1705
 
do_node_down_names(Node) ->
1706
 
    [[] || {_, Pid} <- ets:lookup(global_node_pids, {name,Node}),
1707
 
           {_, Name} <- ets:lookup(global_pid_names, Pid),
1708
 
           ok =/= delete_global_name(Name, Pid)].
1709
 
 
1710
 
do_node_down_locks(Node) ->
1711
 
    NodePids = ets:lookup(global_node_pids, {lock, Node}),
1712
 
    ?trace({do_node_down_locks, {node_pids, NodePids}}),
1713
 
    Pids = lists:usort([Pid || {_Node, Pid} <- NodePids]),
1714
 
    lists:foreach(fun async_del_lock/1, Pids).
1715
 
 
1716
 
async_del_lock(Pid) ->
1717
 
    lists:foreach(fun({ResourceId, LockRequesterId, Pids}) -> 
1718
 
                          remove_lock(ResourceId, LockRequesterId, Pid, Pids)
1719
 
                  end, pid_locks(Pid)).
 
2009
                      end, ets:lookup(global_pid_ids, Ref)),
 
2010
    [Lock || Lock = {_Id, _Req, PidRefs} <- L, 
 
2011
             rpid_is_locking(Ref, PidRefs)].
 
2012
 
 
2013
rpid_is_locking(Ref, PidRefs) ->
 
2014
    lists:keysearch(Ref, 3, PidRefs) =/= false.
 
2015
 
 
2016
%% Send {async_del_lock, ...} to old nodes (pre R11B-3).
 
2017
del_locks([{ResourceId, _LockReqId, PidRefs} | Tail], Ref, KnownNodes) ->
 
2018
    {value, {Pid, _RPid, Ref}} = lists:keysearch(Ref, 3, PidRefs),
 
2019
    case node(Pid) =:= node()  of
 
2020
        true -> 
 
2021
            gen_server:abcast(KnownNodes, global_name_server,
 
2022
                              {async_del_lock, ResourceId, Pid});
 
2023
        false -> 
 
2024
            ok
 
2025
    end,
 
2026
    del_locks(Tail, Ref, KnownNodes);
 
2027
del_locks([], _Ref, _KnownNodes) -> 
 
2028
    ok.
 
2029
 
 
2030
handle_nodedown(Node, S) ->
 
2031
    %% DOWN signals from monitors have removed locks and registered names.
 
2032
    #state{known = Known, synced = Syncs} = S,
 
2033
    NewS = cancel_locker(Node, S, get({sync_tag_my, Node})),
 
2034
    NewS#state.the_locker ! {remove_from_known, Node},
 
2035
    reset_node_state(Node),
 
2036
    NewS#state{known = lists:delete(Node, Known),
 
2037
               synced = lists:delete(Node, Syncs)}.
1720
2038
 
1721
2039
get_names() ->
1722
 
    ets:tab2list(global_names).
 
2040
    ets:select(global_names, 
 
2041
               ets:fun2ms(fun({Name, Pid, Method, _RPid, _Ref}) -> 
 
2042
                                  {Name, Pid, Method} 
 
2043
                          end)).
1723
2044
 
1724
2045
get_names_ext() ->
1725
2046
    ets:tab2list(global_names_ext).
1751
2072
 
1752
2073
send_again(Msg) ->
1753
2074
    Me = self(),
1754
 
    spawn_link(fun() -> timer(Me, Msg) end).
 
2075
    spawn(fun() -> timer(Me, Msg) end).
1755
2076
 
1756
2077
timer(Pid, Msg) ->
1757
2078
    random_sleep(5),
1758
2079
    Pid ! Msg.
1759
2080
 
1760
2081
change_our_node_name(NewNode, S) ->
1761
 
    S#state{node_name = NewNode}.
 
2082
    S1 = trace_message(S, {new_node_name, NewNode}, []),
 
2083
    S1#state{node_name = NewNode}.
 
2084
 
 
2085
trace_message(#state{trace = no_trace}=S, _M, _X) ->
 
2086
    S;
 
2087
trace_message(S, M, X) ->
 
2088
    S#state{trace = [trace_message(M, X) | S#state.trace]}.
 
2089
 
 
2090
trace_message(M, X) ->
 
2091
    {node(), now(), M, nodes(), X}.
1762
2092
 
1763
2093
%%-----------------------------------------------------------------
1764
2094
%% Each sync process corresponds to one call to sync. Each such
1835
2165
%%-----------------------------------------------------------------
1836
2166
 
1837
2167
start_the_deleter(Global) ->
1838
 
    spawn_link(
1839
 
      fun () -> 
1840
 
              loop_the_deleter(Global)
1841
 
      end).
 
2168
    spawn_link(fun() -> loop_the_deleter(Global) end).
1842
2169
 
1843
2170
loop_the_deleter(Global) ->
1844
2171
    Deletions = collect_deletions(Global, []),
1854
2181
    trans_all_known(
1855
2182
      fun(Known) ->
1856
2183
              lists:map(
1857
 
                fun ({Name,Pid}) ->
 
2184
                fun({Name,Pid}) ->
1858
2185
                        gen_server:abcast(Known, global_name_server,
1859
2186
                                          {async_del_name, Name, Pid})
1860
2187
                end, Deletions)
1866
2193
        {delete_name, Global, Name, Pid} ->
1867
2194
            collect_deletions(Global, [{Name,Pid} | Deletions]);
1868
2195
        Other ->
1869
 
            error_logger:error_msg("The global_name_server deleter process "
1870
 
                                   "received an unexpected message:\n~p\n", 
1871
 
                                   [Other]),
 
2196
            unexpected_message(Other, deleter),
1872
2197
            collect_deletions(Global, Deletions)
1873
2198
    after case Deletions of
1874
2199
              [] -> infinity;
1877
2202
            lists:reverse(Deletions)
1878
2203
    end.
1879
2204
 
 
2205
%% The registrar is a helper process that registers and unregisters
 
2206
%% names. Since it never dies it assures that names are registered and
 
2207
%% unregistered on all known nodes. It is started by and linked to
 
2208
%% global_name_server.
 
2209
 
 
2210
start_the_registrar() ->
 
2211
    spawn_link(fun() -> loop_the_registrar() end).
 
2212
                       
 
2213
loop_the_registrar() ->
 
2214
    receive 
 
2215
        {trans_all_known, Fun, From} ->
 
2216
            ?trace({loop_the_registrar, self(), Fun, From}),
 
2217
            gen_server:reply(From, trans_all_known(Fun));
 
2218
        Other ->
 
2219
            unexpected_message(Other, register)
 
2220
    end,
 
2221
    loop_the_registrar().
 
2222
 
 
2223
unexpected_message({'EXIT', _Pid, _Reason}, _What) ->
 
2224
    %% global_name_server died
 
2225
    ok;
 
2226
unexpected_message(Message, What) -> 
 
2227
    error_logger:warning_msg("The global_name_server ~w process "
 
2228
                             "received an unexpected message:\n~p\n", 
 
2229
                             [What, Message]).
 
2230
 
1880
2231
%%% Utilities
1881
2232
 
 
2233
%% When/if erlang:monitor() returns before trying to connect to the
 
2234
%% other node this function can be removed.
 
2235
do_monitor(Pid) ->
 
2236
    case (node(Pid) =:= node()) orelse lists:member(node(Pid), nodes()) of
 
2237
        true ->
 
2238
            %% Assume the node is still up
 
2239
            {Pid, erlang:monitor(process, Pid)};
 
2240
        false ->
 
2241
            F = fun() -> 
 
2242
                        Ref = erlang:monitor(process, Pid),
 
2243
                        receive 
 
2244
                            {'DOWN', Ref, process, Pid, _Info} ->
 
2245
                                exit(normal)
 
2246
                        end
 
2247
                end,
 
2248
            erlang:spawn_monitor(F)
 
2249
    end.
 
2250
 
1882
2251
intersection(_, []) -> 
1883
2252
    [];
1884
2253
intersection(L1, L2) ->