Skip to content

Commit 47f5cc1

Browse files
apapirovskidanbev
authored andcommitted
lib: faster FreeList
Make FreeList faster by using Reflect.apply and not using is_reused_symbol, but rather just checking whether any items are present in the list prior to calling alloc. PR-URL: #27021 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 547576f commit 47f5cc1

File tree

7 files changed

+20
-25
lines changed

7 files changed

+20
-25
lines changed

benchmark/misc/freelist.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ const bench = common.createBenchmark(main, {
99
});
1010

1111
function main({ n }) {
12-
const { FreeList } = require('internal/freelist');
12+
let FreeList = require('internal/freelist');
13+
if (FreeList.FreeList)
14+
FreeList = FreeList.FreeList;
1315
const poolSize = 1000;
1416
const list = new FreeList('test', poolSize, Object);
1517
var j;

lib/_http_client.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ const {
4646
ERR_UNESCAPED_CHARACTERS
4747
} = require('internal/errors').codes;
4848
const { getTimerDuration } = require('internal/timers');
49-
const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol;
5049
const {
5150
DTRACE_HTTP_CLIENT_REQUEST,
5251
DTRACE_HTTP_CLIENT_RESPONSE
@@ -631,10 +630,11 @@ function emitFreeNT(socket) {
631630
}
632631

633632
function tickOnSocket(req, socket) {
633+
const isParserReused = parsers.hasItems();
634634
const parser = parsers.alloc();
635635
req.socket = socket;
636636
req.connection = socket;
637-
parser.reinitialize(HTTPParser.RESPONSE, parser[is_reused_symbol]);
637+
parser.reinitialize(HTTPParser.RESPONSE, isParserReused);
638638
parser.socket = socket;
639639
parser.outgoing = req;
640640
req.parser = parser;

lib/_http_common.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const { methods, HTTPParser } =
2929
getOptionValue('--http-parser') === 'legacy' ?
3030
internalBinding('http_parser') : internalBinding('http_parser_llhttp');
3131

32-
const { FreeList } = require('internal/freelist');
32+
const FreeList = require('internal/freelist');
3333
const { ondrain } = require('internal/http');
3434
const incoming = require('_http_incoming');
3535
const {

lib/_http_server.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ const {
4141
defaultTriggerAsyncIdScope,
4242
getOrSetAsyncId
4343
} = require('internal/async_hooks');
44-
const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol;
4544
const { IncomingMessage } = require('_http_incoming');
4645
const {
4746
ERR_HTTP_HEADERS_SENT,
@@ -348,8 +347,9 @@ function connectionListenerInternal(server, socket) {
348347
socket.setTimeout(server.timeout);
349348
socket.on('timeout', socketOnTimeout);
350349

350+
const isParserReused = parsers.hasItems();
351351
const parser = parsers.alloc();
352-
parser.reinitialize(HTTPParser.REQUEST, parser[is_reused_symbol]);
352+
parser.reinitialize(HTTPParser.REQUEST, isParserReused);
353353
parser.socket = socket;
354354

355355
// We are starting to wait for our headers.

lib/internal/freelist.js

+9-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const is_reused_symbol = Symbol('isReused');
3+
const { Reflect } = primordials;
44

55
class FreeList {
66
constructor(name, max, ctor) {
@@ -10,16 +10,14 @@ class FreeList {
1010
this.list = [];
1111
}
1212

13+
hasItems() {
14+
return this.list.length > 0;
15+
}
16+
1317
alloc() {
14-
let item;
15-
if (this.list.length > 0) {
16-
item = this.list.pop();
17-
item[is_reused_symbol] = true;
18-
} else {
19-
item = this.ctor.apply(this, arguments);
20-
item[is_reused_symbol] = false;
21-
}
22-
return item;
18+
return this.list.length > 0 ?
19+
this.list.pop() :
20+
Reflect.apply(this.ctor, this, arguments);
2321
}
2422

2523
free(obj) {
@@ -31,9 +29,4 @@ class FreeList {
3129
}
3230
}
3331

34-
module.exports = {
35-
FreeList,
36-
symbols: {
37-
is_reused_symbol
38-
}
39-
};
32+
module.exports = FreeList;

test/parallel/test-freelist.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
require('../common');
66
const assert = require('assert');
7-
const { FreeList } = require('internal/freelist');
7+
const FreeList = require('internal/freelist');
88

99
assert.strictEqual(typeof FreeList, 'function');
1010

test/sequential/test-http-regr-gh-2928.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
const common = require('../common');
77
const assert = require('assert');
88
const httpCommon = require('_http_common');
9-
const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol;
109
const { HTTPParser } = require('_http_common');
1110
const net = require('net');
1211

@@ -25,14 +24,15 @@ function execAndClose() {
2524
process.stdout.write('.');
2625

2726
const parser = parsers.pop();
28-
parser.reinitialize(HTTPParser.RESPONSE, parser[is_reused_symbol]);
27+
parser.reinitialize(HTTPParser.RESPONSE, !!parser.reused);
2928

3029
const socket = net.connect(common.PORT);
3130
socket.on('error', (e) => {
3231
// If SmartOS and ECONNREFUSED, then retry. See
3332
// https://github.com/nodejs/node/issues/2663.
3433
if (common.isSunOS && e.code === 'ECONNREFUSED') {
3534
parsers.push(parser);
35+
parser.reused = true;
3636
socket.destroy();
3737
setImmediate(execAndClose);
3838
return;

0 commit comments

Comments
 (0)