Merge pull request #671 from calzoneman/knex

The knexening: part 1
This commit is contained in:
Calvin Montgomery 2017-05-29 13:16:35 -07:00 committed by GitHub
commit 7fcf31dec6
3 changed files with 72 additions and 93 deletions

View File

@ -31,6 +31,7 @@
"graceful-fs": "^4.1.2", "graceful-fs": "^4.1.2",
"http-errors": "^1.3.1", "http-errors": "^1.3.1",
"json-typecheck": "^0.1.3", "json-typecheck": "^0.1.3",
"knex": "^0.13.0",
"lodash": "^4.13.1", "lodash": "^4.13.1",
"morgan": "^1.6.1", "morgan": "^1.6.1",
"mysql": "^2.9.0", "mysql": "^2.9.0",

View File

@ -6,30 +6,57 @@ var net = require("net");
var util = require("./utilities"); var util = require("./utilities");
import * as Metrics from 'cytube-common/lib/metrics/metrics'; import * as Metrics from 'cytube-common/lib/metrics/metrics';
import { LoggerFactory } from '@calzoneman/jsli'; import { LoggerFactory } from '@calzoneman/jsli';
import knex from 'knex';
const LOGGER = LoggerFactory.getLogger('database'); const LOGGER = LoggerFactory.getLogger('database');
var pool = null;
var global_ipbans = {}; var global_ipbans = {};
let db = null;
class Database {
constructor() {
const config = {
client: 'mysql',
connection: {
host: Config.get('mysql.server'),
port: Config.get('mysql.port'),
user: Config.get('mysql.user'),
password: Config.get('mysql.password'),
database: Config.get('mysql.database'),
multipleStatements: true, // Legacy thing
charset: 'UTF8MB4_GENERAL_CI'
},
pool: {
min: Config.get('mysql.pool-size'),
max: Config.get('mysql.pool-size')
},
debug: !!process.env.KNEX_DEBUG
};
this.knex = knex(config);
}
}
module.exports.init = function () { module.exports.init = function () {
pool = mysql.createPool({ db = new Database();
host: Config.get("mysql.server"), db.knex.raw('select 1 from dual')
port: Config.get("mysql.port"), .catch(error => {
user: Config.get("mysql.user"), LOGGER.error('Initial database connection failed: %s', error.stack);
password: Config.get("mysql.password"), process.exit(1);
database: Config.get("mysql.database"), }).then(() => {
multipleStatements: true, process.nextTick(legacySetup);
charset: "UTF8MB4_GENERAL_CI", // Needed for emoji and other non-BMP unicode
connectionLimit: Config.get("mysql.pool-size")
}); });
// Test the connection global_ipbans = {};
pool.getConnection(function (err, conn) { module.exports.users = require("./database/accounts");
if (err) { module.exports.channels = require("./database/channels");
LOGGER.error("Initial database connection failed: " + err.stack); };
process.exit(1);
} else { module.exports.getDB = function getDB() {
return db;
};
function legacySetup() {
tables.init(module.exports.query, function (err) { tables.init(module.exports.query, function (err) {
if (err) { if (err) {
return; return;
@ -39,18 +66,7 @@ module.exports.init = function () {
}); });
// Refresh global IP bans // Refresh global IP bans
module.exports.listGlobalBans(); module.exports.listGlobalBans();
} }
});
pool.on("enqueue", function () {
Metrics.incCounter("db:queryQueued", 1);
});
global_ipbans = {};
module.exports.users = require("./database/accounts");
module.exports.channels = require("./database/channels");
module.exports.pool = pool;
};
/** /**
* Execute a database query * Execute a database query
@ -60,49 +76,25 @@ module.exports.query = function (query, sub, callback) {
// 2nd argument is optional // 2nd argument is optional
if (typeof sub === "function") { if (typeof sub === "function") {
callback = sub; callback = sub;
sub = false; sub = undefined;
} }
if (typeof callback !== "function") { if (typeof callback !== "function") {
callback = blackHole; callback = blackHole;
} }
pool.getConnection(function (err, conn) {
if (err) {
LOGGER.error("! DB connection failed: " + err);
callback("Database failure", null);
} else {
function cback(err, res) {
conn.release();
if (err) {
LOGGER.error("! DB query failed: " + query);
if (sub) {
LOGGER.error("Substitutions: " + sub);
}
LOGGER.error(err);
callback("Database failure", null);
} else {
callback(null, res);
}
Metrics.stopTimer(timer);
}
if (process.env.SHOW_SQL) { if (process.env.SHOW_SQL) {
console.log(query); console.log(query);
} }
try { db.knex.raw(query, sub)
if (sub) { .then(res => {
conn.query(query, sub, cback); process.nextTick(callback, null, res[0]);
} else { }).catch(error => {
conn.query(query, cback); LOGGER.error('Legacy DB query failed. Query: %s, Substitutions: %j, Error: %s', query, sub, error);
} process.nextTick(callback, 'Database failure', null);
} catch (error) { }).finally(() => {
LOGGER.error("Broken query: " + error.stack); Metrics.stopTimer(timer);
callback("Broken query", null);
conn.release();
}
}
}); });
}; };

View File

@ -363,29 +363,15 @@ function populateUsernameDedupeColumn(cb) {
} }
Promise.map(rows, row => { Promise.map(rows, row => {
return new Promise((resolve, reject) => {
db.pool.getConnection((error, conn) => {
if (error) {
reject(error);
return;
}
const dedupedName = dbUsers.dedupeUsername(row.name); const dedupedName = dbUsers.dedupeUsername(row.name);
LOGGER.info(`Deduping [${row.name}] as [${dedupedName}]`); LOGGER.info(`Deduping [${row.name}] as [${dedupedName}]`);
conn.query("UPDATE users SET name_dedupe = ? WHERE id = ?", [dedupedName, row.id], (error, res) => { return db.getDB().knex.raw("UPDATE users SET name_dedupe = ? WHERE id = ?", [dedupedName, row.id])
conn.release(); .catch(error => {
if (error) {
if (error.errno === 1062) { if (error.errno === 1062) {
LOGGER.info(`WARNING: could not set name_dedupe for [${row.name}] due to an existing row for [${dedupedName}]`); LOGGER.info(`WARNING: could not set name_dedupe for [${row.name}] due to an existing row for [${dedupedName}]`);
resolve();
} else { } else {
reject(error); throw error;
} }
} else {
resolve();
}
});
});
}); });
}, { concurrency: 10 }).then(() => { }, { concurrency: 10 }).then(() => {
cb(); cb();