From e79284e75f6f000a7c92d1686c83d091b895fe1c Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 9 Apr 2014 23:22:43 -0400 Subject: [PATCH] LevelDB init --- mocks/databasemock.js | 5 +- package.json | 7 +- src/database/level.js | 400 ++++++++++++++++++++++++++++++++++++++++++ tests/database.js | 184 +++++++++---------- 4 files changed, 501 insertions(+), 95 deletions(-) create mode 100644 src/database/level.js diff --git a/mocks/databasemock.js b/mocks/databasemock.js index bc6bbbc019..eff47bfeb1 100644 --- a/mocks/databasemock.js +++ b/mocks/databasemock.js @@ -74,7 +74,7 @@ } winston.info('test_database flushed'); - + /* meta.configs.init(function () { nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path')); nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-vanilla/templates')); @@ -85,7 +85,8 @@ sockets.init(webserver.server); done(); - }); + });*/ + done(); }); }); }); diff --git a/package.json b/package.json index cc185a1f4d..5df4aaa5f5 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "scripts": { "start": "./nodebb start", "stop": "./nodebb stop", - "test": "mocha ./tests -t 10000" + "test": "mocha ./tests/database.js -t 1000" }, "dependencies": { "socket.io": "~0.9.16", @@ -54,7 +54,10 @@ "hiredis": "~0.1.15", "connect-redis": "1.4.5", "mongodb": "~1.3.19", - "connect-mongo": "0.4.0" + "connect-mongo": "0.4.0", + "levelup": "^0.18.2", + "leveldown": "^0.10.2", + "connect-leveldb": "^0.1.5" }, "devDependencies": { "mocha": "~1.13.0" diff --git a/src/database/level.js b/src/database/level.js new file mode 100644 index 0000000000..b1e80b16c1 --- /dev/null +++ b/src/database/level.js @@ -0,0 +1,400 @@ +'use strict'; + +(function(module) { + /* + * Okay, so LevelDB was made by Google. Therefore its skalable. + * BUT, I created 99% of the rest of NodeBB's expected functionality out of just simple get and set commands. + * Therefore, it is unskalable. + * + * With much <3, psychobunny. + */ + + var winston = require('winston'), + nconf = require('nconf'), + path = require('path'), + async = require('async'), + express = require('express'), + utils = require('./../../public/src/utils.js'), + levelup, + leveldown, + connectLevel, + db, ld; + + try { + levelup = require('levelup'); + leveldown = require('leveldown'); + connectLevel = require('connect-leveldb')(express); + } catch (err) { + winston.error('Unable to initialize Level DB! Is Level DB installed? Error :' + err.message); + process.exit(); + } + + module.init = function(callback) { + db = levelup(nconf.get('level:database')); + ld = leveldown(nconf.get('level:database')); + + db.on('error', function (err) { + winston.error(err.message); + process.exit(); + }); + + module.client = db; + + module.sessionStore = new connectLevel({ + db: db, + ttl: 60 * 60 * 24 * 14 + }); + + if(typeof callback === 'function') { + callback(); + } + }; + + module.close = function() { + db.quit(); + }; + + // + // Exported functions + // + module.searchIndex = function(key, content, id) { + + }; + + module.search = function(key, term, limit, callback) { + + }; + + module.searchRemove = function(key, id, callback) { + + }; + + module.flushdb = function(callback) { + db.close(function() { + leveldown.destroy(nconf.get('level:database'), function() { + db.open(callback); + }); + }); + }; + + module.info = function(callback) { + + }; + + // key + + module.exists = function(key, callback) { + db.get(key, function(err, value) { + callback(null, !!value); + }); + }; + + module.delete = function(key, callback) { + db.del(key, callback); + }; + + module.get = function(key, callback) { + db.get(key, function(err, value) { + callback(false, value); + }); + }; + + module.set = function(key, value, callback) { + db.put(key, value, callback); + }; + + module.rename = function(oldKey, newKey, callback) { + //db.rename(oldKey, newKey, callback); + }; + + module.expire = function(key, seconds, callback) { + //db.expire(key, seconds, callback); + }; + + module.expireAt = function(key, timestamp, callback) { + //db.expireat(key, timestamp, callback); + }; + + //hashes + + module.setObject = function(key, obj, callback) { + async.parallel([ + function(next) { + async.each(obj, function(objKey, next) { + module.setObjectField(key, objKey, obj[objKey], next); + }, next); + }, + function(next) { + module.set('leveldb:object:' + key, Object.keys(obj).join('-ldb-')); + next(); + } + ], callback); + }; + + module.setObjectField = function(key, field, value, callback) { + module.set(key + ':' + field, value, callback); + }; + + module.getObject = function(key, callback) { + var obj = {}; + + module.get('leveldb:object:' + key, function(err, keys) { + if (keys) { + keys = keys.split('-ldb-'); + async.each(keys, function(key, next) { + module.get(key, function(err, value) { + obj[key] = value; + next(err); + }); + }, function(err) { + callback(err, obj); + }); + } else { + callback(err, {}); + } + }); + }; + + module.getObjects = function(keys, callback) { + var objs = {}; + + async.each(keys, function(key, next) { + module.getObject(key, function(err, val) { + objs[key] = val; + next(); + }); + }, function(err) { + callback(err, objs); + }); + }; + + module.getObjectField = function(key, field, callback) { + module.get(key + ':' + field, callback); + }; + + module.getObjectFields = function(key, fields, callback) { + // can be improved with multi. + var obj = {}; + async.each(fields, function(field, next) { + module.getObjectField(key, field, function(err, value) { + obj[field] = value; + next(); + }); + }, function(err) { + callback(err, obj); + }); + }; + + module.getObjectsFields = function(keys, fields, callback) { + var objs = {}; + + async.each(keys, function(key, next) { + module.getObjectFields(key, fields, function(err, obj) { + objs[key] = obj; + next(); + }); + }, function(err) { + callback(err, objs); + }); + }; + + module.getObjectKeys = function(key, callback) { + module.get('leveldb:object:' + key, callback); + }; + + module.getObjectValues = function(key, callback) { + module.getObject(key, function(err, obj) { + var values = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + values.push(obj[key]); + } + } + + callback(err, values); + }); + }; + + module.isObjectField = function(key, field, callback) { + module.get(key + ':' + field, function(err, val) { + callback(err, !!val); + }); + }; + + module.deleteObjectField = function(key, field, callback) { + module.delete(key + ':' + field, callback); + }; + + module.incrObjectField = function(key, field, callback) { + module.get(key + ':' + field, function(err, val) { + module.set(key + ':' + field, val + 1, callback); + }); + }; + + module.decrObjectField = function(key, field, callback) { + module.get(key + ':' + field, function(err, val) { + module.set(key + ':' + field, val - 1, callback); + }); + }; + + module.incrObjectFieldBy = function(key, field, value, callback) { + module.get(key + ':' + field, function(err, val) { + module.set(key + ':' + field, val + value, callback); + }); + }; + + module.decrObjectFieldBy = function(key, field, value, callback) { + module.get(key + ':' + field, function(err, val) { + module.set(key + ':' + field, val - value, callback); + }); + }; + + + // sets + + module.setAdd = function(key, value, callback) { + db.sadd(key, value, callback); + }; + + module.setRemove = function(key, value, callback) { + db.srem(key, value, callback); + }; + + module.isSetMember = function(key, value, callback) { + db.sismember(key, value, function(err, result) { + if(err) { + return callback(err); + } + + callback(null, result === 1); + }); + }; + + module.isSetMembers = function(key, values, callback) { + var multi = db.multi(); + for (var i=0; i