This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new d9ce07e332 Reduce TLS write-path overhead (#13202)
d9ce07e332 is described below
commit d9ce07e332f7bb1f75972c8043c525af3c8b52b8
Author: Leif Hedstrom <[email protected]>
AuthorDate: Tue Jun 9 14:50:29 2026 -0600
Reduce TLS write-path overhead (#13202)
* Reduce TLS write-path syscalls by coalescing records
A response split across many small IOBuffer blocks issued one
SSL_write -- and thus one TLS record and often one write() syscall --
per block. Gather the blocks into a per-thread scratch buffer (bounded
to one max TLS record) and issue a single SSL_write, so a fragmented
buffer yields one record and one write(). Contiguous blocks still write
in place, preserving the dynamic record-sizing ramp and prior behavior.
* Address Copilot's review
Drop the redundant per-iteration read_avail() walk in the TLS write
path. towrite is already bounded by read_avail() in the caller
(write_to_net_io), so use towrite - total_written directly and avoid
re-walking the IOBufferBlock chain (O(n)) on the write hot path.
* Address review comments on TLS write-path
Rephrase gather_buf rationale to cite SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
(per Mo) and add an ink_assert enforcing the towrite <= read_avail()
precondition (per Josiah) so the O(1) hot-path computation is verified
in debug builds.
---
src/iocore/net/SSLNetVConnection.cc | 38 +++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/src/iocore/net/SSLNetVConnection.cc
b/src/iocore/net/SSLNetVConnection.cc
index 9b1bccd973..95b7e57f11 100644
--- a/src/iocore/net/SSLNetVConnection.cc
+++ b/src/iocore/net/SSLNetVConnection.cc
@@ -739,18 +739,18 @@ SSLNetVConnection::load_buffer_and_write(int64_t towrite,
MIOBufferAccessor &buf
Dbg(dbg_ctl_ssl, "towrite=%" PRId64, towrite);
+ // SSL_write retries (WANT_WRITE/READ) must reuse the same address;
thread_local gives the
+ // coalesce path a stable one. SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is off.
+ static thread_local char gather_buf[SSL_MAX_TLS_RECORD_SIZE];
+
+ // Caller bounds towrite by read_avail(); asserting lets the loop skip an
O(n) chain walk.
+ ink_assert(towrite <= buf.reader()->read_avail());
+
ERR_clear_error();
do {
- // What is remaining left in the next block?
- l = buf.reader()->block_read_avail();
- char *current_block = buf.reader()->start();
+ IOBufferReader *reader = buf.reader();
- // check if to amount to write exceeds that in this buffer
- int64_t wavail = towrite - total_written;
-
- if (l > wavail) {
- l = wavail;
- }
+ l = towrite - total_written;
// TS-2365: If the SSL max record size is set and we have
// more data than that, break this into smaller write
@@ -782,15 +782,29 @@ SSLNetVConnection::load_buffer_and_write(int64_t towrite,
MIOBufferAccessor &buf
break;
}
+ // Coalesce across blocks only when it fits one record; else write in
place, capped to the block.
+ const char *write_block;
+ int64_t block_avail = reader->block_read_avail();
+
+ if (block_avail < l && l <= static_cast<int64_t>(sizeof(gather_buf))) {
+ reader->memcpy(gather_buf, l, 0);
+ write_block = gather_buf;
+ } else {
+ if (l > block_avail) {
+ l = block_avail;
+ }
+ write_block = reader->start();
+ }
+
try_to_write = l;
num_really_written = 0;
- Dbg(dbg_ctl_v_ssl, "b=%p l=%" PRId64, current_block, l);
- err = this->_ssl_write_buffer(current_block, l, num_really_written);
+ Dbg(dbg_ctl_v_ssl, "b=%p l=%" PRId64, write_block, l);
+ err = this->_ssl_write_buffer(write_block, l, num_really_written);
// We wrote all that we thought we should
if (num_really_written > 0) {
total_written += num_really_written;
- buf.reader()->consume(num_really_written);
+ reader->consume(num_really_written);
}
Dbg(dbg_ctl_ssl, "try_to_write=%" PRId64 " written=%" PRId64 "
total_written=%" PRId64, try_to_write, num_really_written,