42
42
% % ra_machine callbacks
43
43
init /1 ,
44
44
apply /3 ,
45
+ live_indexes /1 ,
45
46
state_enter /2 ,
46
47
tick /2 ,
47
48
overview /1 ,
@@ -680,6 +681,15 @@ apply(_Meta, Cmd, State) ->
680
681
? LOG_DEBUG (" rabbit_fifo: unhandled command ~W " , [Cmd , 10 ]),
681
682
{State , ok , []}.
682
683
684
+ -spec live_indexes (state ()) ->
685
+ [ra :index ()].
686
+ live_indexes (#? STATE {returns = Returns ,
687
+ messages = Messages ,
688
+ dlx = Dlx }) ->
689
+ DlxIndexes = rabbit_fifo_dlx :live_indexes (Dlx ),
690
+ RtnIndexes = [I || ? MSG (I , _ ) <- lqueue :to_list (Returns )],
691
+ DlxIndexes ++ RtnIndexes ++ rabbit_fifo_q :indexes (Messages ).
692
+
683
693
convert_v3_to_v4 (#{} = _Meta , StateV3 ) ->
684
694
% % TODO: consider emitting release cursors as checkpoints
685
695
Messages0 = rabbit_fifo_v3 :get_field (messages , StateV3 ),
@@ -932,7 +942,7 @@ get_checked_out(CKey, From, To, #?STATE{consumers = Consumers}) ->
932
942
end .
933
943
934
944
-spec version () -> pos_integer ().
935
- version () -> 7 .
945
+ version () -> 8 .
936
946
937
947
which_module (0 ) -> rabbit_fifo_v0 ;
938
948
which_module (1 ) -> rabbit_fifo_v1 ;
@@ -941,7 +951,8 @@ which_module(3) -> rabbit_fifo_v3;
941
951
which_module (4 ) -> ? MODULE ;
942
952
which_module (5 ) -> ? MODULE ;
943
953
which_module (6 ) -> ? MODULE ;
944
- which_module (7 ) -> ? MODULE .
954
+ which_module (7 ) -> ? MODULE ;
955
+ which_module (8 ) -> ? MODULE .
945
956
946
957
-define (AUX , aux_v3 ).
947
958
@@ -951,6 +962,12 @@ which_module(7) -> ?MODULE.
951
962
messages_total :: non_neg_integer (),
952
963
indexes = ? CHECK_MIN_INDEXES :: non_neg_integer (),
953
964
bytes_in = 0 :: non_neg_integer ()}).
965
+ -record (snapshot , {index :: ra :index (),
966
+ timestamp :: milliseconds (),
967
+ % smallest_index :: undefined | ra:index(),
968
+ messages_total :: non_neg_integer (),
969
+ % indexes = ?CHECK_MIN_INDEXES :: non_neg_integer(),
970
+ bytes_out = 0 :: non_neg_integer ()}).
954
971
-record (aux_gc , {last_raft_idx = 0 :: ra :index ()}).
955
972
-record (aux , {name :: atom (),
956
973
capacity :: term (),
@@ -961,7 +978,7 @@ which_module(7) -> ?MODULE.
961
978
gc = # aux_gc {} :: # aux_gc {},
962
979
tick_pid :: undefined | pid (),
963
980
cache = #{} :: map (),
964
- last_checkpoint :: # checkpoint {},
981
+ last_checkpoint :: # checkpoint {} | # snapshot {} ,
965
982
bytes_in = 0 :: non_neg_integer (),
966
983
bytes_out = 0 :: non_neg_integer ()}).
967
984
@@ -973,10 +990,10 @@ init_aux(Name) when is_atom(Name) ->
973
990
Now = erlang :monotonic_time (microsecond ),
974
991
#? AUX {name = Name ,
975
992
capacity = {inactive , Now , 1 , 1.0 },
976
- last_checkpoint = # checkpoint {index = 0 ,
977
- timestamp = erlang :system_time (millisecond ),
978
- messages_total = 0 ,
979
- bytes_in = 0 }}.
993
+ last_checkpoint = # snapshot {index = 0 ,
994
+ timestamp = erlang :system_time (millisecond ),
995
+ messages_total = 0 ,
996
+ bytes_out = 0 }}.
980
997
981
998
handle_aux (RaftState , Tag , Cmd , # aux {name = Name ,
982
999
capacity = Cap ,
@@ -994,13 +1011,16 @@ handle_aux(RaftState, Tag, Cmd, AuxV2, RaAux)
994
1011
handle_aux (leader , cast , eval ,
995
1012
#? AUX {last_decorators_state = LastDec ,
996
1013
bytes_in = BytesIn ,
1014
+ bytes_out = BytesOut ,
997
1015
last_checkpoint = Check0 } = Aux0 ,
998
1016
RaAux ) ->
999
1017
#? STATE {cfg = # cfg {resource = QName }} = MacState =
1000
1018
ra_aux :machine_state (RaAux ),
1001
1019
1002
1020
Ts = erlang :system_time (millisecond ),
1003
- {Check , Effects0 } = do_checkpoints (Ts , Check0 , RaAux , BytesIn , false ),
1021
+ EffMacVer = ra_aux :effective_machine_version (RaAux ),
1022
+ {Check , Effects0 } = do_checkpoints (EffMacVer , Ts , Check0 , RaAux ,
1023
+ BytesIn , BytesOut , false ),
1004
1024
1005
1025
% % this is called after each batch of commands have been applied
1006
1026
% % set timer for message expire
@@ -1017,15 +1037,23 @@ handle_aux(leader, cast, eval,
1017
1037
end ;
1018
1038
handle_aux (_RaftState , cast , eval ,
1019
1039
#? AUX {last_checkpoint = Check0 ,
1020
- bytes_in = BytesIn } = Aux0 ,
1040
+ bytes_in = BytesIn ,
1041
+ bytes_out = BytesOut
1042
+ } = Aux0 ,
1021
1043
RaAux ) ->
1022
1044
Ts = erlang :system_time (millisecond ),
1023
- {Check , Effects } = do_checkpoints (Ts , Check0 , RaAux , BytesIn , false ),
1045
+ EffMacVer = ra_aux :effective_machine_version (RaAux ),
1046
+ {Check , Effects } = do_checkpoints (EffMacVer , Ts , Check0 , RaAux ,
1047
+ BytesIn , BytesOut , false ),
1024
1048
{no_reply , Aux0 #? AUX {last_checkpoint = Check }, RaAux , Effects };
1025
1049
handle_aux (_RaftState , cast , {bytes_in , {MetaSize , BodySize }},
1026
1050
#? AUX {bytes_in = Bytes } = Aux0 ,
1027
1051
RaAux ) ->
1028
1052
{no_reply , Aux0 #? AUX {bytes_in = Bytes + MetaSize + BodySize }, RaAux , []};
1053
+ handle_aux (_RaftState , cast , {bytes_out , BodySize },
1054
+ #? AUX {bytes_out = Bytes } = Aux0 ,
1055
+ RaAux ) ->
1056
+ {no_reply , Aux0 #? AUX {bytes_out = Bytes + BodySize }, RaAux , []};
1029
1057
handle_aux (_RaftState , cast , {# return {msg_ids = MsgIds ,
1030
1058
consumer_key = Key } = Ret , Corr , Pid },
1031
1059
Aux0 , RaAux0 ) ->
@@ -1156,12 +1184,15 @@ handle_aux(_, _, garbage_collection, Aux, RaAux) ->
1156
1184
{no_reply , force_eval_gc (RaAux , Aux ), RaAux };
1157
1185
handle_aux (_RaState , _ , force_checkpoint ,
1158
1186
#? AUX {last_checkpoint = Check0 ,
1159
- bytes_in = BytesIn } = Aux , RaAux ) ->
1187
+ bytes_in = BytesIn ,
1188
+ bytes_out = BytesOut } = Aux , RaAux ) ->
1160
1189
Ts = erlang :system_time (millisecond ),
1161
1190
#? STATE {cfg = # cfg {resource = QR }} = ra_aux :machine_state (RaAux ),
1162
1191
? LOG_DEBUG (" ~ts : rabbit_fifo: forcing checkpoint at ~b " ,
1163
1192
[rabbit_misc :rs (QR ), ra_aux :last_applied (RaAux )]),
1164
- {Check , Effects } = do_checkpoints (Ts , Check0 , RaAux , BytesIn , true ),
1193
+ EffMacVer = ra_aux :effective_machine_version (RaAux ),
1194
+ {Check , Effects } = do_checkpoints (EffMacVer , Ts , Check0 , RaAux ,
1195
+ BytesIn , BytesOut , true ),
1165
1196
{no_reply , Aux #? AUX {last_checkpoint = Check }, RaAux , Effects };
1166
1197
handle_aux (RaState , _ , {dlx , _ } = Cmd , Aux0 , RaAux ) ->
1167
1198
#? STATE {dlx = DlxState ,
@@ -1791,25 +1822,27 @@ complete(Meta, ConsumerKey, [MsgId],
1791
1822
# consumer {checked_out = Checked0 } = Con0 ,
1792
1823
#? STATE {ra_indexes = Indexes0 ,
1793
1824
msg_bytes_checkout = BytesCheckout ,
1794
- messages_total = Tot } = State0 ) ->
1825
+ messages_total = Tot } = State0 ,
1826
+ Effects ) ->
1795
1827
case maps :take (MsgId , Checked0 ) of
1796
1828
{? MSG (Idx , Hdr ), Checked } ->
1797
1829
SettledSize = get_header (size , Hdr ),
1798
1830
Indexes = rabbit_fifo_index :delete (Idx , Indexes0 ),
1799
1831
Con = Con0 # consumer {checked_out = Checked ,
1800
1832
credit = increase_credit (Con0 , 1 )},
1801
1833
State1 = update_or_remove_con (Meta , ConsumerKey , Con , State0 ),
1802
- State1 #? STATE {ra_indexes = Indexes ,
1834
+ { State1 #? STATE {ra_indexes = Indexes ,
1803
1835
msg_bytes_checkout = BytesCheckout - SettledSize ,
1804
- messages_total = Tot - 1 };
1836
+ messages_total = Tot - 1 },
1837
+ [{aux , {bytes_out , SettledSize }}, Effects ]};
1805
1838
error ->
1806
- State0
1839
+ { State0 , Effects }
1807
1840
end ;
1808
1841
complete (Meta , ConsumerKey , MsgIds ,
1809
1842
# consumer {checked_out = Checked0 } = Con0 ,
1810
1843
#? STATE {ra_indexes = Indexes0 ,
1811
1844
msg_bytes_checkout = BytesCheckout ,
1812
- messages_total = Tot } = State0 ) ->
1845
+ messages_total = Tot } = State0 , Effects ) ->
1813
1846
{SettledSize , Checked , Indexes }
1814
1847
= lists :foldl (
1815
1848
fun (MsgId , {S0 , Ch0 , Idxs }) ->
@@ -1825,9 +1858,10 @@ complete(Meta, ConsumerKey, MsgIds,
1825
1858
Con = Con0 # consumer {checked_out = Checked ,
1826
1859
credit = increase_credit (Con0 , Len )},
1827
1860
State1 = update_or_remove_con (Meta , ConsumerKey , Con , State0 ),
1828
- State1 #? STATE {ra_indexes = Indexes ,
1861
+ { State1 #? STATE {ra_indexes = Indexes ,
1829
1862
msg_bytes_checkout = BytesCheckout - SettledSize ,
1830
- messages_total = Tot - Len }.
1863
+ messages_total = Tot - Len },
1864
+ [{aux , {bytes_out , SettledSize }}, Effects ]}.
1831
1865
1832
1866
increase_credit (# consumer {cfg = # consumer_cfg {lifetime = once },
1833
1867
credit = Credit }, _ ) ->
@@ -1854,11 +1888,12 @@ increase_credit(#consumer{credit = Current}, Credit) ->
1854
1888
complete_and_checkout (#{} = Meta , MsgIds , ConsumerKey ,
1855
1889
# consumer {} = Con0 ,
1856
1890
Effects0 , State0 ) ->
1857
- State1 = complete (Meta , ConsumerKey , MsgIds , Con0 , State0 ),
1891
+ {State1 , Effects1 } = complete (Meta , ConsumerKey , MsgIds ,
1892
+ Con0 , State0 , Effects0 ),
1858
1893
% % a completion could have removed the active/quiescing consumer
1859
- Effects1 = add_active_effect (Con0 , State1 , Effects0 ),
1860
- {State2 , Effects2 } = activate_next_consumer (State1 , Effects1 ),
1861
- checkout (Meta , State0 , State2 , Effects2 ).
1894
+ Effects2 = add_active_effect (Con0 , State1 , Effects1 ),
1895
+ {State2 , Effects } = activate_next_consumer (State1 , Effects2 ),
1896
+ checkout (Meta , State0 , State2 , Effects ).
1862
1897
1863
1898
add_active_effect (# consumer {status = quiescing } = Consumer ,
1864
1899
#? STATE {cfg = # cfg {consumer_strategy = single_active },
@@ -1950,8 +1985,9 @@ return_one(Meta, MsgId, ?MSG(_, _) = Msg0, DelivFailed, Anns,
1950
1985
{DlxState , DlxEffects } =
1951
1986
rabbit_fifo_dlx :discard ([Msg ], delivery_limit , DLH , DlxState0 ),
1952
1987
State1 = State0 #? STATE {dlx = DlxState },
1953
- State = complete (Meta , ConsumerKey , [MsgId ], Con0 , State1 ),
1954
- {State , DlxEffects ++ Effects0 };
1988
+ {State , Effects } = complete (Meta , ConsumerKey , [MsgId ],
1989
+ Con0 , State1 , Effects0 ),
1990
+ {State , DlxEffects ++ Effects };
1955
1991
_ ->
1956
1992
Checked = maps :remove (MsgId , Checked0 ),
1957
1993
Con = Con0 # consumer {checked_out = Checked ,
@@ -2817,7 +2853,10 @@ convert(Meta, 5, To, State) ->
2817
2853
convert (Meta , 6 , To , State );
2818
2854
convert (Meta , 6 , To , State ) ->
2819
2855
% % no conversion needed, this version only includes a logic change
2820
- convert (Meta , 7 , To , State ).
2856
+ convert (Meta , 7 , To , State );
2857
+ convert (Meta , 7 , To , State ) ->
2858
+ % % no conversion needed, this version only includes a logic change
2859
+ convert (Meta , 8 , To , State ).
2821
2860
2822
2861
smallest_raft_index (#? STATE {messages = Messages ,
2823
2862
ra_indexes = Indexes ,
@@ -2987,12 +3026,43 @@ priority_tag(Msg) ->
2987
3026
end .
2988
3027
2989
3028
2990
- do_checkpoints (Ts , # checkpoint {index = ChIdx ,
2991
- timestamp = ChTime ,
2992
- smallest_index = LastSmallest ,
2993
- bytes_in = LastBytesIn ,
2994
- indexes = MinIndexes } = Check0 ,
2995
- RaAux , BytesIn , Force ) ->
3029
+ do_checkpoints (MacVer , Ts , # checkpoint {index = _ChIdx ,
3030
+ timestamp = _SnapTime },
3031
+ RaAux , BytesIn , BytesOut , Force ) when MacVer >= 8 ->
3032
+ do_checkpoints (MacVer , Ts , # snapshot {}, RaAux , BytesIn , BytesOut , Force );
3033
+ do_checkpoints (MacVer , Ts , # snapshot {index = _ChIdx ,
3034
+ timestamp = SnapTime ,
3035
+ bytes_out = LastBytesOut } = Snap0 ,
3036
+ RaAux , _BytesIn , BytesOut , _Force ) when MacVer >= 8 ->
3037
+ LastAppliedIdx = ra_aux :last_applied (RaAux ),
3038
+ #? STATE {} = MacState = ra_aux :machine_state (RaAux ),
3039
+ TimeSince = Ts - SnapTime ,
3040
+ MsgsTot = messages_total (MacState ),
3041
+ ra_aux :overview (RaAux ),
3042
+ % MaxBytesFactor = max(1, MsgsTot / CheckMaxIndexes),
3043
+ EnoughDataRemoved = BytesOut - LastBytesOut > ? SNAP_OUT_BYTES ,
3044
+ {CheckMinInterval , _CheckMinIndexes , _CheckMaxIndexes } =
3045
+ persistent_term :get (quorum_queue_checkpoint_config ,
3046
+ {? CHECK_MIN_INTERVAL_MS , ? CHECK_MIN_INDEXES ,
3047
+ ? CHECK_MAX_INDEXES }),
3048
+ EnoughTimeHasPassed = TimeSince > CheckMinInterval ,
3049
+ case (EnoughTimeHasPassed andalso
3050
+ EnoughDataRemoved ) of
3051
+ true ->
3052
+ {# snapshot {index = LastAppliedIdx ,
3053
+ timestamp = Ts ,
3054
+ messages_total = MsgsTot ,
3055
+ bytes_out = BytesOut },
3056
+ [{release_cursor , LastAppliedIdx , MacState }]};
3057
+ false ->
3058
+ {Snap0 , []}
3059
+ end ;
3060
+ do_checkpoints (MacVer ,Ts , # checkpoint {index = ChIdx ,
3061
+ timestamp = ChTime ,
3062
+ smallest_index = LastSmallest ,
3063
+ bytes_in = LastBytesIn ,
3064
+ indexes = MinIndexes } = Check0 ,
3065
+ RaAux , BytesIn , _BytesOut , Force ) when MacVer < 8 ->
2996
3066
LastAppliedIdx = ra_aux :last_applied (RaAux ),
2997
3067
IndexesSince = LastAppliedIdx - ChIdx ,
2998
3068
#? STATE {} = MacState = ra_aux :machine_state (RaAux ),
@@ -3022,7 +3092,7 @@ do_checkpoints(Ts, #checkpoint{index = ChIdx,
3022
3092
% % condition 1: enough indexes have been committed since the last
3023
3093
% % checkpoint
3024
3094
(IndexesSince > MinIndexes ) orelse
3025
- % % condition 2: the queue is empty and _some_ commands
3095
+ % % condition 2: the queue is empty and _some_ commands
3026
3096
% % have been applied since the last checkpoint
3027
3097
(MsgsTot == 0 andalso IndexesSince > 32 )
3028
3098
)
0 commit comments