in proxygen/lib/http/session/HTTPSession.cpp [1878:1967]
void HTTPSession::detach(HTTPTransaction* txn) noexcept {
DestructorGuard guard(this);
HTTPCodec::StreamID streamID = txn->getID();
auto txnSeqn = txn->getSequenceNumber();
auto it = transactions_.find(txn->getID());
DCHECK(it != transactions_.end());
DCHECK(transactionIds_.count(txn->getID()));
if (txn->isIngressPaused()) {
// Someone detached a transaction that was paused. Make the resumeIngress
// call to keep liveTransactions_ in order
VLOG(4) << *this << " detached paused transaction=" << streamID;
resumeIngress(txn);
}
VLOG(4) << *this << " removing streamID=" << streamID
<< ", liveTransactions was " << liveTransactions_;
CHECK_GT(liveTransactions_, 0);
liveTransactions_--;
if (txn->isPushed()) {
auto assocTxn = findTransaction(*txn->getAssocTxnId());
if (assocTxn) {
assocTxn->removePushedTransaction(streamID);
}
}
if (txn->getControlStream()) {
auto controlTxn = findTransaction(*txn->getControlStream());
if (controlTxn) {
controlTxn->removeExTransaction(streamID);
}
}
// do not track a detached control stream
controlStreamIds_.erase(txn->getID());
auto oldStreamCount = getPipelineStreamCount();
decrementTransactionCount(txn, true, true);
if (lastTxn_ == txn) {
lastTxn_ = nullptr;
}
DCHECK(transactionIds_.count(it->first));
transactionIds_.erase(it->first);
transactions_.erase(it);
if (transactions_.empty()) {
HTTPSessionBase::setLatestActive();
if (pingProber_) {
pingProber_->cancelProbes();
}
if (infoCallback_) {
infoCallback_->onDeactivateConnection(*this);
}
if (getConnectionManager()) {
getConnectionManager()->onDeactivated(*this);
}
} else {
if (infoCallback_) {
infoCallback_->onTransactionDetached(*this);
}
}
if (!readsShutdown()) {
if (maybeResumePausedPipelinedTransaction(oldStreamCount, txnSeqn)) {
return;
} else {
// this will resume reads if they were paused (eg: 0 HTTP transactions)
resumeReads();
}
}
if (liveTransactions_ == 0 && transactions_.empty() && !isScheduled()) {
resetTimeout();
}
// It's possible that this is the last transaction in the session,
// so check whether the conditions for shutdown are satisfied.
if (transactions_.empty()) {
if (shouldShutdown()) {
writesDraining_ = true;
}
// Handle the case where we are draining writes but all remaining
// transactions terminated with no egress.
if (writesDraining_ && !writesShutdown() && !hasMoreWrites()) {
shutdownTransport(false, true);
return;
}
}
checkForShutdown();
}