add explain cache and cache status route
This commit is contained in:
parent
977f7d0e79
commit
7e074bbc98
@ -20,17 +20,23 @@ var express = require('express')
|
|||||||
}))
|
}))
|
||||||
, Step = require('step')
|
, Step = require('step')
|
||||||
, csv = require('csv')
|
, csv = require('csv')
|
||||||
|
, crypto = require('crypto')
|
||||||
, Meta = require(global.settings.app_root + '/app/models/metadata')
|
, Meta = require(global.settings.app_root + '/app/models/metadata')
|
||||||
, oAuth = require(global.settings.app_root + '/app/models/oauth')
|
, oAuth = require(global.settings.app_root + '/app/models/oauth')
|
||||||
, PSQL = require(global.settings.app_root + '/app/models/psql')
|
, PSQL = require(global.settings.app_root + '/app/models/psql')
|
||||||
, ApiKeyAuth = require(global.settings.app_root + '/app/models/apikey_auth')
|
, ApiKeyAuth = require(global.settings.app_root + '/app/models/apikey_auth')
|
||||||
, _ = require('underscore');
|
, _ = require('underscore')
|
||||||
|
, tableCache = {};
|
||||||
|
|
||||||
app.use(express.bodyParser());
|
app.use(express.bodyParser());
|
||||||
app.enable('jsonp callback');
|
app.enable('jsonp callback');
|
||||||
|
|
||||||
|
// basic routing
|
||||||
app.all('/api/v1/sql', function(req, res) { handleQuery(req, res) } );
|
app.all('/api/v1/sql', function(req, res) { handleQuery(req, res) } );
|
||||||
app.all('/api/v1/sql.:f', function(req, res) { handleQuery(req, res) } );
|
app.all('/api/v1/sql.:f', function(req, res) { handleQuery(req, res) } );
|
||||||
|
app.get('/api/v1/cachestatus', function(req, res) { handleCacheStatus(req, res) } );
|
||||||
|
|
||||||
|
// request handlers
|
||||||
function handleQuery(req, res){
|
function handleQuery(req, res){
|
||||||
|
|
||||||
// sanitize input
|
// sanitize input
|
||||||
@ -54,6 +60,9 @@ function handleQuery(req, res){
|
|||||||
// setup step run
|
// setup step run
|
||||||
var start = new Date().getTime();
|
var start = new Date().getTime();
|
||||||
|
|
||||||
|
// initialise MD5 key of sql for cache lookups
|
||||||
|
var sql_md5 = generateMD5(sql);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!_.isString(sql)) throw new Error("You must indicate a sql query");
|
if (!_.isString(sql)) throw new Error("You must indicate a sql query");
|
||||||
var pg, explain_result;
|
var pg, explain_result;
|
||||||
@ -81,14 +90,23 @@ function handleQuery(req, res){
|
|||||||
// store postgres connection
|
// store postgres connection
|
||||||
pg = new PSQL(user_id, database, limit, offset);
|
pg = new PSQL(user_id, database, limit, offset);
|
||||||
|
|
||||||
// get all the tables
|
// get all the tables from Cache or SQL
|
||||||
|
|
||||||
|
if (!_.isNull(tableCache[sql_md5]) && !_.isUndefined(tableCache[sql_md5])){
|
||||||
|
tableCache[sql_md5].hits++;
|
||||||
|
return true;
|
||||||
|
} else{
|
||||||
pg.query("SELECT CDB_QueryTables($$" + sql + "$$)", this);
|
pg.query("SELECT CDB_QueryTables($$" + sql + "$$)", this);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
function queryResult(err, result){
|
function queryResult(err, result){
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
// store explain result
|
// store explain result in local Cache
|
||||||
explain_result = result;
|
if (_.isUndefined(tableCache[sql_md5])){
|
||||||
|
tableCache[sql_md5] = result;
|
||||||
|
tableCache[sql_md5].hits = 1; //initialise hit counter
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: refactor formats to external object
|
// TODO: refactor formats to external object
|
||||||
if (format === 'geojson'){
|
if (format === 'geojson'){
|
||||||
@ -110,7 +128,7 @@ function handleQuery(req, res){
|
|||||||
// set cache headers
|
// set cache headers
|
||||||
res.header('Last-Modified', new Date().toUTCString());
|
res.header('Last-Modified', new Date().toUTCString());
|
||||||
res.header('Cache-Control', 'no-cache,max-age=3600,must-revalidate, public');
|
res.header('Cache-Control', 'no-cache,max-age=3600,must-revalidate, public');
|
||||||
res.header('X-Cache-Channel', generateCacheKey(database,explain_result));
|
res.header('X-Cache-Channel', generateCacheKey(database, tableCache[sql_md5]));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
@ -147,6 +165,15 @@ function handleQuery(req, res){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCacheStatus(req, res){
|
||||||
|
var tableCacheValues = _.values(tableCache);
|
||||||
|
var totalExplainHits = _.reduce(tableCacheValues, function(memo, res) { return memo + res.hits}, 0);
|
||||||
|
var totalExplainKeys = tableCacheValues.length;
|
||||||
|
|
||||||
|
res.send({explain: {hits: totalExplainHits, keys : totalExplainKeys }});
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper functions
|
||||||
function toGeoJSON(data, res, callback){
|
function toGeoJSON(data, res, callback){
|
||||||
try{
|
try{
|
||||||
var out = {
|
var out = {
|
||||||
@ -218,6 +245,12 @@ function generateCacheKey(database,tables){
|
|||||||
return database + ":" + tables.rows[0].cdb_querytables.split(/^\{(.*)\}$/)[1];
|
return database + ":" + tables.rows[0].cdb_querytables.split(/^\{(.*)\}$/)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateMD5(data){
|
||||||
|
var hash = crypto.createHash('md5');
|
||||||
|
hash.update(data);
|
||||||
|
return hash.digest('hex');
|
||||||
|
}
|
||||||
|
|
||||||
function handleException(err, res){
|
function handleException(err, res){
|
||||||
var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
|
var msg = (global.settings.environment == 'development') ? {error:[err.message], stack: err.stack} : {error:[err.message]}
|
||||||
if (global.settings.environment !== 'test'){
|
if (global.settings.environment !== 'test'){
|
||||||
|
Loading…
Reference in New Issue
Block a user