mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
r11468@Kushana: nickm | 2006-12-07 14:56:57 -0500
Revise logic used to flush state to disk. Now, we try to batch non-urgent changes so that we do not do too many writes, and we save very-non-urgent changes every once in a rare while, and we never save more than once per second. svn:r9047
This commit is contained in:
parent
c304a10fd3
commit
7c79495137
@ -3,6 +3,9 @@ Changes in version 0.1.2.5-xxxx - 200?-??-??
|
|||||||
- Start using the state file to store bandwidth accounting data:
|
- Start using the state file to store bandwidth accounting data:
|
||||||
the bw_accounting file is now obsolete. We'll keep generating it
|
the bw_accounting file is now obsolete. We'll keep generating it
|
||||||
for a while for people who are still using 0.1.2.4-alpha.
|
for a while for people who are still using 0.1.2.4-alpha.
|
||||||
|
- Try to batch changes to the state so that we do as few disk writes
|
||||||
|
as possible while still storing important things in a timely
|
||||||
|
fashion.
|
||||||
|
|
||||||
o Minor bugfixes;
|
o Minor bugfixes;
|
||||||
- Fix a bug when a PF socket is first used. (Patch from Fabian
|
- Fix a bug when a PF socket is first used. (Patch from Fabian
|
||||||
|
@ -2376,13 +2376,16 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Our list of entry guards has changed, or some element of one
|
/** Our list of entry guards has changed, or some element of one
|
||||||
* of our entry guards has changed. Write the changes to disk. */
|
* of our entry guards has changed. Write the changes to disk within
|
||||||
|
* the next 5 minutes.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
entry_guards_changed(void)
|
entry_guards_changed(void)
|
||||||
{
|
{
|
||||||
entry_guards_dirty = 1;
|
entry_guards_dirty = 1;
|
||||||
|
|
||||||
or_state_save();
|
/* or_state_save() will call entry_guards_update_state(). */
|
||||||
|
or_state_mark_dirty(get_or_state(), time(NULL)+600);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If the entry guard info has not changed, do nothing and return.
|
/** If the entry guard info has not changed, do nothing and return.
|
||||||
@ -2433,7 +2436,7 @@ entry_guards_update_state(or_state_t *state)
|
|||||||
next = &(line->next);
|
next = &(line->next);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
state->dirty = 1;
|
or_state_mark_dirty(get_or_state(), 0);
|
||||||
entry_guards_dirty = 0;
|
entry_guards_dirty = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3934,8 +3934,8 @@ or_state_load(void)
|
|||||||
or_state_set(new_state);
|
or_state_set(new_state);
|
||||||
new_state = NULL;
|
new_state = NULL;
|
||||||
if (!contents) {
|
if (!contents) {
|
||||||
global_state->dirty = 1;
|
global_state->next_write = 0;
|
||||||
or_state_save();
|
or_state_save(time(NULL));
|
||||||
}
|
}
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
@ -3950,7 +3950,7 @@ or_state_load(void)
|
|||||||
|
|
||||||
/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
|
/** Write the persistent state to disk. Return 0 for success, <0 on failure. */
|
||||||
int
|
int
|
||||||
or_state_save(void)
|
or_state_save(time_t now)
|
||||||
{
|
{
|
||||||
char *state, *contents;
|
char *state, *contents;
|
||||||
char tbuf[ISO_TIME_LEN+1];
|
char tbuf[ISO_TIME_LEN+1];
|
||||||
@ -3959,11 +3959,14 @@ or_state_save(void)
|
|||||||
|
|
||||||
tor_assert(global_state);
|
tor_assert(global_state);
|
||||||
|
|
||||||
|
if (global_state->next_write > now)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Call everything else that might dirty the state even more, in order
|
||||||
|
* to avoid redundant writes. */
|
||||||
entry_guards_update_state(global_state);
|
entry_guards_update_state(global_state);
|
||||||
rep_hist_update_state(global_state);
|
rep_hist_update_state(global_state);
|
||||||
|
accounting_run_housekeeping(now);
|
||||||
if (!global_state->dirty)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
global_state->LastWritten = time(NULL);
|
global_state->LastWritten = time(NULL);
|
||||||
tor_free(global_state->TorVersion);
|
tor_free(global_state->TorVersion);
|
||||||
@ -3988,7 +3991,7 @@ or_state_save(void)
|
|||||||
tor_free(fname);
|
tor_free(fname);
|
||||||
tor_free(contents);
|
tor_free(contents);
|
||||||
|
|
||||||
global_state->dirty = 0;
|
global_state->next_write = TIME_MAX;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,8 +391,8 @@ reset_accounting(time_t now)
|
|||||||
static INLINE int
|
static INLINE int
|
||||||
time_to_record_bandwidth_usage(time_t now)
|
time_to_record_bandwidth_usage(time_t now)
|
||||||
{
|
{
|
||||||
/* Note every 60 sec */
|
/* Note every 600 sec */
|
||||||
#define NOTE_INTERVAL (60)
|
#define NOTE_INTERVAL (600)
|
||||||
/* Or every 20 megabytes */
|
/* Or every 20 megabytes */
|
||||||
#define NOTE_BYTES 20*(1024*1024)
|
#define NOTE_BYTES 20*(1024*1024)
|
||||||
static uint64_t last_read_bytes_noted = 0;
|
static uint64_t last_read_bytes_noted = 0;
|
||||||
@ -575,7 +575,7 @@ accounting_record_bandwidth_usage(time_t now, or_state_t *state)
|
|||||||
state->AccountingBytesWrittenInInterval = n_bytes_written_in_interval;
|
state->AccountingBytesWrittenInInterval = n_bytes_written_in_interval;
|
||||||
state->AccountingSecondsActive = n_seconds_active_in_interval;
|
state->AccountingSecondsActive = n_seconds_active_in_interval;
|
||||||
state->AccountingExpectedUsage = expected_bandwidth_usage;
|
state->AccountingExpectedUsage = expected_bandwidth_usage;
|
||||||
state->dirty = 1;
|
or_state_mark_dirty(state, 60);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -760,6 +760,7 @@ hibernate_begin(int new_state, time_t now)
|
|||||||
|
|
||||||
hibernate_state = new_state;
|
hibernate_state = new_state;
|
||||||
accounting_record_bandwidth_usage(now, get_or_state());
|
accounting_record_bandwidth_usage(now, get_or_state());
|
||||||
|
or_state_mark_dirty(get_or_state(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when we've been hibernating and our timeout is reached. */
|
/** Called when we've been hibernating and our timeout is reached. */
|
||||||
@ -827,6 +828,7 @@ hibernate_go_dormant(time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
accounting_record_bandwidth_usage(now, get_or_state());
|
accounting_record_bandwidth_usage(now, get_or_state());
|
||||||
|
or_state_mark_dirty(get_or_state(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when hibernate_end_time has arrived. */
|
/** Called when hibernate_end_time has arrived. */
|
||||||
|
@ -830,9 +830,6 @@ run_scheduled_events(time_t now)
|
|||||||
* and the rend cache. */
|
* and the rend cache. */
|
||||||
rep_history_clean(now - options->RephistTrackTime);
|
rep_history_clean(now - options->RephistTrackTime);
|
||||||
rend_cache_clean();
|
rend_cache_clean();
|
||||||
/* And while we are at it, save the state with bandwidth history
|
|
||||||
* and more. */
|
|
||||||
or_state_save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2b. Once per minute, regenerate and upload the descriptor if the old
|
/* 2b. Once per minute, regenerate and upload the descriptor if the old
|
||||||
@ -935,6 +932,10 @@ run_scheduled_events(time_t now)
|
|||||||
*/
|
*/
|
||||||
close_closeable_connections();
|
close_closeable_connections();
|
||||||
|
|
||||||
|
/** 8b. And if anything in our state is ready to get flushed to disk, we
|
||||||
|
* flush it. */
|
||||||
|
or_state_save(now);
|
||||||
|
|
||||||
/** 9. and if we're a server, check whether our DNS is telling stories to
|
/** 9. and if we're a server, check whether our DNS is telling stories to
|
||||||
* us. */
|
* us. */
|
||||||
if (server_mode(options) && time_to_check_for_wildcarded_dns < now) {
|
if (server_mode(options) && time_to_check_for_wildcarded_dns < now) {
|
||||||
@ -1595,7 +1596,8 @@ tor_cleanup(void)
|
|||||||
unlink(options->PidFile);
|
unlink(options->PidFile);
|
||||||
if (accounting_is_enabled(options))
|
if (accounting_is_enabled(options))
|
||||||
accounting_record_bandwidth_usage(time(NULL), get_or_state());
|
accounting_record_bandwidth_usage(time(NULL), get_or_state());
|
||||||
or_state_save();
|
or_state_mark_dirty(get_or_state(), 0); /* force an immediate save. */
|
||||||
|
or_state_save(time(NULL));
|
||||||
}
|
}
|
||||||
tor_free_all(0); /* move tor_free_all back into the ifdef below later. XXX*/
|
tor_free_all(0); /* move tor_free_all back into the ifdef below later. XXX*/
|
||||||
crypto_global_cleanup();
|
crypto_global_cleanup();
|
||||||
|
32
src/or/or.h
32
src/or/or.h
@ -1655,19 +1655,30 @@ typedef struct {
|
|||||||
/** Persistent state for an onion router, as saved to disk. */
|
/** Persistent state for an onion router, as saved to disk. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t _magic;
|
uint32_t _magic;
|
||||||
/** True iff this state has been changed since it was last read/written
|
/** The time at which we next plan to write the state to the disk. Equal to
|
||||||
* to the disk. */
|
* TIME_MAX if there are no saveable changes, 0 if there are changes that
|
||||||
int dirty;
|
* should be saved right away. */
|
||||||
|
time_t next_write;
|
||||||
|
|
||||||
|
/** When was the state last written to disk? */
|
||||||
time_t LastWritten;
|
time_t LastWritten;
|
||||||
|
|
||||||
|
/** Fields for */
|
||||||
time_t AccountingIntervalStart;
|
time_t AccountingIntervalStart;
|
||||||
uint64_t AccountingBytesReadInInterval;
|
uint64_t AccountingBytesReadInInterval;
|
||||||
uint64_t AccountingBytesWrittenInInterval;
|
uint64_t AccountingBytesWrittenInInterval;
|
||||||
int AccountingSecondsActive;
|
int AccountingSecondsActive;
|
||||||
uint64_t AccountingExpectedUsage;
|
uint64_t AccountingExpectedUsage;
|
||||||
|
|
||||||
|
/** A list of Entry Guard-related configuration lines. */
|
||||||
config_line_t *EntryGuards;
|
config_line_t *EntryGuards;
|
||||||
|
|
||||||
|
/** These fields hold information on the history of bandwidth usage for
|
||||||
|
* servers. The "Ends" fields hold the time when we last updated the
|
||||||
|
* bandwidth usage. The "Interval" fields hold the granularity, in seconds,
|
||||||
|
* of the entries of Values. The "Values" lists hold decimal string
|
||||||
|
* representations of the number of bytes read or written in each
|
||||||
|
* interval. */
|
||||||
time_t BWHistoryReadEnds;
|
time_t BWHistoryReadEnds;
|
||||||
int BWHistoryReadInterval;
|
int BWHistoryReadInterval;
|
||||||
smartlist_t *BWHistoryReadValues;
|
smartlist_t *BWHistoryReadValues;
|
||||||
@ -1675,11 +1686,24 @@ typedef struct {
|
|||||||
int BWHistoryWriteInterval;
|
int BWHistoryWriteInterval;
|
||||||
smartlist_t *BWHistoryWriteValues;
|
smartlist_t *BWHistoryWriteValues;
|
||||||
|
|
||||||
|
/** What version of Tor write this state file? */
|
||||||
char *TorVersion;
|
char *TorVersion;
|
||||||
|
|
||||||
|
/** holds any unrecognized values we found in the state file, in the order
|
||||||
|
* in which we found them. */
|
||||||
config_line_t *ExtraLines;
|
config_line_t *ExtraLines;
|
||||||
} or_state_t;
|
} or_state_t;
|
||||||
|
|
||||||
|
static void or_state_mark_dirty(or_state_t *state, time_t when);
|
||||||
|
/** Change the next_write time of <b>state</b> to <b>when</b>, unless the
|
||||||
|
* state is already scheduled to be written to disk earlier than <b>when</b>.
|
||||||
|
*/
|
||||||
|
static INLINE void or_state_mark_dirty(or_state_t *state, time_t when)
|
||||||
|
{
|
||||||
|
if (state->next_write > when)
|
||||||
|
state->next_write = when;
|
||||||
|
}
|
||||||
|
|
||||||
#define MAX_SOCKS_REPLY_LEN 1024
|
#define MAX_SOCKS_REPLY_LEN 1024
|
||||||
#define MAX_SOCKS_ADDR_LEN 256
|
#define MAX_SOCKS_ADDR_LEN 256
|
||||||
#define SOCKS_COMMAND_CONNECT 0x01
|
#define SOCKS_COMMAND_CONNECT 0x01
|
||||||
@ -1897,7 +1921,7 @@ const char *get_torrc_fname(void);
|
|||||||
|
|
||||||
or_state_t *get_or_state(void);
|
or_state_t *get_or_state(void);
|
||||||
int or_state_load(void);
|
int or_state_load(void);
|
||||||
int or_state_save(void);
|
int or_state_save(time_t now);
|
||||||
|
|
||||||
int config_getinfo_helper(const char *question, char **answer);
|
int config_getinfo_helper(const char *question, char **answer);
|
||||||
|
|
||||||
|
@ -666,6 +666,8 @@ rep_hist_update_state(or_state_t *state)
|
|||||||
if (! server_mode(get_options())) {
|
if (! server_mode(get_options())) {
|
||||||
/* Clients don't need to store bandwidth history persistently;
|
/* Clients don't need to store bandwidth history persistently;
|
||||||
* force these values to the defaults. */
|
* force these values to the defaults. */
|
||||||
|
if (*s_begins != 0 || *s_interval != 900)
|
||||||
|
or_state_mark_dirty(get_or_state(), time(NULL)+600);
|
||||||
*s_begins = 0;
|
*s_begins = 0;
|
||||||
*s_interval = 900;
|
*s_interval = 900;
|
||||||
*s_values = smartlist_create();
|
*s_values = smartlist_create();
|
||||||
@ -682,7 +684,8 @@ rep_hist_update_state(or_state_t *state)
|
|||||||
smartlist_split_string(*s_values, buf, ",", SPLIT_SKIP_SPACE, 0);
|
smartlist_split_string(*s_values, buf, ",", SPLIT_SKIP_SPACE, 0);
|
||||||
}
|
}
|
||||||
tor_free(buf);
|
tor_free(buf);
|
||||||
state->dirty = 1;
|
if (server_mode(get_options()))
|
||||||
|
or_state_mark_dirty(get_or_state(), time(NULL)+(2*3600));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set bandwidth history from our saved state. */
|
/** Set bandwidth history from our saved state. */
|
||||||
|
Loading…
Reference in New Issue
Block a user