|
62 | 62 | make_discard/2,
|
63 | 63 | make_credit/4,
|
64 | 64 | make_purge/0,
|
| 65 | + make_purge_nodes/1, |
65 | 66 | make_update_config/1
|
66 | 67 | ]).
|
67 | 68 |
|
|
83 | 84 | delivery_count :: non_neg_integer(),
|
84 | 85 | drain :: boolean()}).
|
85 | 86 | -record(purge, {}).
|
| 87 | +-record(purge_nodes, {nodes :: [node()]}). |
86 | 88 | -record(update_config, {config :: config()}).
|
87 | 89 |
|
88 | 90 | -opaque protocol() ::
|
|
93 | 95 | #discard{} |
|
94 | 96 | #credit{} |
|
95 | 97 | #purge{} |
|
| 98 | + #purge_nodes{} | |
96 | 99 | #update_config{}.
|
97 | 100 |
|
98 | 101 | -type command() :: protocol() | ra_machine:builtin_command().
|
@@ -396,28 +399,9 @@ apply(Meta, {down, Pid, noconnection},
|
396 | 399 | _ ->
|
397 | 400 | [{monitor, node, Node}]
|
398 | 401 | end ++ Effects1,
|
399 |
| - %% TODO: should we run a checkout here? |
400 | 402 | checkout(Meta, State#?MODULE{enqueuers = Enqs}, Effects);
|
401 |
| -apply(Meta, {down, Pid, _Info}, #?MODULE{consumers = Cons0, |
402 |
| - enqueuers = Enqs0} = State0) -> |
403 |
| - % Remove any enqueuer for the same pid and enqueue any pending messages |
404 |
| - % This should be ok as we won't see any more enqueues from this pid |
405 |
| - State1 = case maps:take(Pid, Enqs0) of |
406 |
| - {#enqueuer{pending = Pend}, Enqs} -> |
407 |
| - lists:foldl(fun ({_, RIdx, RawMsg}, S) -> |
408 |
| - enqueue(RIdx, RawMsg, S) |
409 |
| - end, State0#?MODULE{enqueuers = Enqs}, Pend); |
410 |
| - error -> |
411 |
| - State0 |
412 |
| - end, |
413 |
| - {Effects1, State2} = handle_waiting_consumer_down(Pid, State1), |
414 |
| - % return checked out messages to main queue |
415 |
| - % Find the consumers for the down pid |
416 |
| - DownConsumers = maps:keys( |
417 |
| - maps:filter(fun({_, P}, _) -> P =:= Pid end, Cons0)), |
418 |
| - {State, Effects} = lists:foldl(fun(ConsumerId, {S, E}) -> |
419 |
| - cancel_consumer(ConsumerId, S, E, down) |
420 |
| - end, {State2, Effects1}, DownConsumers), |
| 403 | +apply(Meta, {down, Pid, _Info}, State0) -> |
| 404 | + {State, Effects} = handle_down(Pid, State0), |
421 | 405 | checkout(Meta, State, Effects);
|
422 | 406 | apply(Meta, {nodeup, Node}, #?MODULE{consumers = Cons0,
|
423 | 407 | enqueuers = Enqs0,
|
@@ -448,16 +432,50 @@ apply(Meta, {nodeup, Node}, #?MODULE{consumers = Cons0,
|
448 | 432 | Acc
|
449 | 433 | end, {Cons0, SQ0, Monitors}, Cons0),
|
450 | 434 | Waiting = update_waiting_consumer_status(Node, State0, up),
|
451 |
| - State1 = State0#?MODULE{consumers = Cons1, enqueuers = Enqs1, |
| 435 | + State1 = State0#?MODULE{consumers = Cons1, |
| 436 | + enqueuers = Enqs1, |
452 | 437 | service_queue = SQ,
|
453 | 438 | waiting_consumers = Waiting},
|
454 | 439 | {State, Effects} = activate_next_consumer(State1, Effects1),
|
455 | 440 | checkout(Meta, State, Effects);
|
456 | 441 | apply(_, {nodedown, _Node}, State) ->
|
457 | 442 | {State, ok};
|
| 443 | +apply(_, #purge_nodes{nodes = Nodes}, State0) -> |
| 444 | + {State, Effects} = lists:foldl(fun(Node, {S, E}) -> |
| 445 | + purge_node(Node, S, E) |
| 446 | + end, {State0, []}, Nodes), |
| 447 | + {State, ok, Effects}; |
458 | 448 | apply(Meta, #update_config{config = Conf}, State) ->
|
459 | 449 | checkout(Meta, update_config(Conf, State), []).
|
460 | 450 |
|
| 451 | +purge_node(Node, State, Effects) -> |
| 452 | + lists:foldl(fun(Pid, {S0, E0}) -> |
| 453 | + {S, E} = handle_down(Pid, S0), |
| 454 | + {S, E0 ++ E} |
| 455 | + end, {State, Effects}, all_pids_for(Node, State)). |
| 456 | + |
| 457 | +%% any downs that re not noconnection |
| 458 | +handle_down(Pid, #?MODULE{consumers = Cons0, |
| 459 | + enqueuers = Enqs0} = State0) -> |
| 460 | + % Remove any enqueuer for the same pid and enqueue any pending messages |
| 461 | + % This should be ok as we won't see any more enqueues from this pid |
| 462 | + State1 = case maps:take(Pid, Enqs0) of |
| 463 | + {#enqueuer{pending = Pend}, Enqs} -> |
| 464 | + lists:foldl(fun ({_, RIdx, RawMsg}, S) -> |
| 465 | + enqueue(RIdx, RawMsg, S) |
| 466 | + end, State0#?MODULE{enqueuers = Enqs}, Pend); |
| 467 | + error -> |
| 468 | + State0 |
| 469 | + end, |
| 470 | + {Effects1, State2} = handle_waiting_consumer_down(Pid, State1), |
| 471 | + % return checked out messages to main queue |
| 472 | + % Find the consumers for the down pid |
| 473 | + DownConsumers = maps:keys( |
| 474 | + maps:filter(fun({_, P}, _) -> P =:= Pid end, Cons0)), |
| 475 | + lists:foldl(fun(ConsumerId, {S, E}) -> |
| 476 | + cancel_consumer(ConsumerId, S, E, down) |
| 477 | + end, {State2, Effects1}, DownConsumers). |
| 478 | + |
461 | 479 | consumer_active_flag_update_function(#?MODULE{cfg = #cfg{consumer_strategy = competing}}) ->
|
462 | 480 | fun(State, ConsumerId, Consumer, Active, ActivityStatus, Effects) ->
|
463 | 481 | consumer_update_active_effects(State, ConsumerId, Consumer, Active,
|
@@ -556,8 +574,10 @@ tick(_Ts, #?MODULE{cfg = #cfg{name = Name,
|
556 | 574 | query_consumer_count(State), % Consumers
|
557 | 575 | EnqueueBytes,
|
558 | 576 | CheckoutBytes},
|
| 577 | + %% TODO: call a handler that works out if any known nodes need to be |
| 578 | + %% purged and emit a command effect to append this to the log |
559 | 579 | [{mod_call, rabbit_quorum_queue,
|
560 |
| - handle_tick, [QName, Metrics]}, {aux, emit}]. |
| 580 | + handle_tick, [QName, Metrics, all_nodes(State)]}, {aux, emit}]. |
561 | 581 |
|
562 | 582 | -spec overview(state()) -> map().
|
563 | 583 | overview(#?MODULE{consumers = Cons,
|
@@ -1495,6 +1515,10 @@ make_credit(ConsumerId, Credit, DeliveryCount, Drain) ->
|
1495 | 1515 | -spec make_purge() -> protocol().
|
1496 | 1516 | make_purge() -> #purge{}.
|
1497 | 1517 |
|
| 1518 | +-spec make_purge_nodes([node()]) -> protocol(). |
| 1519 | +make_purge_nodes(Nodes) -> |
| 1520 | + #purge_nodes{nodes = Nodes}. |
| 1521 | + |
1498 | 1522 | -spec make_update_config(config()) -> protocol().
|
1499 | 1523 | make_update_config(Config) ->
|
1500 | 1524 | #update_config{config = Config}.
|
@@ -1532,6 +1556,39 @@ message_size(Msg) ->
|
1532 | 1556 | %% probably only hit this for testing so ok to use erts_debug
|
1533 | 1557 | erts_debug:size(Msg).
|
1534 | 1558 |
|
| 1559 | +all_nodes(#?MODULE{consumers = Cons0, |
| 1560 | + enqueuers = Enqs0, |
| 1561 | + waiting_consumers = WaitingConsumers0}) -> |
| 1562 | + Nodes0 = maps:fold(fun({_, P}, _, Acc) -> |
| 1563 | + Acc#{node(P) => ok} |
| 1564 | + end, #{}, Cons0), |
| 1565 | + Nodes1 = maps:fold(fun(P, _, Acc) -> |
| 1566 | + Acc#{node(P) => ok} |
| 1567 | + end, Nodes0, Enqs0), |
| 1568 | + maps:keys( |
| 1569 | + lists:foldl(fun({{_, P}, _}, Acc) -> |
| 1570 | + Acc#{node(P) => ok} |
| 1571 | + end, Nodes1, WaitingConsumers0)). |
| 1572 | + |
| 1573 | +all_pids_for(Node, #?MODULE{consumers = Cons0, |
| 1574 | + enqueuers = Enqs0, |
| 1575 | + waiting_consumers = WaitingConsumers0}) -> |
| 1576 | + Cons = maps:fold(fun({_, P}, _, Acc) |
| 1577 | + when node(P) =:= Node -> |
| 1578 | + [P | Acc]; |
| 1579 | + (_, _, Acc) -> Acc |
| 1580 | + end, [], Cons0), |
| 1581 | + Enqs = maps:fold(fun(P, _, Acc) |
| 1582 | + when node(P) =:= Node -> |
| 1583 | + [P | Acc]; |
| 1584 | + (_, _, Acc) -> Acc |
| 1585 | + end, Cons, Enqs0), |
| 1586 | + lists:foldl(fun({{_, P}, _}, Acc) |
| 1587 | + when node(P) =:= Node -> |
| 1588 | + [P | Acc]; |
| 1589 | + (_, Acc) -> Acc |
| 1590 | + end, Enqs, WaitingConsumers0). |
| 1591 | + |
1535 | 1592 | suspected_pids_for(Node, #?MODULE{consumers = Cons0,
|
1536 | 1593 | enqueuers = Enqs0,
|
1537 | 1594 | waiting_consumers = WaitingConsumers0}) ->
|
|
0 commit comments