|
@@ -1383,25 +1383,56 @@ n_cells_in_circ_queues(const circuit_t *c)
|
|
|
return n;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- * order. */
|
|
|
+
|
|
|
+ * Return the age of the oldest cell queued on <b>c</b>, in milliseconds.
|
|
|
+ * Return 0 if there are no cells queued on c. Requires that <b>now</b> be
|
|
|
+ * the current time in milliseconds since the epoch, truncated.
|
|
|
+ *
|
|
|
+ * This function will return incorrect results if the oldest cell queued on
|
|
|
+ * the circuit is older than 2**32 msec (about 49 days) old.
|
|
|
+ */
|
|
|
+static uint32_t
|
|
|
+circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
|
|
|
+{
|
|
|
+ uint32_t age = 0;
|
|
|
+ if (c->n_conn_cells.head)
|
|
|
+ age = now - c->n_conn_cells.head->inserted_time;
|
|
|
+
|
|
|
+ if (! CIRCUIT_IS_ORIGIN(c)) {
|
|
|
+ const or_circuit_t *orcirc = TO_OR_CIRCUIT((circuit_t*)c);
|
|
|
+ if (orcirc->p_conn_cells.head) {
|
|
|
+ uint32_t age2 = now - orcirc->p_conn_cells.head->inserted_time;
|
|
|
+ if (age2 > age)
|
|
|
+ return age2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return age;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * kludge to work around the fact that qsort doesn't provide a way for
|
|
|
+ * comparison functions to take an extra argument. */
|
|
|
+static uint32_t circcomp_now_tmp;
|
|
|
+
|
|
|
+
|
|
|
+ * order. Requires that circcomp_now_tmp is set correctly. */
|
|
|
static int
|
|
|
-circuits_compare_by_queue_len_(const void **a_, const void **b_)
|
|
|
+circuits_compare_by_oldest_queued_cell_(const void **a_, const void **b_)
|
|
|
{
|
|
|
const circuit_t *a = *a_;
|
|
|
const circuit_t *b = *b_;
|
|
|
- size_t a_n = n_cells_in_circ_queues(a);
|
|
|
- size_t b_n = n_cells_in_circ_queues(b);
|
|
|
+ uint32_t age_a = circuit_max_queued_cell_age(a, circcomp_now_tmp);
|
|
|
+ uint32_t age_b = circuit_max_queued_cell_age(b, circcomp_now_tmp);
|
|
|
|
|
|
- if (a_n < b_n)
|
|
|
+ if (age_a < age_b)
|
|
|
return 1;
|
|
|
- else if (a_n == b_n)
|
|
|
+ else if (age_a == age_b)
|
|
|
return 0;
|
|
|
else
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-#define FRACTION_OF_CIRCS_TO_RETAIN_ON_OOM 0.90
|
|
|
+#define FRACTION_OF_CELLS_TO_RETAIN_ON_OOM 0.90
|
|
|
|
|
|
|
|
|
* bytes' worth. Kill the 'worst' circuits until we're under
|
|
@@ -1414,13 +1445,14 @@ circuits_handle_oom(size_t current_allocation)
|
|
|
circuit_t *circ;
|
|
|
size_t n_cells_removed=0, n_cells_to_remove;
|
|
|
int n_circuits_killed=0;
|
|
|
+ struct timeval now;
|
|
|
log_notice(LD_GENERAL, "We're low on memory. Killing circuits with "
|
|
|
"over-long queues. (This behavior is controlled by "
|
|
|
"MaxMemInCellQueues.)");
|
|
|
|
|
|
{
|
|
|
size_t mem_target = (size_t)(get_options()->MaxMemInCellQueues *
|
|
|
- FRACTION_OF_CIRCS_TO_RETAIN_ON_OOM);
|
|
|
+ FRACTION_OF_CELLS_TO_RETAIN_ON_OOM);
|
|
|
size_t mem_to_recover;
|
|
|
if (current_allocation <= mem_target)
|
|
|
return;
|
|
@@ -1433,9 +1465,13 @@ circuits_handle_oom(size_t current_allocation)
|
|
|
for (circ = global_circuitlist; circ; circ = circ->next)
|
|
|
smartlist_add(circlist, circ);
|
|
|
|
|
|
+
|
|
|
+ tor_gettimeofday_cached(&now);
|
|
|
+ circcomp_now_tmp = (uint32_t)tv_to_msec(&now);
|
|
|
+
|
|
|
|
|
|
* Let's hope this doesn't happen enough to be in the critical path. */
|
|
|
- smartlist_sort(circlist, circuits_compare_by_queue_len_);
|
|
|
+ smartlist_sort(circlist, circuits_compare_by_oldest_queued_cell_);
|
|
|
|
|
|
|
|
|
* them, and reclaim their storage aggressively. */
|