Skip to content

Conversation

@addaleax
Copy link
Member

  • tls: refactor write queues away

    The TLS implementation previously had two separate queues for
    WriteWrap instances, one for currently active and one for
    finishing writes (i.e. where the encrypted output is being written
    to the underlying socket).

    However, the streams implementation in Node doesn’t allow for
    more than one write to be active at a time; effectively,
    the only possible states were that:

    • No write was active.
    • The first write queue had one item, the second one was empty.
    • Only the second write queue had one item, the first one was empty.

    To reduce overhead and implementation complexity, remove these
    queues, and instead store a single WriteWrap pointer and
    keep track of whether its write callback should be called
    on the next invocation of InvokeQueued() or not
    (which is what being in the second queue previously effected).

  • tls: remove cleartext input data queue

    The TLS implementation previously kept a separate buffer for
    incoming pieces of data, into which buffers were copied
    before they were up for writing.

    This removes this buffer, and replaces it with a simple list
    of uv_buf_ts:

    • The previous implementation copied all incoming data into
      that buffer, both allocating new storage and wasting time
      with copy operations. Node’s streams/net implementation
      already has to make sure that the allocated memory stays
      fresh until the write is finished, since that is what
      libuv streams rely on anyway.
    • The fact that a separate kind of buffer, crypto::NodeBIO
      was used, was confusing: These BIO instances are
      only used to communicate with openssl’s streams system
      otherwise, whereas this one was purely for internal
      memory management.
    • The name clear_in_ was not very helpful.
Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)

tls

@addaleaxaddaleax added the tls Issues and PRs related to the tls subsystem. label Dec 27, 2017
@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. tls Issues and PRs related to the tls subsystem. labels Dec 27, 2017
@addaleax
Copy link
MemberAuthor

@apapirovski
Copy link
Contributor

Related failure here: https://ci.nodejs.org/job/node-test-commit-linux/15238/nodes=fedora24/tapResults/ 😢

@addaleax
Copy link
MemberAuthor

@apapirovski I couldn’t reproduce locally in a couple thousand runs … I’ll wait until CI has freed up a bit, then run stress tests to verify it’s a problem with this PR (if the rest of the CI doesn’t already point that out)

@apapirovski
Copy link
Contributor

@addaleax It's also very possible this is related to #17863 — maybe you could just land that, rebase and then run the stress test?

@addaleax
Copy link
MemberAuthor

addaleax commented Dec 27, 2017

@apapirovski That would make a lot of sense! I’ll try that tomorrow or so – don’t want to rush in #17863 since it’s holiday season for a lot of people … :)

Edit:
Stress test this PR: https://ci.nodejs.org/job/node-stress-single-test/1589/
Stress test master: https://ci.nodejs.org/job/node-stress-single-test/1590/
Stress test #17863: https://ci.nodejs.org/job/node-stress-single-test/1591/

src/tls_wrap.cc Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove MoveBack() from util.h and util-inl.h now, this is the only place that uses it.

src/tls_wrap.cc Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pending_cleartext_input_.insert(pending_cleartext_input_.end(), &buffers[i], buffers.end());?

src/tls_wrap.cc Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise.

src/tls_wrap.cc Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As well, I wouldn't object to removing MakePending() and inlining write_callback_scheduled_ = true at its two or three call sites. It arguably obscures more than it abstracts.

src/tls_wrap.h Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a std::list be more appropriate here?

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TimothyGu Why? uv_buf_t is a pretty small structure, so what I would guess is that the overhead of possibly having a small number of them being unused is more or less negligible compared to allocating a list node for every buffer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on the variations I tried with http2, the performance difference is inconsequential. Using std::vector here is just fine.

@addaleax
Copy link
MemberAuthor

@addaleaxaddaleax added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. dont-land-on-v4.x labels Jan 2, 2018
The TLS implementation previously had two separate queues for WriteWrap instances, one for currently active and one for finishing writes (i.e. where the encrypted output is being written to the underlying socket). However, the streams implementation in Node doesn’t allow for more than one write to be active at a time; effectively, the only possible states were that: - No write was active. - The first write queue had one item, the second one was empty. - Only the second write queue had one item, the first one was empty. To reduce overhead and implementation complexity, remove these queues, and instead store a single `WriteWrap` pointer and keep track of whether its write callback should be called on the next invocation of `InvokeQueued()` or not (which is what being in the second queue previously effected).
The TLS implementation previously kept a separate buffer for incoming pieces of data, into which buffers were copied before they were up for writing. This removes this buffer, and replaces it with a simple list of `uv_buf_t`s: - The previous implementation copied all incoming data into that buffer, both allocating new storage and wasting time with copy operations. Node’s streams/net implementation already has to make sure that the allocated memory stays fresh until the write is finished, since that is what libuv streams rely on anyway. - The fact that a separate kind of buffer, `crypto::NodeBIO` was used, was confusing: These `BIO` instances are only used to communicate with openssl’s streams system otherwise, whereas this one was purely for internal memory management. - The name `clear_in_` was not very helpful.
@addaleax
Copy link
MemberAuthor

