Skip to content

Commit 21701c9

Browse files
Joanna Jometa-codesync[bot]
authored andcommitted
Refactor CoroWtSession with TransportIf
Summary: Refactoring CoroWtSession with TransportIf so that it can be used over both HTTP/2 WebTransport and QMux. Reviewed By: hanidamlaj Differential Revision: D93130683 fbshipit-source-id: 47f8761d7b61d273a6ff9a58e2d3bc69b9730459
1 parent ff8749e commit 21701c9

3 files changed

Lines changed: 57 additions & 69 deletions

File tree

third-party/proxygen/src/proxygen/lib/http/coro/HTTPCoroSession.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3793,14 +3793,17 @@ folly::coro::Task<WtReqResult> HTTPUniplexTransportSession::sendWtReq(
37933793
}
37943794

37953795
// wt upgrade successful
3796+
auto transport = detail::makeHttpSourceTransport(
3797+
eventBase_.get(), std::move(egressSource), std::move(*res));
37963798
auto wt = std::make_shared<CoroWtSessionImpl>(
37973799
eventBase_.get(),
37983800
::proxygen::detail::WtDir::Client,
37993801
::proxygen::detail::getWtConfig(codec_->getIngressSettings(),
38003802
codec_->getEgressSettings()),
3801-
std::move(wtHandler));
3803+
std::move(wtHandler),
3804+
std::move(transport));
38023805
wt->ka_ = acquireKeepAlive();
3803-
wt->start(wt, std::move(*res), std::move(egressSource));
3806+
wt->start(wt);
38043807

38053808
ret.wt = std::move(wt);
38063809
co_return ret;

