Skip to content

Commit d3ff6d1

Browse files
cursoragentanonrig
andcommitted
stream: address remaining webstreams review comments
Merge main so this work sits on the landed promise-churn helpers (kResolvedPromise / thenAlgorithmResult). Remaining review items: - Use the shared kResolvedPromise instead of allocating PromiseResolve() on the pull/write hot path. - Drop pipeTo's synchronous FillSync so consecutive pulls stay one-per-microtask and the change is no longer semver-major for that reason. - Call readableStreamDefaultControllerError instead of looking up controller.error. - Document and test subclass constructor materialization of the deferred empty-stream controller. Assisted-by: Grok Co-authored-by: Yagiz Nizipli <anonrig@users.noreply.github.com>
2 parents 1cf7319 + 45d6d31 commit d3ff6d1

1,503 files changed

Lines changed: 76072 additions & 15845 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CONTRIBUTING.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ See [details on our policy on Code of Conduct](./doc/contributing/code-of-conduc
4747

4848
Pull Requests are the way concrete changes are made to the code, documentation,
4949
dependencies, and tools contained in the `nodejs/node` repository.
50+
Contributors who are not Collaborators may have no more than 10 pull requests
51+
open at a time.
5052

5153
* [Dependencies](./doc/contributing/pull-requests.md#dependencies)
5254
* [Setting up your local environment](./doc/contributing/pull-requests.md#setting-up-your-local-environment)

‎Makefile‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,15 +1449,15 @@ binary: $(BINARYTAR) ## Build release binary tarballs.
14491449
# Note: this is strictly for release builds on release machines only.
14501450
binary-upload: binary
14511451
ssh $(STAGINGSERVER) "mkdir -p nodejs/$(DISTTYPEDIR)/$(FULLVERSION)"
1452-
chmod 664 $(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz
1453-
scp -p $(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz
1454-
ssh $(STAGINGSERVER) "rclone copyto nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz $(CLOUDFLARE_BUCKET)/nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz"
1455-
ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.gz.done"
1452+
chmod 664 $(BINARYNAME).tar.gz
1453+
scp -p $(BINARYNAME).tar.gz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.gz
1454+
ssh $(STAGINGSERVER) "rclone copyto nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.gz $(CLOUDFLARE_BUCKET)/nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.gz"
1455+
ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.gz.done"
14561456
ifeq ($(XZ), 1)
1457-
chmod 664 $(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz
1458-
scp -p $(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz
1459-
ssh $(STAGINGSERVER) "rclone copyto nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz $(CLOUDFLARE_BUCKET)/nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz"
1460-
ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(TARNAME)-$(OSTYPE)-$(ARCH).tar.xz.done"
1457+
chmod 664 $(BINARYNAME).tar.xz
1458+
scp -p $(BINARYNAME).tar.xz $(STAGINGSERVER):nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.xz
1459+
ssh $(STAGINGSERVER) "rclone copyto nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.xz $(CLOUDFLARE_BUCKET)/nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.xz"
1460+
ssh $(STAGINGSERVER) "touch nodejs/$(DISTTYPEDIR)/$(FULLVERSION)/$(BINARYNAME).tar.xz.done"
14611461
endif
14621462

14631463
.PHONY: bench-all

‎benchmark/misc/startup-core.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ function main({ n, script, mode }) {
6464
const warmup = 3;
6565
const state = { n, finished: -warmup };
6666
if (mode === 'worker') {
67+
// eslint-disable-next-line no-global-assign
6768
Worker = require('worker_threads').Worker;
6869
spawnWorker(script, bench, state);
6970
} else {

‎benchmark/repl/completion.js‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const repl = require('node:repl');
5+
const { PassThrough, Writable } = require('node:stream');
6+
7+
const bench = common.createBenchmark(main, {
8+
n: [5e3],
9+
query: [
10+
'cons',
11+
'console.lo',
12+
'Buffer.prototype.wri',
13+
"require('f",
14+
],
15+
useGlobal: [0, 1],
16+
});
17+
18+
function main({ n, query, useGlobal }) {
19+
const input = new PassThrough();
20+
const output = new Writable({ write(c, e, cb) { cb(); } });
21+
const server = new repl.REPLServer({
22+
input,
23+
output,
24+
terminal: false,
25+
useGlobal: !!useGlobal,
26+
});
27+
28+
// Inspector callbacks do not keep the event loop alive on their own.
29+
const keepAlive = setInterval(() => {}, 0x7fffffff);
30+
let remaining = n;
31+
32+
function complete() {
33+
server.complete(query, onComplete);
34+
}
35+
36+
function onComplete(err) {
37+
if (err) {
38+
throw err;
39+
}
40+
41+
if (--remaining === 0) {
42+
bench.end(n);
43+
clearInterval(keepAlive);
44+
server.close();
45+
return;
46+
}
47+
48+
setImmediate(complete);
49+
}
50+
51+
bench.start();
52+
setImmediate(complete);
53+
}

‎benchmark/repl/creation.js‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const repl = require('node:repl');
5+
const { PassThrough, Writable } = require('node:stream');
6+
7+
const bench = common.createBenchmark(main, {
8+
n: [500],
9+
preview: [0, 1],
10+
terminal: [0, 1],
11+
useGlobal: [0, 1],
12+
}, {
13+
combinationFilter: ({ preview, terminal }) => !!terminal || !preview,
14+
});
15+
16+
function main({ n, preview, terminal, useGlobal }) {
17+
const inputs = Array.from({ length: n }, () => new PassThrough());
18+
const outputs = Array.from(
19+
{ length: n },
20+
() => new Writable({ write(c, e, cb) { cb(); } }),
21+
);
22+
const servers = new Array(n);
23+
24+
bench.start();
25+
for (let i = 0; i < n; i++) {
26+
servers[i] = new repl.REPLServer({
27+
input: inputs[i],
28+
output: outputs[i],
29+
preview: !!preview,
30+
terminal: !!terminal,
31+
useGlobal: !!useGlobal,
32+
});
33+
}
34+
bench.end(n);
35+
36+
for (const server of servers) {
37+
server.close();
38+
}
39+
}

‎benchmark/repl/evaluate.js‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const repl = require('node:repl');
5+
const { PassThrough, Writable } = require('node:stream');
6+
7+
const bench = common.createBenchmark(main, {
8+
n: [2e4],
9+
code: [
10+
'1 + 1',
11+
'({ answer: 42 })',
12+
'Promise.resolve(42)',
13+
'await Promise.resolve(42)',
14+
],
15+
mode: ['sloppy', 'strict'],
16+
useGlobal: [0, 1],
17+
});
18+
19+
function main({ n, code, mode, useGlobal }) {
20+
const input = new PassThrough();
21+
const output = new Writable({ write(c, e, cb) { cb(); } });
22+
const server = new repl.REPLServer({
23+
input,
24+
output,
25+
replMode: mode === 'strict' ?
26+
repl.REPL_MODE_STRICT :
27+
repl.REPL_MODE_SLOPPY,
28+
terminal: false,
29+
useGlobal: !!useGlobal,
30+
});
31+
32+
// Inspector callbacks do not keep the event loop alive on their own.
33+
const keepAlive = setInterval(() => {}, 0x7fffffff);
34+
let remaining = n;
35+
36+
function evaluate() {
37+
server.eval(`${code}\n`, server.context, 'repl', onEvaluate);
38+
}
39+
40+
function onEvaluate(err) {
41+
if (err) {
42+
throw err;
43+
}
44+
45+
if (--remaining === 0) {
46+
bench.end(n);
47+
clearInterval(keepAlive);
48+
server.close();
49+
return;
50+
}
51+
52+
setImmediate(evaluate);
53+
}
54+
55+
bench.start();
56+
setImmediate(evaluate);
57+
}

‎benchmark/repl/process-lines.js‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const repl = require('node:repl');
5+
const { PassThrough, Writable } = require('node:stream');
6+
7+
const bench = common.createBenchmark(main, {
8+
n: [1e4],
9+
code: [
10+
'1 + 1\n',
11+
'Promise.resolve(42)\n',
12+
],
13+
mode: ['sloppy', 'strict'],
14+
terminal: [0, 1],
15+
useGlobal: [0, 1],
16+
});
17+
18+
function main({ n, code: inputCode, mode, terminal, useGlobal }) {
19+
const input = new PassThrough();
20+
const output = new Writable({ write(c, e, cb) { cb(); } });
21+
const server = new repl.REPLServer({
22+
input,
23+
output,
24+
replMode: mode === 'strict' ?
25+
repl.REPL_MODE_STRICT :
26+
repl.REPL_MODE_SLOPPY,
27+
terminal: !!terminal,
28+
useGlobal: !!useGlobal,
29+
});
30+
const originalEval = server.eval;
31+
// TTY input dispatch can briefly have no other active event loop handles.
32+
const keepAlive = setInterval(() => {}, 0x7fffffff);
33+
let remaining = n;
34+
35+
// eslint-disable-next-line node-core/func-name-matching
36+
server.eval = function REPLEval(code, context, file, callback) {
37+
originalEval(code, context, file, function onEvaluate() {
38+
const result = Reflect.apply(callback, this, arguments);
39+
if (--remaining === 0) {
40+
bench.end(n);
41+
clearInterval(keepAlive);
42+
server.close();
43+
} else {
44+
setImmediate(() => input.write(inputCode));
45+
}
46+
return result;
47+
});
48+
};
49+
50+
bench.start();
51+
input.write(inputCode);
52+
}

‎benchmark/repl/reset-context.js‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const repl = require('node:repl');
5+
const { PassThrough, Writable } = require('node:stream');
6+
7+
const bench = common.createBenchmark(main, {
8+
n: [1e3],
9+
});
10+
11+
function main({ n }) {
12+
const input = new PassThrough();
13+
const output = new Writable({ write(c, e, cb) { cb(); } });
14+
const server = new repl.REPLServer({
15+
input,
16+
output,
17+
terminal: false,
18+
});
19+
20+
bench.start();
21+
for (let i = 0; i < n; i++) {
22+
server.resetContext();
23+
}
24+
bench.end(n);
25+
server.close();
26+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict';
2+
const common = require('../common.js');
3+
const sqlite = require('node:sqlite');
4+
const dc = require('node:diagnostics_channel');
5+
const assert = require('node:assert');
6+
7+
const bench = common.createBenchmark(main, {
8+
n: [1e5],
9+
mode: ['none', 'subscribed', 'unsubscribed'],
10+
});
11+
12+
function main(conf) {
13+
const { n, mode } = conf;
14+
15+
const db = new sqlite.DatabaseSync(':memory:');
16+
db.exec('CREATE TABLE t (x INTEGER)');
17+
const insert = db.prepare('INSERT INTO t VALUES (?)');
18+
19+
let subscriber;
20+
if (mode === 'subscribed') {
21+
subscriber = () => {};
22+
dc.subscribe('sqlite.db.query', subscriber);
23+
} else if (mode === 'unsubscribed') {
24+
subscriber = () => {};
25+
dc.subscribe('sqlite.db.query', subscriber);
26+
dc.unsubscribe('sqlite.db.query', subscriber);
27+
}
28+
// mode === 'none': no subscription ever made
29+
30+
let result;
31+
bench.start();
32+
for (let i = 0; i < n; i++) {
33+
result = insert.run(i);
34+
}
35+
bench.end(n);
36+
37+
if (mode === 'subscribed') {
38+
dc.unsubscribe('sqlite.db.query', subscriber);
39+
}
40+
41+
assert.ok(result !== undefined);
42+
}

‎benchmark/webstreams/pipe-to.js‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,27 @@ const {
77

88
const bench = common.createBenchmark(main, {
99
n: [5e5],
10-
highWaterMarkR: [512, 1024, 2048, 4096],
11-
highWaterMarkW: [512, 1024, 2048, 4096],
10+
highWaterMarkR: [1, 1024, 4096],
11+
highWaterMarkW: [1, 1024, 4096],
1212
});
1313

1414

1515
async function main({ n, highWaterMarkR, highWaterMarkW }) {
1616
const b = Buffer.alloc(1024);
1717
let i = 0;
1818
const rs = new ReadableStream({
19-
highWaterMark: highWaterMarkR,
2019
pull: function(controller) {
2120
if (i++ < n) {
2221
controller.enqueue(b);
2322
} else {
2423
controller.close();
2524
}
2625
},
27-
});
26+
}, { highWaterMark: highWaterMarkR });
2827
const ws = new WritableStream({
29-
highWaterMark: highWaterMarkW,
3028
write(chunk, controller) {},
3129
close() { bench.end(n); },
32-
});
30+
}, { highWaterMark: highWaterMarkW });
3331

3432
bench.start();
3533
rs.pipeTo(ws);

0 commit comments

Comments
 (0)