Commit 7a2b30fe authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Merge remote-tracking branch 'origin/maint-0.2.4'

Conflicts:
	src/or/relay.c

Conflict changes were easy; compilation fixes required were using
using TOR_SIMPLEQ_FIRST to get head of cell queue.
parents 4aa9affe 59f50c80
Loading
Loading
Loading
Loading

changes/bug9093

0 → 100644
+7 −0
Original line number Diff line number Diff line
  o Minor features:
    - Improve the circuit queue out-of-memory handler. Previously, when
      we ran low on memory, we'd close whichever circuits had the most
      queued cells. Now, we close those that have the *oldest* queued
      cells, on the theory that those are most responsible for us
      running low on memory. Based on analysis from a forthcoming paper
      by Jansen, Tschorsch, Johnson, and Scheuermann. Fixes bug 9093.
 No newline at end of file
+12 −0
Original line number Diff line number Diff line
@@ -1303,6 +1303,18 @@ tv_mdiff(const struct timeval *start, const struct timeval *end)
  return mdiff;
}

/**
 * Converts timeval to milliseconds.
 */
int64_t
tv_to_msec(const struct timeval *tv)
{
  int64_t conv = ((int64_t)tv->tv_sec)*1000L;
  /* Round ghetto-style */
  conv += ((int64_t)tv->tv_usec+500)/1000L;
  return conv;
}

/** Yield true iff <b>y</b> is a leap-year. */
#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400)))
/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */
+1 −0
Original line number Diff line number Diff line
@@ -253,6 +253,7 @@ int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
/* Time helpers */
long tv_udiff(const struct timeval *start, const struct timeval *end);
long tv_mdiff(const struct timeval *start, const struct timeval *end);
int64_t tv_to_msec(const struct timeval *tv);
int tor_timegm(const struct tm *tm, time_t *time_out);
#define RFC1123_TIME_LEN 29
void format_rfc1123_time(char *buf, time_t t);
+48 −10
Original line number Diff line number Diff line
@@ -1620,25 +1620,58 @@ n_cells_in_circ_queues(const circuit_t *c)
  return n;
}

/** helper to sort a list of circuit_q by total queue lengths, in descending
 * 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;
  packed_cell_t *cell;

  if (NULL != (cell = TOR_SIMPLEQ_FIRST(&c->n_chan_cells.head)))
    age = now - cell->inserted_time;

  if (! CIRCUIT_IS_ORIGIN(c)) {
    const or_circuit_t *orcirc = TO_OR_CIRCUIT((circuit_t*)c);
    if (NULL != (cell = TOR_SIMPLEQ_FIRST(&orcirc->p_chan_cells.head))) {
      uint32_t age2 = now - cell->inserted_time;
      if (age2 > age)
        return age2;
    }
  }
  return age;
}

/** Temporary variable for circuits_compare_by_oldest_queued_cell_ This is a
 * 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;

/** Helper to sort a list of circuit_t by age of oldest cell, in descending
 * 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

/** We're out of memory for cells, having allocated <b>current_allocation</b>
 * bytes' worth.  Kill the 'worst' circuits until we're under
@@ -1651,13 +1684,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;
@@ -1670,9 +1704,13 @@ circuits_handle_oom(size_t current_allocation)
  TOR_LIST_FOREACH(circ, &global_circuitlist, head)
    smartlist_add(circlist, circ);

  /* Set circcomp_now_tmp so that the sort can work. */
  tor_gettimeofday_cached(&now);
  circcomp_now_tmp = (uint32_t)tv_to_msec(&now);

  /* This is O(n log n); there are faster algorithms we could use instead.
   * 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_);

  /* Okay, now the worst circuits are at the front of the list. Let's mark
   * them, and reclaim their storage aggressively. */
+5 −0
Original line number Diff line number Diff line
@@ -1120,8 +1120,13 @@ typedef struct packed_cell_t {
  /** Next cell queued on this circuit. */
  TOR_SIMPLEQ_ENTRY(packed_cell_t) next;
  char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */
  uint32_t inserted_time; /**< Time (in milliseconds since epoch, with high
                           * bits truncated) when this cell was inserted. */
} packed_cell_t;

/* XXXX This next structure may be obsoleted by inserted_time in
 * packed_cell_t */

/** Number of cells added to a circuit queue including their insertion
 * time on 10 millisecond detail; used for buffer statistics. */
typedef struct insertion_time_elem_t {
Loading