Browse Source

[net2] inline write on empty write buffer for performance

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
90295d9fce
  1. 83
      lib/net.js
  2. 3
      test/simple/test-net-pingpong.js

83
lib/net.js

@ -501,6 +501,83 @@ Stream.prototype.write = function (data, encoding) {
if (!self.writable) throw new Error('Stream is not writable');
if (self._writeQueue && self._writeQueue.length) {
return self._writeQueued(data, encoding); // slow
} else {
// The most common case. There is no write queue. Just push the data
// directly to the socket.
var bytesWritten;
var buffer = data, off = 0, len = data.length;
if (typeof data == 'string') {
encoding = (encoding || 'utf8').toLowerCase();
var bytes = encoding == 'utf8' ? Buffer.utf8ByteLength(data) : data.length;
//debug('write string :' + JSON.stringify(data));
if (!recvBuffer) allocRecvBuffer();
if (recvBuffer.length - recvBuffer.used < bytes) {
// not enough room - go to slow case
return self._writeQueued(data, encoding);
}
var charsWritten;
if (encoding == 'utf8') {
recvBuffer.utf8Write(data, recvBuffer.used);
} else {
// ascii
recvBuffer.asciiWrite(data, recvBuffer.used);
}
buffer = recvBuffer;
off = recvBuffer.used;
len = bytes;
}
//debug('write [fd, off, len] =' + JSON.stringify([self.fd, off, len]));
// Send the buffer.
try {
bytesWritten = write(self.fd, buffer, off, len);
} catch (e) {
self.forceClose(e);
return false;
}
//debug('wrote ' + bytesWritten);
// Note: if using the recvBuffer - we don't need to increase
// recvBuffer.used because it was all sent. Just reuse that space.
if (bytesWritten == len) return true;
//debug('write incomplete ' + bytesWritten + ' < ' + len);
if (buffer == data) {
data.sent = bytesWritten || 0;
data.used = data.length;
} else {
// string
recvBuffer.used += bytesWritten;
data = recvBuffer.slice(off+bytesWritten, off+len+bytesWritten);
data.sent = 0;
data.used = data.length;
}
//if (!self._writeQueue) initWriteStream(self);
self._writeQueue.push(data);
self._writeQueueSize += data.used;
return false;
}
}
Stream.prototype._writeQueued = function (data, encoding) {
//debug('_writeQueued');
var self = this;
if (self.__writeQueueLast() == END_OF_FILE) {
throw new Error('socket.close() called already; cannot write.');
}
@ -597,7 +674,7 @@ Stream.prototype.flush = function () {
} else {
b.sent += bytesWritten;
self._writeQueueSize -= bytesWritten;
debug('bytes sent: ' + b.sent);
//debug('bytes sent: ' + b.sent);
}
}
if (self._writeWatcher) self._writeWatcher.stop();
@ -654,7 +731,7 @@ Stream.prototype.connect = function () {
if (port >= 0) {
self.fd = socket('tcp');
debug('new fd = ' + self.fd);
//debug('new fd = ' + self.fd);
self.type = 'tcp';
// TODO dns resolution on arguments[1]
var port = arguments[0];
@ -726,7 +803,7 @@ Stream.prototype.forceClose = function (exception) {
// FIXME Bug when this.fd == 0
if (this.fd) {
close(this.fd);
debug('close ' + this.fd);
//debug('close ' + this.fd);
this.fd = null;
process.nextTick(function () {
if (exception) self.emit('error', exception);

3
test/simple/test-net-pingpong.js

@ -20,6 +20,7 @@ function pingPongTest (port, host) {
socket.setNoDelay();
socket.timeout = 0;
socket.setEncoding('utf8');
socket.addListener("data", function (data) {
puts("server got: " + data);
assert.equal(true, socket.writable);
@ -53,6 +54,7 @@ function pingPongTest (port, host) {
var client = net.createConnection(port, host);
client.setEncoding('ascii');
client.addListener("connect", function () {
assert.equal(true, client.readable);
assert.equal(true, client.writable);
@ -106,4 +108,5 @@ pingPongTest("/tmp/pingpong.sock");
process.addListener("exit", function () {
assert.equal(4, tests_run);
puts('done');
});

Loading…
Cancel
Save