From 4ae6b558160721bff3fb46bd57ae03f2bb27dfe1 Mon Sep 17 00:00:00 2001 From: Louis Chatriot Date: Fri, 12 Jul 2013 14:55:32 +0200 Subject: [PATCH] Externalized persistence of the cached db and of new state --- lib/datastore.js | 67 ++++++------------------------------------ lib/persistence.js | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 59 deletions(-) create mode 100644 lib/persistence.js diff --git a/lib/datastore.js b/lib/datastore.js index 9f1f4c1..c2b1500 100644 --- a/lib/datastore.js +++ b/lib/datastore.js @@ -7,6 +7,7 @@ var fs = require('fs') , Index = require('./indexes') , util = require('util') , _ = require('underscore') + , Persistence = require('./persistence') ; @@ -46,6 +47,9 @@ function Datastore (options) { this.filename = customUtils.getNWAppFilename(options.nodeWebkitAppName, this.filename); } + // Persistence handling + this.persistence = new Persistence({ db: this }); + // This new executor is ready if we don't use persistence // If we do, it will only be ready once loadDatabase is called this.executor = new Executor(); @@ -278,7 +282,7 @@ Datastore.prototype._loadDatabase = function (cb) { } self.datafileSize = treatedData.length; - self.persistCachedDatabase(cb); + self.persistence.persistCachedDatabase(cb); }); }); }); @@ -330,61 +334,7 @@ Datastore.treatRawData = function (rawData) { }; -/** - * Persist cached database - * This serves as a compaction function since the cache always contains only the number of documents in the collection - * while the data file is append-only so it may grow larger - * @param {Function} cb Optional callback, signature: err - */ -Datastore.prototype.persistCachedDatabase = function (cb) { - var callback = cb || function () {} - , toPersist = '' - ; - - this.getAllData().forEach(function (doc) { - toPersist += model.serialize(doc) + '\n'; - }); - - if (toPersist.length === 0) { return callback(null); } - fs.writeFile(this.filename, toPersist, function (err) { return callback(err); }); -}; - - -/** - * Persist new state for the given newDocs (can be insertion, update or removal) - * Use an append-only format - * @param {Array} newDocs Can be empty if no doc was updated/removed - * @param {Function} cb Optional, signature: err - */ -Datastore.prototype._persistNewState = function (newDocs, cb) { - var self = this - , toPersist = '' - , callback = cb || function () {} - ; - - // In-memory only datastore - if (self.inMemoryOnly) { return callback(null); } - - self.datafileSize += newDocs.length; - - newDocs.forEach(function (doc) { - toPersist += model.serialize(doc) + '\n'; - }); - - if (toPersist.length === 0) { return callback(null); } - - fs.appendFile(self.filename, toPersist, 'utf8', function (err) { - return callback(err); - }); -}; -Datastore.prototype.persistNewState = function (newDocs, cb) { - if (this.inMemoryOnly) { - cb(); - } else { - this._persistNewState(newDocs, cb); - } -}; /** @@ -411,7 +361,7 @@ Datastore.prototype._insert = function (newDoc, cb) { // Insert in all indexes (also serves to ensure uniqueness) try { self.addToIndexes(insertedDoc); } catch (e) { return callback(e); } - this.persistNewState([newDoc], function (err) { + this.persistence.persistNewState([newDoc], function (err) { if (err) { return callback(err); } return callback(null, newDoc); }); @@ -546,7 +496,7 @@ Datastore.prototype._update = function (query, updateQuery, options, cb) { return callback(err); } - self.persistNewState(updatedDocs, function (err) { + self.persistence.persistNewState(updatedDocs, function (err) { if (err) { return callback(err); } return callback(null, numReplaced); }); @@ -591,7 +541,7 @@ Datastore.prototype._remove = function (query, options, cb) { }); } catch (err) { return callback(err); } - self.persistNewState(removedDocs, function (err) { + self.persistence.persistNewState(removedDocs, function (err) { if (err) { return callback(err); } return callback(null, numRemoved); }); @@ -602,5 +552,4 @@ Datastore.prototype.remove = function () { - module.exports = Datastore; diff --git a/lib/persistence.js b/lib/persistence.js new file mode 100644 index 0000000..a720fc1 --- /dev/null +++ b/lib/persistence.js @@ -0,0 +1,72 @@ +/** + * Handle every persistence-related task + */ + +var fs = require('fs') + , path = require('path') + , model = require('./model') + , customUtils = require('./customUtils') + ; + + +/** + * Create a new Persistence object for database options.db + * @param {Datastore} options.db + */ +function Persistence (options) { + this.db = options.db; +} + + +/** + * Persist cached database + * This serves as a compaction function since the cache always contains only the number of documents in the collection + * while the data file is append-only so it may grow larger + * @param {Function} cb Optional callback, signature: err + */ +Persistence.prototype.persistCachedDatabase = function (cb) { + var callback = cb || function () {} + , toPersist = '' + ; + + this.db.getAllData().forEach(function (doc) { + toPersist += model.serialize(doc) + '\n'; + }); + + if (toPersist.length === 0) { return callback(null); } + + fs.writeFile(this.db.filename, toPersist, function (err) { return callback(err); }); +}; + + +/** + * Persist new state for the given newDocs (can be insertion, update or removal) + * Use an append-only format + * @param {Array} newDocs Can be empty if no doc was updated/removed + * @param {Function} cb Optional, signature: err + */ +Persistence.prototype.persistNewState = function (newDocs, cb) { + var self = this + , toPersist = '' + , callback = cb || function () {} + ; + + // In-memory only datastore + if (self.db.inMemoryOnly) { return callback(null); } + + self.db.datafileSize += newDocs.length; + + newDocs.forEach(function (doc) { + toPersist += model.serialize(doc) + '\n'; + }); + + if (toPersist.length === 0) { return callback(null); } + + fs.appendFile(self.db.filename, toPersist, 'utf8', function (err) { + return callback(err); + }); +}; + + +// Interface +module.exports = Persistence;