From 8025de6b3ba059d3e52728827fc58b147ffbf523 Mon Sep 17 00:00:00 2001 From: Thomas FORGIONE Date: Mon, 28 Sep 2015 15:14:59 +0200 Subject: [PATCH] Improved database perf Transfarring some of the computations to the server. Things seem to work now. --- controllers/prototype/dbrequests.js | 127 +++++++++++++++++++--------- controllers/prototype/index.js | 23 ++++- load.js | 10 +-- 3 files changed, 112 insertions(+), 48 deletions(-) diff --git a/controllers/prototype/dbrequests.js b/controllers/prototype/dbrequests.js index e83bb4a..3bb0dc8 100644 --- a/controllers/prototype/dbrequests.js +++ b/controllers/prototype/dbrequests.js @@ -553,9 +553,10 @@ DBReq.UserCreator.prototype.finish = function() { * @memberof DBReq * @constructor */ -DBReq.ExpCreator = function(userId, finishAction) { +DBReq.ExpCreator = function(userId, experiments, finishAction) { this.finishAction = finishAction; this.userId = userId; + this.experiments = experiments; this.finalResult = {}; // Connect to db @@ -574,6 +575,20 @@ DBReq.ExpCreator = function(userId, finishAction) { }); }; +function predicate(line) { + + return function(elt, idx, arr) { + + console.log(elt.recommendationStyle, line.recommendationStyle); + return ( + elt.recommendationStyle.trim() === line.recommendationStyle.trim() || + line.id === elt.coinCombinationId + ); + + }; + +} + /** * Executes the SQL request and calls the callback */ @@ -582,7 +597,7 @@ DBReq.ExpCreator.prototype.execute = function() { var self = this; this.client.query( "SELECT DISTINCT \n" + - " RecommendationStyle.name, \n" + + " RecommendationStyle.name AS \"recommendationStyle\", \n" + " CoinCombination.scene_id AS \"sceneId\", \n" + " CoinCombination.id, \n" + " coin_1 AS coin1, \n" + @@ -601,47 +616,68 @@ DBReq.ExpCreator.prototype.execute = function() { " Other.id = Experiment.user_id AND\n" + " Other.rating = U.rating AND\n" + " Other.id != U.id AND\n" + - " U.id = $1 AND\n" + - " RecommendationStyle.name NOT IN (\n" + - " SELECT DISTINCT Experiment.recommendation_style\n" + - " FROM CoinCombination, Experiment, Users U, Users Other\n" + - " WHERE\n" + - " CoinCombination.id = Experiment.coin_combination_id AND\n" + - " Other.id = Experiment.user_id AND\n" + - " Other.rating = U.rating AND\n" + - " Other.id != U.id AND\n" + - " CoinCombination.scene_id = Scene.id\n" + - " ) AND\n" + - " RecommendationStyle.name NOT IN (\n" + - " SELECT DISTINCT Experiment.recommendation_style\n" + - " FROM Experiment\n" + - " WHERE Experiment.user_id = $1 AND Experiment.recommendation_style != ''\n" + - " ) AND\n" + - " CoinCombination.scene_id NOT IN (\n" + - " SELECT DISTINCT scene_id\n" + - " FROM Experiment, CoinCombination\n" + - " WHERE Experiment.coin_combination_id = CoinCombination.id AND Experiment.user_id = $1\n" + - " )\n" + - "LIMIT 1;", + " U.id = $1 \n" + + "EXCEPT \n" + + "SELECT DISTINCT \n" + + " Experiment.recommendation_style AS \"recommendationStyle\", \n" + + " CoinCombination.scene_id AS \"sceneId\", \n" + + " CoinCombination.id, \n" + + " coin_1 AS coin1, \n" + + " coin_2 AS coin2, \n" + + " coin_3 AS coin3, \n" + + " coin_4 AS coin4, \n" + + " coin_5 AS coin5, \n" + + " coin_6 AS coin6, \n" + + " coin_7 AS coin7, \n" + + " coin_8 AS coin8\n" + + "FROM CoinCombination, Experiment\n" + + "WHERE\n" + + " CoinCombination.id = Experiment.coin_combination_id;", [self.userId], function(err, result) { if (err !== null) { Log.dberror(err + ' in ExpCreator first request'); } - if (result.rows.length > 0) { + + var line, found = false; + + while ((line = result.rows.shift()) !== undefined) { + + if (line === undefined) { + + break; + + } + + // Look for an experiment impossible + var elt = self.experiments.find(predicate(line)); + + // console.log(elt); + + // Line is a valid experiment + if (elt === undefined) { + + found = true; + break; + + } + + } + + if (found) { // Set the result - self.finalResult.coinCombinationId = result.rows[0].id; - self.finalResult.sceneId = result.rows[0].sceneId; - self.finalResult.recommendationStyle = result.rows[0].name; + self.finalResult.coinCombinationId = line.id; + self.finalResult.sceneId = line.sceneId; + self.finalResult.recommendationStyle = line.recommendationStyle; self.finalResult.coins = [ - result.rows[0].coin1, - result.rows[0].coin2, - result.rows[0].coin3, - result.rows[0].coin4, - result.rows[0].coin5, - result.rows[0].coin6, - result.rows[0].coin7, - result.rows[0].coin8 + line.coin1, + line.coin2, + line.coin3, + line.coin4, + line.coin5, + line.coin6, + line.coin7, + line.coin8 ]; // There is a suggested experiment : create it @@ -649,7 +685,7 @@ DBReq.ExpCreator.prototype.execute = function() { "INSERT INTO Experiment(user_id, coin_combination_id, recommendation_style)\n" + "VALUES($1,$2,$3)\n" + "RETURNING id", - [self.userId, result.rows[0].id, result.rows[0].name], + [self.userId, line.id, line.recommendationStyle], function(err, result) { if (err !== null) { Log.dberror(err + ' in ExpCreator second request (with suggested experiment)'); @@ -950,7 +986,8 @@ DBReq.LastExpGetter.prototype.execute = function() { ' coin_6, \n' + ' coin_7, \n' + ' coin_8, \n' + - ' Experiment.recommendation_style AS "recommendationStyle" \n' + + ' Experiment.recommendation_style AS "recommendationStyle", \n' + + ' CoinCombination.id as "coinCombinationId" \n' + 'FROM Experiment, CoinCombination \n' + 'WHERE Experiment.coin_combination_id = CoinCombination.id \n' + ' AND Experiment.user_id = $1 \n' + @@ -970,6 +1007,7 @@ DBReq.LastExpGetter.prototype.execute = function() { result.rows[0].coin_7, result.rows[0].coin_8 ]; + self.finalResult.coinCombinationId = result.rows[0].coinCombinationId; self.finish(); } ); @@ -980,8 +1018,13 @@ DBReq.LastExpGetter.prototype.finish = function() { this.client = null; this.release = null; - this.finishAction(this.finalResult.sceneId, this.finalResult.recommendationStyle, this.finalResult.coins); -} + this.finishAction( + this.finalResult.sceneId, + this.finalResult.coinCombinationId, + this.finalResult.recommendationStyle, + this.finalResult.coins + ); +}; /** * Class that gets the info from all experiment @@ -1152,8 +1195,8 @@ DBReq.createUser = function(workerId, age, male, rating, lastTime, callback) { * @param sceneId {Number} id of the scene on which the experiment is * @param callback {function} callback called on the new experiment id */ -DBReq.createExp = function(id, callback) { - new DBReq.ExpCreator(id, callback); +DBReq.createExp = function(id, experiments, callback) { + new DBReq.ExpCreator(id, experiments, callback); }; DBReq.createTutorial = function(id, callback) { diff --git a/controllers/prototype/index.js b/controllers/prototype/index.js index 42de5ee..c0defdb 100644 --- a/controllers/prototype/index.js +++ b/controllers/prototype/index.js @@ -26,12 +26,16 @@ var sceneToFunction = function(scene) { module.exports.game = function(req, res) { + req.session.experiments = req.session.experiments || []; + req.session.save(); + db.checkUserId(req.session.userId, function(ok) { if (ok) { db.createExp( req.session.userId, + req.session.experiments, function(expId, coinCombinationId, sceneId, recommendationStyle, coins) { // if (expId === undefined) { @@ -73,12 +77,22 @@ module.exports.play = function(req, res) { } - db.getLastExp(req.session.userId, function(sceneId, recoStyle, coins) { + req.session.experiments = req.session.experiments || []; + + db.getLastExp(req.session.userId, function(sceneId, coinId, recoStyle, coins) { res.locals.scene = sceneToFunction(sceneId); res.locals.recommendationStyle= recoStyle; res.locals.coins = coins; + req.session.experiments.push({ + sceneId: sceneId, + recommendationStyle: recoStyle, + coinCombinationId : coinId + }); + + req.session.save(); + // Prepare next experiment module.exports.game(req, null); @@ -113,6 +127,13 @@ module.exports.replay = function(req, res, next) { // Get id parameter res.locals.id = tools.filterInt(req.params.id); + if (res.locals.id <= 0) { + var err = new Error("This replay does not exist"); + err.status = 404; + next(err); + return; + } + db.checkExpId(res.locals.id, function(sceneId) { if (sceneId === null) { var err = new Error("This replay does not exist"); diff --git a/load.js b/load.js index 2593ca6..8c397d2 100644 --- a/load.js +++ b/load.js @@ -16,7 +16,7 @@ var casper = require('casper').create({ waitTimeout: 100000 }); -var limit = 100; +var limit = 1; casper.start('http://localhost:4000/'); @@ -42,10 +42,10 @@ for (var i = 0; i < limit; i++) { // }, true); - this.thenOpen('http://localhost:4000/prototype/game'); - this.thenOpen('http://localhost:4000/prototype/game'); - this.thenOpen('http://localhost:4000/prototype/game'); - this.thenOpen('http://localhost:4000/prototype/game'); + this.thenOpen('http://localhost:4000/prototype/tutorial'); + this.thenOpen('http://localhost:4000/prototype/play'); + this.thenOpen('http://localhost:4000/prototype/play'); + this.thenOpen('http://localhost:4000/prototype/play'); this.thenOpen('http://localhost:4000/logout');