Skip to content

Commit 9208c89

Browse files
committed
stream: Raise readable high water mark in powers of 2
This prevents excessively raising the buffer level in tiny increments in pathological cases.
1 parent a978bed commit 9208c89

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

lib/_stream_readable.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,19 @@ Readable.prototype.setEncoding = function(enc) {
161161
this._readableState.decoder = new StringDecoder(enc);
162162
};
163163

164+
// Don't raise the hwm > 128MB
165+
var MAX_HWM = 0x800000;
166+
function roundUpToNextPowerOf2(n) {
167+
if (n >= MAX_HWM) {
168+
n = MAX_HWM;
169+
} else {
170+
// Get the next highest power of 2
171+
n--;
172+
for (var p = 1; p < 32; p <<= 1) n |= n >> p;
173+
n++;
174+
}
175+
return n;
176+
}
164177

165178
function howMuchToRead(n, state) {
166179
if (state.length === 0 && state.ended)
@@ -181,9 +194,11 @@ function howMuchToRead(n, state) {
181194
return 0;
182195

183196
// If we're asking for more than the target buffer level,
184-
// then raise the water mark.
197+
// then raise the water mark. Bump up to the next highest
198+
// power of 2, to prevent increasing it excessively in tiny
199+
// amounts.
185200
if (n > state.highWaterMark)
186-
state.highWaterMark = n;
201+
state.highWaterMark = roundUpToNextPowerOf2(n);
187202

188203
// don't have that much. return null, unless we've ended.
189204
if (n > state.length) {

test/simple/test-stream-readable-flow-recursion.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,15 @@ process.throwDeprecation = true;
3434

3535
var stream = new Readable({ highWaterMark: 2 });
3636
var reads = 0;
37+
var total = 5000;
3738
stream._read = function(size) {
3839
reads++;
39-
stream.push(new Buffer(size));
40+
size = Math.min(size, total);
41+
total -= size;
42+
if (size === 0)
43+
stream.push(null);
44+
else
45+
stream.push(new Buffer(size));
4046
};
4147

4248
var depth = 0;
@@ -61,8 +67,9 @@ flow(stream, 5000, function() {
6167
process.on('exit', function(code) {
6268
assert.equal(reads, 2);
6369
// we pushed up the high water mark
64-
assert.equal(stream._readableState.highWaterMark, 5000);
65-
assert.equal(stream._readableState.length, 5000);
70+
assert.equal(stream._readableState.highWaterMark, 8192);
71+
// length is 0 right now, because we pulled it all out.
72+
assert.equal(stream._readableState.length, 0);
6673
assert(!code);
6774
assert.equal(depth, 0);
6875
console.log('ok');

0 commit comments

Comments
 (0)