Ejemplo n.º 1
0
void nghttp2_stream_reschedule(nghttp2_stream *stream) {
  nghttp2_stream *dep_stream;

  assert(stream->queued);

  dep_stream = stream->dep_prev;

  for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
    if (nghttp2_pq_size(&dep_stream->obq) == 1) {
      dep_stream->descendant_last_cycle = 0;
      stream->cycle = 0;
    } else {
      dep_stream->descendant_last_cycle =
          nghttp2_max(dep_stream->descendant_last_cycle, stream->cycle);

      stream->cycle =
          stream_next_cycle(stream, dep_stream->descendant_last_cycle);

      nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
      nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
    }

    DEBUGF(fprintf(stderr, "stream: stream=%d obq resched cycle=%ld\n",
                   stream->stream_id, stream->cycle));

    dep_stream->last_writelen = stream->last_writelen;
  }
}
Ejemplo n.º 2
0
static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
  /* This is required for Android NDK r10d */
  int rv = 0;
  nghttp2_outbound_item *item;

  assert(stream->item);
  assert(stream->item->queued == 0);

  item = stream->item;

  /* If item is now sent, don't push it to the queue.  Otherwise, we
     may push same item twice. */
  if (session->aob.item == item) {
    return 0;
  }

  /* Penalize item by delaying scheduling according to effective
     weight.  This will delay low priority stream, which is good.
     OTOH, this may incur delay for high priority item.  Will see. */
  item->cycle =
      session->last_cycle +
      NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT / stream->effective_weight;

  switch (item->frame.hd.type) {
  case NGHTTP2_DATA:
    rv = nghttp2_pq_push(&session->ob_da_pq, item);
    break;
  case NGHTTP2_HEADERS:
    if (stream->state == NGHTTP2_STREAM_RESERVED) {
      rv = nghttp2_pq_push(&session->ob_ss_pq, item);
    } else {
      rv = nghttp2_pq_push(&session->ob_pq, item);
    }
    break;
  default:
    /* should not reach here */
    assert(0);
  }

  if (rv != 0) {
    return rv;
  }

  item->queued = 1;

  return 0;
}
Ejemplo n.º 3
0
static int stream_push_data(nghttp2_stream *stream, nghttp2_session *session) {
  int rv;
  nghttp2_outbound_item *item;

  assert(stream->data_item);
  assert(stream->data_item->queued == 0);

  item = stream->data_item;

  /* If item is now sent, don't push it to the queue.  Otherwise, we
     may push same item twice. */
  if (session->aob.item == item) {
    return 0;
  }

  if (item->weight > stream->effective_weight) {
    item->weight = stream->effective_weight;
  }

  item->cycle = session->last_cycle;

  switch (item->frame.hd.type) {
  case NGHTTP2_DATA:
    rv = nghttp2_pq_push(&session->ob_da_pq, item);
    break;
  case NGHTTP2_HEADERS:
    if (stream->state == NGHTTP2_STREAM_RESERVED) {
      rv = nghttp2_pq_push(&session->ob_ss_pq, item);
    } else {
      rv = nghttp2_pq_push(&session->ob_pq, item);
    }
    break;
  default:
    /* should not reach here */
    assert(0);
  }

  if (rv != 0) {
    return rv;
  }

  item->queued = 1;

  return 0;
}
Ejemplo n.º 4
0
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
  nghttp2_stream *dep_stream;
  uint32_t last_cycle;
  int32_t old_weight;
  uint32_t wlen_penalty;

  if (stream->weight == weight) {
    return;
  }

  old_weight = stream->weight;
  stream->weight = weight;

  dep_stream = stream->dep_prev;

  if (!dep_stream) {
    return;
  }

  dep_stream->sum_dep_weight += weight - old_weight;

  if (!stream->queued) {
    return;
  }

  nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);

  wlen_penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;

  /* Compute old stream->pending_penalty we used to calculate
     stream->cycle */
  stream->pending_penalty =
      (uint32_t)((stream->pending_penalty + (uint32_t)old_weight -
                  (wlen_penalty % (uint32_t)old_weight)) %
                 (uint32_t)old_weight);

  last_cycle = stream->cycle -
               (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight;

  /* Now we have old stream->pending_penalty and new stream->weight in
     place */
  stream_next_cycle(stream, last_cycle);

  if (stream->cycle < dep_stream->descendant_last_cycle &&
      (dep_stream->descendant_last_cycle - stream->cycle) <=
          NGHTTP2_MAX_CYCLE_DISTANCE) {
    stream->cycle = dep_stream->descendant_last_cycle;
  }

  /* Continue to use same stream->seq */

  nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);

  DEBUGF("stream: stream=%d obq resched cycle=%d\n", stream->stream_id,
         stream->cycle);
}
Ejemplo n.º 5
0
void test_nghttp2_pq(void) {
  int i;
  nghttp2_pq pq;
  nghttp2_pq_init(&pq, pq_compar);
  CU_ASSERT(nghttp2_pq_empty(&pq));
  CU_ASSERT(0 == nghttp2_pq_size(&pq));
  CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"foo"));
  CU_ASSERT(0 == nghttp2_pq_empty(&pq));
  CU_ASSERT(1 == nghttp2_pq_size(&pq));
  CU_ASSERT(strcmp("foo", nghttp2_pq_top(&pq)) == 0);
  CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"bar"));
  CU_ASSERT(strcmp("bar", nghttp2_pq_top(&pq)) == 0);
  CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"baz"));
  CU_ASSERT(strcmp("bar", nghttp2_pq_top(&pq)) == 0);
  CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"C"));
  CU_ASSERT(4 == nghttp2_pq_size(&pq));
  CU_ASSERT(strcmp("C", nghttp2_pq_top(&pq)) == 0);
  nghttp2_pq_pop(&pq);
  CU_ASSERT(3 == nghttp2_pq_size(&pq));
  CU_ASSERT(strcmp("bar", nghttp2_pq_top(&pq)) == 0);
  nghttp2_pq_pop(&pq);
  CU_ASSERT(strcmp("baz", nghttp2_pq_top(&pq)) == 0);
  nghttp2_pq_pop(&pq);
  CU_ASSERT(strcmp("foo", nghttp2_pq_top(&pq)) == 0);
  nghttp2_pq_pop(&pq);
  CU_ASSERT(nghttp2_pq_empty(&pq));
  CU_ASSERT(0 == nghttp2_pq_size(&pq));
  CU_ASSERT(NULL == nghttp2_pq_top(&pq));

  /* Add bunch of entry to see realloc works */
  for (i = 0; i < 10000; ++i) {
    CU_ASSERT(0 == nghttp2_pq_push(&pq, (void *)"foo"));
    CU_ASSERT((size_t)(i + 1) == nghttp2_pq_size(&pq));
  }
  for (i = 10000; i > 0; --i) {
    CU_ASSERT(NULL != nghttp2_pq_top(&pq));
    nghttp2_pq_pop(&pq);
    CU_ASSERT((size_t)(i - 1) == nghttp2_pq_size(&pq));
  }

  nghttp2_pq_free(&pq);
}
Ejemplo n.º 6
0
void nghttp2_stream_reschedule(nghttp2_stream *stream) {
  nghttp2_stream *dep_stream;

  assert(stream->queued);

  dep_stream = stream->dep_prev;

  for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
    nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);

    stream_next_cycle(stream, dep_stream->descendant_last_cycle);
    stream->seq = dep_stream->descendant_next_seq++;

    nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);

    DEBUGF("stream: stream=%d obq resched cycle=%d\n", stream->stream_id,
           stream->cycle);

    dep_stream->last_writelen = stream->last_writelen;
  }
}
Ejemplo n.º 7
0
static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
  int rv;

  for (; dep_stream && !stream->queued;
       stream = dep_stream, dep_stream = dep_stream->dep_prev) {
    stream->cycle =
        stream_next_cycle(stream, dep_stream->descendant_last_cycle);

    DEBUGF(fprintf(stderr, "stream: stream=%d obq push cycle=%ld\n",
                   stream->stream_id, stream->cycle));

    DEBUGF(fprintf(stderr, "stream: push stream %d to stream %d\n",
                   stream->stream_id, dep_stream->stream_id));

    rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
    if (rv != 0) {
      return rv;
    }
    stream->queued = 1;
  }

  return 0;
}
Ejemplo n.º 8
0
void test_nghttp2_pq(void) {
  int i;
  nghttp2_pq pq;
  string_entry *top;

  nghttp2_pq_init(&pq, pq_less, nghttp2_mem_default());
  CU_ASSERT(nghttp2_pq_empty(&pq));
  CU_ASSERT(0 == nghttp2_pq_size(&pq));
  CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("foo")->ent));
  CU_ASSERT(0 == nghttp2_pq_empty(&pq));
  CU_ASSERT(1 == nghttp2_pq_size(&pq));
  top = (string_entry *)nghttp2_pq_top(&pq);
  CU_ASSERT(strcmp("foo", top->s) == 0);
  CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("bar")->ent));
  top = (string_entry *)nghttp2_pq_top(&pq);
  CU_ASSERT(strcmp("bar", top->s) == 0);
  CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("baz")->ent));
  top = (string_entry *)nghttp2_pq_top(&pq);
  CU_ASSERT(strcmp("bar", top->s) == 0);
  CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("C")->ent));
  CU_ASSERT(4 == nghttp2_pq_size(&pq));

  top = (string_entry *)nghttp2_pq_top(&pq);
  CU_ASSERT(strcmp("C", top->s) == 0);
  string_entry_del(top);
  nghttp2_pq_pop(&pq);

  CU_ASSERT(3 == nghttp2_pq_size(&pq));

  top = (string_entry *)nghttp2_pq_top(&pq);
  CU_ASSERT(strcmp("bar", top->s) == 0);
  nghttp2_pq_pop(&pq);
  string_entry_del(top);

  top = (string_entry *)nghttp2_pq_top(&pq);
  CU_ASSERT(strcmp("baz", top->s) == 0);
  nghttp2_pq_pop(&pq);
  string_entry_del(top);

  top = (string_entry *)nghttp2_pq_top(&pq);
  CU_ASSERT(strcmp("foo", top->s) == 0);
  nghttp2_pq_pop(&pq);
  string_entry_del(top);

  CU_ASSERT(nghttp2_pq_empty(&pq));
  CU_ASSERT(0 == nghttp2_pq_size(&pq));
  CU_ASSERT(NULL == nghttp2_pq_top(&pq));

  /* Add bunch of entry to see realloc works */
  for (i = 0; i < 10000; ++i) {
    CU_ASSERT(0 == nghttp2_pq_push(&pq, &string_entry_new("foo")->ent));
    CU_ASSERT((size_t)(i + 1) == nghttp2_pq_size(&pq));
  }
  for (i = 10000; i > 0; --i) {
    top = (string_entry *)nghttp2_pq_top(&pq);
    CU_ASSERT(NULL != top);
    nghttp2_pq_pop(&pq);
    string_entry_del(top);
    CU_ASSERT((size_t)(i - 1) == nghttp2_pq_size(&pq));
  }

  nghttp2_pq_free(&pq);
}