203203 delayed_op / 0 ]).
204204
205205-spec init (config ()) -> state ().
206- init (#{name := Name ,
207- queue_resource := Resource } = Conf ) ->
206+ init (#{name := Name , queue_resource := Resource } = Conf ) ->
208207 update_config (Conf , #? STATE {cfg = # cfg {name = Name ,
209208 resource = Resource }}).
210209
@@ -696,9 +695,12 @@ apply_(Meta, {nodeup, Node}, #?STATE{consumers = Cons0,
696695apply_ (_ , {nodedown , _Node }, State ) ->
697696 {State , ok };
698697apply_ (Meta , # purge_nodes {nodes = Nodes }, State0 ) ->
699- {State , Effects } = lists :foldl (fun (Node , {S , E }) ->
698+ {State1 , Effects } = lists :foldl (fun (Node , {S , E }) ->
700699 purge_node (Meta , Node , S , E )
701700 end , {State0 , []}, Nodes ),
701+ State = State1 #? STATE {
702+ ingress_bytes_by_node =
703+ maps :without (Nodes , State1 #? STATE .ingress_bytes_by_node )},
702704 {State , ok , Effects };
703705apply_ (Meta ,
704706 # update_config {config = #{} = Conf },
@@ -967,8 +969,7 @@ credit_reply_resend_effect(#?STATE{waiting_consumers = Waiting,
967969 end , [], maps :merge (Consumers , maps :from_list (Waiting ))).
968970
969971convert_v8_to_v9 (#{} = _Meta , StateV8 ) ->
970- State = StateV8 ,
971- State .
972+ erlang :append_element (StateV8 , #{}).
972973
973974purge_node (Meta , Node , State , Effects ) ->
974975 lists :foldl (fun (Pid , {S0 , E0 }) ->
@@ -1171,7 +1172,8 @@ overview(#?STATE{consumers = Cons,
11711172 reclaimable_bytes_count => ReclaimableBytes ,
11721173 smallest_raft_index => smallest_raft_index (State ),
11731174 num_active_priorities => NumActivePriorities ,
1174- messages_by_priority => Detail
1175+ messages_by_priority => Detail ,
1176+ ingress_bytes_by_node => State #? STATE .ingress_bytes_by_node
11751177 },
11761178 DlxOverview = dlx_overview (DlxState ),
11771179 maps :merge (maps :merge (Overview , DlxOverview ), SacOverview ).
@@ -1205,7 +1207,13 @@ which_module(7) -> rabbit_fifo_v7;
12051207which_module (8 ) -> rabbit_fifo_v8 ;
12061208which_module (9 ) -> ? MODULE .
12071209
1208- -define (AUX , aux_v4 ).
1210+ -define (AUX , aux_v5 ).
1211+ -define (DEFAULT_INGRESS_DECAY_MS , 60_000 ).
1212+
1213+ -record (ingress_aux ,
1214+ {last_totals = #{} :: #{node () | undefined => non_neg_integer ()},
1215+ estimators = #{} :: #{node () | undefined => ra_li :state ()},
1216+ decay_ms = ? DEFAULT_INGRESS_DECAY_MS :: pos_integer ()}).
12091217
12101218-record (snapshot , {index :: ra :index (),
12111219 timestamp :: milliseconds (),
@@ -1220,7 +1228,8 @@ which_module(9) -> ?MODULE.
12201228 gc = # aux_gc {} :: # aux_gc {},
12211229 tick_pid :: undefined | pid (),
12221230 cache = #{} :: map (),
1223- last_checkpoint :: tuple () | # snapshot {}
1231+ last_checkpoint :: tuple () | # snapshot {},
1232+ ingress = # ingress_aux {} :: # ingress_aux {}
12241233 }).
12251234
12261235init_aux (Name ) when is_atom (Name ) ->
@@ -1234,11 +1243,38 @@ init_aux(Name) when is_atom(Name) ->
12341243 ? SNAP_MIN_RECLAIMABLE_B }),
12351244 Range = max (1 , SnapMinReclaimable - ? SNAP_MIN_RECLAIMABLE_LOW_B ),
12361245 MinReclaimable = ? SNAP_MIN_RECLAIMABLE_LOW_B + rand :uniform (Range ),
1246+ DecayMs = persistent_term :get (rabbit_fifo_ingress_decay_ms ,
1247+ ? DEFAULT_INGRESS_DECAY_MS ),
12371248 #? AUX {name = Name ,
12381249 last_checkpoint = # snapshot {index = 0 ,
12391250 timestamp = erlang :system_time (millisecond ),
12401251 messages_total = 0 ,
1241- min_reclaimable = MinReclaimable }}.
1252+ min_reclaimable = MinReclaimable },
1253+ ingress = # ingress_aux {decay_ms = DecayMs }}.
1254+
1255+ update_ingress (Overview , Nodes , # ingress_aux {last_totals = LastTotals ,
1256+ estimators = Estimators0 ,
1257+ decay_ms = DecayMs } = Ingress ) ->
1258+ NewTotals = maps :get (ingress_bytes_by_node , Overview , #{}),
1259+ Ts = erlang :monotonic_time (millisecond ),
1260+ Estimators1 =
1261+ maps :fold (fun (Node , NewTotal , Est ) ->
1262+ Delta = NewTotal - maps :get (Node , LastTotals , 0 ),
1263+ Li0 = maps :get (Node , Est , ra_li :new (DecayMs )),
1264+ Li1 = ra_li :update (Delta , Ts , Li0 ),
1265+ Est #{Node => Li1 }
1266+ end , Estimators0 , NewTotals ),
1267+ ActiveNodes = sets :from_list (Nodes , [{version , 2 }]),
1268+ Estimators = maps :filter (fun (Node , _ ) ->
1269+ Node =:= undefined orelse
1270+ sets :is_element (Node , ActiveNodes )
1271+ end , Estimators1 ),
1272+ Ingress # ingress_aux {last_totals = NewTotals ,
1273+ estimators = Estimators }.
1274+
1275+ compute_ingress_rates (# ingress_aux {estimators = Estimators }) ->
1276+ Ts = erlang :monotonic_time (millisecond ),
1277+ maps :map (fun (_Node , Li ) -> ra_li :rate (Ts , Li ) end , Estimators ).
12421278
12431279handle_aux (RaftState , Tag , Cmd , AuxV2 , RaAux )
12441280 when element (1 , AuxV2 ) == aux_v2 ->
@@ -1256,6 +1292,19 @@ handle_aux(RaftState, Tag, Cmd, AuxV3, RaAux)
12561292 last_checkpoint = element (8 , AuxV3 )
12571293 },
12581294 handle_aux (RaftState , Tag , Cmd , AuxV4 , RaAux );
1295+ handle_aux (RaftState , Tag , Cmd , AuxV4 , RaAux )
1296+ when element (1 , AuxV4 ) == aux_v4 ->
1297+ DecayMs = persistent_term :get (rabbit_fifo_ingress_decay_ms ,
1298+ ? DEFAULT_INGRESS_DECAY_MS ),
1299+ AuxV5 = #? AUX {name = element (2 , AuxV4 ),
1300+ last_decorators_state = element (3 , AuxV4 ),
1301+ last_consumer_timeout = element (4 , AuxV4 ),
1302+ gc = element (5 , AuxV4 ),
1303+ tick_pid = element (6 , AuxV4 ),
1304+ cache = element (7 , AuxV4 ),
1305+ last_checkpoint = element (8 , AuxV4 ),
1306+ ingress = # ingress_aux {decay_ms = DecayMs }},
1307+ handle_aux (RaftState , Tag , Cmd , AuxV5 , RaAux );
12591308handle_aux (leader , cast , eval ,
12601309 #? AUX {last_decorators_state = LastDec ,
12611310 last_consumer_timeout = LastConTimeout0 ,
@@ -1348,22 +1397,25 @@ handle_aux(_RaftState, cast, {#return{msg_ids = MsgIds,
13481397 % % for returns with a delivery limit set we can just return as before
13491398 {no_reply , Aux0 , RaAux0 , [{append , Ret , {notify , Corr , Pid }}]}
13501399 end ;
1351- handle_aux (leader , _ , {handle_tick , [QName , Overview0 , Nodes ]},
1352- #? AUX {tick_pid = Pid } = Aux , RaAux ) ->
1353- Overview = Overview0 #{members_info => ra_aux :members_info (RaAux )},
1354- NewPid =
1355- case process_is_alive (Pid ) of
1356- false ->
1357- % % No active TICK pid
1358- % % this function spawns and returns the tick process pid
1359- rabbit_quorum_queue :handle_tick (QName , Overview , Nodes );
1360- true ->
1361- % % Active TICK pid, do nothing
1362- Pid
1363- end ,
13641400
1365- % % TODO: check consumer timeouts
1366- {no_reply , Aux #? AUX {tick_pid = NewPid }, RaAux , []};
1401+ handle_aux (RaftState , _ , {handle_tick , [QName , Overview0 , Nodes ]},
1402+ #? AUX {tick_pid = Pid , ingress = Ingress0 } = Aux , RaAux ) ->
1403+ Overview = Overview0 #{members_info => ra_aux :members_info (RaAux )},
1404+ Ingress = update_ingress (Overview0 , Nodes , Ingress0 ),
1405+ Aux1 = Aux #? AUX {ingress = Ingress },
1406+ case RaftState of
1407+ leader ->
1408+ NewPid =
1409+ case process_is_alive (Pid ) of
1410+ false ->
1411+ rabbit_quorum_queue :handle_tick (QName , Overview , Nodes );
1412+ true ->
1413+ Pid
1414+ end ,
1415+ {no_reply , Aux1 #? AUX {tick_pid = NewPid }, RaAux , []};
1416+ _ ->
1417+ {no_reply , Aux1 , RaAux , []}
1418+ end ;
13671419handle_aux (_ , _ , {get_checked_out , ConsumerKey , MsgIds }, Aux0 , RaAux0 ) ->
13681420 #? STATE {cfg = # cfg {},
13691421 consumers = Consumers } = ra_aux :machine_state (RaAux0 ),
@@ -1460,6 +1512,10 @@ handle_aux(leader, _, {dlx, setup}, Aux, RaAux) ->
14601512handle_aux (_ , _ , {dlx , teardown , Pid }, Aux , RaAux ) ->
14611513 terminate_dlx_worker (Pid ),
14621514 {no_reply , Aux , RaAux };
1515+ handle_aux (_ , {call , _From }, get_ingress_rates ,
1516+ #? AUX {ingress = Ingress } = Aux , RaAux ) ->
1517+ Rates = compute_ingress_rates (Ingress ),
1518+ {reply , {ok , Rates }, Aux , RaAux };
14631519handle_aux (_ , _ , Unhandled , Aux , RaAux ) ->
14641520 #? STATE {cfg = # cfg {resource = QR }} = ra_aux :machine_state (RaAux ),
14651521 ? LOG_DEBUG (" ~ts : rabbit_fifo: unhandled aux command ~P " ,
@@ -1907,12 +1963,24 @@ maybe_return_all(#{system_time := Ts} = Meta, ConsumerKey,
19071963 Effects }
19081964 end .
19091965
1966+ node_of (undefined ) -> undefined ;
1967+ node_of (Pid ) when is_pid (Pid ) -> node (Pid ).
1968+
1969+ bump_ingress (Node , Size , Map ) ->
1970+ maps :update_with (Node , fun (V ) -> V + Size end , Size , Map ).
1971+
19101972apply_enqueue (#{index := RaftIdx ,
19111973 system_time := Ts } = Meta , From ,
19121974 Seq , RawMsg , Size , State0 ) ->
19131975 case maybe_enqueue (RaftIdx , Ts , From , Seq , RawMsg , Size , [], State0 ) of
19141976 {ok , State1 , Effects1 } ->
1915- checkout (Meta , State0 , State1 , Effects1 );
1977+ {MetaSize , BodySize } = Size ,
1978+ TotalSize = MetaSize + BodySize ,
1979+ IngressByNode = State1 #? STATE .ingress_bytes_by_node ,
1980+ State2 = State1 #? STATE {
1981+ ingress_bytes_by_node =
1982+ bump_ingress (node_of (From ), TotalSize , IngressByNode )},
1983+ checkout (Meta , State0 , State2 , Effects1 );
19161984 {out_of_sequence , State , Effects } ->
19171985 {State , not_enqueued , Effects };
19181986 {duplicate , State , Effects } ->
0 commit comments