|
113 | 113 | %% a set of the reasons why we are |
114 | 114 | %% blocked: {resource, memory}, {resource, disk}. |
115 | 115 | %% More reasons can be added in the future. |
116 | | - blocked_by, |
| 116 | + blocked_by = sets:new([{version, 2}]) :: |
| 117 | + sets:set(flow | {resource, |
| 118 | + rabbit_alarm:resource_alarm_source()}), |
| 119 | + %% the set of queue types which have been published to |
| 120 | + %% by channels on this connection, used for per-queue |
| 121 | + %% type disk alarm blocking |
| 122 | + queue_types_published = #{} :: #{ChannelPid :: pid() => |
| 123 | + sets:set(rabbit_queue_type:queue_type())}, |
117 | 124 | %% true if received any publishes, false otherwise |
118 | 125 | %% note that this will also be true when connection is |
119 | 126 | %% already blocked |
@@ -335,7 +342,6 @@ start_connection(Parent, HelperSups, RanchRef, Deb, Sock) -> |
335 | 342 | throttle = #throttle{ |
336 | 343 | last_blocked_at = never, |
337 | 344 | should_block = false, |
338 | | - blocked_by = sets:new([{version, 2}]), |
339 | 345 | connection_blocked_message_sent = false |
340 | 346 | }, |
341 | 347 | proxy_socket = rabbit_net:maybe_get_proxy_socket(Sock)}, |
@@ -677,6 +683,14 @@ handle_other({'$gen_cast', {force_event_refresh, Ref}}, State) |
677 | 683 | handle_other({'$gen_cast', {force_event_refresh, _Ref}}, State) -> |
678 | 684 | %% Ignore, we will emit a created event once we start running. |
679 | 685 | State; |
| 686 | +handle_other({'$gen_cast', {channel_published_to_queue_type, ChPid, QT}}, |
| 687 | + #v1{throttle = Throttle0} = State0) -> |
| 688 | + QTs = maps:update_with( |
| 689 | + ChPid, fun(ChQTs) -> sets:add_element(QT, ChQTs) end, |
| 690 | + sets:from_list([QT], [{version, 2}]), |
| 691 | + Throttle0#throttle.queue_types_published), |
| 692 | + Throttle = Throttle0#throttle{queue_types_published = QTs}, |
| 693 | + control_throttle(State0#v1{throttle = Throttle}); |
680 | 694 | handle_other(ensure_stats, State) -> |
681 | 695 | ensure_stats_timer(State); |
682 | 696 | handle_other(emit_stats, State) -> |
@@ -1007,14 +1021,21 @@ is_over_node_channel_limit() -> |
1007 | 1021 | end |
1008 | 1022 | end. |
1009 | 1023 |
|
1010 | | -channel_cleanup(ChPid, State = #v1{channel_count = ChannelCount}) -> |
| 1024 | +channel_cleanup(ChPid, State = #v1{channel_count = ChannelCount, |
| 1025 | + throttle = Throttle0} = State) -> |
1011 | 1026 | case get({ch_pid, ChPid}) of |
1012 | | - undefined -> {undefined, State}; |
1013 | | - {Channel, MRef} -> credit_flow:peer_down(ChPid), |
1014 | | - erase({channel, Channel}), |
1015 | | - erase({ch_pid, ChPid}), |
1016 | | - erlang:demonitor(MRef, [flush]), |
1017 | | - {Channel, State#v1{channel_count = ChannelCount - 1}} |
| 1027 | + undefined -> |
| 1028 | + {undefined, State}; |
| 1029 | + {Channel, MRef} -> |
| 1030 | + credit_flow:peer_down(ChPid), |
| 1031 | + erase({channel, Channel}), |
| 1032 | + erase({ch_pid, ChPid}), |
| 1033 | + erlang:demonitor(MRef, [flush]), |
| 1034 | + QT = maps:remove(ChPid, |
| 1035 | + Throttle0#throttle.queue_types_published), |
| 1036 | + Throttle = Throttle0#throttle{queue_types_published = QT}, |
| 1037 | + {Channel, State#v1{channel_count = ChannelCount - 1, |
| 1038 | + throttle = Throttle}} |
1018 | 1039 | end. |
1019 | 1040 |
|
1020 | 1041 | all_channels() -> [ChPid || {{ch_pid, ChPid}, _ChannelMRef} <- get()]. |
@@ -1738,22 +1759,44 @@ update_last_blocked_at(Throttle) -> |
1738 | 1759 | connection_blocked_message_sent( |
1739 | 1760 | #throttle{connection_blocked_message_sent = BS}) -> BS. |
1740 | 1761 |
|
1741 | | -should_send_blocked(Throttle = #throttle{blocked_by = Reasons}) -> |
| 1762 | +should_send_blocked(Throttle) -> |
1742 | 1763 | should_block(Throttle) |
1743 | 1764 | andalso |
1744 | | - sets:size(sets:del_element(flow, Reasons)) =/= 0 |
| 1765 | + do_throttle_reasons_apply(Throttle) |
1745 | 1766 | andalso |
1746 | 1767 | not connection_blocked_message_sent(Throttle). |
1747 | 1768 |
|
1748 | | -should_send_unblocked(Throttle = #throttle{blocked_by = Reasons}) -> |
| 1769 | +should_send_unblocked(Throttle) -> |
1749 | 1770 | connection_blocked_message_sent(Throttle) |
1750 | 1771 | andalso |
1751 | | - sets:size(sets:del_element(flow, Reasons)) == 0. |
| 1772 | + not do_throttle_reasons_apply(Throttle). |
| 1773 | + |
| 1774 | +do_throttle_reasons_apply(#throttle{blocked_by = Reasons} = Throttle) -> |
| 1775 | + lists:any( |
| 1776 | + fun ({resource, disk}) -> |
| 1777 | + true; |
| 1778 | + ({resource, memory}) -> |
| 1779 | + true; |
| 1780 | + ({resource, {disk, QT}}) -> |
| 1781 | + has_published_to_queue_type(QT, Throttle); |
| 1782 | + (_) -> |
| 1783 | + %% Flow control should not send connection.blocked |
| 1784 | + false |
| 1785 | + end, sets:to_list(Reasons)). |
| 1786 | + |
| 1787 | +has_published_to_queue_type(QT, #throttle{queue_types_published = QTs}) -> |
| 1788 | + rabbit_misc:maps_any( |
| 1789 | + fun(_ChPid, ChQT) -> sets:is_element(QT, ChQT) end, QTs). |
1752 | 1790 |
|
1753 | 1791 | %% Returns true if we have a reason to block |
1754 | 1792 | %% this connection. |
1755 | | -has_reasons_to_block(#throttle{blocked_by = Reasons}) -> |
1756 | | - sets:size(Reasons) > 0. |
| 1793 | +has_reasons_to_block(#throttle{blocked_by = Reasons} = Throttle) -> |
| 1794 | + lists:any( |
| 1795 | + fun ({resource, {disk, QType}}) -> |
| 1796 | + has_published_to_queue_type(QType, Throttle); |
| 1797 | + (_) -> |
| 1798 | + true |
| 1799 | + end, sets:to_list(Reasons)). |
1757 | 1800 |
|
1758 | 1801 | is_blocked_by_flow(#throttle{blocked_by = Reasons}) -> |
1759 | 1802 | sets:is_element(flow, Reasons). |
|
0 commit comments