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,

Reply via email to