Skip to content

Commit 5545152

Browse files
author
Daniil Fedotov
committed
Migrate queues in batches of 100 in parallel. Write recovery terms for migrated queues.
1 parent 03bdc78 commit 5545152

File tree

2 files changed

+54
-36
lines changed

2 files changed

+54
-36
lines changed

src/rabbit_queue_index.erl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
-export([scan_queue_segments/3]).
2727

2828
%% Migrates from global to per-vhost message stores
29-
-export([move_to_per_vhost_stores/1]).
29+
-export([move_to_per_vhost_stores/1, update_recovery_term/2]).
3030

3131
-define(CLEAN_FILENAME, "clean.dot").
3232

@@ -1419,3 +1419,7 @@ move_to_per_vhost_stores(#resource{} = QueueName) ->
14191419
[QueueName])
14201420
end,
14211421
ok.
1422+
1423+
update_recovery_term(#resource{} = QueueName, Term) ->
1424+
Key = queue_name_to_dir_name(QueueName),
1425+
rabbit_recovery_terms:store(Key, Term).

src/rabbit_variable_queue.erl

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
-export([stop_vhost_msg_store/1]).
3838
-include_lib("stdlib/include/qlc.hrl").
3939

40+
-define(QUEUE_MIGRATION_BATCH_SIZE, 100).
41+
4042
%%----------------------------------------------------------------------------
4143
%% Messages, and their position in the queue, can be in memory or on
4244
%% disk, or both. Persistent messages will have both message and
@@ -351,7 +353,7 @@
351353
%%----------------------------------------------------------------------------
352354

353355
-rabbit_upgrade({multiple_routing_keys, local, []}).
354-
-rabbit_upgrade({move_messages_to_vhost_store, queues, []}).
356+
-rabbit_upgrade({move_messages_to_vhost_store, message_store, []}).
355357

356358
-compile(export_all).
357359

@@ -2716,7 +2718,7 @@ move_messages_to_vhost_store() ->
27162718
rabbit_log:info("Moving messages to per-vhost message store"),
27172719
Queues = list_persistent_queues(),
27182720
%% Move the queue index for each persistent queue to the new store
2719-
lists:map(
2721+
lists:foreach(
27202722
fun(Queue) ->
27212723
#amqqueue{name = QueueName} = Queue,
27222724
rabbit_queue_index:move_to_per_vhost_stores(QueueName)
@@ -2725,39 +2727,49 @@ move_messages_to_vhost_store() ->
27252727
%% Legacy (global) msg_store may require recovery.
27262728
%% This upgrade step should only be started
27272729
%% if we are upgrading from a pre-3.7.0 version.
2728-
{RecoveryTerms, StartFunState} = start_recovery_terms(Queues),
2729-
OldStore = run_old_persistent_store(RecoveryTerms, StartFunState),
2730+
{QueuesWithTerms, RecoveryRefs, StartFunState} = start_recovery_terms(Queues),
2731+
2732+
OldStore = run_old_persistent_store(RecoveryRefs, StartFunState),
27302733
%% New store should not be recovered.
27312734
NewStoreSup = start_new_store_sup(),
2735+
in_batches(?QUEUE_MIGRATION_BATCH_SIZE,
2736+
{rabbit_variable_queue, migrate_queue, [OldStore, NewStoreSup]},
2737+
QueuesWithTerms),
27322738

2733-
% {ok, Gatherer} = gatherer:start_link(),
2734-
lists:map(
2735-
fun(Queue) ->
2736-
migrate_queue(Queue, OldStore, NewStoreSup),
2737-
#amqqueue{name = QueueName} = Queue,
2738-
rabbit_log:info("Queue migration finished ~p", [QueueName])
2739-
% ok = gatherer:fork(Gatherer),
2740-
% ok = worker_pool:submit_async(
2741-
% fun () ->
2742-
% migrate_queue(Queue, OldStore, NewStoreSup),
2743-
% gatherer:finish(Gatherer)
2744-
% end)
2745-
end,
2746-
Queues),
2747-
% empty = gatherer:out(Gatherer),
2748-
% ok = gatherer:stop(Gatherer),
2749-
2739+
rabbit_log:info("Message store migration finished"),
27502740
delete_old_store(OldStore),
27512741

27522742
ok = rabbit_queue_index:stop(),
2753-
ok = rabbit_sup:stop_child(NewStoreSup).
2743+
ok = rabbit_sup:stop_child(NewStoreSup),
2744+
ok.
27542745

2755-
migrate_queue(Queue, OldStore, NewStoreSup) ->
2756-
#amqqueue{name = QueueName} = Queue,
2746+
in_batches(Size, MFA, List) ->
2747+
in_batches(Size, 1, MFA, List).
2748+
2749+
in_batches(_, _, _, []) -> ok;
2750+
in_batches(Size, BatchNum, MFA, List) ->
2751+
{Batch, Tail} = case Size > length(List) of
2752+
true -> {List, []};
2753+
false -> lists:split(Size, List)
2754+
end,
2755+
rabbit_log:info("Migrating batch ~p of ~p queues ~n", [BatchNum, Size]),
2756+
{M, F, A} = MFA,
2757+
Keys = [ rpc:async_call(node(), M, F, [El | A]) || El <- Batch ],
2758+
lists:foreach(fun(Key) ->
2759+
case rpc:yield(Key) of
2760+
{badrpc, Err} -> throw(Err);
2761+
_ -> ok
2762+
end
2763+
end,
2764+
Keys),
2765+
rabbit_log:info("Batch ~p of ~p queues migrated ~n", [BatchNum, Size]),
2766+
in_batches(Size, BatchNum + 1, MFA, Tail).
2767+
2768+
migrate_queue({QueueName, RecoveryTerm}, OldStore, NewStoreSup) ->
27572769
rabbit_log:info("Migrating messages in queue ~s in vhost ~s to per-vhost message store~n",
27582770
[QueueName#resource.name, QueueName#resource.virtual_host]),
27592771
OldStoreClient = get_global_store_client(OldStore),
2760-
NewStoreClient = get_per_vhost_store_client(Queue, NewStoreSup),
2772+
NewStoreClient = get_per_vhost_store_client(QueueName, NewStoreSup),
27612773
%% WARNING: During scan_queue_segments queue index state is being recovered
27622774
%% and terminated. This can cause side effects!
27632775
rabbit_queue_index:scan_queue_segments(
@@ -2771,23 +2783,25 @@ migrate_queue(Queue, OldStore, NewStoreSup) ->
27712783
OldC
27722784
end,
27732785
OldStoreClient,
2774-
QueueName).
2786+
QueueName),
2787+
rabbit_msg_store:client_terminate(OldStoreClient),
2788+
rabbit_msg_store:client_terminate(NewStoreClient),
2789+
NewClientRef = rabbit_msg_store:client_ref(NewStoreClient),
2790+
NewRecoveryTerm = lists:keyreplace(persistent_ref, 1, RecoveryTerm,
2791+
{persistent_ref, NewClientRef}),
2792+
rabbit_queue_index:update_recovery_term(QueueName, NewRecoveryTerm),
2793+
rabbit_log:info("Queue migration finished ~p", [QueueName]),
2794+
{QueueName, NewClientRef}.
27752795

27762796
migrate_message(MsgId, OldC, NewC) ->
27772797
case rabbit_msg_store:read(MsgId, OldC) of
27782798
{{ok, Msg}, OldC1} ->
2779-
case rabbit_msg_store:contains(MsgId, NewC) of
2780-
false -> ok = rabbit_msg_store:write(MsgId, Msg, NewC);
2781-
true -> ok
2782-
end,
2783-
% TODO: maybe remove in batches?
2784-
ok = rabbit_msg_store:remove([MsgId], OldC1),
2799+
ok = rabbit_msg_store:write(MsgId, Msg, NewC),
27852800
OldC1;
27862801
_ -> OldC
27872802
end.
27882803

2789-
get_per_vhost_store_client(#amqqueue{name = #resource{virtual_host = VHost}},
2790-
NewStoreSup) ->
2804+
get_per_vhost_store_client(#resource{virtual_host = VHost}, NewStoreSup) ->
27912805
rabbit_msg_store_vhost_sup:client_init(NewStoreSup,
27922806
rabbit_guid:gen(),
27932807
fun(_,_) -> ok end,
@@ -2820,7 +2834,7 @@ start_recovery_terms(Queues) ->
28202834
Ref = proplists:get_value(persistent_ref, Terms),
28212835
Ref =/= undefined
28222836
end],
2823-
{Refs, StartFunState}.
2837+
{lists:zip(QueueNames, AllTerms), Refs, StartFunState}.
28242838

28252839
run_old_persistent_store(Refs, StartFunState) ->
28262840
OldStoreName = ?PERSISTENT_MSG_STORE,

0 commit comments

Comments
 (0)