Commit 4bd65f0f authored by Peter Palfrader's avatar Peter Palfrader
Browse files

Keep bandwidth history accross restarts/crashes


svn:r5637
parent f7e82bab
Loading
Loading
Loading
Loading
+10 −1
Changes for src/or/config.c: 10 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -229,6 +229,13 @@ static config_var_t _state_vars[] = {
  VAR("HelperNodes",             LINELIST_V,  HelperNodes,          NULL),
  VAR("LastWritten",             ISOTIME,     LastWritten,          NULL),

  VAR("BWHistoryReadEnds",       ISOTIME,     BWHistoryReadEnds,      NULL),
  VAR("BWHistoryReadInterval",   UINT,        BWHistoryReadInterval,  NULL),
  VAR("BWHistoryReadValues",     CSV,         BWHistoryReadValues,    NULL),
  VAR("BWHistoryWriteEnds",      ISOTIME,     BWHistoryWriteEnds,     NULL),
  VAR("BWHistoryWriteInterval",  UINT,        BWHistoryWriteInterval, NULL),
  VAR("BWHistoryWriteValues",    CSV,         BWHistoryWriteValues,   NULL),

  { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, NULL }
};

@@ -3516,7 +3523,8 @@ or_state_set(or_state_t *new_state)
  global_state = new_state;
  if (helper_nodes_parse_state(global_state, 1, &err)<0)
    warn(LD_GENERAL,"Unparseable helper nodes state: %s",err);

  if (rep_hist_load_state(global_state, &err)<0)
    warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
}

/* DOCDOC */
@@ -3589,6 +3597,7 @@ or_state_save(void)
  char *fname;

  helper_nodes_update_state(global_state);
  rep_hist_update_state(global_state);

  if (!global_state->dirty)
    return 0;
+4 −0
Changes for src/or/main.c: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -779,6 +779,9 @@ run_scheduled_events(time_t now)
     * and the rend cache. */
    rep_history_clean(now - options->RephistTrackTime);
    rend_cache_clean();
    /* And while we are at it, save the state with bandwidth history
     * and more. */
    or_state_save();
  }

  /* Caches need to fetch running_routers; directory clients don't. */
@@ -1494,6 +1497,7 @@ tor_cleanup(void)
    unlink(options->PidFile);
  if (accounting_is_enabled(options))
    accounting_record_bandwidth_usage(time(NULL));
  or_state_save();
  tor_free_all(0); /* move tor_free_all back into the ifdef below later. XXX*/
  crypto_global_cleanup();
#ifdef USE_DMALLOC
+10 −0
Changes for src/or/or.h: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -1369,6 +1369,13 @@ typedef struct {
  uint64_t AccountingExpectedUsage;

  config_line_t *HelperNodes;

  time_t      BWHistoryReadEnds;
  int         BWHistoryReadInterval;
  smartlist_t *BWHistoryReadValues;
  time_t      BWHistoryWriteEnds;
  int         BWHistoryWriteInterval;
  smartlist_t *BWHistoryWriteValues;
} or_state_t;

#define MAX_SOCKS_REPLY_LEN 1024
@@ -2024,6 +2031,9 @@ void rep_hist_note_used_internal(time_t now, int need_uptime,
int rep_hist_get_predicted_internal(time_t now, int *need_uptime,
                                    int *need_capacity);

int rep_hist_update_state(or_state_t *state);
int rep_hist_load_state(or_state_t *state, const char **err);

void rep_hist_free_all(void);

/********************************* rendclient.c ***************************/
+141 −20
Changes for src/or/rephist.c: 141 added lines, 20 removed lines.
Original line number Diff line number Diff line
@@ -579,6 +579,41 @@ rep_hist_bandwidth_assess(void)
  return 0;
}

/**
 * Print the bandwidth history of b (either read_array or write_array)
 * into the buffer pointed to by buf.  The format is simply comma
 * separated numbers, from oldest to newest.
 *
 * It returns the number of bytes written.
 */
size_t
rep_hist_fill_bandwidth_history(char *buf, size_t len, bw_array_t *b)
{
  char *cp = buf;
  int i, n;

  if (b->num_maxes_set <= b->next_max_idx) {
    /* We haven't been through the circular array yet; time starts at i=0.*/
    i = 0;
  } else {
    /* We've been around the array at least once.  The next i to be
       overwritten is the oldest. */
    i = b->next_max_idx;
  }

  for (n=0; n<b->num_maxes_set; ++n,++i) {
    while (i >= NUM_TOTALS) i -= NUM_TOTALS;
    if (n==(b->num_maxes_set-1))
      tor_snprintf(cp, len-(cp-buf), U64_FORMAT,
                   U64_PRINTF_ARG(b->totals[i]));
    else
      tor_snprintf(cp, len-(cp-buf), U64_FORMAT",",
                   U64_PRINTF_ARG(b->totals[i]));
    cp += strlen(cp);
  }
  return cp-buf;
}

