aboutsummaryrefslogtreecommitdiff
path: root/src/or/routerlist.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2012-08-09 12:21:37 -0400
committerNick Mathewson <nickm@torproject.org>2012-08-09 12:21:37 -0400
commite106812a778f53760c819ab20a214ac3222b3b15 (patch)
tree38d5ff9ade183c3cfa93a2dd75ecf9a935a6d12c /src/or/routerlist.c
parent91b52a259a271df7ceeea6d8bf7adbd4d7e15a6c (diff)
downloadtor-e106812a778f53760c819ab20a214ac3222b3b15.tar.gz
tor-e106812a778f53760c819ab20a214ac3222b3b15.zip
Change smartlist_choose_node_by_bandwidth to avoid double
This should make our preferred solution to #6538 easier to implement, avoid a bunch of potential nastiness with excessive int-vs-double math, and generally make the code there a little less scary. "But wait!" you say. "Is it really safe to do this? Won't the results come out differently?" Yes, but not much. We now round every weighted bandwidth to the nearest byte before computing on it. This will make every node that had a fractional part of its weighted bandwidth before either slighty more likely or slightly less likely. Further, the rand_bw value was only ever set with integer precision, so it can't accurately sample routers with tiny fractional bandwidth values anyway. Finally, doing repeated double-vs-uint64 comparisons is just plain sad; it will involve an implicit cast to double, which is never a fun thing.
Diffstat (limited to 'src/or/routerlist.c')
-rw-r--r--src/or/routerlist.c48
1 files changed, 28 insertions, 20 deletions
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 4979b933ad..382d45746c 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1702,12 +1702,12 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
bandwidth_weight_rule_t rule)
{
int64_t weight_scale;
- int64_t rand_bw;
+ uint64_t rand_bw;
double Wg = -1, Wm = -1, We = -1, Wd = -1;
double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1;
- double weighted_bw = 0, unweighted_bw = 0;
- double *bandwidths;
- double tmp = 0;
+ uint64_t weighted_bw = 0, unweighted_bw = 0;
+ uint64_t *bandwidths;
+ uint64_t tmp;
unsigned int i;
unsigned int i_chosen;
unsigned int i_has_been_chosen;
@@ -1792,7 +1792,7 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
Web /= weight_scale;
Wdb /= weight_scale;
- bandwidths = tor_malloc_zero(sizeof(double)*smartlist_len(sl));
+ bandwidths = tor_malloc_zero(sizeof(uint64_t)*smartlist_len(sl));
// Cycle through smartlist and total the bandwidth.
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
@@ -1831,24 +1831,30 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
} else { // middle
weight = (is_dir ? Wmb*Wm : Wm);
}
-
- bandwidths[node_sl_idx] = weight*this_bw;
- weighted_bw += weight*this_bw;
+ /* These should be impossible; but overflows here would be bad, so let's
+ * make sure. */
+ if (this_bw < 0)
+ this_bw = 0;
+ if (weight < 0.0)
+ weight = 0.0;
+
+ bandwidths[node_sl_idx] = tor_llround(weight*this_bw + 0.5);
+ weighted_bw += bandwidths[node_sl_idx];
unweighted_bw += this_bw;
if (is_me)
- sl_last_weighted_bw_of_me = weight*this_bw;
+ sl_last_weighted_bw_of_me = bandwidths[node_sl_idx];
} SMARTLIST_FOREACH_END(node);
/* XXXX this is a kludge to expose these values. */
sl_last_total_weighted_bw = weighted_bw;
log_debug(LD_CIRC, "Choosing node for rule %s based on weights "
- "Wg=%f Wm=%f We=%f Wd=%f with total bw %f",
+ "Wg=%f Wm=%f We=%f Wd=%f with total bw "U64_FORMAT,
bandwidth_weight_rule_to_string(rule),
- Wg, Wm, We, Wd, weighted_bw);
+ Wg, Wm, We, Wd, U64_PRINTF_ARG(weighted_bw));
/* If there is no bandwidth, choose at random */
- if (DBL_TO_U64(weighted_bw) == 0) {
+ if (weighted_bw == 0) {
/* Don't warn when using bridges/relays not in the consensus */
if (!have_unknown) {
#define ZERO_BANDWIDTH_WARNING_INTERVAL (15)
@@ -1858,24 +1864,25 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
if ((msg = rate_limit_log(&zero_bandwidth_warning_limit,
approx_time()))) {
log_warn(LD_CIRC,
- "Weighted bandwidth is %f in node selection for rule %s "
- "(unweighted was %f) %s",
- weighted_bw, bandwidth_weight_rule_to_string(rule),
- unweighted_bw, msg);
+ "Weighted bandwidth is "U64_FORMAT" in node selection for "
+ "rule %s (unweighted was "U64_FORMAT") %s",
+ U64_PRINTF_ARG(weighted_bw),
+ bandwidth_weight_rule_to_string(rule),
+ U64_PRINTF_ARG(unweighted_bw), msg);
}
}
tor_free(bandwidths);
return smartlist_choose(sl);
}
- rand_bw = crypto_rand_uint64(DBL_TO_U64(weighted_bw));
+ rand_bw = crypto_rand_uint64(weighted_bw);
rand_bw++; /* crypto_rand_uint64() counts from 0, and we need to count
* from 1 below. See bug 1203 for details. */
/* Last, count through sl until we get to the element we picked */
i_chosen = (unsigned)smartlist_len(sl);
i_has_been_chosen = 0;
- tmp = 0.0;
+ tmp = 0;
for (i=0; i < (unsigned)smartlist_len(sl); i++) {
tmp += bandwidths[i];
if (tmp >= rand_bw && !i_has_been_chosen) {
@@ -1892,8 +1899,9 @@ smartlist_choose_node_by_bandwidth_weights(smartlist_t *sl,
--i;
log_warn(LD_BUG, "Round-off error in computing bandwidth had an effect on "
" which router we chose. Please tell the developers. "
- "%f " U64_FORMAT " %f", tmp, U64_PRINTF_ARG(rand_bw),
- weighted_bw);
+ U64_FORMAT" "U64_FORMAT" "U64_FORMAT,
+ U64_PRINTF_ARG(tmp), U64_PRINTF_ARG(rand_bw),
+ U64_PRINTF_ARG(weighted_bw));
}
tor_free(bandwidths);
return smartlist_get(sl, i);