/src/tor/src/feature/stats/bwhist.c
Line | Count | Source |
1 | | /* Copyright (c) 2001 Matej Pfajfar. |
2 | | * Copyright (c) 2001-2004, Roger Dingledine. |
3 | | * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. |
4 | | * Copyright (c) 2007-2021, The Tor Project, Inc. */ |
5 | | /* See LICENSE for licensing information */ |
6 | | |
7 | | /** |
8 | | * @file bwhist.c |
9 | | * @brief Tracking for relay bandwidth history |
10 | | * |
11 | | * This module handles bandwidth usage history, used by relays to |
12 | | * self-report how much bandwidth they've used for different |
13 | | * purposes over last day or so, in order to generate the |
14 | | * {dirreq-,}{read,write}-history lines in that they publish. |
15 | | **/ |
16 | | |
17 | | #define BWHIST_PRIVATE |
18 | | #include "orconfig.h" |
19 | | #include "core/or/or.h" |
20 | | #include "feature/stats/bwhist.h" |
21 | | |
22 | | #include "app/config/config.h" |
23 | | #include "app/config/statefile.h" |
24 | | #include "feature/relay/routermode.h" |
25 | | |
26 | | #include "feature/stats/bw_array_st.h" |
27 | | #include "app/config/or_state_st.h" |
28 | | #include "app/config/or_options_st.h" |
29 | | |
30 | | /** Shift the current period of b forward by one. */ |
31 | | STATIC void |
32 | | commit_max(bw_array_t *b) |
33 | 0 | { |
34 | | /* Store total from current period. */ |
35 | 0 | b->totals[b->next_max_idx] = b->total_in_period; |
36 | | /* Store maximum from current period. */ |
37 | 0 | b->maxima[b->next_max_idx++] = b->max_total; |
38 | | /* Advance next_period and next_max_idx */ |
39 | 0 | b->next_period += NUM_SECS_BW_SUM_INTERVAL; |
40 | 0 | if (b->next_max_idx == NUM_TOTALS) |
41 | 0 | b->next_max_idx = 0; |
42 | 0 | if (b->num_maxes_set < NUM_TOTALS) |
43 | 0 | ++b->num_maxes_set; |
44 | | /* Reset max_total. */ |
45 | 0 | b->max_total = 0; |
46 | | /* Reset total_in_period. */ |
47 | 0 | b->total_in_period = 0; |
48 | 0 | } |
49 | | |
50 | | /** Shift the current observation time of <b>b</b> forward by one second. */ |
51 | | STATIC void |
52 | | advance_obs(bw_array_t *b) |
53 | 0 | { |
54 | 0 | int nextidx; |
55 | 0 | uint64_t total; |
56 | | |
57 | | /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE |
58 | | * seconds; adjust max_total as needed.*/ |
59 | 0 | total = b->total_obs + b->obs[b->cur_obs_idx]; |
60 | 0 | if (total > b->max_total) |
61 | 0 | b->max_total = total; |
62 | |
|
63 | 0 | nextidx = b->cur_obs_idx+1; |
64 | 0 | if (nextidx == NUM_SECS_ROLLING_MEASURE) |
65 | 0 | nextidx = 0; |
66 | |
|
67 | 0 | b->total_obs = total - b->obs[nextidx]; |
68 | 0 | b->obs[nextidx]=0; |
69 | 0 | b->cur_obs_idx = nextidx; |
70 | |
|
71 | 0 | if (++b->cur_obs_time >= b->next_period) |
72 | 0 | commit_max(b); |
73 | 0 | } |
74 | | |
75 | | /** Add <b>n</b> bytes to the number of bytes in <b>b</b> for second |
76 | | * <b>when</b>. */ |
77 | | STATIC void |
78 | | add_obs(bw_array_t *b, time_t when, uint64_t n) |
79 | 0 | { |
80 | 0 | if (when < b->cur_obs_time) |
81 | 0 | return; /* Don't record data in the past. */ |
82 | | |
83 | | /* If we're currently adding observations for an earlier second than |
84 | | * 'when', advance b->cur_obs_time and b->cur_obs_idx by an |
85 | | * appropriate number of seconds, and do all the other housekeeping. */ |
86 | 0 | while (when > b->cur_obs_time) { |
87 | | /* Doing this one second at a time is potentially inefficient, if we start |
88 | | with a state file that is very old. Fortunately, it doesn't seem to |
89 | | show up in profiles, so we can just ignore it for now. */ |
90 | 0 | advance_obs(b); |
91 | 0 | } |
92 | |
|
93 | 0 | b->obs[b->cur_obs_idx] += n; |
94 | 0 | b->total_in_period += n; |
95 | 0 | } |
96 | | |
97 | | /** Allocate, initialize, and return a new bw_array. */ |
98 | | STATIC bw_array_t * |
99 | | bw_array_new(void) |
100 | 0 | { |
101 | 0 | bw_array_t *b; |
102 | 0 | time_t start; |
103 | 0 | b = tor_malloc_zero(sizeof(bw_array_t)); |
104 | 0 | start = time(NULL); |
105 | 0 | b->cur_obs_time = start; |
106 | 0 | b->next_period = start + NUM_SECS_BW_SUM_INTERVAL; |
107 | 0 | return b; |
108 | 0 | } |
109 | | |
110 | | /** Free storage held by bandwidth array <b>b</b>. */ |
111 | | STATIC void |
112 | | bw_array_free_(bw_array_t *b) |
113 | 0 | { |
114 | 0 | if (!b) { |
115 | 0 | return; |
116 | 0 | } |
117 | | |
118 | 0 | tor_free(b); |
119 | 0 | } |
120 | | |
121 | | /** Recent history of bandwidth observations for (all) read operations. */ |
122 | | static bw_array_t *read_array = NULL; |
123 | | /** Recent history of bandwidth observations for IPv6 read operations. */ |
124 | | static bw_array_t *read_array_ipv6 = NULL; |
125 | | /** Recent history of bandwidth observations for (all) write operations. */ |
126 | | STATIC bw_array_t *write_array = NULL; |
127 | | /** Recent history of bandwidth observations for IPv6 write operations. */ |
128 | | static bw_array_t *write_array_ipv6 = NULL; |
129 | | /** Recent history of bandwidth observations for read operations for the |
130 | | directory protocol. */ |
131 | | static bw_array_t *dir_read_array = NULL; |
132 | | /** Recent history of bandwidth observations for write operations for the |
133 | | directory protocol. */ |
134 | | static bw_array_t *dir_write_array = NULL; |
135 | | |
136 | | /** Set up structures for bandwidth history, clearing them if they already |
137 | | * exist. */ |
138 | | void |
139 | | bwhist_init(void) |
140 | 0 | { |
141 | 0 | bw_array_free(read_array); |
142 | 0 | bw_array_free(read_array_ipv6); |
143 | 0 | bw_array_free(write_array); |
144 | 0 | bw_array_free(write_array_ipv6); |
145 | 0 | bw_array_free(dir_read_array); |
146 | 0 | bw_array_free(dir_write_array); |
147 | |
|
148 | 0 | read_array = bw_array_new(); |
149 | 0 | read_array_ipv6 = bw_array_new(); |
150 | 0 | write_array = bw_array_new(); |
151 | 0 | write_array_ipv6 = bw_array_new(); |
152 | 0 | dir_read_array = bw_array_new(); |
153 | 0 | dir_write_array = bw_array_new(); |
154 | 0 | } |
155 | | |
156 | | /** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>. |
157 | | * |
158 | | * Add num_bytes to the current running total for <b>when</b>. |
159 | | * |
160 | | * <b>when</b> can go back to time, but it's safe to ignore calls |
161 | | * earlier than the latest <b>when</b> you've heard of. |
162 | | */ |
163 | | void |
164 | | bwhist_note_bytes_written(uint64_t num_bytes, time_t when, bool ipv6) |
165 | 0 | { |
166 | | /* Maybe a circular array for recent seconds, and step to a new point |
167 | | * every time a new second shows up. Or simpler is to just to have |
168 | | * a normal array and push down each item every second; it's short. |
169 | | */ |
170 | | /* When a new second has rolled over, compute the sum of the bytes we've |
171 | | * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it |
172 | | * somewhere. See bwhist_bandwidth_assess() below. |
173 | | */ |
174 | 0 | add_obs(write_array, when, num_bytes); |
175 | 0 | if (ipv6) |
176 | 0 | add_obs(write_array_ipv6, when, num_bytes); |
177 | 0 | } |
178 | | |
179 | | /** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>. |
180 | | * (like bwhist_note_bytes_written() above) |
181 | | */ |
182 | | void |
183 | | bwhist_note_bytes_read(uint64_t num_bytes, time_t when, bool ipv6) |
184 | 0 | { |
185 | | /* if we're smart, we can make this func and the one above share code */ |
186 | 0 | add_obs(read_array, when, num_bytes); |
187 | 0 | if (ipv6) |
188 | 0 | add_obs(read_array_ipv6, when, num_bytes); |
189 | 0 | } |
190 | | |
191 | | /** Remember that we wrote <b>num_bytes</b> directory bytes in second |
192 | | * <b>when</b>. (like bwhist_note_bytes_written() above) |
193 | | */ |
194 | | void |
195 | | bwhist_note_dir_bytes_written(uint64_t num_bytes, time_t when) |
196 | 0 | { |
197 | 0 | add_obs(dir_write_array, when, num_bytes); |
198 | 0 | } |
199 | | |
200 | | /** Remember that we read <b>num_bytes</b> directory bytes in second |
201 | | * <b>when</b>. (like bwhist_note_bytes_written() above) |
202 | | */ |
203 | | void |
204 | | bwhist_note_dir_bytes_read(uint64_t num_bytes, time_t when) |
205 | 0 | { |
206 | 0 | add_obs(dir_read_array, when, num_bytes); |
207 | 0 | } |
208 | | |
209 | | /** |
210 | | * Helper: Return the largest value in b->maxima. (This is equal to the |
211 | | * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last |
212 | | * NUM_SECS_BW_SUM_IS_VALID seconds.) |
213 | | * |
214 | | * Also include the current period if we have been observing it for |
215 | | * at least min_observation_time seconds. |
216 | | */ |
217 | | STATIC uint64_t |
218 | | find_largest_max(bw_array_t *b, int min_observation_time) |
219 | 0 | { |
220 | 0 | int i; |
221 | 0 | uint64_t max; |
222 | 0 | time_t period_start = b->next_period - NUM_SECS_BW_SUM_INTERVAL; |
223 | 0 | if (b->cur_obs_time > period_start + min_observation_time) |
224 | 0 | max = b->max_total; |
225 | 0 | else |
226 | 0 | max = 0; |
227 | 0 | for (i=0; i<NUM_TOTALS; ++i) { |
228 | 0 | if (b->maxima[i]>max) |
229 | 0 | max = b->maxima[i]; |
230 | 0 | } |
231 | 0 | return max; |
232 | 0 | } |
233 | | |
234 | | /** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly) |
235 | | * seconds. Find one sum for reading and one for writing. They don't have |
236 | | * to be at the same time. |
237 | | * |
238 | | * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE. |
239 | | */ |
240 | | MOCK_IMPL(int, |
241 | | bwhist_bandwidth_assess,(void)) |
242 | 0 | { |
243 | 0 | uint64_t w,r; |
244 | 0 | int min_obs_time = get_options()->TestingMinTimeToReportBandwidth; |
245 | 0 | r = find_largest_max(read_array, min_obs_time); |
246 | 0 | w = find_largest_max(write_array, min_obs_time); |
247 | 0 | if (r>w) |
248 | 0 | return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE); |
249 | 0 | else |
250 | 0 | return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE); |
251 | 0 | } |
252 | | |
253 | | /** Print the bandwidth history of b (either [dir-]read_array or |
254 | | * [dir-]write_array) into the buffer pointed to by buf. The format is |
255 | | * simply comma separated numbers, from oldest to newest. |
256 | | * |
257 | | * It returns the number of bytes written. |
258 | | */ |
259 | | STATIC size_t |
260 | | bwhist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b) |
261 | 0 | { |
262 | 0 | char *cp = buf; |
263 | 0 | int i, n; |
264 | 0 | const or_options_t *options = get_options(); |
265 | 0 | uint64_t cutoff; |
266 | |
|
267 | 0 | if (b->num_maxes_set <= b->next_max_idx) { |
268 | | /* We haven't been through the circular array yet; time starts at i=0.*/ |
269 | 0 | i = 0; |
270 | 0 | } else { |
271 | | /* We've been around the array at least once. The next i to be |
272 | | overwritten is the oldest. */ |
273 | 0 | i = b->next_max_idx; |
274 | 0 | } |
275 | |
|
276 | 0 | if (options->RelayBandwidthRate) { |
277 | | /* We don't want to report that we used more bandwidth than the max we're |
278 | | * willing to relay; otherwise everybody will know how much traffic |
279 | | * we used ourself. */ |
280 | 0 | cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL; |
281 | 0 | } else { |
282 | 0 | cutoff = UINT64_MAX; |
283 | 0 | } |
284 | |
|
285 | 0 | for (n=0; n<b->num_maxes_set; ++n,++i) { |
286 | 0 | uint64_t total; |
287 | 0 | if (i >= NUM_TOTALS) |
288 | 0 | i -= NUM_TOTALS; |
289 | 0 | tor_assert(i < NUM_TOTALS); |
290 | | /* Round the bandwidth used down to the nearest 1k. */ |
291 | 0 | total = b->totals[i] & ~0x3ff; |
292 | 0 | if (total > cutoff) |
293 | 0 | total = cutoff; |
294 | |
|
295 | 0 | if (n==(b->num_maxes_set-1)) |
296 | 0 | tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total)); |
297 | 0 | else |
298 | 0 | tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total)); |
299 | 0 | cp += strlen(cp); |
300 | 0 | } |
301 | 0 | return cp-buf; |
302 | 0 | } |
303 | | |
304 | | /** Encode a single bandwidth history line into <b>buf</b>. */ |
305 | | static void |
306 | | bwhist_get_one_bandwidth_line(buf_t *buf, const char *desc, |
307 | | const bw_array_t *b) |
308 | 0 | { |
309 | | /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */ |
310 | | /* The n,n,n part above. Largest representation of a uint64_t is 20 chars |
311 | | * long, plus the comma. */ |
312 | 0 | #define MAX_HIST_VALUE_LEN (21*NUM_TOTALS) |
313 | |
|
314 | 0 | char tmp[MAX_HIST_VALUE_LEN]; |
315 | 0 | char end[ISO_TIME_LEN+1]; |
316 | |
|
317 | 0 | size_t slen = bwhist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b); |
318 | | /* If we don't have anything to write, skip to the next entry. */ |
319 | 0 | if (slen == 0) |
320 | 0 | return; |
321 | | |
322 | 0 | format_iso_time(end, b->next_period-NUM_SECS_BW_SUM_INTERVAL); |
323 | 0 | buf_add_printf(buf, "%s %s (%d s) %s\n", |
324 | 0 | desc, end, NUM_SECS_BW_SUM_INTERVAL, tmp); |
325 | 0 | } |
326 | | |
327 | | /** Allocate and return lines for representing this server's bandwidth |
328 | | * history in its descriptor. We publish these lines in our extra-info |
329 | | * descriptor. |
330 | | */ |
331 | | char * |
332 | | bwhist_get_bandwidth_lines(void) |
333 | 0 | { |
334 | 0 | buf_t *buf = buf_new(); |
335 | |
|
336 | 0 | bwhist_get_one_bandwidth_line(buf, "write-history", write_array); |
337 | 0 | bwhist_get_one_bandwidth_line(buf, "read-history", read_array); |
338 | 0 | bwhist_get_one_bandwidth_line(buf, "ipv6-write-history", write_array_ipv6); |
339 | 0 | bwhist_get_one_bandwidth_line(buf, "ipv6-read-history", read_array_ipv6); |
340 | 0 | bwhist_get_one_bandwidth_line(buf, "dirreq-write-history", dir_write_array); |
341 | 0 | bwhist_get_one_bandwidth_line(buf, "dirreq-read-history", dir_read_array); |
342 | |
|
343 | 0 | char *result = buf_extract(buf, NULL); |
344 | 0 | buf_free(buf); |
345 | 0 | return result; |
346 | 0 | } |
347 | | |
348 | | /** Write a single bw_array_t into the Values, Ends, Interval, and Maximum |
349 | | * entries of an or_state_t. Done before writing out a new state file. */ |
350 | | static void |
351 | | bwhist_update_bwhist_state_section(or_state_t *state, |
352 | | const bw_array_t *b, |
353 | | smartlist_t **s_values, |
354 | | smartlist_t **s_maxima, |
355 | | time_t *s_begins, |
356 | | int *s_interval) |
357 | 0 | { |
358 | 0 | int i,j; |
359 | 0 | uint64_t maxval; |
360 | |
|
361 | 0 | if (*s_values) { |
362 | 0 | SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val)); |
363 | 0 | smartlist_free(*s_values); |
364 | 0 | } |
365 | 0 | if (*s_maxima) { |
366 | 0 | SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val)); |
367 | 0 | smartlist_free(*s_maxima); |
368 | 0 | } |
369 | 0 | if (! server_mode(get_options())) { |
370 | | /* Clients don't need to store bandwidth history persistently; |
371 | | * force these values to the defaults. */ |
372 | | /* FFFF we should pull the default out of config.c's state table, |
373 | | * so we don't have two defaults. */ |
374 | 0 | if (*s_begins != 0 || *s_interval != 900) { |
375 | 0 | time_t now = time(NULL); |
376 | 0 | time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600; |
377 | 0 | or_state_mark_dirty(state, save_at); |
378 | 0 | } |
379 | 0 | *s_begins = 0; |
380 | 0 | *s_interval = 900; |
381 | 0 | *s_values = smartlist_new(); |
382 | 0 | *s_maxima = smartlist_new(); |
383 | 0 | return; |
384 | 0 | } |
385 | 0 | *s_begins = b->next_period; |
386 | 0 | *s_interval = NUM_SECS_BW_SUM_INTERVAL; |
387 | |
|
388 | 0 | *s_values = smartlist_new(); |
389 | 0 | *s_maxima = smartlist_new(); |
390 | | /* Set i to first position in circular array */ |
391 | 0 | i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx; |
392 | 0 | for (j=0; j < b->num_maxes_set; ++j,++i) { |
393 | 0 | if (i >= NUM_TOTALS) |
394 | 0 | i = 0; |
395 | 0 | smartlist_add_asprintf(*s_values, "%"PRIu64, |
396 | 0 | (b->totals[i] & ~0x3ff)); |
397 | 0 | maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE; |
398 | 0 | smartlist_add_asprintf(*s_maxima, "%"PRIu64, |
399 | 0 | (maxval & ~0x3ff)); |
400 | 0 | } |
401 | 0 | smartlist_add_asprintf(*s_values, "%"PRIu64, |
402 | 0 | (b->total_in_period & ~0x3ff)); |
403 | 0 | maxval = b->max_total / NUM_SECS_ROLLING_MEASURE; |
404 | 0 | smartlist_add_asprintf(*s_maxima, "%"PRIu64, |
405 | 0 | (maxval & ~0x3ff)); |
406 | 0 | } |
407 | | |
408 | | /** Update <b>state</b> with the newest bandwidth history. Done before |
409 | | * writing out a new state file. */ |
410 | | void |
411 | | bwhist_update_state(or_state_t *state) |
412 | 0 | { |
413 | 0 | #define UPDATE(arrname,st) \ |
414 | 0 | bwhist_update_bwhist_state_section(state,\ |
415 | 0 | (arrname),\ |
416 | 0 | &state->BWHistory ## st ## Values, \ |
417 | 0 | &state->BWHistory ## st ## Maxima, \ |
418 | 0 | &state->BWHistory ## st ## Ends, \ |
419 | 0 | &state->BWHistory ## st ## Interval) |
420 | |
|
421 | 0 | UPDATE(write_array, Write); |
422 | 0 | UPDATE(read_array, Read); |
423 | 0 | UPDATE(write_array_ipv6, IPv6Write); |
424 | 0 | UPDATE(read_array_ipv6, IPv6Read); |
425 | 0 | UPDATE(dir_write_array, DirWrite); |
426 | 0 | UPDATE(dir_read_array, DirRead); |
427 | |
|
428 | 0 | if (server_mode(get_options())) { |
429 | 0 | or_state_mark_dirty(state, time(NULL)+(2*3600)); |
430 | 0 | } |
431 | 0 | #undef UPDATE |
432 | 0 | } |
433 | | |
434 | | /** Load a single bw_array_t from its Values, Ends, Maxima, and Interval |
435 | | * entries in an or_state_t. Done while reading the state file. */ |
436 | | static int |
437 | | bwhist_load_bwhist_state_section(bw_array_t *b, |
438 | | const smartlist_t *s_values, |
439 | | const smartlist_t *s_maxima, |
440 | | const time_t s_begins, |
441 | | const int s_interval) |
442 | 0 | { |
443 | 0 | time_t now = time(NULL); |
444 | 0 | int retval = 0; |
445 | 0 | time_t start; |
446 | |
|
447 | 0 | uint64_t v, mv; |
448 | 0 | int i,ok,ok_m = 0; |
449 | 0 | int have_maxima = s_maxima && s_values && |
450 | 0 | (smartlist_len(s_values) == smartlist_len(s_maxima)); |
451 | |
|
452 | 0 | if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) { |
453 | 0 | start = s_begins - s_interval*(smartlist_len(s_values)); |
454 | 0 | if (start > now) |
455 | 0 | return 0; |
456 | 0 | b->cur_obs_time = start; |
457 | 0 | b->next_period = start + NUM_SECS_BW_SUM_INTERVAL; |
458 | 0 | SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) { |
459 | 0 | const char *maxstr = NULL; |
460 | 0 | v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL); |
461 | 0 | if (have_maxima) { |
462 | 0 | maxstr = smartlist_get(s_maxima, cp_sl_idx); |
463 | 0 | mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL); |
464 | 0 | mv *= NUM_SECS_ROLLING_MEASURE; |
465 | 0 | } else { |
466 | | /* No maxima known; guess average rate to be conservative. */ |
467 | 0 | mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE; |
468 | 0 | } |
469 | 0 | if (!ok) { |
470 | 0 | retval = -1; |
471 | 0 | log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp); |
472 | 0 | } |
473 | 0 | if (maxstr && !ok_m) { |
474 | 0 | retval = -1; |
475 | 0 | log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'", |
476 | 0 | maxstr); |
477 | 0 | } |
478 | |
|
479 | 0 | if (start < now) { |
480 | 0 | time_t cur_start = start; |
481 | 0 | time_t actual_interval_len = s_interval; |
482 | 0 | uint64_t cur_val = 0; |
483 | | /* Calculate the average per second. This is the best we can do |
484 | | * because our state file doesn't have per-second resolution. */ |
485 | 0 | if (start + s_interval > now) |
486 | 0 | actual_interval_len = now - start; |
487 | 0 | cur_val = v / actual_interval_len; |
488 | | /* This is potentially inefficient, but since we don't do it very |
489 | | * often it should be ok. */ |
490 | 0 | while (cur_start < start + actual_interval_len) { |
491 | 0 | add_obs(b, cur_start, cur_val); |
492 | 0 | ++cur_start; |
493 | 0 | } |
494 | 0 | b->max_total = mv; |
495 | | /* This will result in some fairly choppy history if s_interval |
496 | | * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */ |
497 | 0 | start += actual_interval_len; |
498 | 0 | } |
499 | 0 | } SMARTLIST_FOREACH_END(cp); |
500 | 0 | } |
501 | | |
502 | | /* Clean up maxima and observed */ |
503 | 0 | for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) { |
504 | 0 | b->obs[i] = 0; |
505 | 0 | } |
506 | 0 | b->total_obs = 0; |
507 | |
|
508 | 0 | return retval; |
509 | 0 | } |
510 | | |
511 | | /** Set bandwidth history from the state file we just loaded. */ |
512 | | int |
513 | | bwhist_load_state(or_state_t *state, char **err) |
514 | 0 | { |
515 | 0 | int all_ok = 1; |
516 | | |
517 | | /* Assert they already have been malloced */ |
518 | 0 | tor_assert(read_array && write_array); |
519 | 0 | tor_assert(read_array_ipv6 && write_array_ipv6); |
520 | 0 | tor_assert(dir_read_array && dir_write_array); |
521 | |
|
522 | 0 | #define LOAD(arrname,st) \ |
523 | 0 | if (bwhist_load_bwhist_state_section( \ |
524 | 0 | (arrname), \ |
525 | 0 | state->BWHistory ## st ## Values, \ |
526 | 0 | state->BWHistory ## st ## Maxima, \ |
527 | 0 | state->BWHistory ## st ## Ends, \ |
528 | 0 | state->BWHistory ## st ## Interval)<0) \ |
529 | 0 | all_ok = 0 |
530 | |
|
531 | 0 | LOAD(write_array, Write); |
532 | 0 | LOAD(read_array, Read); |
533 | 0 | LOAD(write_array_ipv6, IPv6Write); |
534 | 0 | LOAD(read_array_ipv6, IPv6Read); |
535 | 0 | LOAD(dir_write_array, DirWrite); |
536 | 0 | LOAD(dir_read_array, DirRead); |
537 | |
|
538 | 0 | #undef LOAD |
539 | 0 | if (!all_ok) { |
540 | 0 | *err = tor_strdup("Parsing of bandwidth history values failed"); |
541 | | /* and create fresh arrays */ |
542 | 0 | bwhist_init(); |
543 | 0 | return -1; |
544 | 0 | } |
545 | 0 | return 0; |
546 | 0 | } |
547 | | |
548 | | void |
549 | | bwhist_free_all(void) |
550 | 0 | { |
551 | 0 | bw_array_free(read_array); |
552 | 0 | bw_array_free(read_array_ipv6); |
553 | 0 | bw_array_free(write_array); |
554 | 0 | bw_array_free(write_array_ipv6); |
555 | 0 | bw_array_free(dir_read_array); |
556 | | bw_array_free(dir_write_array); |
557 | 0 | } |