瀏覽代碼

Separate cpuworker queues by handshake type

Now we prioritize ntor create cells over tap create cells.

Starts to address ticket 9574.
Roger Dingledine 11 年之前
父節點
當前提交
87a18514ef
共有 1 個文件被更改,包括 37 次插入16 次删除
  1. 37 16
      src/or/onion.c

+ 37 - 16
src/or/onion.c

@@ -28,6 +28,7 @@
 typedef struct onion_queue_t {
   TOR_TAILQ_ENTRY(onion_queue_t) next;
   or_circuit_t *circ;
+  uint16_t handshake_type;
   create_cell_t *onionskin;
   time_t when_added;
 } onion_queue_t;
@@ -35,11 +36,16 @@ typedef struct onion_queue_t {
 /** 5 seconds on the onion queue til we just send back a destroy */
 #define ONIONQUEUE_WAIT_CUTOFF 5
 
-/** Queue of circuits waiting for CPU workers, or NULL if the list is empty.*/
-TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t) ol_list =
-  TOR_TAILQ_HEAD_INITIALIZER(ol_list);
+/** Array of queues of circuits waiting for CPU workers. An element is NULL
+ * if that queue is empty.*/
+TOR_TAILQ_HEAD(onion_queue_head_t, onion_queue_t)
+              ol_list[MAX_ONION_HANDSHAKE_TYPE+1] = {
+  TOR_TAILQ_HEAD_INITIALIZER(ol_list[0]), /* tap */
+  TOR_TAILQ_HEAD_INITIALIZER(ol_list[1]), /* fast */
+  TOR_TAILQ_HEAD_INITIALIZER(ol_list[2]), /* ntor */
+};
 
-/** Number of entries of each type currently in ol_list. */
+/** Number of entries of each type currently in each element of ol_list[]. */
 static int ol_entries[MAX_ONION_HANDSHAKE_TYPE+1];
 
 static void onion_queue_entry_remove(onion_queue_t *victim);
@@ -60,8 +66,7 @@ have_room_for_onionskin(uint16_t type)
   int num_cpus;
   uint64_t tap_usec, ntor_usec;
   /* If we've got fewer than 50 entries, we always have room for one more. */
-  if (ol_entries[ONION_HANDSHAKE_TYPE_TAP] +
-      ol_entries[ONION_HANDSHAKE_TYPE_NTOR] < 50)
+  if (ol_entries[type] < 50)
     return 1;
   num_cpus = get_num_cpus(options);
   /* Compute how many microseconds we'd expect to need to clear all
@@ -72,10 +77,17 @@ have_room_for_onionskin(uint16_t type)
   ntor_usec = estimated_usec_for_onionskins(
                                     ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
                                     ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
+
   /* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
    * this. */
-  if ((tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay)
+  if (type == ONION_HANDSHAKE_TYPE_NTOR &&
+      ntor_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay)
     return 0;
+
+  if (type == ONION_HANDSHAKE_TYPE_TAP &&
+      (tap_usec + ntor_usec) / 1000 > (uint64_t)options->MaxOnionQueueDelay)
+    return 0;
+
 #ifdef CURVE25519_ENABLED
   /* If we support the ntor handshake, then don't let TAP handshakes use
    * more than 2/3 of the space on the queue. */
@@ -100,6 +112,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
 
   tmp = tor_malloc_zero(sizeof(onion_queue_t));
   tmp->circ = circ;
+  tmp->handshake_type = onionskin->handshake_type;
   tmp->onionskin = onionskin;
   tmp->when_added = now;
 
@@ -108,7 +121,8 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
     static ratelim_t last_warned =
       RATELIM_INIT(WARN_TOO_MANY_CIRC_CREATIONS_INTERVAL);
     char *m;
-    if ((m = rate_limit_log(&last_warned, approx_time()))) {
+    if (onionskin->handshake_type == ONION_HANDSHAKE_TYPE_NTOR &&
+        (m = rate_limit_log(&last_warned, approx_time()))) {
       log_warn(LD_GENERAL,
                "Your computer is too slow to handle this many circuit "
                "creation requests! Please consider using the "
@@ -122,11 +136,11 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
 
   ++ol_entries[onionskin->handshake_type];
   circ->onionqueue_entry = tmp;
-  TOR_TAILQ_INSERT_TAIL(&ol_list, tmp, next);
+  TOR_TAILQ_INSERT_TAIL(&ol_list[onionskin->handshake_type], tmp, next);
 
   /* cull elderly requests. */
   while (1) {
-    onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list);
+    onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[onionskin->handshake_type]);
     if (now - head->when_added < (time_t)ONIONQUEUE_WAIT_CUTOFF)
       break;
 
@@ -140,14 +154,18 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
   return 0;
 }
 
-/** Remove the first item from ol_list and return it, or return
- * NULL if the list is empty.
+/** Remove the highest priority item from ol_list[] and return it, or
+ * return NULL if the lists are empty.
  */
 or_circuit_t *
 onion_next_task(create_cell_t **onionskin_out)
 {
   or_circuit_t *circ;
-  onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list);
+
+  /* skip ol_list[ONION_HANDSHAKE_TYPE_FAST] since we know it'll be empty */
+  onion_queue_t *head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_NTOR]);
+  if (!head)
+    head = TOR_TAILQ_FIRST(&ol_list[ONION_HANDSHAKE_TYPE_TAP]);
 
   if (!head)
     return NULL; /* no onions pending, we're done */
@@ -186,7 +204,7 @@ onion_pending_remove(or_circuit_t *circ)
 static void
 onion_queue_entry_remove(onion_queue_t *victim)
 {
-  TOR_TAILQ_REMOVE(&ol_list, victim, next);
+  TOR_TAILQ_REMOVE(&ol_list[victim->handshake_type], victim, next);
 
   if (victim->circ)
     victim->circ->onionqueue_entry = NULL;
@@ -204,8 +222,11 @@ void
 clear_pending_onions(void)
 {
   onion_queue_t *victim;
-  while ((victim = TOR_TAILQ_FIRST(&ol_list))) {
-    onion_queue_entry_remove(victim);
+  int i;
+  for (i=0; i<=MAX_ONION_HANDSHAKE_TYPE; i++) {
+    while ((victim = TOR_TAILQ_FIRST(&ol_list[i]))) {
+      onion_queue_entry_remove(victim);
+    }
   }
   memset(ol_entries, 0, sizeof(ol_entries));
 }