summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2018-09-30 16:13:07 -0400
committerAnna Henningsen <anna@addaleax.net>2018-10-08 20:06:45 -0700
commite688fe6b7e60d3dd50f0aa922a1ab74d85cb39b5 (patch)
treeaa455d2514f6b98acbb40cc64d2d7b2bd6d9b446 /lib
parentc001ba65753f3eb41ecd8df3b013126593d95247 (diff)
downloadandroid-node-v8-e688fe6b7e60d3dd50f0aa922a1ab74d85cb39b5.tar.gz
android-node-v8-e688fe6b7e60d3dd50f0aa922a1ab74d85cb39b5.tar.bz2
android-node-v8-e688fe6b7e60d3dd50f0aa922a1ab74d85cb39b5.zip
zlib: simplify flushing mechanism
Previously, flushing on zlib streams was implemented through stream 'drain' handlers. This has a number of downsides; in particular, it is complex, and could lead to unpredictable behaviour, since it meant that in a sequence like ```js compressor.write('abc'); compressor.flush(); waitForMoreDataAsynchronously(() => { compressor.write('def'); }); ``` it was not fully deterministic whether the flush happens after the second chunk is written or the first one. This commit replaces this mechanism by one that piggy-backs along the stream’s write queue, using a “special” `Buffer` instance that signals that a flush is currently due. PR-URL: https://github.com/nodejs/node/pull/23186 Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/zlib.js48
1 files changed, 19 insertions, 29 deletions
diff --git a/lib/zlib.js b/lib/zlib.js
index 68d06fa93f..5d5ef3e083 100644
--- a/lib/zlib.js
+++ b/lib/zlib.js
@@ -311,10 +311,9 @@ function Zlib(opts, mode) {
this._level = level;
this._strategy = strategy;
this._chunkSize = chunkSize;
- this._flushFlag = flush;
- this._scheduledFlushFlag = Z_NO_FLUSH;
- this._origFlushFlag = flush;
+ this._defaultFlushFlag = flush;
this._finishFlushFlag = finishFlush;
+ this._nextFlush = -1;
this._info = opts && opts.info;
this.once('end', this.close);
}
@@ -398,6 +397,7 @@ function maxFlush(a, b) {
return flushiness[a] > flushiness[b] ? a : b;
}
+const flushBuffer = Buffer.alloc(0);
Zlib.prototype.flush = function flush(kind, callback) {
var ws = this._writableState;
@@ -412,21 +412,13 @@ Zlib.prototype.flush = function flush(kind, callback) {
} else if (ws.ending) {
if (callback)
this.once('end', callback);
- } else if (ws.needDrain) {
- const alreadyHadFlushScheduled = this._scheduledFlushFlag !== Z_NO_FLUSH;
- this._scheduledFlushFlag = maxFlush(kind, this._scheduledFlushFlag);
-
- // If a callback was passed, always register a new `drain` + flush handler,
- // mostly because that's simpler and flush callbacks piling up is a rare
- // thing anyway.
- if (!alreadyHadFlushScheduled || callback) {
- const drainHandler = () => this.flush(this._scheduledFlushFlag, callback);
- this.once('drain', drainHandler);
- }
+ } else if (this._nextFlush !== -1) {
+ // This means that there is a flush currently in the write queue.
+ // We currently coalesce this flush into the pending one.
+ this._nextFlush = maxFlush(this._nextFlush, kind);
} else {
- this._flushFlag = kind;
- this.write(Buffer.alloc(0), '', callback);
- this._scheduledFlushFlag = Z_NO_FLUSH;
+ this._nextFlush = kind;
+ this.write(flushBuffer, '', callback);
}
};
@@ -436,20 +428,18 @@ Zlib.prototype.close = function close(callback) {
};
Zlib.prototype._transform = function _transform(chunk, encoding, cb) {
- // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag
- // (or whatever flag was provided using opts.finishFlush).
- // If it's explicitly flushing at some other time, then we use
- // Z_FULL_FLUSH. Otherwise, use the original opts.flush flag.
- var flushFlag;
+ var flushFlag = this._defaultFlushFlag;
+ // We use a 'fake' zero-length chunk to carry information about flushes from
+ // the public API to the actual stream implementation.
+ if (chunk === flushBuffer) {
+ flushFlag = this._nextFlush;
+ this._nextFlush = -1;
+ }
+
+ // For the last chunk, also apply `_finishFlushFlag`.
var ws = this._writableState;
if ((ws.ending || ws.ended) && ws.length === chunk.byteLength) {
- flushFlag = this._finishFlushFlag;
- } else {
- flushFlag = this._flushFlag;
- // once we've flushed the last of the queue, stop flushing and
- // go back to the normal behavior.
- if (chunk.byteLength >= ws.length)
- this._flushFlag = this._origFlushFlag;
+ flushFlag = maxFlush(flushFlag, this._finishFlushFlag);
}
processChunk(this, chunk, flushFlag, cb);
};