@@ -696,9 +696,12 @@ apply_(Meta, {nodeup, Node}, #?STATE{consumers = Cons0,
696696apply_ (_ , {nodedown , _Node }, State ) ->
697697 {State , ok };
698698apply_ (Meta , # purge_nodes {nodes = Nodes }, State0 ) ->
699- {State , Effects } = lists :foldl (fun (Node , {S , E }) ->
699+ {State1 , Effects } = lists :foldl (fun (Node , {S , E }) ->
700700 purge_node (Meta , Node , S , E )
701701 end , {State0 , []}, Nodes ),
702+ State = State1 #? STATE {
703+ ingress_bytes_by_node =
704+ maps :without (Nodes , State1 #? STATE .ingress_bytes_by_node )},
702705 {State , ok , Effects };
703706apply_ (Meta ,
704707 # update_config {config = #{} = Conf },
@@ -967,8 +970,7 @@ credit_reply_resend_effect(#?STATE{waiting_consumers = Waiting,
967970 end , [], maps :merge (Consumers , maps :from_list (Waiting ))).
968971
969972convert_v8_to_v9 (#{} = _Meta , StateV8 ) ->
970- State = StateV8 ,
971- State .
973+ StateV8 #? STATE {ingress_bytes_by_node = #{}}.
972974
973975purge_node (Meta , Node , State , Effects ) ->
974976 lists :foldl (fun (Pid , {S0 , E0 }) ->
@@ -1171,7 +1173,8 @@ overview(#?STATE{consumers = Cons,
11711173 reclaimable_bytes_count => ReclaimableBytes ,
11721174 smallest_raft_index => smallest_raft_index (State ),
11731175 num_active_priorities => NumActivePriorities ,
1174- messages_by_priority => Detail
1176+ messages_by_priority => Detail ,
1177+ ingress_bytes_by_node => State #? STATE .ingress_bytes_by_node
11751178 },
11761179 DlxOverview = dlx_overview (DlxState ),
11771180 maps :merge (maps :merge (Overview , DlxOverview ), SacOverview ).
@@ -1205,7 +1208,13 @@ which_module(7) -> rabbit_fifo_v7;
12051208which_module (8 ) -> rabbit_fifo_v8 ;
12061209which_module (9 ) -> ? MODULE .
12071210
1208- -define (AUX , aux_v4 ).
1211+ -define (AUX , aux_v5 ).
1212+ -define (DEFAULT_INGRESS_DECAY_MS , 60_000 ).
1213+
1214+ -record (ingress_aux ,
1215+ {last_totals = #{} :: #{node () | undefined => non_neg_integer ()},
1216+ estimators = #{} :: #{node () | undefined => ra_li :state ()},
1217+ decay_ms = ? DEFAULT_INGRESS_DECAY_MS :: pos_integer ()}).
12091218
12101219-record (snapshot , {index :: ra :index (),
12111220 timestamp :: milliseconds (),
@@ -1220,7 +1229,8 @@ which_module(9) -> ?MODULE.
12201229 gc = # aux_gc {} :: # aux_gc {},
12211230 tick_pid :: undefined | pid (),
12221231 cache = #{} :: map (),
1223- last_checkpoint :: tuple () | # snapshot {}
1232+ last_checkpoint :: tuple () | # snapshot {},
1233+ ingress = # ingress_aux {} :: # ingress_aux {}
12241234 }).
12251235
12261236init_aux (Name ) when is_atom (Name ) ->
@@ -1234,11 +1244,38 @@ init_aux(Name) when is_atom(Name) ->
12341244 ? SNAP_MIN_RECLAIMABLE_B }),
12351245 Range = max (1 , SnapMinReclaimable - ? SNAP_MIN_RECLAIMABLE_LOW_B ),
12361246 MinReclaimable = ? SNAP_MIN_RECLAIMABLE_LOW_B + rand :uniform (Range ),
1247+ DecayMs = persistent_term :get (rabbit_fifo_ingress_decay_ms ,
1248+ ? DEFAULT_INGRESS_DECAY_MS ),
12371249 #? AUX {name = Name ,
12381250 last_checkpoint = # snapshot {index = 0 ,
12391251 timestamp = erlang :system_time (millisecond ),
12401252 messages_total = 0 ,
1241- min_reclaimable = MinReclaimable }}.
1253+ min_reclaimable = MinReclaimable },
1254+ ingress = # ingress_aux {decay_ms = DecayMs }}.
1255+
1256+ update_ingress (Overview , Nodes , # ingress_aux {last_totals = LastTotals ,
1257+ estimators = Estimators0 ,
1258+ decay_ms = DecayMs } = Ingress ) ->
1259+ NewTotals = maps :get (ingress_bytes_by_node , Overview , #{}),
1260+ Ts = erlang :monotonic_time (millisecond ),
1261+ Estimators1 =
1262+ maps :fold (fun (Node , NewTotal , Est ) ->
1263+ Delta = NewTotal - maps :get (Node , LastTotals , 0 ),
1264+ Li0 = maps :get (Node , Est , ra_li :new (DecayMs )),
1265+ Li1 = ra_li :update (Delta , Ts , Li0 ),
1266+ Est #{Node => Li1 }
1267+ end , Estimators0 , NewTotals ),
1268+ ActiveNodes = sets :from_list (Nodes , [{version , 2 }]),
1269+ Estimators = maps :filter (fun (Node , _ ) ->
1270+ Node =:= undefined orelse
1271+ sets :is_element (Node , ActiveNodes )
1272+ end , Estimators1 ),
1273+ Ingress # ingress_aux {last_totals = NewTotals ,
1274+ estimators = Estimators }.
1275+
1276+ compute_ingress_rates (# ingress_aux {estimators = Estimators }) ->
1277+ Ts = erlang :monotonic_time (millisecond ),
1278+ maps :map (fun (_Node , Li ) -> ra_li :rate (Ts , Li ) end , Estimators ).
12421279
12431280handle_aux (RaftState , Tag , Cmd , AuxV2 , RaAux )
12441281 when element (1 , AuxV2 ) == aux_v2 ->
@@ -1256,6 +1293,19 @@ handle_aux(RaftState, Tag, Cmd, AuxV3, RaAux)
12561293 last_checkpoint = element (8 , AuxV3 )
12571294 },
12581295 handle_aux (RaftState , Tag , Cmd , AuxV4 , RaAux );
1296+ handle_aux (RaftState , Tag , Cmd , AuxV4 , RaAux )
1297+ when element (1 , AuxV4 ) == aux_v4 ->
1298+ DecayMs = persistent_term :get (rabbit_fifo_ingress_decay_ms ,
1299+ ? DEFAULT_INGRESS_DECAY_MS ),
1300+ AuxV5 = #? AUX {name = element (2 , AuxV4 ),
1301+ last_decorators_state = element (3 , AuxV4 ),
1302+ last_consumer_timeout = element (4 , AuxV4 ),
1303+ gc = element (5 , AuxV4 ),
1304+ tick_pid = element (6 , AuxV4 ),
1305+ cache = element (7 , AuxV4 ),
1306+ last_checkpoint = element (8 , AuxV4 ),
1307+ ingress = # ingress_aux {decay_ms = DecayMs }},
1308+ handle_aux (RaftState , Tag , Cmd , AuxV5 , RaAux );
12591309handle_aux (leader , cast , eval ,
12601310 #? AUX {last_decorators_state = LastDec ,
12611311 last_consumer_timeout = LastConTimeout0 ,
@@ -1348,22 +1398,25 @@ handle_aux(_RaftState, cast, {#return{msg_ids = MsgIds,
13481398 % % for returns with a delivery limit set we can just return as before
13491399 {no_reply , Aux0 , RaAux0 , [{append , Ret , {notify , Corr , Pid }}]}
13501400 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 ,
13641401
1365- % % TODO: check consumer timeouts
1366- {no_reply , Aux #? AUX {tick_pid = NewPid }, RaAux , []};
1402+ handle_aux (RaftState , _ , {handle_tick , [QName , Overview0 , Nodes ]},
1403+ #? AUX {tick_pid = Pid , ingress = Ingress0 } = Aux , RaAux ) ->
1404+ Overview = Overview0 #{members_info => ra_aux :members_info (RaAux )},
1405+ Ingress = update_ingress (Overview0 , Nodes , Ingress0 ),
1406+ Aux1 = Aux #? AUX {ingress = Ingress },
1407+ case RaftState of
1408+ leader ->
1409+ NewPid =
1410+ case process_is_alive (Pid ) of
1411+ false ->
1412+ rabbit_quorum_queue :handle_tick (QName , Overview , Nodes );
1413+ true ->
1414+ Pid
1415+ end ,
1416+ {no_reply , Aux1 #? AUX {tick_pid = NewPid }, RaAux , []};
1417+ _ ->
1418+ {no_reply , Aux1 , RaAux , []}
1419+ end ;
13671420handle_aux (_ , _ , {get_checked_out , ConsumerKey , MsgIds }, Aux0 , RaAux0 ) ->
13681421 #? STATE {cfg = # cfg {},
13691422 consumers = Consumers } = ra_aux :machine_state (RaAux0 ),
@@ -1460,6 +1513,10 @@ handle_aux(leader, _, {dlx, setup}, Aux, RaAux) ->
14601513handle_aux (_ , _ , {dlx , teardown , Pid }, Aux , RaAux ) ->
14611514 terminate_dlx_worker (Pid ),
14621515 {no_reply , Aux , RaAux };
1516+ handle_aux (_ , {call , _From }, get_ingress_rates ,
1517+ #? AUX {ingress = Ingress } = Aux , RaAux ) ->
1518+ Rates = compute_ingress_rates (Ingress ),
1519+ {reply , {ok , Rates }, Aux , RaAux };
14631520handle_aux (_ , _ , Unhandled , Aux , RaAux ) ->
14641521 #? STATE {cfg = # cfg {resource = QR }} = ra_aux :machine_state (RaAux ),
14651522 ? LOG_DEBUG (" ~ts : rabbit_fifo: unhandled aux command ~P " ,
@@ -1907,12 +1964,24 @@ maybe_return_all(#{system_time := Ts} = Meta, ConsumerKey,
19071964 Effects }
19081965 end .
19091966
1967+ node_of (undefined ) -> undefined ;
1968+ node_of (Pid ) when is_pid (Pid ) -> node (Pid ).
1969+
1970+ bump_ingress (Node , Size , Map ) ->
1971+ maps :update_with (Node , fun (V ) -> V + Size end , Size , Map ).
1972+
19101973apply_enqueue (#{index := RaftIdx ,
19111974 system_time := Ts } = Meta , From ,
19121975 Seq , RawMsg , Size , State0 ) ->
19131976 case maybe_enqueue (RaftIdx , Ts , From , Seq , RawMsg , Size , [], State0 ) of
19141977 {ok , State1 , Effects1 } ->
1915- checkout (Meta , State0 , State1 , Effects1 );
1978+ {MetaSize , BodySize } = Size ,
1979+ TotalSize = MetaSize + BodySize ,
1980+ IngressByNode = State1 #? STATE .ingress_bytes_by_node ,
1981+ State2 = State1 #? STATE {
1982+ ingress_bytes_by_node =
1983+ bump_ingress (node_of (From ), TotalSize , IngressByNode )},
1984+ checkout (Meta , State0 , State2 , Effects1 );
19161985 {out_of_sequence , State , Effects } ->
19171986 {State , not_enqueued , Effects };
19181987 {duplicate , State , Effects } ->
0 commit comments