/**
 * Allocate and return lines for representing this server's bandwidth
 * history in its descriptor.
@@ -588,7 +623,7 @@ rep_hist_get_bandwidth_lines(void)
{
  char *buf, *cp;
  char t[ISO_TIME_LEN+1];
  int r, i, n;
  int r;
  bw_array_t *b;
  size_t len;

@@ -604,31 +639,117 @@ rep_hist_get_bandwidth_lines(void)
                 r ? "read-history" : "write-history", t,
                 NUM_SECS_BW_SUM_INTERVAL);
    cp += strlen(cp);

    if (b->num_maxes_set <= b->next_max_idx)
      /* We haven't been through the circular array yet; time starts at i=0.*/
      i = 0;
    else
      /* We've been around the array at least once.  The next i to be
         overwritten is the oldest. */
      i = b->next_max_idx;

    for (n=0; n<b->num_maxes_set; ++n,++i) {
      while (i >= NUM_TOTALS) i -= NUM_TOTALS;
      if (n==(b->num_maxes_set-1))
        tor_snprintf(cp, len-(cp-buf), U64_FORMAT,
                     U64_PRINTF_ARG(b->totals[i]));
      else
        tor_snprintf(cp, len-(cp-buf), U64_FORMAT",",
                     U64_PRINTF_ARG(b->totals[i]));
      cp += strlen(cp);
    }
    cp += rep_hist_fill_bandwidth_history(cp, len-(cp-buf), b);
    strlcat(cp, "\n", len-(cp-buf));
    ++cp;
  }
  return buf;
}

/** Update the state with bandwidth history
 * A return value of 0 means nothing was updated,
 * a value of 1 means something has
 */
int
rep_hist_update_state(or_state_t *state)
{
  int len, r;
  char *buf, *cp;
  smartlist_t **s_values;
  time_t *s_begins;
  int *s_interval;
  bw_array_t *b;

  len = 20*NUM_TOTALS+1;
  buf = tor_malloc_zero(len);

  for (r=0;r<2;++r) {
    b = r?read_array:write_array;
    s_begins  = r?&state->BWHistoryReadEnds    :&state->BWHistoryWriteEnds;
    s_interval= r?&state->BWHistoryReadInterval:&state->BWHistoryWriteInterval;
    s_values  = r?&state->BWHistoryReadValues  :&state->BWHistoryWriteValues;

    *s_begins = b->next_period;
    *s_interval = NUM_SECS_BW_SUM_INTERVAL;
    if (*s_values) {
      SMARTLIST_FOREACH(*s_values, char *, cp, tor_free(cp));
      smartlist_free(*s_values);
    }
    cp = buf;
    cp += rep_hist_fill_bandwidth_history(cp, len, b);
    tor_snprintf(cp, len-(cp-buf), cp == buf ? U64_FORMAT : ","U64_FORMAT,
                 U64_PRINTF_ARG(b->total_in_period));
    *s_values = smartlist_create();
    smartlist_split_string(*s_values, buf, ",", SPLIT_SKIP_SPACE, 0);
  }
  tor_free(buf);
  state->dirty = 1;
  return 1;
}

/** Set bandwidth history from our saved state.
 */
int
rep_hist_load_state(or_state_t *state, const char **err)
{
  time_t s_begins, start;
  time_t now = time(NULL);
  uint64_t v;
  int r,i,ok;
  int all_ok = 1;
  int s_interval;
  smartlist_t *s_values;
  bw_array_t *b;

  /* Assert they already have been malloced */
  tor_assert(read_array && write_array);

  for (r=0;r<2;++r) {
    b = r?read_array:write_array;
    s_begins = r?state->BWHistoryReadEnds:state->BWHistoryWriteEnds;
    s_interval =  r?state->BWHistoryReadInterval:state->BWHistoryWriteInterval;
    s_values =  r?state->BWHistoryReadValues:state->BWHistoryWriteValues;
    if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
      start = s_begins - s_interval*(smartlist_len(s_values));

      b->cur_obs_time = start;
      b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
      SMARTLIST_FOREACH(s_values, char *, cp, {
        v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
        if (!ok) {
          all_ok=0;
          notice(LD_GENERAL, "Could not parse '%s' into a number.'", cp);
        }
        add_obs(b, start, v);
        start += NUM_SECS_BW_SUM_INTERVAL;
      });
    }

    /* Clean up maxima and observed */
    /* Do we really want to zero this for the purpose of max capacity? */
    for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
      b->obs[i] = 0;
    }
    b->total_obs = 0;
    for (i=0; i<NUM_TOTALS; ++i) {
      b->maxima[i] = 0;
    }
    b->max_total = 0;
  }

  if (!all_ok) {
    if (err)
      *err = "Parsing of bandwidth history values failed";
    /* and create fresh arrays */
    tor_free(read_array);
    tor_free(write_array);
    read_array = bw_array_new();
    write_array = bw_array_new();
    return -1;
  }
  return 0;
}

/** A list of port numbers that have been used recently. */
static smartlist_t *predicted_ports_list=NULL;
/** The corresponding most recently used time for each port. */