Loading changes/bug1789 0 → 100644 +16 −0 Original line number Diff line number Diff line o Minor features: - Be more generous with how much bandwidth we'd use up (with accounting enabled) before entering "soft hibernation". Previously, we'd hibernate once we'd used up 95% of our allotment. Now, we use up 95% of our allotment, AND make sure that we have no more than 500MB (or 3 hours of expected traffic, whichever is lower) remaining before we enter soft hibernation. o Minor bugfixes: - For bandwidth accounting, calculate our expected bandwidth rate based on the time during which we were active and not in soft-hibernation during the last interval. Previously, we were also considering the time spent in soft-hibernation. If this was a long time, we would wind up underestimating our bandwidth by a lot, and skewing our wakeup time towards the start of the accounting interval. Fixes bug 1789. Bugfix on 0.0.9pre5. src/or/config.c +3 −0 Original line number Diff line number Diff line Loading @@ -428,6 +428,9 @@ static config_var_t _state_vars[] = { V(AccountingExpectedUsage, MEMUNIT, NULL), V(AccountingIntervalStart, ISOTIME, NULL), V(AccountingSecondsActive, INTERVAL, NULL), V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL), V(AccountingSoftLimitHitAt, ISOTIME, NULL), V(AccountingBytesAtSoftLimit, MEMUNIT, NULL), VAR("EntryGuard", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL), Loading src/or/hibernate.c +87 −16 Original line number Diff line number Diff line Loading @@ -95,6 +95,13 @@ static uint64_t n_bytes_read_in_interval = 0; static uint64_t n_bytes_written_in_interval = 0; /** How many seconds have we been running this interval? */ static uint32_t n_seconds_active_in_interval = 0; /** How many seconds were we active in this interval before we hit our soft * limit? */ static int n_seconds_to_hit_soft_limit = 0; /** When in this interval was the soft limit hit. */ static time_t soft_limit_hit_at = 0; /** How many bytes had we read/written when we hit the soft limit? */ static uint64_t n_bytes_at_soft_limit = 0; /** When did this accounting interval start? */ static time_t interval_start_time = 0; /** When will this accounting interval end? */ Loading Loading @@ -374,23 +381,42 @@ configure_accounting(time_t now) static void update_expected_bandwidth(void) { uint64_t used, expected; uint64_t max_configured = (get_options()->BandwidthRate * 60); if (n_seconds_active_in_interval < 1800) { uint64_t expected; or_options_t *options= get_options(); uint64_t max_configured = (options->RelayBandwidthRate > 0 ? options->RelayBandwidthRate : options->BandwidthRate) * 60; #define MIN_TIME_FOR_MEASUREMENT (1800) if (soft_limit_hit_at > interval_start_time && n_bytes_at_soft_limit && (soft_limit_hit_at - interval_start_time) > MIN_TIME_FOR_MEASUREMENT) { /* If we hit our soft limit last time, only count the bytes up to that * time. This is a better predictor of our actual bandwidth than * considering the entirety of the last interval, since we likely started * using bytes very slowly once we hit our soft limit. */ expected = n_bytes_at_soft_limit / (soft_limit_hit_at - interval_start_time); expected /= 60; } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) { /* Otherwise, we either measured enough time in the last interval but * never hit our soft limit, or we're using a state file from a Tor that * doesn't know to store soft-limit info. Just take rate at which * we were reading/writing in the last interval as our expected rate. */ uint64_t used = MAX(n_bytes_written_in_interval, n_bytes_read_in_interval); expected = used / (n_seconds_active_in_interval / 60); } else { /* If we haven't gotten enough data last interval, set 'expected' * to 0. This will set our wakeup to the start of the interval. * Next interval, we'll choose our starting time based on how much * we sent this interval. */ expected = 0; } else { used = n_bytes_written_in_interval < n_bytes_read_in_interval ? n_bytes_read_in_interval : n_bytes_written_in_interval; expected = used / (n_seconds_active_in_interval / 60); } if (expected > max_configured) expected = max_configured; } expected_bandwidth_usage = expected; } Loading @@ -408,6 +434,9 @@ reset_accounting(time_t now) n_bytes_read_in_interval = 0; n_bytes_written_in_interval = 0; n_seconds_active_in_interval = 0; n_bytes_at_soft_limit = 0; soft_limit_hit_at = 0; n_seconds_to_hit_soft_limit = 0; } /** Return true iff we should save our bandwidth usage to disk. */ Loading Loading @@ -568,6 +597,10 @@ accounting_record_bandwidth_usage(time_t now, or_state_t *state) state->AccountingSecondsActive = n_seconds_active_in_interval; state->AccountingExpectedUsage = expected_bandwidth_usage; state->AccountingSecondsToReachSoftLimit = n_seconds_to_hit_soft_limit; state->AccountingSoftLimitHitAt = soft_limit_hit_at; state->AccountingBytesAtSoftLimit = n_bytes_at_soft_limit; or_state_mark_dirty(state, now+(get_options()->AvoidDiskWrites ? 7200 : 60)); Loading @@ -591,10 +624,6 @@ read_bandwidth_usage(void) if (!state) return -1; /* Okay; it looks like the state file is more up-to-date than the * bw_accounting file, or the bw_accounting file is nonexistent, * or the bw_accounting file is corrupt. */ log_info(LD_ACCT, "Reading bandwidth accounting data from state file"); n_bytes_read_in_interval = state->AccountingBytesReadInInterval; n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval; Loading @@ -602,6 +631,21 @@ read_bandwidth_usage(void) interval_start_time = state->AccountingIntervalStart; expected_bandwidth_usage = state->AccountingExpectedUsage; /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these * fields. If you switch back and forth, you might get an * AccountingSoftLimitHitAt value from long before the most recent * interval_start_time. If that's so, then ignore the softlimit-related * values. */ if (state->AccountingSoftLimitHitAt > interval_start_time) { soft_limit_hit_at = state->AccountingSoftLimitHitAt; n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit; n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit; } else { soft_limit_hit_at = 0; n_bytes_at_soft_limit = 0; n_seconds_to_hit_soft_limit = 0; } { char tbuf1[ISO_TIME_LEN+1]; char tbuf2[ISO_TIME_LEN+1]; Loading Loading @@ -641,8 +685,27 @@ hibernate_hard_limit_reached(void) static int hibernate_soft_limit_reached(void) { uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(get_options()->AccountingMax) * .95); const uint64_t acct_max = get_options()->AccountingMax; #define SOFT_LIM_PCT (.95) #define SOFT_LIM_BYTES (500*1024*1024) #define SOFT_LIM_MINUTES (3*60) /* The 'soft limit' is a fair bit more complicated now than once it was. * We want to stop accepting connections when ALL of the following are true: * - We expect to use up the remaining bytes in under 3 hours * - We have used up 95% of our bytes. * - We have less than 500MB of bytes left. */ uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT); if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) { soft_limit = acct_max - SOFT_LIM_BYTES; } if (expected_bandwidth_usage) { const uint64_t expected_usage = expected_bandwidth_usage * SOFT_LIM_MINUTES; if (acct_max > expected_usage && acct_max - expected_usage > soft_limit) soft_limit = acct_max - expected_usage; } if (!soft_limit) return 0; return n_bytes_read_in_interval >= soft_limit Loading @@ -667,6 +730,14 @@ hibernate_begin(hibernate_state_t new_state, time_t now) exit(0); } if (new_state == HIBERNATE_STATE_LOWBANDWIDTH && hibernate_state == HIBERNATE_STATE_LIVE) { soft_limit_hit_at = now; n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, n_bytes_written_in_interval); } /* close listeners. leave control listener(s). */ while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) || (conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) || Loading src/or/or.h +3 −0 Original line number Diff line number Diff line Loading @@ -2831,6 +2831,9 @@ typedef struct { uint64_t AccountingBytesReadInInterval; uint64_t AccountingBytesWrittenInInterval; int AccountingSecondsActive; int AccountingSecondsToReachSoftLimit; time_t AccountingSoftLimitHitAt; uint64_t AccountingBytesAtSoftLimit; uint64_t AccountingExpectedUsage; /** A list of Entry Guard-related configuration lines. */ Loading Loading
changes/bug1789 0 → 100644 +16 −0 Original line number Diff line number Diff line o Minor features: - Be more generous with how much bandwidth we'd use up (with accounting enabled) before entering "soft hibernation". Previously, we'd hibernate once we'd used up 95% of our allotment. Now, we use up 95% of our allotment, AND make sure that we have no more than 500MB (or 3 hours of expected traffic, whichever is lower) remaining before we enter soft hibernation. o Minor bugfixes: - For bandwidth accounting, calculate our expected bandwidth rate based on the time during which we were active and not in soft-hibernation during the last interval. Previously, we were also considering the time spent in soft-hibernation. If this was a long time, we would wind up underestimating our bandwidth by a lot, and skewing our wakeup time towards the start of the accounting interval. Fixes bug 1789. Bugfix on 0.0.9pre5.
src/or/config.c +3 −0 Original line number Diff line number Diff line Loading @@ -428,6 +428,9 @@ static config_var_t _state_vars[] = { V(AccountingExpectedUsage, MEMUNIT, NULL), V(AccountingIntervalStart, ISOTIME, NULL), V(AccountingSecondsActive, INTERVAL, NULL), V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL), V(AccountingSoftLimitHitAt, ISOTIME, NULL), V(AccountingBytesAtSoftLimit, MEMUNIT, NULL), VAR("EntryGuard", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL), Loading
src/or/hibernate.c +87 −16 Original line number Diff line number Diff line Loading @@ -95,6 +95,13 @@ static uint64_t n_bytes_read_in_interval = 0; static uint64_t n_bytes_written_in_interval = 0; /** How many seconds have we been running this interval? */ static uint32_t n_seconds_active_in_interval = 0; /** How many seconds were we active in this interval before we hit our soft * limit? */ static int n_seconds_to_hit_soft_limit = 0; /** When in this interval was the soft limit hit. */ static time_t soft_limit_hit_at = 0; /** How many bytes had we read/written when we hit the soft limit? */ static uint64_t n_bytes_at_soft_limit = 0; /** When did this accounting interval start? */ static time_t interval_start_time = 0; /** When will this accounting interval end? */ Loading Loading @@ -374,23 +381,42 @@ configure_accounting(time_t now) static void update_expected_bandwidth(void) { uint64_t used, expected; uint64_t max_configured = (get_options()->BandwidthRate * 60); if (n_seconds_active_in_interval < 1800) { uint64_t expected; or_options_t *options= get_options(); uint64_t max_configured = (options->RelayBandwidthRate > 0 ? options->RelayBandwidthRate : options->BandwidthRate) * 60; #define MIN_TIME_FOR_MEASUREMENT (1800) if (soft_limit_hit_at > interval_start_time && n_bytes_at_soft_limit && (soft_limit_hit_at - interval_start_time) > MIN_TIME_FOR_MEASUREMENT) { /* If we hit our soft limit last time, only count the bytes up to that * time. This is a better predictor of our actual bandwidth than * considering the entirety of the last interval, since we likely started * using bytes very slowly once we hit our soft limit. */ expected = n_bytes_at_soft_limit / (soft_limit_hit_at - interval_start_time); expected /= 60; } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) { /* Otherwise, we either measured enough time in the last interval but * never hit our soft limit, or we're using a state file from a Tor that * doesn't know to store soft-limit info. Just take rate at which * we were reading/writing in the last interval as our expected rate. */ uint64_t used = MAX(n_bytes_written_in_interval, n_bytes_read_in_interval); expected = used / (n_seconds_active_in_interval / 60); } else { /* If we haven't gotten enough data last interval, set 'expected' * to 0. This will set our wakeup to the start of the interval. * Next interval, we'll choose our starting time based on how much * we sent this interval. */ expected = 0; } else { used = n_bytes_written_in_interval < n_bytes_read_in_interval ? n_bytes_read_in_interval : n_bytes_written_in_interval; expected = used / (n_seconds_active_in_interval / 60); } if (expected > max_configured) expected = max_configured; } expected_bandwidth_usage = expected; } Loading @@ -408,6 +434,9 @@ reset_accounting(time_t now) n_bytes_read_in_interval = 0; n_bytes_written_in_interval = 0; n_seconds_active_in_interval = 0; n_bytes_at_soft_limit = 0; soft_limit_hit_at = 0; n_seconds_to_hit_soft_limit = 0; } /** Return true iff we should save our bandwidth usage to disk. */ Loading Loading @@ -568,6 +597,10 @@ accounting_record_bandwidth_usage(time_t now, or_state_t *state) state->AccountingSecondsActive = n_seconds_active_in_interval; state->AccountingExpectedUsage = expected_bandwidth_usage; state->AccountingSecondsToReachSoftLimit = n_seconds_to_hit_soft_limit; state->AccountingSoftLimitHitAt = soft_limit_hit_at; state->AccountingBytesAtSoftLimit = n_bytes_at_soft_limit; or_state_mark_dirty(state, now+(get_options()->AvoidDiskWrites ? 7200 : 60)); Loading @@ -591,10 +624,6 @@ read_bandwidth_usage(void) if (!state) return -1; /* Okay; it looks like the state file is more up-to-date than the * bw_accounting file, or the bw_accounting file is nonexistent, * or the bw_accounting file is corrupt. */ log_info(LD_ACCT, "Reading bandwidth accounting data from state file"); n_bytes_read_in_interval = state->AccountingBytesReadInInterval; n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval; Loading @@ -602,6 +631,21 @@ read_bandwidth_usage(void) interval_start_time = state->AccountingIntervalStart; expected_bandwidth_usage = state->AccountingExpectedUsage; /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these * fields. If you switch back and forth, you might get an * AccountingSoftLimitHitAt value from long before the most recent * interval_start_time. If that's so, then ignore the softlimit-related * values. */ if (state->AccountingSoftLimitHitAt > interval_start_time) { soft_limit_hit_at = state->AccountingSoftLimitHitAt; n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit; n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit; } else { soft_limit_hit_at = 0; n_bytes_at_soft_limit = 0; n_seconds_to_hit_soft_limit = 0; } { char tbuf1[ISO_TIME_LEN+1]; char tbuf2[ISO_TIME_LEN+1]; Loading Loading @@ -641,8 +685,27 @@ hibernate_hard_limit_reached(void) static int hibernate_soft_limit_reached(void) { uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(get_options()->AccountingMax) * .95); const uint64_t acct_max = get_options()->AccountingMax; #define SOFT_LIM_PCT (.95) #define SOFT_LIM_BYTES (500*1024*1024) #define SOFT_LIM_MINUTES (3*60) /* The 'soft limit' is a fair bit more complicated now than once it was. * We want to stop accepting connections when ALL of the following are true: * - We expect to use up the remaining bytes in under 3 hours * - We have used up 95% of our bytes. * - We have less than 500MB of bytes left. */ uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT); if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) { soft_limit = acct_max - SOFT_LIM_BYTES; } if (expected_bandwidth_usage) { const uint64_t expected_usage = expected_bandwidth_usage * SOFT_LIM_MINUTES; if (acct_max > expected_usage && acct_max - expected_usage > soft_limit) soft_limit = acct_max - expected_usage; } if (!soft_limit) return 0; return n_bytes_read_in_interval >= soft_limit Loading @@ -667,6 +730,14 @@ hibernate_begin(hibernate_state_t new_state, time_t now) exit(0); } if (new_state == HIBERNATE_STATE_LOWBANDWIDTH && hibernate_state == HIBERNATE_STATE_LIVE) { soft_limit_hit_at = now; n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, n_bytes_written_in_interval); } /* close listeners. leave control listener(s). */ while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) || (conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) || Loading
src/or/or.h +3 −0 Original line number Diff line number Diff line Loading @@ -2831,6 +2831,9 @@ typedef struct { uint64_t AccountingBytesReadInInterval; uint64_t AccountingBytesWrittenInInterval; int AccountingSecondsActive; int AccountingSecondsToReachSoftLimit; time_t AccountingSoftLimitHitAt; uint64_t AccountingBytesAtSoftLimit; uint64_t AccountingExpectedUsage; /** A list of Entry Guard-related configuration lines. */ Loading