Skip to content

Commit

Permalink
stream: do not unconditionally call _read() on resume()
Browse files Browse the repository at this point in the history
`readable.resume()` calls `.read(0)`, which in turn previously set
`needReadable = true`, and so a subsequent `.read()` call would
call `_read()` even though enough data was already available.

This can lead to elevated memory usage, because calling `_read()`
when enough data is in the readable buffer means that backpressure
is not being honoured.

Fixes: #26957

PR-URL: #26965
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Signed-off-by: Beth Griggs <Bethany.Griggs@uk.ibm.com>
  • Loading branch information
addaleax authored and BethGriggs committed Apr 9, 2019
1 parent 3c92926 commit ea47189
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/_stream_readable.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ Readable.prototype.read = function(n) {
ret = null;

if (ret === null) {
state.needReadable = true;
state.needReadable = state.length <= state.highWaterMark;
n = 0;
} else {
state.length -= n;
Expand Down
21 changes: 21 additions & 0 deletions test/parallel/test-stream-readable-resume-hwm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';
const common = require('../common');
const { Readable } = require('stream');

// readable.resume() should not lead to a ._read() call being scheduled
// when we exceed the high water mark already.

const readable = new Readable({
read: common.mustNotCall(),
highWaterMark: 100
});

// Fill up the internal buffer so that we definitely exceed the HWM:
for (let i = 0; i < 10; i++)
readable.push('a'.repeat(200));

// Call resume, and pause after one chunk.
// The .pause() is just so that we don’t empty the buffer fully, which would
// be a valid reason to call ._read().
readable.resume();
readable.once('data', common.mustCall(() => readable.pause()));

0 comments on commit ea47189

Please sign in to comment.