Skip to content

Commit

Permalink
http: batch writes together more efficiently
Browse files Browse the repository at this point in the history
This commit opts for a simpler way to batch writes to HTTP clients into
fewer packets. Instead of the complicated snafu which was before, now
OutgoingMessage#write automatically corks the socket and uncorks on the
next tick, allowing streams to batch them efficiently. It also makes the
code cleaner and removes an ugly-ish hack.

Fixes: nodejs#7914
  • Loading branch information
brendanashworth authored and jbergstroem committed Oct 7, 2016
1 parent b2534f1 commit 2e9d9c1
Showing 1 changed file with 19 additions and 23 deletions.
42 changes: 19 additions & 23 deletions lib/_http_outgoing.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,35 +112,29 @@ OutgoingMessage.prototype.setTimeout = function(msecs, callback) {
// any messages, before ever calling this. In that case, just skip
// it, since something else is destroying this connection anyway.
OutgoingMessage.prototype.destroy = function(error) {
if (this.socket)
if (this.socket) {
// If the socket is corked from a write, uncork it before destroying it.
if (this.socket._writableState.corked)
this.socket.uncork();

this.socket.destroy(error);
else
} else {
this.once('socket', function(socket) {
socket.destroy(error);
});
}
};


// This abstract either writing directly to the socket or buffering it.
OutgoingMessage.prototype._send = function(data, encoding, callback) {
// This is a shameful hack to get the headers and first body chunk onto
// the same packet. Future versions of Node are going to take care of
// this at a lower level and in a more general way.
// Send the headers before the body. OutgoingMessage#write should cork
// the stream before calling #_send, batching them in the same packet.
if (!this._headerSent) {
if (typeof data === 'string' &&
encoding !== 'hex' &&
encoding !== 'base64') {
data = this._header + data;
} else {
this.output.unshift(this._header);
this.outputEncodings.unshift('latin1');
this.outputCallbacks.unshift(null);
this.outputSize += this._header.length;
if (typeof this._onPendingData === 'function')
this._onPendingData(this._header.length);
}
this._writeRaw(this._header, 'latin1', null);
this._headerSent = true;
}

return this._writeRaw(data, encoding, callback);
};

Expand Down Expand Up @@ -461,6 +455,13 @@ OutgoingMessage.prototype.write = function(chunk, encoding, callback) {
// signal the user to keep writing.
if (chunk.length === 0) return true;

// By corking the socket and uncorking after a tick, we manage to
// batch writes together, i.e. the header with the body.
if (this.connection) {
this.connection.cork();
process.nextTick(connectionCorkNT, this.connection);
}

var len, ret;
if (this.chunkedEncoding) {
if (typeof chunk === 'string' &&
Expand All @@ -477,10 +478,6 @@ OutgoingMessage.prototype.write = function(chunk, encoding, callback) {
else
len = chunk.length;

if (this.connection && !this.connection.corked) {
this.connection.cork();
process.nextTick(connectionCorkNT, this.connection);
}
this._send(len.toString(16), 'latin1', null);
this._send(crlf_buf, null, null);
this._send(chunk, encoding, null);
Expand Down Expand Up @@ -670,12 +667,11 @@ OutgoingMessage.prototype._flushOutput = function _flushOutput(socket) {
var output = this.output;
var outputEncodings = this.outputEncodings;
var outputCallbacks = this.outputCallbacks;
socket.cork();

for (var i = 0; i < outputLength; i++) {
ret = socket.write(output[i], outputEncodings[i],
outputCallbacks[i]);
}
socket.uncork();

this.output = [];
this.outputEncodings = [];
Expand Down

0 comments on commit 2e9d9c1

Please sign in to comment.