Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
tls: reduce memory overhead, reuse buffer
Browse files Browse the repository at this point in the history
Instead of allocating a new 64KB buffer each time when checking if there is
something to transform, continue to use the same buffer. Once the buffer is
exhausted, allocate a new buffer. This solves the problem of huge allocations
when small fragments of data are processed, but will also continue to work
well with big pieces of data.
  • Loading branch information
yosefd authored and bnoordhuis committed Mar 29, 2012
1 parent daa6b95 commit d7c96cf
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 7 deletions.
22 changes: 15 additions & 7 deletions lib/tls.js
Expand Up @@ -339,12 +339,18 @@ CryptoStream.prototype._push = function() {
}

while (!this._paused) {
var bytesRead = 0;
var chunkBytes = 0;
var pool = new Buffer(16 * 4096); // alloc every time?
if (!this._pool || (this._poolStart >= this._poolEnd)) {
this._pool = new Buffer(16 * 4096);
this._poolStart = 0;
this._poolEnd = this._pool.length;
}
var start = this._poolStart;

do {
chunkBytes = this._pusher(pool, bytesRead, pool.length - bytesRead);
chunkBytes = this._pusher(this._pool,
this._poolStart,
this._poolEnd - this._poolStart);

if (this.pair.ssl && this.pair.ssl.error) {
this.pair.error();
Expand All @@ -354,10 +360,12 @@ CryptoStream.prototype._push = function() {
this.pair.maybeInitFinished();

if (chunkBytes >= 0) {
bytesRead += chunkBytes;
this._poolStart += chunkBytes;
}

} while (chunkBytes > 0 && bytesRead < pool.length);
} while (chunkBytes > 0 && this._poolStart < this._poolEnd);

var bytesRead = this._poolStart - start;

assert(bytesRead >= 0);

Expand All @@ -369,7 +377,7 @@ CryptoStream.prototype._push = function() {
return;
}

var chunk = pool.slice(0, bytesRead);
var chunk = this._pool.slice(start, this._poolStart);

if (this === this.pair.cleartext) {
debug('cleartext emit "data" with ' + bytesRead + ' bytes');
Expand All @@ -385,7 +393,7 @@ CryptoStream.prototype._push = function() {
}

// Optimization: emit the original buffer with end points
if (this.ondata) this.ondata(pool, 0, bytesRead);
if (this.ondata) this.ondata(this._pool, start, this._poolStart);
}
};

Expand Down
63 changes: 63 additions & 0 deletions test/pummel/test-tls-fragmentation.js
@@ -0,0 +1,63 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

if (!process.versions.openssl) {
console.error('Skipping because node compiled without OpenSSL.');
process.exit(0);
}

var common = require('../common');
var assert = require('assert');
var tls = require('tls');
var fs = require('fs');
var path = require('path');

var options = {
key: fs.readFileSync(path.join(common.fixturesDir, 'test_key.pem')),
cert: fs.readFileSync(path.join(common.fixturesDir, 'test_cert.pem'))
};

var fragment = 'fr';
var dataSize = 1024 * 1024;
var sent = 0;
var received = 0;

var server = tls.createServer(options, function (stream) {
for (sent = 0; sent <= dataSize; sent += fragment.length) {
stream.write(fragment);
}
stream.end();
});

server.listen(common.PORT, function () {
var client = tls.connect(common.PORT, function () {
client.on('data', function (data) {
received += data.length;
});
client.on('end', function () {
server.close();
});
});
});

process.on('exit', function () {
assert.equal(sent, received);
});

0 comments on commit d7c96cf

Please sign in to comment.