From b8460d033e67584961182a48327d7d5bb1f7fb54 Mon Sep 17 00:00:00 2001 From: Raul Ochoa Date: Tue, 8 Mar 2016 14:48:56 +0100 Subject: [PATCH] Add a cache decorator over QueryTables --- app/app.js | 2 +- app/controllers/query_controller.js | 7 +++--- app/services/cached-query-tables.js | 38 +++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 app/services/cached-query-tables.js diff --git a/app/app.js b/app/app.js index 1f44b399..5b05e4be 100644 --- a/app/app.js +++ b/app/app.js @@ -188,7 +188,7 @@ function App() { var genericController = new GenericController(); genericController.route(app); - var queryController = new QueryController(userDatabaseService, statsd_client); + var queryController = new QueryController(userDatabaseService, tableCache, statsd_client); queryController.route(app); var jobController = new JobController(userDatabaseService, jobBackend, jobCanceller); diff --git a/app/controllers/query_controller.js b/app/controllers/query_controller.js index 661ac0d7..32e3a032 100644 --- a/app/controllers/query_controller.js +++ b/app/controllers/query_controller.js @@ -4,7 +4,7 @@ var _ = require('underscore'); var step = require('step'); var assert = require('assert'); var PSQL = require('cartodb-psql'); -var QueryTables = require('cartodb-query-tables'); +var CachedQueryTables = require('../services/cached-query-tables'); var AuthApi = require('../auth/auth_api'); var queryMayWrite = require('../utils/query_may_write'); @@ -19,9 +19,10 @@ var ONE_YEAR_IN_SECONDS = 31536000; // 1 year time to live by default var cdbReq = new CdbRequest(); -function QueryController(userDatabaseService, statsd_client) { +function QueryController(userDatabaseService, tableCache, statsd_client) { this.statsd_client = statsd_client; this.userDatabaseService = userDatabaseService; + this.queryTables = new CachedQueryTables(tableCache); } QueryController.prototype.route = function (app) { @@ -136,7 +137,7 @@ QueryController.prototype.handleQuery = function (req, res) { var pg = new PSQL(authDbParams, {}, { destroyOnError: true }); - QueryTables.getAffectedTablesFromQuery(pg, sql, function(err, result) { + self.queryTables.getAffectedTablesFromQuery(pg, sql, function(err, result) { if (err) { var errorMessage = (err && err.message) || 'unknown error'; console.error("Error on query explain '%s': %s", sql, errorMessage); diff --git a/app/services/cached-query-tables.js b/app/services/cached-query-tables.js new file mode 100644 index 00000000..760c5c32 --- /dev/null +++ b/app/services/cached-query-tables.js @@ -0,0 +1,38 @@ +var QueryTables = require('cartodb-query-tables'); + +var generateMD5 = require('../utils/md5'); + +function CachedQueryTables(tableCache) { + this.tableCache = tableCache; +} + +module.exports = CachedQueryTables; + +CachedQueryTables.prototype.getAffectedTablesFromQuery = function(pg, sql, callback) { + var self = this; + + var cacheKey = sqlCacheKey(pg.username(), sql); + var cachedResult = this.tableCache.get(cacheKey); + + if (cachedResult) { + cachedResult.hits++; + return callback(null, cachedResult.result); + } else { + QueryTables.getAffectedTablesFromQuery(pg, sql, function(err, result) { + if (err) { + return callback(err); + } + + self.tableCache.set(cacheKey, { + result: result, + hits: 1 + }); + + return callback(null, result); + }); + } +}; + +function sqlCacheKey(user, sql) { + return user + ':' + generateMD5(sql); +}