Landed in d5fa4de, 46f783d

@addaleaxaddaleax closed this Jan 7, 2018
@addaleaxaddaleax removed the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jan 7, 2018
@addaleaxaddaleax deleted the tls-simplify-writes branch January 7, 2018 21:36
addaleax added a commit that referenced this pull request Jan 7, 2018
The TLS implementation previously had two separate queues for WriteWrap instances, one for currently active and one for finishing writes (i.e. where the encrypted output is being written to the underlying socket). However, the streams implementation in Node doesn’t allow for more than one write to be active at a time; effectively, the only possible states were that: - No write was active. - The first write queue had one item, the second one was empty. - Only the second write queue had one item, the first one was empty. To reduce overhead and implementation complexity, remove these queues, and instead store a single `WriteWrap` pointer and keep track of whether its write callback should be called on the next invocation of `InvokeQueued()` or not (which is what being in the second queue previously effected). PR-URL: #17883 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
addaleax added a commit that referenced this pull request Jan 7, 2018
The TLS implementation previously kept a separate buffer for incoming pieces of data, into which buffers were copied before they were up for writing. This removes this buffer, and replaces it with a simple list of `uv_buf_t`s: - The previous implementation copied all incoming data into that buffer, both allocating new storage and wasting time with copy operations. Node’s streams/net implementation already has to make sure that the allocated memory stays fresh until the write is finished, since that is what libuv streams rely on anyway. - The fact that a separate kind of buffer, `crypto::NodeBIO` was used, was confusing: These `BIO` instances are only used to communicate with openssl’s streams system otherwise, whereas this one was purely for internal memory management. - The name `clear_in_` was not very helpful. PR-URL: #17883 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
@MylesBorins
Copy link
Contributor

This does not land cleanly on v9.x, could it be manually backported?

@addaleax
Copy link
MemberAuthor

This should apply cleanly after #17650 is backported

evanlucas pushed a commit that referenced this pull request Jan 30, 2018
The TLS implementation previously had two separate queues for WriteWrap instances, one for currently active and one for finishing writes (i.e. where the encrypted output is being written to the underlying socket). However, the streams implementation in Node doesn’t allow for more than one write to be active at a time; effectively, the only possible states were that: - No write was active. - The first write queue had one item, the second one was empty. - Only the second write queue had one item, the first one was empty. To reduce overhead and implementation complexity, remove these queues, and instead store a single `WriteWrap` pointer and keep track of whether its write callback should be called on the next invocation of `InvokeQueued()` or not (which is what being in the second queue previously effected). PR-URL: #17883 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
@evanlucasevanlucas mentioned this pull request Jan 30, 2018
MylesBorins pushed a commit that referenced this pull request Feb 20, 2018
The TLS implementation previously kept a separate buffer for incoming pieces of data, into which buffers were copied before they were up for writing. This removes this buffer, and replaces it with a simple list of `uv_buf_t`s: - The previous implementation copied all incoming data into that buffer, both allocating new storage and wasting time with copy operations. Node’s streams/net implementation already has to make sure that the allocated memory stays fresh until the write is finished, since that is what libuv streams rely on anyway. - The fact that a separate kind of buffer, `crypto::NodeBIO` was used, was confusing: These `BIO` instances are only used to communicate with openssl’s streams system otherwise, whereas this one was purely for internal memory management. - The name `clear_in_` was not very helpful. PR-URL: #17883 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
@MylesBorinsMylesBorins mentioned this pull request Feb 21, 2018
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++Issues and PRs that require attention from people who are familiar with C++.tlsIssues and PRs related to the tls subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@addaleax@apapirovski@MylesBorins@bnoordhuis@jasnell@TimothyGu@tniessen@nodejs-github-bot