rounderdb
Version:
A low-I/O, fixed size, round robin db with in-mem support. Store in RAM and sync periodically to disk.
189 lines (159 loc) • 5.43 kB
JavaScript
var os = require('os');
var path = require('path');
var fs = require('fs');
var Archive = require('./lib/Archive.js');
var debugLog = false;
function RounderDB() {
this._archives = {};
this._DBfile = 'NODISK';
this._syncInterval;
this._persistenceHandler = null;
this._intervalHandler = null;
this._syncActive = false;
}
/** Static factory method to create instances from config.
*
* @param config
* @returns {RounderDB} instance
*/
RounderDB.createInstance = function (config) {
var rb = new RounderDB();
for (var archiveName in config) {
if (!config.hasOwnProperty(archiveName) || archiveName == 'persistenceConf')
continue;
log("Rounder:: Creating archive: " + archiveName);
rb.addArchive(archiveName, Archive.createInstance(config[archiveName]));
}
if (config.persistenceConf.dbDir != 'NODISK')
rb.setDBFile(config.persistenceConf.dbFile);
rb.setSyncInterval(config.persistenceConf.syncInterval);
log("ROUNDER instance created: " + JSON.stringify(rb, null, 4));
return rb;
}
RounderDB.loadInstance = function (dataObj) {
var rb = new RounderDB();
rb.setDBFile(dataObj._DBfile);
rb.setSyncInterval(dataObj._syncInterval);
for (var n in dataObj._archives) {
rb.addArchive(n, Archive.loadInstance(dataObj._archives[n]));
}
rb.setSync(dataObj._syncActive);
return rb;
}
RounderDB.saveInstance = function (rDB, callback) {
var fileName = rDB.getDBFile();
if (fileName != null && fileName != 'NODISK')
fs.writeFile(fileName, JSON.stringify(rDB), {encoding: 'utf8'}, callback);
}
/** Add new value to a named archive.
*
* @param archiveName
* @param val
* @param timeStamp Optional argument. If omitted, server time stamp will be used
* @returns {*}
*/
RounderDB.prototype.add = function (archiveName, val, timeStamp) {
if (typeof timeStamp === 'undefined')
timeStamp = new Date().getTime();
if (this._archives[archiveName] == null)
return null;
return this._archives[archiveName].add(val, timeStamp);
}
/** Set the function which handles persistence to disk
*
* @param callback
*/
RounderDB.prototype.setPersistenceHandler = function (callback) {
this._persistenceHandler = callback;
}
RounderDB.prototype.getPersistenceHandler = function () {
return this._persistenceHandler;
}
RounderDB.prototype.addArchive = function (name, archiveInstance) {
this._archives[name] = archiveInstance;
}
RounderDB.prototype.getArchive = function (name) {
return this._archives[name];
}
/** Clear all in-memory data and remove any files on disk
*
*/
RounderDB.prototype.reset = function () {
this._archives = {};
this.setSync(false);
if (this._DBfile != 'NODISK')
fs.unlinkSync(this._DBfile);
this._DBfile = 'NODISK';
}
RounderDB.prototype.getDBFile = function () {
return this._DBfile;
}
/** Set the directory in which to store data. Also, sets a default persistence handler.
* If file == 'TMP', a temporary directory will be created in the OS temp file.
* If file == 'NODISK', no disk persistence will be used (in-mem only operation)
* The default value is 'NODISK'.
*
* @param file File name to save to
* @param cb Callback to execute on save (receives err and data)
*/
RounderDB.prototype.setDBFile = function (file, cb) {
if (file == null)
return;
else if (file == 'TMP') {
var tmpFile = path.join(os.tmpDir(), "rounderDB.json");
try {
if (fs.existsSync(tmpFile))
fs.unlinkSync(tmpFile);
} catch (err) {
console.error("RounderDB:setDBFile ERROR creating temp file: " + err);
}
} else
this._DBfile = path.resolve(file);
this.setPersistenceHandler((function (rDB, callback) {
return function() {
// console.log("SAVING to file: "+rDB.getDBFile());
RounderDB.saveInstance(rDB, callback);
};
})(this, cb));
log("Setting DB file to file: " + this._DBfile);
}
RounderDB.prototype.getNrArchives = function () {
return Object.keys(this._archives).length;
}
/** Set the sync interval for persisting data to disk.
*
* @param interval in seconds. 0 means never (also removed any active job)
*/
RounderDB.prototype.setSyncInterval = function (interval) {
if (interval < 0)
interval = 0;
else if (interval == 0 && this._intervalHandler != null)
this.setSync(false);
this._syncInterval = interval;
}
/** If set to true, and interval handler will be scheduled to run
* each syncInterval to persist data to disk.
*
* If 'NODISK' is used, no handler will be started regardless.
*
* If set to false, it will remove any interval handler.
*
* @param state Set to true or false.
*/
RounderDB.prototype.setSync = function (state) {
if (state && this._DBfile != 'NODISK') {
if (this._persistenceHandler == null)
throw Error("RounderDB:setSync: Cannot schedule persistenceHandler 'null'");
this._intervalHandler = setInterval(this._persistenceHandler, this._syncInterval*1000);
this._syncActive = true;
} else if (this._intervalHandler != null) {
clearInterval(this._intervalHandler);
this._syncActive = false;
}
}
// Internal helpers below
var log = function (msg) {
if (debugLog)
console.log(msg);
};
module.exports = RounderDB;