Repository navigation
perf: run TLS on a bridge to the socket instead of a DuplexPair - #1796
Open
arthurschreiber wants to merge 1 commit into
Open
arthurschreiber wants to merge 1 commit into
arthurschreiber wants to merge 1 commit into
Conversation
With `encrypt: true`, TDS negotiates TLS inside `PRELOGIN` messages, so the TLS layer can not run on the socket directly. It used to run on one end of a `DuplexPair`, whose other end was piped to and from the socket once the handshake completed - two extra stream hops for every byte. `TlsBridge` is a single `Duplex` between the TLS layer and the socket. During the handshake, it sends the TLS data written in one go as a `PRELOGIN` message and hands the server's response back to TLS. Afterwards, it passes the data between TLS and the socket as is, with backpressure in both directions, and closes once the socket closed. This removes the `native-duplexpair` dependency. The tests use Node's built-in `stream.duplexPair()` instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HGJsu1u44CHnt4nkkQ5ias
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1796 +/- ##
==========================================
+ Coverage 84.38% 84.58% +0.19%
==========================================
Files 95 96 +1
Lines 4702 4754 +52
Branches 880 888 +8
==========================================
+ Hits 3968 4021 +53
+ Misses 473 472 -1
Partials 261 261 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With
encrypt: true, TDS negotiates TLS insidePRELOGINmessages, so the TLS layer can't run on the socket directly. Until now it ran on one end of aDuplexPair. Once the handshake completed, the pair's other end was piped to and from the socket, which added two extra stream hops for every byte sent or received.Changes
src/tls-bridge.ts(TlsBridge). A singleDuplexbetweentls.connectand the socket.PRELOGINmessage, and the payload of the server's response is pushed back to TLS. Data written while a response is outstanding is sent after that response arrives.secureConnect(startPassthrough()): data passes between TLS and the socket unchanged, with backpressure in both directions. If the TLS layer stops reading, the socket is paused. If the socket doesn't drain, the bridge holds back the write callback.draincan't stall.MessageIO.startTlsuses the bridge. TheonReadableloop and its re-arming are gone.securePairis replaced bytlsSocket, which is only used internally forsetMaxSendFragment.native-duplexpairis removed from the dependencies, along with its type stub intypes/. The server side of thestartTlsunit tests now uses Node's built-instream.duplexPair(), which exists on every Node version in the CI matrix. Production code doesn't use it.benchmarks/package-lock.jsonstill listsnative-duplexpairas a dependency offile:... That lockfile is already stale in other ways, and regenerating it changes ~160 unrelated lines, so I left it alone.Performance
Selecting a 1 MB
nvarchar(max)value over TLS withpacketSize: 16384. Medians of 6 interleaved runs of 300 queries each:That's about 240 µs less client CPU per MB received over TLS.
Tests
test/unit/tls-bridge-test.ts. It covers:drain(this test times out if the bridge doesn't listen forclose).MessageIO#startTlsunit tests pass unchanged, apart from theduplexPairswitch.npm run lintandnpm testpass (556 passing).encrypt: true: 469 passing. The one failure (should not leave any dangling sockets after connection timeout) fails the same way on master in this environment, because the sandbox rejects connections to 192.0.2.1 instead of letting them time out.🤖 Generated with Claude Code
https://claude.ai/code/session_01HGJsu1u44CHnt4nkkQ5ias
Generated by Claude Code