LCOV - code coverage report
Current view: top level - feature/stats - bwhist.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 187 239 78.2 %
Date: 2021-11-24 03:28:48 Functions: 20 20 100.0 %

          Line data    Source code
       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          28 : commit_max(bw_array_t *b)
      33             : {
      34             :   /* Store total from current period. */
      35          28 :   b->totals[b->next_max_idx] = b->total_in_period;
      36             :   /* Store maximum from current period. */
      37          28 :   b->maxima[b->next_max_idx++] = b->max_total;
      38             :   /* Advance next_period and next_max_idx */
      39          28 :   b->next_period += NUM_SECS_BW_SUM_INTERVAL;
      40          28 :   if (b->next_max_idx == NUM_TOTALS)
      41           5 :     b->next_max_idx = 0;
      42          28 :   if (b->num_maxes_set < NUM_TOTALS)
      43          28 :     ++b->num_maxes_set;
      44             :   /* Reset max_total. */
      45          28 :   b->max_total = 0;
      46             :   /* Reset total_in_period. */
      47          28 :   b->total_in_period = 0;
      48          28 : }
      49             : 
      50             : /** Shift the current observation time of <b>b</b> forward by one second. */
      51             : STATIC void
      52     1818090 : advance_obs(bw_array_t *b)
      53             : {
      54     1818090 :   int nextidx;
      55     1818090 :   uint64_t total;
      56             : 
      57             :   /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
      58             :    * seconds; adjust max_total as needed.*/
      59     1818090 :   total = b->total_obs + b->obs[b->cur_obs_idx];
      60     1818090 :   if (total > b->max_total)
      61          32 :     b->max_total = total;
      62             : 
      63     1818090 :   nextidx = b->cur_obs_idx+1;
      64     1818090 :   if (nextidx == NUM_SECS_ROLLING_MEASURE)
      65      181806 :     nextidx = 0;
      66             : 
      67     1818090 :   b->total_obs = total - b->obs[nextidx];
      68     1818090 :   b->obs[nextidx]=0;
      69     1818090 :   b->cur_obs_idx = nextidx;
      70             : 
      71     1818090 :   if (++b->cur_obs_time >= b->next_period)
      72          22 :     commit_max(b);
      73     1818090 : }
      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          50 : add_obs(bw_array_t *b, time_t when, uint64_t n)
      79             : {
      80          50 :   if (when < b->cur_obs_time)
      81             :     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     1818127 :   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     1818078 :     advance_obs(b);
      91             :   }
      92             : 
      93          49 :   b->obs[b->cur_obs_idx] += n;
      94          49 :   b->total_in_period += n;
      95             : }
      96             : 
      97             : /** Allocate, initialize, and return a new bw_array. */
      98             : STATIC bw_array_t *
      99        1474 : bw_array_new(void)
     100             : {
     101        1474 :   bw_array_t *b;
     102        1474 :   time_t start;
     103        1474 :   b = tor_malloc_zero(sizeof(bw_array_t));
     104        1474 :   start = time(NULL);
     105        1474 :   b->cur_obs_time = start;
     106        1474 :   b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
     107        1474 :   return b;
     108             : }
     109             : 
     110             : /** Free storage held by bandwidth array <b>b</b>. */
     111             : STATIC void
     112        2890 : bw_array_free_(bw_array_t *b)
     113             : {
     114        2890 :   if (!b) {
     115             :     return;
     116             :   }
     117             : 
     118        1426 :   tor_free(b);
     119             : }
     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         245 : bwhist_init(void)
     140             : {
     141         245 :   bw_array_free(read_array);
     142         245 :   bw_array_free(read_array_ipv6);
     143         245 :   bw_array_free(write_array);
     144         245 :   bw_array_free(write_array_ipv6);
     145         245 :   bw_array_free(dir_read_array);
     146         245 :   bw_array_free(dir_write_array);
     147             : 
     148         245 :   read_array = bw_array_new();
     149         245 :   read_array_ipv6 = bw_array_new();
     150         245 :   write_array = bw_array_new();
     151         245 :   write_array_ipv6 = bw_array_new();
     152         245 :   dir_read_array = bw_array_new();
     153         245 :   dir_write_array = bw_array_new();
     154         245 : }
     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          28 : bwhist_note_bytes_written(uint64_t num_bytes, time_t when, bool ipv6)
     165             : {
     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          28 :   add_obs(write_array, when, num_bytes);
     175          28 :   if (ipv6)
     176           0 :     add_obs(write_array_ipv6, when, num_bytes);
     177          28 : }
     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           6 : bwhist_note_bytes_read(uint64_t num_bytes, time_t when, bool ipv6)
     184             : {
     185             : /* if we're smart, we can make this func and the one above share code */
     186           6 :   add_obs(read_array, when, num_bytes);
     187           6 :   if (ipv6)
     188           0 :     add_obs(read_array_ipv6, when, num_bytes);
     189           6 : }
     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           6 : bwhist_note_dir_bytes_written(uint64_t num_bytes, time_t when)
     196             : {
     197           6 :   add_obs(dir_write_array, when, num_bytes);
     198           6 : }
     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           6 : bwhist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
     205             : {
     206           6 :   add_obs(dir_read_array, when, num_bytes);
     207           6 : }
     208             : 
     209             : /** Helper: Return the largest value in b->maxima.  (This is equal to the
     210             :  * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
     211             :  * NUM_SECS_BW_SUM_IS_VALID seconds.)
     212             :  */
     213             : STATIC uint64_t
     214          12 : find_largest_max(bw_array_t *b)
     215             : {
     216          12 :   int i;
     217          12 :   uint64_t max;
     218          12 :   max=0;
     219          72 :   for (i=0; i<NUM_TOTALS; ++i) {
     220          60 :     if (b->maxima[i]>max)
     221             :       max = b->maxima[i];
     222             :   }
     223          12 :   return max;
     224             : }
     225             : 
     226             : /** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
     227             :  * seconds. Find one sum for reading and one for writing. They don't have
     228             :  * to be at the same time.
     229             :  *
     230             :  * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
     231             :  */
     232           5 : MOCK_IMPL(int,
     233             : bwhist_bandwidth_assess,(void))
     234             : {
     235           5 :   uint64_t w,r;
     236           5 :   r = find_largest_max(read_array);
     237           5 :   w = find_largest_max(write_array);
     238           5 :   if (r>w)
     239           0 :     return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE);
     240             :   else
     241           5 :     return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE);
     242             : }
     243             : 
     244             : /** Print the bandwidth history of b (either [dir-]read_array or
     245             :  * [dir-]write_array) into the buffer pointed to by buf.  The format is
     246             :  * simply comma separated numbers, from oldest to newest.
     247             :  *
     248             :  * It returns the number of bytes written.
     249             :  */
     250             : STATIC size_t
     251          50 : bwhist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
     252             : {
     253          50 :   char *cp = buf;
     254          50 :   int i, n;
     255          50 :   const or_options_t *options = get_options();
     256          50 :   uint64_t cutoff;
     257             : 
     258          50 :   if (b->num_maxes_set <= b->next_max_idx) {
     259             :     /* We haven't been through the circular array yet; time starts at i=0.*/
     260             :     i = 0;
     261             :   } else {
     262             :     /* We've been around the array at least once.  The next i to be
     263             :        overwritten is the oldest. */
     264           7 :     i = b->next_max_idx;
     265             :   }
     266             : 
     267          50 :   if (options->RelayBandwidthRate) {
     268             :     /* We don't want to report that we used more bandwidth than the max we're
     269             :      * willing to relay; otherwise everybody will know how much traffic
     270             :      * we used ourself. */
     271           1 :     cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL;
     272             :   } else {
     273             :     cutoff = UINT64_MAX;
     274             :   }
     275             : 
     276          95 :   for (n=0; n<b->num_maxes_set; ++n,++i) {
     277          45 :     uint64_t total;
     278          45 :     if (i >= NUM_TOTALS)
     279           2 :       i -= NUM_TOTALS;
     280          45 :     tor_assert(i < NUM_TOTALS);
     281             :     /* Round the bandwidth used down to the nearest 1k. */
     282          45 :     total = b->totals[i] & ~0x3ff;
     283          45 :     if (total > cutoff)
     284             :       total = cutoff;
     285             : 
     286          45 :     if (n==(b->num_maxes_set-1))
     287          11 :       tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total));
     288             :     else
     289          34 :       tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total));
     290          45 :     cp += strlen(cp);
     291             :   }
     292          50 :   return cp-buf;
     293             : }
     294             : 
     295             : /** Encode a single bandwidth history line into <b>buf</b>. */
     296             : static void
     297          42 : bwhist_get_one_bandwidth_line(buf_t *buf, const char *desc,
     298             :                               const bw_array_t *b)
     299             : {
     300             :   /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
     301             :   /* The n,n,n part above. Largest representation of a uint64_t is 20 chars
     302             :    * long, plus the comma. */
     303             : #define MAX_HIST_VALUE_LEN (21*NUM_TOTALS)
     304             : 
     305          42 :   char tmp[MAX_HIST_VALUE_LEN];
     306          42 :   char end[ISO_TIME_LEN+1];
     307             : 
     308          42 :   size_t slen = bwhist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
     309             :   /* If we don't have anything to write, skip to the next entry. */
     310          42 :   if (slen == 0)
     311          38 :     return;
     312             : 
     313           4 :   format_iso_time(end, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
     314           4 :   buf_add_printf(buf, "%s %s (%d s) %s\n",
     315             :                  desc, end, NUM_SECS_BW_SUM_INTERVAL, tmp);
     316             : }
     317             : 
     318             : /** Allocate and return lines for representing this server's bandwidth
     319             :  * history in its descriptor. We publish these lines in our extra-info
     320             :  * descriptor.
     321             :  */
     322             : char *
     323           7 : bwhist_get_bandwidth_lines(void)
     324             : {
     325           7 :   buf_t *buf = buf_new();
     326             : 
     327           7 :   bwhist_get_one_bandwidth_line(buf, "write-history", write_array);
     328           7 :   bwhist_get_one_bandwidth_line(buf, "read-history", read_array);
     329           7 :   bwhist_get_one_bandwidth_line(buf, "ipv6-write-history", write_array_ipv6);
     330           7 :   bwhist_get_one_bandwidth_line(buf, "ipv6-read-history", read_array_ipv6);
     331           7 :   bwhist_get_one_bandwidth_line(buf, "dirreq-write-history", dir_write_array);
     332           7 :   bwhist_get_one_bandwidth_line(buf, "dirreq-read-history", dir_read_array);
     333             : 
     334           7 :   char *result = buf_extract(buf, NULL);
     335           7 :   buf_free(buf);
     336           7 :   return result;
     337             : }
     338             : 
     339             : /** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
     340             :  * entries of an or_state_t. Done before writing out a new state file. */
     341             : static void
     342          24 : bwhist_update_bwhist_state_section(or_state_t *state,
     343             :                                      const bw_array_t *b,
     344             :                                      smartlist_t **s_values,
     345             :                                      smartlist_t **s_maxima,
     346             :                                      time_t *s_begins,
     347             :                                      int *s_interval)
     348             : {
     349          24 :   int i,j;
     350          24 :   uint64_t maxval;
     351             : 
     352          24 :   if (*s_values) {
     353          24 :     SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
     354          24 :     smartlist_free(*s_values);
     355             :   }
     356          24 :   if (*s_maxima) {
     357          24 :     SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
     358          24 :     smartlist_free(*s_maxima);
     359             :   }
     360          24 :   if (! server_mode(get_options())) {
     361             :     /* Clients don't need to store bandwidth history persistently;
     362             :      * force these values to the defaults. */
     363             :     /* FFFF we should pull the default out of config.c's state table,
     364             :      * so we don't have two defaults. */
     365           0 :     if (*s_begins != 0 || *s_interval != 900) {
     366           0 :       time_t now = time(NULL);
     367           0 :       time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
     368           0 :       or_state_mark_dirty(state, save_at);
     369             :     }
     370           0 :     *s_begins = 0;
     371           0 :     *s_interval = 900;
     372           0 :     *s_values = smartlist_new();
     373           0 :     *s_maxima = smartlist_new();
     374           0 :     return;
     375             :   }
     376          24 :   *s_begins = b->next_period;
     377          24 :   *s_interval = NUM_SECS_BW_SUM_INTERVAL;
     378             : 
     379          24 :   *s_values = smartlist_new();
     380          24 :   *s_maxima = smartlist_new();
     381             :   /* Set i to first position in circular array */
     382          24 :   i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
     383          24 :   for (j=0; j < b->num_maxes_set; ++j,++i) {
     384           0 :     if (i >= NUM_TOTALS)
     385           0 :       i = 0;
     386           0 :     smartlist_add_asprintf(*s_values, "%"PRIu64,
     387           0 :                            (b->totals[i] & ~0x3ff));
     388           0 :     maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
     389           0 :     smartlist_add_asprintf(*s_maxima, "%"PRIu64,
     390             :                            (maxval & ~0x3ff));
     391             :   }
     392          24 :   smartlist_add_asprintf(*s_values, "%"PRIu64,
     393          24 :                          (b->total_in_period & ~0x3ff));
     394          24 :   maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
     395          24 :   smartlist_add_asprintf(*s_maxima, "%"PRIu64,
     396             :                          (maxval & ~0x3ff));
     397             : }
     398             : 
     399             : /** Update <b>state</b> with the newest bandwidth history. Done before
     400             :  * writing out a new state file. */
     401             : void
     402           4 : bwhist_update_state(or_state_t *state)
     403             : {
     404             : #define UPDATE(arrname,st) \
     405             :   bwhist_update_bwhist_state_section(state,\
     406             :                                        (arrname),\
     407             :                                        &state->BWHistory ## st ## Values, \
     408             :                                        &state->BWHistory ## st ## Maxima, \
     409             :                                        &state->BWHistory ## st ## Ends, \
     410             :                                        &state->BWHistory ## st ## Interval)
     411             : 
     412           4 :   UPDATE(write_array, Write);
     413           4 :   UPDATE(read_array, Read);
     414           4 :   UPDATE(write_array_ipv6, IPv6Write);
     415           4 :   UPDATE(read_array_ipv6, IPv6Read);
     416           4 :   UPDATE(dir_write_array, DirWrite);
     417           4 :   UPDATE(dir_read_array, DirRead);
     418             : 
     419           4 :   if (server_mode(get_options())) {
     420           4 :     or_state_mark_dirty(state, time(NULL)+(2*3600));
     421             :   }
     422             : #undef UPDATE
     423           4 : }
     424             : 
     425             : /** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
     426             :  * entries in an or_state_t. Done while reading the state file. */
     427             : static int
     428          24 : bwhist_load_bwhist_state_section(bw_array_t *b,
     429             :                                    const smartlist_t *s_values,
     430             :                                    const smartlist_t *s_maxima,
     431             :                                    const time_t s_begins,
     432             :                                    const int s_interval)
     433             : {
     434          24 :   time_t now = time(NULL);
     435          24 :   int retval = 0;
     436          24 :   time_t start;
     437             : 
     438          24 :   uint64_t v, mv;
     439          24 :   int i,ok,ok_m = 0;
     440          24 :   int have_maxima = s_maxima && s_values &&
     441          24 :     (smartlist_len(s_values) == smartlist_len(s_maxima));
     442             : 
     443          24 :   if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
     444           0 :     start = s_begins - s_interval*(smartlist_len(s_values));
     445           0 :     if (start > now)
     446             :       return 0;
     447           0 :     b->cur_obs_time = start;
     448           0 :     b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
     449           0 :     SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
     450           0 :         const char *maxstr = NULL;
     451           0 :         v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
     452           0 :         if (have_maxima) {
     453           0 :           maxstr = smartlist_get(s_maxima, cp_sl_idx);
     454           0 :           mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
     455           0 :           mv *= NUM_SECS_ROLLING_MEASURE;
     456             :         } else {
     457             :           /* No maxima known; guess average rate to be conservative. */
     458           0 :           mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
     459             :         }
     460           0 :         if (!ok) {
     461           0 :           retval = -1;
     462           0 :           log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
     463             :         }
     464           0 :         if (maxstr && !ok_m) {
     465           0 :           retval = -1;
     466           0 :           log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
     467             :                      maxstr);
     468             :         }
     469             : 
     470           0 :         if (start < now) {
     471           0 :           time_t cur_start = start;
     472           0 :           time_t actual_interval_len = s_interval;
     473           0 :           uint64_t cur_val = 0;
     474             :           /* Calculate the average per second. This is the best we can do
     475             :            * because our state file doesn't have per-second resolution. */
     476           0 :           if (start + s_interval > now)
     477           0 :             actual_interval_len = now - start;
     478           0 :           cur_val = v / actual_interval_len;
     479             :           /* This is potentially inefficient, but since we don't do it very
     480             :            * often it should be ok. */
     481           0 :           while (cur_start < start + actual_interval_len) {
     482           0 :             add_obs(b, cur_start, cur_val);
     483           0 :             ++cur_start;
     484             :           }
     485           0 :           b->max_total = mv;
     486             :           /* This will result in some fairly choppy history if s_interval
     487             :            * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
     488           0 :           start += actual_interval_len;
     489             :         }
     490           0 :     } SMARTLIST_FOREACH_END(cp);
     491             :   }
     492             : 
     493             :   /* Clean up maxima and observed */
     494         264 :   for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
     495         240 :     b->obs[i] = 0;
     496             :   }
     497          24 :   b->total_obs = 0;
     498             : 
     499          24 :   return retval;
     500             : }
     501             : 
     502             : /** Set bandwidth history from the state file we just loaded. */
     503             : int
     504           4 : bwhist_load_state(or_state_t *state, char **err)
     505             : {
     506           4 :   int all_ok = 1;
     507             : 
     508             :   /* Assert they already have been malloced */
     509           4 :   tor_assert(read_array && write_array);
     510           4 :   tor_assert(read_array_ipv6 && write_array_ipv6);
     511           4 :   tor_assert(dir_read_array && dir_write_array);
     512             : 
     513             : #define LOAD(arrname,st)                                                \
     514             :   if (bwhist_load_bwhist_state_section(                               \
     515             :                                 (arrname),                              \
     516             :                                 state->BWHistory ## st ## Values,       \
     517             :                                 state->BWHistory ## st ## Maxima,       \
     518             :                                 state->BWHistory ## st ## Ends,         \
     519             :                                 state->BWHistory ## st ## Interval)<0)  \
     520             :     all_ok = 0
     521             : 
     522           4 :   LOAD(write_array, Write);
     523           4 :   LOAD(read_array, Read);
     524           4 :   LOAD(write_array_ipv6, IPv6Write);
     525           4 :   LOAD(read_array_ipv6, IPv6Read);
     526           4 :   LOAD(dir_write_array, DirWrite);
     527           4 :   LOAD(dir_read_array, DirRead);
     528             : 
     529             : #undef LOAD
     530           4 :   if (!all_ok) {
     531           0 :     *err = tor_strdup("Parsing of bandwidth history values failed");
     532             :     /* and create fresh arrays */
     533           0 :     bwhist_init();
     534           0 :     return -1;
     535             :   }
     536             :   return 0;
     537             : }
     538             : 
     539             : void
     540         236 : bwhist_free_all(void)
     541             : {
     542         236 :   bw_array_free(read_array);
     543         236 :   bw_array_free(read_array_ipv6);
     544         236 :   bw_array_free(write_array);
     545         236 :   bw_array_free(write_array_ipv6);
     546         236 :   bw_array_free(dir_read_array);
     547         236 :   bw_array_free(dir_write_array);
     548         236 : }

Generated by: LCOV version 1.14