17
17
sync_batch_size /1 , log_info /3 , log_warning /3 ]).
18
18
-export ([stop_all_slaves /5 ]).
19
19
20
- -export ([sync_queue /1 , cancel_sync_queue /1 ]).
20
+ -export ([sync_queue /1 , cancel_sync_queue /1 , queue_length / 1 ]).
21
21
22
- -export ([transfer_leadership / 2 , queue_length / 1 , get_replicas / 1 ]).
22
+ -export ([get_replicas / 1 , transfer_leadership / 2 , migrate_leadership_to_existing_replica / 2 ]).
23
23
24
24
% % for testing only
25
25
-export ([module /1 ]).
@@ -201,12 +201,13 @@ drop_mirror(QName, MirrorNode) ->
201
201
case rabbit_amqqueue :lookup (QName ) of
202
202
{ok , Q } when ? is_amqqueue (Q ) ->
203
203
Name = amqqueue :get_name (Q ),
204
- QPid = amqqueue :get_pid (Q ),
205
- SPids = amqqueue :get_slave_pids (Q ),
206
- case [Pid || Pid <- [QPid | SPids ], node (Pid ) =:= MirrorNode ] of
204
+ PrimaryPid = amqqueue :get_pid (Q ),
205
+ MirrorPids = amqqueue :get_slave_pids (Q ),
206
+ AllReplicaPids = [PrimaryPid | MirrorPids ],
207
+ case [Pid || Pid <- AllReplicaPids , node (Pid ) =:= MirrorNode ] of
207
208
[] ->
208
209
{error , {queue_not_mirrored_on_node , MirrorNode }};
209
- [QPid ] when SPids =:= [] ->
210
+ [PrimaryPid ] when MirrorPids =:= [] ->
210
211
{error , cannot_drop_only_mirror };
211
212
[Pid ] ->
212
213
log_info (Name , " Dropping queue mirror on node ~p~n " ,
@@ -235,11 +236,9 @@ add_mirror(QName, MirrorNode, SyncMode) ->
235
236
case rabbit_vhost_sup_sup :get_vhost_sup (VHost , MirrorNode ) of
236
237
{ok , _ } ->
237
238
try
238
- SPid = rabbit_amqqueue_sup_sup :start_queue_process (
239
- MirrorNode , Q , slave ),
240
- log_info (QName , " Adding mirror on node ~p : ~p~n " ,
241
- [MirrorNode , SPid ]),
242
- rabbit_mirror_queue_slave :go (SPid , SyncMode )
239
+ MirrorPid = rabbit_amqqueue_sup_sup :start_queue_process (MirrorNode , Q , slave ),
240
+ log_info (QName , " Adding mirror on node ~p : ~p~n " , [MirrorNode , MirrorPid ]),
241
+ rabbit_mirror_queue_slave :go (MirrorPid , SyncMode )
243
242
of
244
243
_ -> ok
245
244
catch
@@ -264,10 +263,10 @@ add_mirror(QName, MirrorNode, SyncMode) ->
264
263
report_deaths (_MirrorPid , _IsMaster , _QueueName , []) ->
265
264
ok ;
266
265
report_deaths (MirrorPid , IsMaster , QueueName , DeadPids ) ->
267
- log_info (QueueName , " ~s ~s saw deaths of mirrors ~s ~n" ,
266
+ log_info (QueueName , " ~s replica of queue ~s detected replica ~s to be down ~n " ,
268
267
[case IsMaster of
269
- true -> " Master " ;
270
- false -> " Slave "
268
+ true -> " Primary " ;
269
+ false -> " Secondary "
271
270
end ,
272
271
rabbit_misc :pid_to_string (MirrorPid ),
273
272
[[$ , rabbit_misc :pid_to_string (P )] || P <- DeadPids ]]).
@@ -447,14 +446,15 @@ is_mirrored_ha_nodes(Q) ->
447
446
end .
448
447
449
448
actual_queue_nodes (Q ) when ? is_amqqueue (Q ) ->
450
- MPid = amqqueue :get_pid (Q ),
451
- SPids = amqqueue :get_slave_pids (Q ),
452
- SSPids = amqqueue :get_sync_slave_pids (Q ),
453
- Nodes = fun (L ) -> [node (Pid ) || Pid <- L ] end ,
454
- {case MPid of
455
- none -> none ;
456
- _ -> node (MPid )
457
- end , Nodes (SPids ), Nodes (SSPids )}.
449
+ PrimaryPid = amqqueue :get_pid (Q ),
450
+ MirrorPids = amqqueue :get_slave_pids (Q ),
451
+ InSyncMirrorPids = amqqueue :get_sync_slave_pids (Q ),
452
+ CollectNodes = fun (L ) -> [node (Pid ) || Pid <- L ] end ,
453
+ NodeHostingPrimary = case PrimaryPid of
454
+ none -> none ;
455
+ _ -> node (PrimaryPid )
456
+ end ,
457
+ {NodeHostingPrimary , CollectNodes (MirrorPids ), CollectNodes (InSyncMirrorPids )}.
458
458
459
459
- spec maybe_auto_sync (amqqueue :amqqueue ()) -> 'ok' .
460
460
@@ -520,19 +520,19 @@ update_mirrors(OldQ, NewQ) when ?amqqueue_pids_are_equal(OldQ, NewQ) ->
520
520
521
521
update_mirrors (Q ) when ? is_amqqueue (Q ) ->
522
522
QName = amqqueue :get_name (Q ),
523
- {OldMNode , OldSNodes , _ } = actual_queue_nodes (Q ),
524
- {NewMNode , NewSNodes } = suggested_queue_nodes (Q ),
525
- OldNodes = [OldMNode | OldSNodes ],
526
- NewNodes = [NewMNode | NewSNodes ],
523
+ {PreTransferPrimaryNode , PreTransferMirrorNodes , __PreTransferInSyncMirrorNodes } = actual_queue_nodes (Q ),
524
+ {NewlySelectedPrimaryNode , NewlySelectedMirrorNodes } = suggested_queue_nodes (Q ),
525
+ PreTransferNodesWithReplicas = [PreTransferPrimaryNode | PreTransferMirrorNodes ],
526
+ NewlySelectedNodesWithReplicas = [NewlySelectedPrimaryNode | NewlySelectedMirrorNodes ],
527
527
% % When a mirror dies, remove_from_queue/2 might have to add new
528
- % % mirrors (in "exactly" mode). It will check mnesia to see which
528
+ % % mirrors (in "exactly" mode). It will check the queue record to see which
529
529
% % mirrors there currently are. If drop_mirror/2 is invoked first
530
530
% % then when we end up in remove_from_queue/2 it will not see the
531
531
% % mirrors that add_mirror/2 will add, and also want to add them
532
532
% % (even though we are not responding to the death of a
533
533
% % mirror). Breakage ensues.
534
- add_mirrors (QName , NewNodes -- OldNodes , async ),
535
- drop_mirrors (QName , OldNodes -- NewNodes ),
534
+ add_mirrors (QName , NewlySelectedNodesWithReplicas -- PreTransferNodesWithReplicas , async ),
535
+ drop_mirrors (QName , PreTransferNodesWithReplicas -- NewlySelectedNodesWithReplicas ),
536
536
% % This is for the case where no extra nodes were added but we changed to
537
537
% % a policy requiring auto-sync.
538
538
maybe_auto_sync (Q ),
@@ -543,15 +543,47 @@ queue_length(Q) ->
543
543
M .
544
544
545
545
get_replicas (Q ) ->
546
- {MNode , SNodes } = suggested_queue_nodes (Q ),
547
- [MNode ] ++ SNodes .
546
+ {PrimaryNode , MirrorNodes } = suggested_queue_nodes (Q ),
547
+ [PrimaryNode ] ++ MirrorNodes .
548
548
549
+ % % Moves the primary replica (leader) of a classic mirrored queue to another node.
550
+ % % Target node can be any node in the cluster, and does not have to host a replica
551
+ % % of this queue.
549
552
transfer_leadership (Q , Destination ) ->
550
553
QName = amqqueue :get_name (Q ),
551
- {OldMNode , OldSNodes , _ } = actual_queue_nodes (Q ),
552
- OldNodes = [OldMNode | OldSNodes ],
553
- add_mirrors (QName , [Destination ] -- OldNodes , async ),
554
- drop_mirrors (QName , OldNodes -- [Destination ]),
554
+ {PreTransferPrimaryNode , PreTransferMirrorNodes , _PreTransferInSyncMirrorNodes } = actual_queue_nodes (Q ),
555
+ PreTransferNodesWithReplicas = [PreTransferPrimaryNode | PreTransferMirrorNodes ],
556
+
557
+ NodesToAddMirrorsOn = [Destination ] -- PreTransferNodesWithReplicas ,
558
+ % % This will wait for the transfer/eager sync to finish before we begin dropping
559
+ % % mirrors on the next step. In this case we cannot add mirrors asynchronously
560
+ % % as that will race with the dropping step.
561
+ add_mirrors (QName , NodesToAddMirrorsOn , sync ),
562
+
563
+ NodesToDropMirrorsOn = PreTransferNodesWithReplicas -- [Destination ],
564
+ drop_mirrors (QName , NodesToDropMirrorsOn ),
565
+
566
+ {Result , NewQ } = wait_for_new_master (QName , Destination ),
567
+ update_mirrors (NewQ ),
568
+ Result .
569
+
570
+ % % Moves the primary replica (leader) of a classic mirrored queue to another node
571
+ % % which already hosts a replica of this queue. In this case we can stop
572
+ % % fewer replicas and reduce the load the operation has on the cluster.
573
+ migrate_leadership_to_existing_replica (Q , Destination ) ->
574
+ QName = amqqueue :get_name (Q ),
575
+ {PreTransferPrimaryNode , PreTransferMirrorNodes , _PreTransferInSyncMirrorNodes } = actual_queue_nodes (Q ),
576
+ PreTransferNodesWithReplicas = [PreTransferPrimaryNode | PreTransferMirrorNodes ],
577
+
578
+ NodesToAddMirrorsOn = [Destination ] -- PreTransferNodesWithReplicas ,
579
+ % % This will wait for the transfer/eager sync to finish before we begin dropping
580
+ % % mirrors on the next step. In this case we cannot add mirrors asynchronously
581
+ % % as that will race with the dropping step.
582
+ add_mirrors (QName , NodesToAddMirrorsOn , sync ),
583
+
584
+ NodesToDropMirrorsOn = [PreTransferPrimaryNode ],
585
+ drop_mirrors (QName , NodesToDropMirrorsOn ),
586
+
555
587
{Result , NewQ } = wait_for_new_master (QName , Destination ),
556
588
update_mirrors (NewQ ),
557
589
Result .
0 commit comments