Ejemplo n.º 1
0
void
HTTPTransaction::sendEOM() {
  DestructorGuard g(this);
  CHECK(HTTPTransactionEgressSM::transit(
      egressState_, HTTPTransactionEgressSM::Event::sendEOM))
    << ", " << *this;
  if (deferredEgressBody_.chainLength() == 0 && chunkHeaders_.empty()) {
    // there is nothing left to send, egress the EOM directly.  For SPDY
    // this will jump the txn queue
    if (!isEnqueued()) {
      size_t nbytes = sendEOMNow();
      transport_.notifyPendingEgress();
      if (transportCallback_) {
        transportCallback_->bodyBytesGenerated(nbytes);
      }
    } else {
      // If the txn is enqueued, sendDeferredBody()
      // should take care of sending the EOM.
      // Nevertheless we never expect this condition to occur,
      // so, log.
      LOG(ERROR) << "Queued egress EOM with no body on "
        << *this
        << "[egressState=" << egressState_ << ", "
        << "ingressState=" << ingressState_ << ", "
        << "egressPaused=" << egressPaused_ << ", "
        << "ingressPaused=" << ingressPaused_ << ", "
        << "aborted=" << aborted_ << ", "
        << "enqueued=" << isEnqueued() << ", "
        << "chainLength=" << deferredEgressBody_.chainLength() << "]";
    }
  } else {
    VLOG(4) << "Queued egress EOM on " << *this;
    notifyTransportPendingEgress();
  }
}
Ejemplo n.º 2
0
bool HTTPTransaction::onWriteReady(const uint32_t maxEgress, double ratio) {
  DestructorGuard g(this);
  DCHECK(isEnqueued());
  cumulativeRatio_ += ratio;
  egressCalls_++;
  sendDeferredBody(maxEgress);
  return isEnqueued();
}
Ejemplo n.º 3
0
void HTTPTransaction::markEgressComplete() {
  VLOG(4) << "Marking egress complete on " << *this;
  if (deferredEgressBody_.chainLength() && isEnqueued()) {
    int64_t deferredEgressBodyBytes =
      folly::to<int64_t>(deferredEgressBody_.chainLength());
    transport_.notifyEgressBodyBuffered(-deferredEgressBodyBytes);
  }
  deferredEgressBody_.move();
  if (isEnqueued()) {
    dequeue();
  }
  egressState_ = HTTPTransactionEgressSM::State::SendingDone;
}
Ejemplo n.º 4
0
// Removes the node from the tree
void
HTTP2PriorityQueue::Node::removeFromTree() {
  if (!children_.empty()) {
    // update child weights so they sum to (approximately) this node's weight.
    double r = double(weight_) / totalChildWeight_;
    for (auto& child: children_) {
      uint64_t newWeight = std::max(uint64_t(child->weight_ * r), uint64_t(1));
      CHECK_LE(newWeight, 256);
      child->updateWeight(uint8_t(newWeight) - 1);
    }
  }

  CHECK(!isEnqueued());
  if (inEgressTree()) {
    // Gah this is tricky.
    // The children of this node are moving to this node's parent.  We need the
    // tree in a consistent state before calling addChildren, so mark the
    // current node's totalEnqueuedWeight_ as 0 and propagate the clear upwards.
    // addChildren will handle re-signalling egress.
    totalEnqueuedWeight_ = 0;
    propagatePendingEgressClear(this);
  }

  // move my children to my parent
  parent_->addChildren(std::move(children_));
  (void)parent_->detachChild(this);
}
Ejemplo n.º 5
0
void CLMatrixLoader::waitEndOfEvaluation()
{
  if ( !isEnqueued() ) {
    throw EvaluationProcessViolation(
          "Cannot wait for evaluation as it is not enqued.");
  } else {
    getEndOfEvaluation().wait();
  }
}
Ejemplo n.º 6
0
// Set a new weight for this node
void
HTTP2PriorityQueue::Node::updateWeight(uint8_t weight) {
  int16_t delta = weight - weight_ + 1;
  weight_ = weight + 1;
  parent_->totalChildWeight_ += delta;
  if (isEnqueued()) {
    parent_->totalEnqueuedWeight_ += delta;
  }
}
Ejemplo n.º 7
0
void HTTPTransaction::sendBody(std::unique_ptr<folly::IOBuf> body) {
  DestructorGuard guard(this);
  CHECK(HTTPTransactionEgressSM::transit(
      egressState_, HTTPTransactionEgressSM::Event::sendBody));
  if (body && isEnqueued()) {
    size_t bodyLen = body->computeChainDataLength();
    transport_.notifyEgressBodyBuffered(bodyLen);
  }
  deferredEgressBody_.append(std::move(body));
  notifyTransportPendingEgress();
}
Ejemplo n.º 8
0
void HTTPTransaction::notifyTransportPendingEgress() {
  DestructorGuard guard(this);
  if (!egressRateLimited_ &&
      (deferredEgressBody_.chainLength() > 0 ||
       isEgressEOMQueued()) &&
      (!useFlowControl_ || sendWindow_.getSize() > 0)) {
    // Egress isn't paused, we have something to send, and flow
    // control isn't blocking us.
    if (!isEnqueued()) {
      // Insert into the queue and let the session know we've got something
      egressQueue_.signalPendingEgress(queueHandle_);
      transport_.notifyPendingEgress();
      transport_.notifyEgressBodyBuffered(deferredEgressBody_.chainLength());
    }
  } else if (isEnqueued()) {
    // Nothing to send, or not allowed to send right now.
    int64_t deferredEgressBodyBytes =
      folly::to<int64_t>(deferredEgressBody_.chainLength());
    transport_.notifyEgressBodyBuffered(-deferredEgressBodyBytes);
    egressQueue_.clearPendingEgress(queueHandle_);
  }
  updateHandlerPauseState();
}
Ejemplo n.º 9
0
HTTPTransaction::~HTTPTransaction() {
  // Cancel transaction timeout if still scheduled.
  if (isScheduled()) {
    cancelTimeout();
  }

  if (stats_) {
    stats_->recordTransactionClosed();
  }
  if (isEnqueued()) {
    dequeue();
  }
  // TODO: handle the case where the priority node hangs out longer than
  // the transaction
  egressQueue_.removeTransaction(queueHandle_);
}
Ejemplo n.º 10
0
void
HTTP2PriorityQueue::Node::updateEnqueuedWeight(bool activeNodes) {
  totalEnqueuedWeightCheck_ = totalChildWeight_;
  for (auto& child: children_) {
    child->updateEnqueuedWeight(activeNodes);
  }
  if (activeNodes) {
    if (totalEnqueuedWeightCheck_ == 0 && !isEnqueued()) {
      // Must only be called with activeCount_ > 0, root cannot be dequeued
      CHECK_NOTNULL(parent_);
      parent_->totalEnqueuedWeightCheck_ -= weight_;
    } else {
      CHECK(parent_ == nullptr || enqueuedHook_.is_linked());
    }
  } else {
    totalEnqueuedWeightCheck_ = 0;
  }
}
Ejemplo n.º 11
0
void HTTPTransaction::onDelayedDestroy(bool delayed) {
  if (!isEgressComplete() || !isIngressComplete() || isEnqueued()
      || deleting_) {
    return;
  }
  VLOG(4) << "destroying transaction " << *this;
  deleting_ = true;
  if (handler_) {
    handler_->detachTransaction();
    handler_ = nullptr;
  }
  transportCallback_ = nullptr;
  const auto bytesBuffered = recvWindow_.getOutstanding();
  if (bytesBuffered) {
    transport_.notifyIngressBodyProcessed(bytesBuffered);
  }
  transport_.detach(this);
  (void)delayed; // prevent unused variable warnings
}
Ejemplo n.º 12
0
bool
HTTP2PriorityQueue::Node::visitBFS(
  double relativeParentWeight,
  const std::function<bool(HTTP2PriorityQueue& queue, HTTPCodec::StreamID,
                           HTTPTransaction *, double)>& fn,
  bool all,
  PendingList& pendingNodes, bool enqueuedChildren) {
  bool invoke = (parent_ != nullptr && (all || isEnqueued()));
  auto relativeEnqueuedWeight = getRelativeEnqueuedWeight();

#ifndef NDEBUG
  CHECK_EQ(totalEnqueuedWeight_, totalEnqueuedWeightCheck_);
#endif
  // Add children when all==true, or for any not invoked node with
  // pending children
  if (all || (!invoke && totalEnqueuedWeight_ > 0)) {
    double newRelWeight = relativeParentWeight * relativeEnqueuedWeight;
    if (enqueuedChildren) {
      for (auto child = enqueuedChildren_.begin();
           child != enqueuedChildren_.end();
           child++) {
        pendingNodes.emplace_back(child->id_, &(*child), newRelWeight);
      }
    } else {
      for (auto& child: children_) {
        pendingNodes.emplace_back(child->id_, child.get(), newRelWeight);
      }
    }
  }

  // Invoke fn last in case it deletes this node
  if (invoke && fn(queue_, id_, txn_,
                   relativeParentWeight * relativeEnqueuedWeight)) {
    return true;
  }

  return false;
}
Ejemplo n.º 13
0
bool
HTTP2PriorityQueue::Node::iterate(
  const std::function<bool(HTTPCodec::StreamID,
                           HTTPTransaction *, double)>& fn,
  const std::function<bool()>& stopFn, bool all) {
  bool stop = false;
  if (stopFn()) {
    return true;
  }
#ifndef NDEBUG
  CHECK_EQ(totalEnqueuedWeight_, totalEnqueuedWeightCheck_);
#endif
  if (parent_ /* exclude root */  && (all || isEnqueued())) {
    stop = fn(id_, txn_, getRelativeWeight());
  }
  for (auto& child: children_) {
    if (stop || stopFn()) {
      return true;
    }
    stop = child->iterate(fn, stopFn, all);
  }
  return stop;
}