Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ext/node): shared global buffer unlock correctness fix #20314

Merged
merged 1 commit into from
Aug 28, 2023

Conversation

mmastrac
Copy link
Contributor

@mmastrac mmastrac commented Aug 28, 2023

The fix for #20188 was not entirely correct -- we were unlocking the global buffer incorrectly. This PR introduces a lock state that ensures we only unlock a lock we have taken out.

@mmastrac mmastrac force-pushed the stream_wrap_fix2 branch 3 times, most recently from caffbe6 to e2298e0 Compare August 28, 2023 15:57
// Try to read again if the underlying stream resource
// changed. This can happen during TLS upgrades (eg. STARTTLS)
if (ridBefore != this[kStreamBaseField]!.rid) {
return this.#read();
}

buf = new Uint8Array(0);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved this line for clarity

Copy link
Collaborator

@aapoalas aapoalas left a comment

Choose a reason for hiding this comment

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

Looks good to me for the changes, didn't analyse the code around it

bufLocked = true;
// Lock safety: We must hold this lock until we are certain that buf is no longer used
// This setup code is a little verbose, but we need to be careful about buffer management
let buf, locked;
Copy link
Collaborator

Choose a reason for hiding this comment

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

nitpick: I'd prep locked to false. I do not know if that helps V8 with optimisation but it might. Also makes TS understand it even in a JS file.


server.close(() => {
p.resolve();
finished.resolve();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that in the old code, p2 was guaranteed to fire before p so there wasn't much sense in waiting on both.

@bartlomieju
Copy link
Member

Fixes #19831

@mmastrac mmastrac linked an issue Aug 28, 2023 that may be closed by this pull request
@mmastrac mmastrac merged commit 7adaf61 into denoland:main Aug 28, 2023
12 checks passed
Comment on lines +317 to +323
if (bufLocked) {
// Already locked, allocate
buf = new Uint8Array(SUGGESTED_SIZE);
} else {
// Not locked, take the buffer + lock
buf = BUF;
locked = bufLocked = true;
Copy link

Choose a reason for hiding this comment

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

Wouldn't the code be much simpler if you always allocate buf = new Uint8Array(SUGGESTED_SIZE);? locked, bufLocked will be deemed useless.

Is the current shared buffer motivated only by a performance gain? @mmastrac

bartlomieju pushed a commit that referenced this pull request Aug 31, 2023
The fix for #20188 was not entirely correct -- we were unlocking the
global buffer incorrectly. This PR introduces a lock state that ensures
we only unlock a lock we have taken out.
bartlomieju added a commit that referenced this pull request Sep 11, 2023
Fixes performance regression introduced by
#20223 and
#20314. It's enough to have one
"shared" buffer per socket
and no locking mechanism is required.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

npm:mongodb fails on v1.35.1
4 participants