Skip to content

Commit b43c056

Browse files
Rahul Duttameta-codesync[bot]
authored andcommitted
Use writeChain instead of writev in Transport::write to have zerocopy support
Summary: Switch both Transport::write() overloads (ByteRange and IOBufQueue) to use writeChain instead of writev/write. This enables the zero-copy (MSG_ZEROCOPY) code path in AsyncSocket::writeChainImpl, which checks zeroCopyEnabled_, isManaged(), and the enable threshold before adding MSG_ZEROCOPY to individual writes. The old writev/write path bypassed writeChainImpl entirely, so zero-copy decisions were never evaluated even when zero copy was enabled on the socket. For the IOBufQueue overload, this also avoids an intermediate std::vector<iovec> allocation from getIov(). For the ByteRange overload, wrapBuffer creates an unmanaged IOBuf so isManaged() returns false, meaning MSG_ZEROCOPY won't be added (which is correct since ByteRange data may point at stack memory). Reviewed By: dmm-fb Differential Revision: D96616945 fbshipit-source-id: 5a53269db20b8f3a0ae53d71530a2ee879a0de4e
1 parent 6b45386 commit b43c056

2 files changed

Lines changed: 54 additions & 3 deletions

File tree

third-party/folly/src/folly/io/coro/Transport.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ Task<folly::Unit> Transport::write(
119119
WriteInfo* writeInfo) {
120120
transport_->setSendTimeout(timeout.count());
121121
WriteCallback cb{*transport_};
122-
transport_->write(&cb, buf.begin(), buf.size(), writeFlags);
122+
transport_->writeChain(
123+
&cb, folly::IOBuf::wrapBuffer(buf.begin(), buf.size()), writeFlags);
123124
auto waitRet = co_await co_awaitTry(cb.wait());
124125
if (waitRet.hasException()) {
125126
if (writeInfo) {
@@ -144,8 +145,7 @@ Task<folly::Unit> Transport::write(
144145
WriteInfo* writeInfo) {
145146
transport_->setSendTimeout(timeout.count());
146147
WriteCallback cb{*transport_};
147-
auto iovec = ioBufQueue.front()->getIov();
148-
transport_->writev(&cb, iovec.data(), iovec.size(), writeFlags);
148+
transport_->writeChain(&cb, ioBufQueue.move(), writeFlags);
149149
auto waitRet = co_await co_awaitTry(cb.wait());
150150
if (waitRet.hasException()) {
151151
if (writeInfo) {

third-party/folly/src/folly/io/coro/test/TransportTest.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,57 @@ TEST_F(ServerTransportTest, SimpleWritev) {
268268
});
269269
}
270270

271+
// Verify that write(IOBufQueue&) moves the data out of the queue and
272+
// delivers it correctly. This exercises the writeChain path.
273+
TEST_F(ServerTransportTest, WriteIOBufQueueMovesData) {
274+
run([&]() -> Task<> {
275+
auto cs = co_await connect();
276+
auto ss = srv.accept(-1);
277+
278+
IOBufQueue sndBuf(IOBufQueue::cacheChainLength());
279+
constexpr auto kBufSize = 4096;
280+
std::array<uint8_t, kBufSize> data;
281+
std::memset(data.data(), 'x', data.size());
282+
sndBuf.append(data.data(), data.size());
283+
284+
EXPECT_EQ(sndBuf.chainLength(), kBufSize);
285+
co_await cs.write(sndBuf);
286+
// After write, the IOBufQueue should be empty (data was moved)
287+
EXPECT_EQ(sndBuf.chainLength(), 0);
288+
289+
std::array<uint8_t, kBufSize> rcvBuf{};
290+
ss->readAll(rcvBuf.data(), rcvBuf.size());
291+
EXPECT_EQ(0, memcmp(data.data(), rcvBuf.data(), rcvBuf.size()));
292+
});
293+
}
294+
295+
// Verify that write(IOBufQueue&) works with a multi-element IOBuf chain.
296+
TEST_F(ServerTransportTest, WriteIOBufQueueChain) {
297+
run([&]() -> Task<> {
298+
auto cs = co_await connect();
299+
auto ss = srv.accept(-1);
300+
301+
IOBufQueue sndBuf(IOBufQueue::cacheChainLength());
302+
constexpr auto kChunkSize = 1024;
303+
constexpr auto kNumChunks = 8;
304+
std::array<uint8_t, kChunkSize * kNumChunks> expected;
305+
for (size_t i = 0; i < kNumChunks; ++i) {
306+
std::memset(
307+
expected.data() + i * kChunkSize,
308+
static_cast<int>('a' + i),
309+
kChunkSize);
310+
sndBuf.append(expected.data() + i * kChunkSize, kChunkSize);
311+
}
312+
313+
co_await cs.write(sndBuf);
314+
EXPECT_EQ(sndBuf.chainLength(), 0);
315+
316+
std::array<uint8_t, kChunkSize * kNumChunks> rcvBuf{};
317+
ss->readAll(rcvBuf.data(), rcvBuf.size());
318+
EXPECT_EQ(0, memcmp(expected.data(), rcvBuf.data(), rcvBuf.size()));
319+
});
320+
}
321+
271322
TEST_F(ServerTransportTest, WriteCancelled) {
272323
run([&]() -> Task<> {
273324
auto cs = co_await connect();

0 commit comments

Comments
 (0)