0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-10-29 08:58:01 -04:00

perf(node/net): optimize socket reads for 'npm:ws' package (#20449)

Fixes performance regression introduced by
https://github.com/denoland/deno/pull/20223 and
https://github.com/denoland/deno/pull/20314. It's enough to have one
"shared" buffer per socket
and no locking mechanism is required.
This commit is contained in:
Bartek Iwańczuk 2023-09-11 20:38:57 +02:00 committed by GitHub
parent 9d1385896f
commit aaff69db3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -114,6 +114,7 @@ export class LibuvStreamWrap extends HandleWrap {
writeQueueSize = 0;
bytesRead = 0;
bytesWritten = 0;
#buf = new Uint8Array(SUGGESTED_SIZE);
onread!: (_arrayBuffer: Uint8Array, _nread: number) => Uint8Array | undefined;
@ -311,37 +312,18 @@ export class LibuvStreamWrap extends HandleWrap {
/** Internal method for reading from the attached stream. */
async #read() {
// 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 = false;
if (bufLocked) {
// Already locked, allocate
buf = new Uint8Array(SUGGESTED_SIZE);
} else {
// Not locked, take the buffer + lock
buf = BUF;
locked = bufLocked = true;
}
try {
let buf = this.#buf;
let nread: number | null;
const ridBefore = this[kStreamBaseField]!.rid;
try {
nread = await this[kStreamBaseField]!.read(buf);
} catch (e) {
// Lock safety: we know that the buffer will not be used in this function again
// All exits from this block either return or re-assign buf to a different value
if (locked) {
bufLocked = locked = false;
}
// 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);
if (
e instanceof Deno.errors.Interrupted ||
e instanceof Deno.errors.BadResource
@ -365,17 +347,7 @@ export class LibuvStreamWrap extends HandleWrap {
this.bytesRead += nread;
}
// We release the lock early so a re-entrant read can make use of the shared buffer, but
// we need to make a copy of the data in the shared buffer.
if (locked) {
// Lock safety: we know that the buffer will not be used in this function again
// We're making a copy of data that lives in the shared buffer
buf = buf.slice(0, nread);
bufLocked = locked = false;
} else {
// The buffer isn't owned, so let's create a subarray view
buf = buf.subarray(0, nread);
}
streamBaseState[kArrayBufferOffset] = 0;
@ -388,12 +360,6 @@ export class LibuvStreamWrap extends HandleWrap {
if (nread >= 0 && this.#reading) {
this.#read();
}
} finally {
// Lock safety: we know that the buffer will not be used in this function again
if (locked) {
bufLocked = locked = false;
}
}
}
/**
@ -454,8 +420,3 @@ export class LibuvStreamWrap extends HandleWrap {
return;
}
}
// Used in #read above
const BUF = new Uint8Array(SUGGESTED_SIZE);
// We need to ensure that only one inflight read request uses the cached buffer above
let bufLocked = false;