Browse Source

tls: reduce memory overhead, reuse buffer

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.
v0.9.1-release
Yosef Dinerstein 13 years ago
committed by Ben Noordhuis
parent
commit
d7c96cf289
  1. 22
      lib/tls.js
  2. 63
      test/pummel/test-tls-fragmentation.js

22
lib/tls.js

@ -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();
@ -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);
@ -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');
@ -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);
}
};

63
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);
});
Loading…
Cancel
Save