2727-define (DEK_TIMER_RETRY_TIME_S , ? get_param (dek_retry_interval , 60 )).
2828-define (DEK_DROP_RETRY_TIME_S (Kind ),
2929 ? get_param ({dek_removal_min_interval , Kind }, 60 * 60 * 3 )).
30+ -define (MIN_DEK_GC_INTERVAL_S , ? get_param (min_dek_gc_interval , 60 )).
3031
3132-ifndef (TEST ).
3233-define (MIN_RECHECK_ROTATION_INTERVAL , ? get_param (min_rotation_recheck_interval ,
138139 deks := [cb_deks :dek ()],
139140 is_enabled := boolean (),
140141 deks_being_dropped := [cb_deks :dek_id ()],
142+ last_deks_gc_datetime := undefined | calendar :datetime (),
141143 last_drop_timestamp := undefined | non_neg_integer ()}.
142144
143145% %%===================================================================
@@ -474,10 +476,16 @@ handle_call(get_node_deks_info, _From,
474476 K #{info => maps :remove (key , Info )}
475477 end , Keys )
476478 end ,
477- # state {deks = Deks } = NewState ,
479+
480+ % % Run gc for deks; it is usefull in case if a compaction has been run
481+ % % recently.
482+ NewState2 = maps :fold (fun (Kind , _ , Acc ) ->
483+ maybe_garbage_collect_deks (Kind , Acc )
484+ end , NewState , NewState # state .deks ),
485+ # state {deks = Deks } = NewState2 ,
478486 Res = maps :map (fun (_K , #{deks := Keys }) -> StripKeyMaterial (Keys ) end ,
479487 Deks ),
480- {reply , Res , NewState }
488+ {reply , Res , NewState2 }
481489 else
482490 [_ | _ ] ->
483491 % % There are still unfinished jobs. That means deks in our state
@@ -896,10 +904,37 @@ maybe_update_deks(Kind, #state{deks = CurDeks} = OldState) ->
896904 {ok , OldState # state {deks = maps :remove (Kind , CurDeks )}}
897905 end .
898906
907+ - spec maybe_garbage_collect_deks (cb_deks :dek_kind (), # state {}) -> # state {}.
908+ maybe_garbage_collect_deks (Kind , # state {deks = DeksInfo } = State ) ->
909+ ShouldRun =
910+ case maps :find (Kind , DeksInfo ) of
911+ {ok , #{last_deks_gc_datetime := undefined }} ->
912+ true ;
913+ {ok , #{last_deks_gc_datetime := DT }} ->
914+ % % The goal is to not call it too often
915+ Deadline = misc :datetime_add (DT , ? MIN_DEK_GC_INTERVAL_S ),
916+ calendar :universal_time () > Deadline ;
917+ error ->
918+ false
919+ end ,
920+ case ShouldRun of
921+ true ->
922+ case garbage_collect_deks (Kind , State ) of
923+ {ok , NewState } -> NewState ;
924+ {error , NewState , Error } ->
925+ ? log_error (" Garbage collecting DEKs failed: ~p " , [Error ]),
926+ NewState
927+ end ;
928+ false ->
929+ ? log_debug (" Skipping garbage collect for ~p " , [Kind ]),
930+ State
931+ end .
932+
899933% % Remove DEKs that are not being used anymore
900934- spec garbage_collect_deks (cb_deks :dek_kind (), # state {}) ->
901935 {ok , # state {}} | {error , # state {}, term ()}.
902936garbage_collect_deks (Kind , # state {deks = DeksInfo } = State ) ->
937+ ? log_debug (" Garbage collecting ~p DEKs" , [Kind ]),
903938 case maps :find (Kind , DeksInfo ) of
904939 {ok , #{active_id := _ActiveId ,
905940 deks := []}} ->
@@ -908,10 +943,14 @@ garbage_collect_deks(Kind, #state{deks = DeksInfo} = State) ->
908943 {ok , #{is_enabled := true , deks := [_ ]}} ->
909944 % % If encryption is enabled, one dek is a minimum. Can't be removed.
910945 {ok , State };
911- {ok , #{}} ->
946+ {ok , #{} = KindDeks } ->
912947 case call_dek_callback (get_ids_in_use_callback , Kind , []) of
913948 {succ , {ok , IdList }} ->
914- retire_unused_deks (Kind , IdList , State );
949+ NewKindDeks = KindDeks #{last_deks_gc_datetime =>
950+ calendar :universal_time ()},
951+ NewState = State # state {deks = DeksInfo #{
952+ Kind => NewKindDeks }},
953+ retire_unused_deks (Kind , IdList , NewState );
915954 {succ , {error , not_found }} ->
916955 % % The entity that uses deks does not exist.
917956 % % Ignoring it here because we assume that deks will
@@ -1033,11 +1072,13 @@ read_deks(Kind, #state{deks = AllDeks} = State) ->
10331072 CurDeksDropped = maps :get (deks_being_dropped , CurKindDeks , []),
10341073 CurDeksDroppedCleaned = CurDeksDropped -- (CurDeksDropped -- DekIds ),
10351074 CurLastDropTS = maps :get (last_drop_timestamp , CurKindDeks , undefined ),
1075+ GCDeksDT = maps :get (last_deks_gc_datetime , CurKindDeks , undefined ),
10361076 KindDeks = #{active_id => ActiveDek ,
10371077 deks => Deks ,
10381078 is_enabled => IsEnabled ,
10391079 deks_being_dropped => CurDeksDroppedCleaned ,
1040- last_drop_timestamp => CurLastDropTS },
1080+ last_drop_timestamp => CurLastDropTS ,
1081+ last_deks_gc_datetime => GCDeksDT },
10411082 functools :chain (State # state {deks = AllDeks #{Kind => KindDeks }},
10421083 [restart_dek_cleanup_timer (_ ),
10431084 restart_dek_rotation_timer (_ )]).
0 commit comments