2929
3030-record (data , {interval :: integer () | infinity ,
3131 strategy :: drop | finish | failed_attribute_and_finish | fun ((opencensus :span ()) -> ok ),
32- ttl :: integer ()}).
32+ ttl :: integer () | infinity ,
33+ storage_size :: integer () | infinity }).
3334
3435start_link () ->
3536 gen_statem :start_link ({local , ? MODULE }, ? MODULE , [], []).
@@ -40,54 +41,84 @@ init([]) ->
4041 Interval = maps :get (interval , SweeperConfig , timer :minutes (5 )),
4142 Strategy = maps :get (strategy , SweeperConfig , drop ),
4243 TTL = maps :get (span_ttl , SweeperConfig , timer :minutes (5 )),
44+ StorageSize = maps :get (storage_size , SweeperConfig , infinity ),
4345 {ok , ready , # data {interval = Interval ,
4446 strategy = Strategy ,
45- ttl = erlang :convert_time_unit (TTL , millisecond , native )},
47+ ttl = maybe_convert_time_unit (TTL ),
48+ storage_size = StorageSize },
4649 [hibernate , {state_timeout , Interval , sweep }]}.
4750
51+
52+ maybe_convert_time_unit (infinity ) ->
53+ infinity ;
54+ maybe_convert_time_unit (TTL ) ->
55+ erlang :convert_time_unit (TTL , millisecond , native ).
56+
4857callback_mode () ->
4958 handle_event_function .
5059
51- handle_event (state_timeout , sweep , _ , # data {interval = Interval ,
52- strategy = drop ,
53- ttl = TTL }) ->
60+ handle_event (state_timeout , sweep , _ , # data {interval = Interval } = Data ) ->
61+ do_gc (Data ),
62+ {keep_state_and_data , [hibernate , {state_timeout , Interval , sweep }]};
63+ handle_event (_ , _ , _ , _Data ) ->
64+ keep_state_and_data .
65+
66+ code_change (_ , State , Data , _ ) ->
67+ {ok , State , Data }.
68+
69+ terminate (_Reason , _State , _Data ) ->
70+ ok .
71+
72+ % %
73+ do_gc (# data {strategy = Strategy ,
74+ ttl = TTL ,
75+ storage_size = infinity }) ->
76+ sweep_spans (Strategy , TTL );
77+ do_gc (# data {strategy = Strategy ,
78+ ttl = TTL ,
79+ storage_size = MaxSize }) ->
80+
81+ StorageSize = ets :info (? SPAN_TAB , memory ) * erlang :system_info ({wordsize , external }),
82+
83+ if
84+ StorageSize >= 2 * MaxSize ->
85+ % % High overload kill storage.
86+ ets :delete_all_objects (? SPAN_TAB );
87+ StorageSize >= MaxSize ->
88+ % % Low overload, reduce TTL
89+ sweep_spans (Strategy , overload_ttl (TTL ));
90+ true ->
91+ sweep_spans (Strategy , TTL )
92+ end .
93+
94+ overload_ttl (infinity ) ->
95+ infinity ;
96+ overload_ttl (TTL ) ->
97+ TTL div 10 .
98+
99+ sweep_spans (_ , infinity ) ->
100+ ok ;
101+ sweep_spans (drop , TTL ) ->
54102 TooOld = erlang :monotonic_time () - TTL ,
55103 case ets :select_delete (? SPAN_TAB , expired_match_spec (TooOld , true )) of
56104 0 ->
57105 ok ;
58106 NumDeleted ->
59107 ? LOG_INFO (" sweep old spans: ttl=~p num_dropped=~p " , [TTL , NumDeleted ])
60- end ,
61- {keep_state_and_data , [hibernate , {state_timeout , Interval , sweep }]};
62- handle_event (state_timeout , sweep , _ , # data {interval = Interval ,
63- strategy = finish ,
64- ttl = TTL }) ->
108+ end ;
109+ sweep_spans (finish , TTL ) ->
65110 Expired = select_expired (TTL ),
66111 [finish_span (Span ) || Span <- Expired ],
67- {keep_state_and_data , [hibernate , {state_timeout , Interval , sweep }]};
68- handle_event (state_timeout , sweep , _ , # data {interval = Interval ,
69- strategy = failed_attribute_and_finish ,
70- ttl = TTL }) ->
112+ ok ;
113+ sweep_spans (failed_attribute_and_finish , TTL ) ->
71114 Expired = select_expired (TTL ),
72115 [finish_span (oc_span :put_attribute (<<" finished_by_sweeper" >>, true , Span )) || Span <- Expired ],
73- {keep_state_and_data , [hibernate , {state_timeout , Interval , sweep }]};
74- handle_event (state_timeout , sweep , _ , # data {interval = Interval ,
75- strategy = Fun ,
76- ttl = TTL }) when is_function (Fun ) ->
116+ ok ;
117+ sweep_spans (Fun , TTL ) when is_function (Fun ) ->
77118 Expired = select_expired (TTL ),
78119 [Fun (Span ) || Span <- Expired ],
79- {keep_state_and_data , [hibernate , {state_timeout , Interval , sweep }]};
80- handle_event (_ , _ , _ , _Data ) ->
81- keep_state_and_data .
82-
83- code_change (_ , State , Data , _ ) ->
84- {ok , State , Data }.
85-
86- terminate (_Reason , _State , _Data ) ->
87120 ok .
88121
89- % %
90-
91122% % ignore these functions because dialyzer doesn't like match spec use of '_'
92123-dialyzer ({nowarn_function , expired_match_spec / 2 }).
93124-dialyzer ({nowarn_function , finish_span / 1 }).
0 commit comments