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

Keep bandwidth history accross restarts/crashes


svn:r5637
parent f7e82bab
......@@ -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;
......
......@@ -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
......
......@@ -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 ***************************/
......
......@@ -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. */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment