From d702c72eb611c4b056b33f3ff7778b3a83a2a0b2 Mon Sep 17 00:00:00 2001 From: Sushant Date: Sat, 17 Sep 2016 12:47:29 +0530 Subject: [PATCH 1/5] added lru cache for statements --- lib/commands/change_user.js | 2 +- lib/connection.js | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/commands/change_user.js b/lib/commands/change_user.js index 7e56bed28a..9edadab4f8 100644 --- a/lib/commands/change_user.js +++ b/lib/commands/change_user.js @@ -37,7 +37,7 @@ ChangeUser.prototype.start = function (packet, connection) { this.currentConfig.database = this.database; this.currentConfig.charsetNumber = this.charsetNumber; // reset prepared statements cache as all statements become invalid after changeUser - connection._statements = {}; + connection._statements.reset(); connection.writePacket(packet.toPacket()); return ChangeUser.prototype.handshakeResult; }; diff --git a/lib/connection.js b/lib/connection.js index 5b99977d14..32c42dc85a 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -4,8 +4,8 @@ var Tls = require('tls'); var Timers = require('timers'); var EventEmitter = require('events').EventEmitter; var Queue = require('double-ended-queue'); - var SqlString = require('sqlstring'); +var LRU = require('lru-cache'); var PacketParser = require('./packet_parser.js'); var Packet = require('./packets/packet.js'); @@ -51,7 +51,10 @@ function Connection (opts) this._paused = false; this._paused_packets = new Queue(); - this._statements = {}; + this._statements = LRU({ + max: 1000, + dispose: function (key, statement) { statement.close(); } + }); // TODO: make it lru cache // https://github.com/mercadolibre/node-simple-lru-cache @@ -498,9 +501,9 @@ Connection.prototype.unprepare = function unprepare (sql) { options.sql = sql; } var key = statementKey(options); - var stmt = this._statements[key]; + var stmt = this._statements.get(key); if (stmt) { - this._statements[key] = null; + this._statements.del(key); stmt.close(); } return stmt; @@ -531,7 +534,7 @@ Connection.prototype.execute = function execute (sql, values, cb) { var connection = this; var key = statementKey(options); - var statement = connection._statements[key]; + var statement = connection._statements.get(key); options.statement = statement; var executeCommand = new Commands.Execute(options, cb); @@ -547,7 +550,7 @@ Connection.prototype.execute = function execute (sql, values, cb) { return; } executeCommand.statement = stmt; - connection._statements[key] = stmt; + connection._statements.set(key, stmt); connection.addCommand(executeCommand); }); } else { From 16d14532bd6f84e517323ca7009ebfe966c5e16b Mon Sep 17 00:00:00 2001 From: Sushant Date: Sat, 17 Sep 2016 12:52:31 +0530 Subject: [PATCH 2/5] added option to override max prepared statements cache --- lib/connection.js | 2 +- lib/connection_config.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/connection.js b/lib/connection.js index 32c42dc85a..5dd1869edf 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -52,7 +52,7 @@ function Connection (opts) this._paused_packets = new Queue(); this._statements = LRU({ - max: 1000, + max: this.config.maxPreparedStatements, dispose: function (key, statement) { statement.close(); } }); diff --git a/lib/connection_config.js b/lib/connection_config.js index 70cc25c23f..d36a43401e 100644 --- a/lib/connection_config.js +++ b/lib/connection_config.js @@ -70,6 +70,7 @@ function ConnectionConfig (options) { options.flags || ''); this.connectAttributes = options.connectAttributes; + this.maxPreparedStatements = options.maxPreparedStatements || 16000; } ConnectionConfig.mergeFlags = function (default_flags, user_flags) { From b679e3bb75be5a243f68109ccebf8cc0f1db61f6 Mon Sep 17 00:00:00 2001 From: Sushant Date: Sat, 17 Sep 2016 13:06:59 +0530 Subject: [PATCH 3/5] fixed test cases to use lru --- test/integration/connection/test-execute-cached.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/integration/connection/test-execute-cached.js b/test/integration/connection/test-execute-cached.js index 03e19203e3..09c10d6d27 100644 --- a/test/integration/connection/test-execute-cached.js +++ b/test/integration/connection/test-execute-cached.js @@ -24,9 +24,9 @@ connection.execute(q, [123], function (err, _rows, _fields) { throw err; } rows2 = _rows; - assert(Object.keys(connection._statements).length == 1); - assert(connection._statements[key].query == q); - assert(connection._statements[key].parameters.length == 1); + assert(connection._statements.length == 1); + assert(connection._statements.get(key).query == q); + assert(connection._statements.get(key).parameters.length == 1); connection.end(); }); }); @@ -38,4 +38,3 @@ process.on('exit', function () { assert.deepEqual(rows1, [{'test': 125}]); assert.deepEqual(rows2, [{'test': 126}]); }); - From 1b8aed2561fb658325454b5b188d5aa36a45d638 Mon Sep 17 00:00:00 2001 From: Sushant Date: Sat, 17 Sep 2016 14:16:35 +0530 Subject: [PATCH 4/5] package.json entry --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 2542e08315..b68b661204 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "double-ended-queue": "2.1.0-0", "iconv-lite": "^0.4.13", "long": "^3.2.0", + "lru-cache": "^4.0.1", "named-placeholders": "1.1.1", "object-assign": "^4.1.0", "readable-stream": "2.1.5", From 1f4e73bbc9f75a2933f1f36d8d5e217915f60d48 Mon Sep 17 00:00:00 2001 From: Sushant Date: Sat, 17 Sep 2016 14:31:19 +0530 Subject: [PATCH 5/5] [ci skip] maxPreparedStatements docs --- documentation/Prepared-Statements.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/documentation/Prepared-Statements.md b/documentation/Prepared-Statements.md index 72cb97bc35..2629ce3eef 100644 --- a/documentation/Prepared-Statements.md +++ b/documentation/Prepared-Statements.md @@ -32,3 +32,7 @@ connection.prepare('select ? + ? as tests', function(err, statement) { }); ``` Note that you should not use statement after connection reset (`changeUser()` or disconnect). Statement scope is connection, you need to prepare statement for each new connection in order to use it. + +# Configuration + +`maxPreparedStatements` : We keep the cached statements in a [lru-cache](https://github.com/isaacs/node-lru-cache). Default size is `16000` but you can use this option to override it. Any statements that are dropped from cache will be `closed`.