third-party/proxygen/src/proxygen/lib/http/coro/util/CoroWtSession.cpp

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace {
1414
using namespace proxygen::coro;
1515
using folly::coro::co_error;
1616
using folly::coro::co_nothrow;
17+
constexpr uint64_t kMaxWriteSize = 65'535;
1718

1819
BufQueue* asBodyEv(HTTPBodyEvent& event) {
1920
return event.eventType == HTTPBodyEvent::BODY ? &event.event.body : nullptr;
@@ -27,10 +28,12 @@ CoroWtSession::CoroWtSession(
2728
folly::EventBase* evb,
2829
WtDir dir,
2930
WtStreamManager::WtConfig wtConfig,
30-
std::unique_ptr<WebTransportHandler> handler) noexcept
31+
std::unique_ptr<WebTransportHandler> handler,
32+
std::unique_ptr<folly::coro::TransportIf> transport) noexcept
3133
: CoroWtSessionBase(dir, wtConfig),
3234
WtSessionBase(evb, sm),
33-
wtHandler_(std::move(handler)) {
35+
wtHandler_(std::move(handler)),
36+
transport_(std::move(transport)) {
3437
}
3538

3639
CoroWtSession::~CoroWtSession() noexcept {
@@ -46,21 +49,26 @@ WtExpected<folly::Unit>::Type CoroWtSession::closeSession(
4649
}
4750

4851
using WtCapsuleCallback = proxygen::detail::WtCapsuleCallback;
49-
folly::coro::Task<void> CoroWtSession::readLoop(Ptr self,
50-
HTTPSourceHolder ingress) {
51-
WtCapsuleCallback wtCapsuleCallback{sm, *this};
52+
folly::coro::Task<void> CoroWtSession::readLoop(Ptr self) {
53+
WtCapsuleCallback wtCapsuleCallback{sm, *self};
5254
WebTransportCapsuleCodec codec{&wtCapsuleCallback, CodecVersion::H2};
53-
54-
while (!sm.isClosed() && ingress.readable()) {
55-
auto maybeEv = co_await co_awaitTry(ingress.readBodyEvent());
56-
if (maybeEv.hasException() ||
57-
maybeEv->eventType != HTTPBodyEvent::BODY) { // skip non-body events
58-
XLOG_IF(DBG4, maybeEv.hasException())
59-
<< "::readLoop ingress ex=" << maybeEv.exception().what();
60-
continue;
55+
folly::IOBufQueue ingressBuf{folly::IOBufQueue::cacheChainLength()};
56+
57+
while (!sm.isClosed()) {
58+
auto readRes = co_await co_awaitTry(transport_->read(
59+
ingressBuf,
60+
/*minReadSize=*/1460,
61+
/*newAllocationSize=*/4000,
62+
/*timeout=*/std::chrono::milliseconds(0))); // TODO: timeout should be
63+
// changed from 0ms
64+
if (readRes.hasException()) {
65+
XLOG(DBG4) << __func__ << "; ex=" << readRes.exception();
66+
break;
6167
}
62-
auto& event = maybeEv.value();
63-
codec.onIngress(event.event.body.move(), event.eom);
68+
69+
const bool eom = (*readRes == 0);
70+
codec.onIngress(ingressBuf.move(), eom);
71+
6472
// handle any new peer streams
6573
auto peerIds = std::move(wtSmIngressCb.peerStreams);
6674
for (auto id : peerIds) {
@@ -72,96 +80,71 @@ folly::coro::Task<void> CoroWtSession::readLoop(Ptr self,
7280
}
7381
}
7482

75-
if (event.eom) {
83+
if (eom) {
7684
break;
7785
}
7886
}
7987
XLOG(DBG4) << "CoroWtSession::readLoop exiting";
80-
// http/2 rst, eom or WtStreamManager closed – in either case invoke
81-
// ::shutdown to exit write loop
8288
sm.shutdown(WtStreamManager::CloseSession{.err = 0x00,
83-
.msg = "h2 stream ingress closed"});
89+
.msg = "stream ingress closed"});
8490
readLoopFinished();
8591
}
8692

87-
folly::coro::Task<void> CoroWtSession::writeLoop(Ptr self,
88-
EgressSourcePtr egress) {
89-
const auto timeout = egress->getReadTimeout();
90-
const folly::IOBuf empty;
93+
folly::coro::Task<void> CoroWtSession::writeLoop(Ptr self) {
9194
folly::IOBufQueue egressBuf{folly::IOBufQueue::cacheChainLength()};
9295
proxygen::detail::WtEventVisitor eventVisitor{.egress = egressBuf};
93-
detail::EgressBackPressure streamSourceCallback;
94-
egress->setCallback(&streamSourceCallback);
9596
auto& waitForEventBaton = wtSmEgressCb.waitForEvent;
9697

9798
while (!eventVisitor.sessionClosed) {
98-
// wait for WtSession egress (i.e. underlying http/2 egress buffer space);
99-
// this is upperbounded by writeTimeout in HTTPBodyEventQueue
100-
XLOG(DBG6) << "waiting for http/2 egress fc";
101-
co_await streamSourceCallback.waitForEgress.wait();
102-
103-
// wait for underlying wt ctrl events or writable streams
99+
// wait for WtStreamManager control events or writable streams
104100
XLOG(DBG6) << "waiting for WtStreamManager event";
105-
auto res = co_await waitForEventBaton.timedWait(evb(), timeout);
106-
if (res == TimedBaton::Status::timedout) {
107-
sm.shutdown(WtStreamManager::CloseSession{.err = 0x00,
108-
.msg = "wt write timed out"});
109-
} // fallthru to writing close_session below
101+
co_await waitForEventBaton.wait();
110102
waitForEventBaton.reset();
111103

112104
XLOG(DBG6) << "received WtStreamManager event";
113-
// always write control frames first (not subject to flow control)
105+
// always write control frames first
114106
auto ctrl = sm.moveEvents();
115107
for (auto& ev : ctrl) {
116108
std::visit(eventVisitor, ev);
117109
}
118-
egress->body(egressBuf.move(), /*padding=*/0, /*eom=*/false);
119110

120-
// write stream data
121111
auto* wh = sm.nextWritable();
122-
while (wh) {
123-
auto bytesAvailable = egress->window().getNonNegativeSize();
124-
XLOG(DBG4) << __func__ << "; id=" << wh->getID() << "; wh=" << wh
125-
<< "; bytesAvailable=" << bytesAvailable;
126-
if (bytesAvailable == 0) {
127-
XLOG(DBG5) << __func__ << " egress blocked";
128-
streamSourceCallback.waitForEgress.reset(); // block on next loop
129-
break;
130-
}
112+
while (wh && egressBuf.chainLength() < kMaxWriteSize) {
131113
auto id = wh->getID();
132-
auto dequeue = sm.dequeue(*wh, /*atMost=*/bytesAvailable);
114+
const auto atMost = kMaxWriteSize - egressBuf.chainLength();
115+
auto dequeue = sm.dequeue(*wh, /*atMost=*/atMost);
133116
writeWTStream(egressBuf,
134117
WTStreamCapsule{.streamId = id,
135118
.streamData = std::move(dequeue.data),
136119
.fin = dequeue.fin});
137-
// ::body overflow checked in next iteration
138-
egress->body(egressBuf.move(), /*padding=*/0, /*eom=*/false);
139120
wh = sm.nextWritable();
140121
}
122+
if (wh) {
123+
waitForEventBaton.signal(); // re-signal for remaining streams
124+
}
141125

142-
if (wh) { // if there's more pending data to be written, signal baton
143-
waitForEventBaton.signal();
126+
if (!egressBuf.empty()) {
127+
auto writeRes = co_await co_awaitTry(
128+
transport_->write(egressBuf)); // TODO: plumb writeTimeout here
129+
if (writeRes.hasException()) {
130+
XLOG(DBG4) << __func__ << "; ex=" << writeRes.exception();
131+
break;
132+
}
144133
}
145134
}
146135

147136
XLOG(DBG4) << "CoroWtSession::writeLoop exiting";
148-
egress->eom();
137+
transport_->shutdownWrite();
149138
writeLoopFinished();
150139
co_return;
151140
}
152141

153-
void CoroWtSession::start(CoroWtSession::Ptr self,
154-
HTTPSourceHolder&& ingress,
155-
EgressSourcePtr&& egress) {
142+
void CoroWtSession::start(CoroWtSession::Ptr self) {
156143
wtHandler_->onWebTransportSession(self);
157144
auto ct = cs_.getToken();
158145
auto* eventBase = evb();
159-
co_withExecutor(eventBase,
160-
co_withCancellation(ct, readLoop(self, std::move(ingress))))
161-
.start();
162-
co_withExecutor(eventBase,
163-
co_withCancellation(ct, writeLoop(self, std::move(egress))))
164-
.start();
146+
co_withExecutor(eventBase, co_withCancellation(ct, readLoop(self))).start();
147+
co_withExecutor(eventBase, co_withCancellation(ct, writeLoop(self))).start();
165148
}
166149

167150
void CoroWtSession::writeLoopFinished() noexcept {

third-party/proxygen/src/proxygen/lib/http/coro/util/CoroWtSession.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,25 +100,27 @@ class CoroWtSession
100100
CoroWtSession(folly::EventBase* evb,
101101
WtDir dir,
102102
WtStreamManager::WtConfig wtConfig,
103-
std::unique_ptr<WebTransportHandler> handler) noexcept;
103+
std::unique_ptr<WebTransportHandler> handler,
104+
std::unique_ptr<folly::coro::TransportIf> transport) noexcept;
104105

105106
~CoroWtSession() noexcept override;
106107

107108
WtExpected<folly::Unit>::Type closeSession(
108109
folly::Optional<uint32_t> error = folly::none) noexcept override;
109110

110111
// launches read & write loops
111-
void start(Ptr self, HTTPSourceHolder&& ingress, EgressSourcePtr&& egress);
112+
void start(Ptr self);
112113

113114
private:
114-
folly::coro::Task<void> readLoop(Ptr self, HTTPSourceHolder ingress);
115-
folly::coro::Task<void> writeLoop(Ptr self, EgressSourcePtr egress);
115+
folly::coro::Task<void> readLoop(Ptr self);
116+
folly::coro::Task<void> writeLoop(Ptr self);
116117

117118
void writeLoopFinished() noexcept;
118119
void readLoopFinished() noexcept;
119120

120121
std::unique_ptr<WebTransportHandler> wtHandler_;
121122
folly::CancellationSource cs_;
123+
std::unique_ptr<folly::coro::TransportIf> transport_;
122124
bool readLoopDone_ : 1 {false};
123125
bool writeLoopDone_ : 1 {false};
124126
};

0 commit comments

Comments
 (0)