Skip to content

Commit b0b1414

Browse files
gireeshpunathiltargos
authored andcommitted
test: regression test for uv threadpool congestion
Validate that massive dns lookups do not block filesytem I/O (or any fast I/O for that matter). Prior to libuv/libuv#1845 few back-to-back dns lookup were sufficient to engage libuv threadpool workers in a blocking manner, throttling other work items that need the pool. this test acts as a regression test for the same. Start slow and fast I/Os together, and make sure fast I/O can complete in at least in 1/100th of time for slow I/O. Refs: libuv/libuv#1845 Refs: #8436 PR-URL: #23099 Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 516f75f commit b0b1414

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict';
2+
3+
// Test to validate massive dns lookups do not block filesytem I/O
4+
// (or any fast I/O). Prior to https://github.com/libuv/libuv/pull/1845
5+
// few back-to-back dns lookups were sufficient to engage libuv
6+
// threadpool workers in a blocking manner, throttling other work items
7+
// that need pool resources. Start slow and fast I/Os together, make sure
8+
// fast I/O can complete in at least in 1/100th of time for slow I/O.
9+
// TEST TIME TO COMPLETION: ~5 seconds.
10+
11+
const common = require('../common');
12+
const dns = require('dns');
13+
const fs = require('fs');
14+
const assert = require('assert');
15+
16+
const start = Date.now();
17+
18+
const slowIOmax = 100;
19+
let slowIOcount = 0;
20+
let fastIOdone = false;
21+
let slowIOend, fastIOend;
22+
23+
function onResolve() {
24+
slowIOcount++;
25+
if (slowIOcount === slowIOmax) {
26+
slowIOend = Date.now();
27+
28+
// Conservative expectation: finish disc I/O
29+
// at least by when the net I/O completes.
30+
assert.ok(fastIOdone,
31+
'fast I/O was throttled due to threadpool congestion.');
32+
33+
// More realistic expectation: finish disc I/O at least within
34+
// a time duration that is 1/100th of net I/O.
35+
// Ideally the slow I/O should not affect the fast I/O as those
36+
// have two different thread-pool buckets. However, this could be
37+
// highly load / platform dependent, so don't be very greedy.
38+
const fastIOtime = fastIOend - start;
39+
const slowIOtime = slowIOend - start;
40+
const expectedMax = slowIOtime / 100;
41+
assert.ok(fastIOtime < expectedMax,
42+
'fast I/O took longer to complete, ' +
43+
`actual: ${fastIOtime}, expected: ${expectedMax}`);
44+
}
45+
}
46+
47+
48+
for (let i = 0; i < slowIOmax; i++) {
49+
// We need to refresh the domain string everytime,
50+
// otherwise the TCP stack that cache the previous lookup
51+
// returns result from memory, breaking all our Math.
52+
dns.lookup(`${randomDomain()}.com`, {}, common.mustCall(onResolve));
53+
}
54+
55+
fs.readFile(__filename, common.mustCall(() => {
56+
fastIOend = Date.now();
57+
fastIOdone = true;
58+
}));
59+
60+
function randomDomain() {
61+
const d = Buffer.alloc(10);
62+
for (let i = 0; i < 10; i++)
63+
d[i] = 97 + (Math.round(Math.random() * 13247)) % 26;
64+
return d.toString();
65+
}

0 commit comments

Comments
 (0)