384384 stashed_eol = [] :: [rabbit_amqqueue :name ()],
385385
386386 queue_states = rabbit_queue_type :init () :: rabbit_queue_type :state (),
387+ queue_types_published = sets :new ([{version , 2 }]) ::
388+ sets :set (rabbit_queue_type :queue_type ()),
387389 permission_cache = [] :: permission_cache (),
388390 topic_permission_cache = [] :: topic_permission_cache ()
389391 }).
@@ -451,9 +453,14 @@ init({ReaderPid, WriterPid, ChannelNum, MaxFrameSize, User, Vhost, ContainerId,
451453 true = is_valid_max (MaxLinkCredit ),
452454 true = is_valid_max (MaxQueueCredit ),
453455 true = is_valid_max (MaxIncomingWindow ),
454- IncomingWindow = case sets :is_empty (Alarms ) of
455- true -> MaxIncomingWindow ;
456- false -> 0
456+ InResourceAlarm = sets :fold (fun ({disk , _ }, Acc ) ->
457+ Acc ;
458+ (_ , _ ) ->
459+ true
460+ end , false , Alarms ),
461+ IncomingWindow = case InResourceAlarm of
462+ true -> 0 ;
463+ false -> MaxIncomingWindow
457464 end ,
458465 NextOutgoingId = ? INITIAL_OUTGOING_TRANSFER_ID ,
459466
@@ -585,36 +592,17 @@ handle_cast({queue_event, _, _} = QEvent, State0) ->
585592 log_error_and_close_session (Error , State0 )
586593 end ;
587594handle_cast ({conserve_resources , Alarm , Conserve },
588- # state {incoming_window = IncomingWindow0 ,
589- cfg = # cfg {resource_alarms = Alarms0 ,
590- incoming_window_margin = Margin0 ,
595+ # state {cfg = # cfg {resource_alarms = Alarms0 ,
591596 writer_pid = WriterPid ,
592- channel_num = Ch ,
593- max_incoming_window = MaxIncomingWindow
597+ channel_num = Ch
594598 } = Cfg
595599 } = State0 ) ->
596600 Alarms = case Conserve of
597601 true -> sets :add_element (Alarm , Alarms0 );
598602 false -> sets :del_element (Alarm , Alarms0 )
599603 end ,
600- {SendFlow , IncomingWindow , Margin } =
601- case {sets :is_empty (Alarms0 ), sets :is_empty (Alarms )} of
602- {true , false } ->
603- % % Alarm kicked in.
604- % % Notify the client to not send us any more TRANSFERs. Since we decrase
605- % % our incoming window dynamically, there might be incoming in-flight
606- % % TRANSFERs. So, let's be lax and allow for some excess TRANSFERs.
607- {true , 0 , MaxIncomingWindow };
608- {false , true } ->
609- % % All alarms cleared.
610- % % Notify the client that it can resume sending us TRANSFERs.
611- {true , MaxIncomingWindow , 0 };
612- _ ->
613- {false , IncomingWindow0 , Margin0 }
614- end ,
615- State = State0 # state {incoming_window = IncomingWindow ,
616- cfg = Cfg # cfg {resource_alarms = Alarms ,
617- incoming_window_margin = Margin }},
604+ State1 = State0 # state {cfg = Cfg # cfg {resource_alarms = Alarms }},
605+ {SendFlow , State } = check_resource_alarm (State0 , State1 ),
618606 case SendFlow of
619607 true ->
620608 Flow = session_flow_fields (# 'v1_0.flow' {}, State ),
@@ -640,6 +628,41 @@ handle_cast({reset_authz, User}, #state{cfg = Cfg} = State0) ->
640628handle_cast (shutdown , State ) ->
641629 {stop , normal , State }.
642630
631+ is_in_resource_alarm (# state {cfg = # cfg {resource_alarms = Alarms },
632+ queue_types_published = QTs }) ->
633+ sets :fold (
634+ fun ({disk , QT }, Acc ) ->
635+ Acc orelse sets :is_element (QT , QTs );
636+ (_ , _ ) ->
637+ true
638+ end , false , Alarms ).
639+
640+ check_resource_alarm (State0 ,
641+ # state {incoming_window = IncomingWindow0 ,
642+ cfg = # cfg {incoming_window_margin = Margin0 ,
643+ max_incoming_window = MaxIncomingWindow
644+ } = Cfg } = State1 ) ->
645+ WasBlocked = is_in_resource_alarm (State0 ),
646+ IsBlocked = is_in_resource_alarm (State1 ),
647+ {SendFlow , IncomingWindow , Margin } =
648+ case IsBlocked of
649+ true when not WasBlocked ->
650+ % % Alarm kicked in.
651+ % % Notify the client to not send us any more TRANSFERs. Since we decrase
652+ % % our incoming window dynamically, there might be incoming in-flight
653+ % % TRANSFERs. So, let's be lax and allow for some excess TRANSFERs.
654+ {true , 0 , MaxIncomingWindow };
655+ false when WasBlocked ->
656+ % % All alarms cleared.
657+ % % Notify the client that it can resume sending us TRANSFERs.
658+ {true , MaxIncomingWindow , 0 };
659+ _ ->
660+ {false , IncomingWindow0 , Margin0 }
661+ end ,
662+ State = State1 # state {incoming_window = IncomingWindow ,
663+ cfg = Cfg # cfg {incoming_window_margin = Margin }},
664+ {SendFlow , State }.
665+
643666log_error_and_close_session (
644667 Error , State = # state {cfg = # cfg {reader_pid = ReaderPid ,
645668 writer_pid = WriterPid ,
@@ -1958,7 +1981,6 @@ session_flow_control_received_transfer(
19581981 incoming_window = InWindow0 ,
19591982 remote_outgoing_window = RemoteOutgoingWindow ,
19601983 cfg = # cfg {incoming_window_margin = Margin ,
1961- resource_alarms = Alarms ,
19621984 max_incoming_window = MaxIncomingWindow }
19631985 } = State ) ->
19641986 InWindow1 = InWindow0 - 1 ,
@@ -1972,7 +1994,7 @@ session_flow_control_received_transfer(
19721994 ok
19731995 end ,
19741996 {Flows , InWindow } = case InWindow1 =< (MaxIncomingWindow div 2 ) andalso
1975- sets : is_empty ( Alarms ) of
1997+ not is_in_resource_alarm ( State ) of
19761998 true ->
19771999 % % We've reached halfway and there are no
19782000 % % disk or memory alarm, open the window.
@@ -2388,6 +2410,7 @@ incoming_link_transfer(
23882410 multi_transfer_msg = MultiTransfer
23892411 } = Link0 ,
23902412 State0 = # state {queue_states = QStates0 ,
2413+ queue_types_published = QTs0 ,
23912414 permission_cache = PermCache0 ,
23922415 topic_permission_cache = TopicPermCache0 ,
23932416 cfg = # cfg {user = User = # user {username = Username },
@@ -2435,19 +2458,26 @@ incoming_link_transfer(
24352458 Qs = rabbit_amqqueue :prepend_extra_bcc (Qs0 ),
24362459 case rabbit_queue_type :deliver (Qs , Mc , Opts , QStates0 ) of
24372460 {ok , QStates , Actions } ->
2461+ QTs1 = sets :from_list (rabbit_amqqueue :queue_types (Qs ),
2462+ [{version , 2 }]),
2463+ QTs = sets :union (QTs0 , QTs1 ),
24382464 State1 = State0 # state {queue_states = QStates ,
2465+ queue_types_published = QTs ,
24392466 permission_cache = PermCache ,
24402467 topic_permission_cache = TopicPermCache },
24412468 % % Confirms must be registered before processing actions
24422469 % % because actions may contain rejections of publishes.
24432470 {U , Reply0 } = process_routing_confirm (
24442471 Qs , Settled , DeliveryId , U0 ),
2445- State = handle_queue_actions (Actions , State1 ),
2472+ State2 = handle_queue_actions (Actions , State1 ),
2473+ {SendAlarmFlow , State } = check_resource_alarm (
2474+ State0 , State2 ),
24462475 DeliveryCount = add (DeliveryCount0 , 1 ),
24472476 Credit1 = Credit0 - 1 ,
24482477 {Credit , Reply1 } = maybe_grant_link_credit (
24492478 Credit1 , MaxLinkCredit ,
2450- DeliveryCount , map_size (U ), Handle ),
2479+ DeliveryCount , map_size (U ), Handle ,
2480+ SendAlarmFlow ),
24512481 Reply = Reply0 ++ Reply1 ,
24522482 Link = Link0 # incoming_link {
24532483 delivery_count = DeliveryCount ,
@@ -2482,7 +2512,8 @@ incoming_link_transfer(
24822512 Credit1 = Credit0 - 1 ,
24832513 {Credit , Reply0 } = maybe_grant_link_credit (
24842514 Credit1 , MaxLinkCredit ,
2485- DeliveryCount , map_size (U0 ), Handle ),
2515+ DeliveryCount , map_size (U0 ), Handle ,
2516+ false ),
24862517 Reply = [Disposition | Reply0 ],
24872518 Link = Link0 # incoming_link {
24882519 delivery_count = DeliveryCount ,
@@ -2613,8 +2644,9 @@ rejected(QNameBin, down) ->
26132644 {{symbol , <<" reason" >>}, {symbol , <<" unavailable" >>}}]}}}.
26142645
26152646
2616- maybe_grant_link_credit (Credit , MaxLinkCredit , DeliveryCount , NumUnconfirmed , Handle ) ->
2617- case grant_link_credit (Credit , MaxLinkCredit , NumUnconfirmed ) of
2647+ maybe_grant_link_credit (Credit , MaxLinkCredit , DeliveryCount , NumUnconfirmed ,
2648+ Handle , AlarmFlow ) ->
2649+ case grant_link_credit (Credit , MaxLinkCredit , NumUnconfirmed ) orelse AlarmFlow of
26182650 true ->
26192651 {MaxLinkCredit , [flow (Handle , DeliveryCount , MaxLinkCredit )]};
26202652 false ->
0 commit comments