Skip to content

Commit

Permalink
(#398) - reuse PouchDB object between calls
Browse files Browse the repository at this point in the history
  • Loading branch information
nolanlawson committed Feb 11, 2017
1 parent 6827e67 commit 17cb28a
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 25 deletions.
52 changes: 52 additions & 0 deletions lib/create-or-delete-dbs.js
@@ -0,0 +1,52 @@
'use strict';

// unified access to creating/deleting PouchDB databases,
// to re-use PouchDB objects and avoid race conditions

var Promise = require('pouchdb-promise');
var PouchMap = require('pouchdb-collections').Map;

var promiseChain = Promise.resolve();

// do all creations/deletions in a single global lock
// obviously this makes this operation slow... but hopefully you aren't
// creating and destroying a lot of databases all the time
function doSequentially(fun) {
promiseChain = promiseChain.then(fun);
return promiseChain;
}

function getOrCreateDB(PouchDB, dbName) {
var map = PouchDB.__dbCacheMap;
if (!map) {
// cache DBs to avoid costly re-allocations
map = PouchDB.__dbCacheMap = new PouchMap();
}
return doSequentially(function () {
var db = map.get(dbName);
if (db) {
return db;
}
db = new PouchDB(dbName);
map.set(dbName, db);
return db;
});
}

function deleteDB(PouchDB, dbName, opts) {
return doSequentially(function () {
var dbCache = PouchDB.__dbCacheMap;
var db = dbCache && dbCache.get(dbName);
if (!db) {
// if the db wasn't cached, we may still need to destroy it
// if it's saved to disk
return PouchDB.destroy(dbName, opts);
}
// if this db was cached, we need to remove it from the cache immediately
dbCache.delete(dbName);
return db.destroy(opts);
});
}

exports.getOrCreateDB = getOrCreateDB;
exports.deleteDB = deleteDB;
9 changes: 6 additions & 3 deletions lib/db-wrapper.js
Expand Up @@ -19,10 +19,13 @@ DatabaseWrapper.prototype.wrap = function (name, db) {
if (typeof db === 'undefined') {
throw new Error("no db defined!");
}
if (db.__wrappedByExpressPouch) {
// dbs are cached, so it might already be wrapped
return Promise.resolve(db);
}
db.__wrappedByExpressPouch = true;
return utils.callAsyncRecursive(this._wrappers, function (wrapper, next) {
return Promise.resolve().then(function () {
return wrapper(name, db, next);
});
return Promise.resolve(wrapper(name, db, next));
}).then(function () {
// https://github.com/pouchdb/pouchdb/issues/1940
delete db.then;
Expand Down
9 changes: 5 additions & 4 deletions lib/replicator.js
Expand Up @@ -2,6 +2,7 @@

var Promise = require('pouchdb-promise');
var utils = require('./utils');
var getOrCreateDB = require('./create-or-delete-dbs').getOrCreateDB;

module.exports = function enableReplicator(app) {
var db, PouchDB;
Expand Down Expand Up @@ -55,10 +56,10 @@ module.exports = function enableReplicator(app) {

return serialExecution(function () {
var name = getReplicatorDBName();
db = new PouchDB(name);

PouchDB.on('destroyed', onDestroy);
return db.startReplicatorDaemon();
return getOrCreateDB(PouchDB, name).then(function (db) {
PouchDB.on('destroyed', onDestroy);
return db.startReplicatorDaemon();
});
});
},
stop: function () {
Expand Down
14 changes: 7 additions & 7 deletions lib/routes/db.js
Expand Up @@ -5,7 +5,8 @@ var startTime = new Date().getTime(),
wrappers = require('pouchdb-wrappers'),
mkdirp = require('mkdirp'),
pathResolve = require('path').resolve,
cleanFilename = require('../clean-filename');
cleanFilename = require('../clean-filename'),
deleteDB = require('../create-or-delete-dbs').deleteDB;

module.exports = function (app) {
// Create a database.
Expand Down Expand Up @@ -63,7 +64,7 @@ module.exports = function (app) {
});

// Delete a database
app.delete('/:db', function (req, res, next) {
app.delete('/:db', function (req, res) {
if (req.query.rev) {
return utils.sendJSON(res, 400, {
error: 'bad_request',
Expand All @@ -73,13 +74,12 @@ module.exports = function (app) {
)
});
}
var name = cleanFilename(req.params.db);
req.PouchDB.destroy(name, utils.makeOpts(req), function (err, info) {
if (err) {
return utils.sendError(res, err);
}

var dbName = cleanFilename(req.params.db);
deleteDB(req.PouchDB, dbName, utils.makeOpts(req)).then(function () {
utils.sendJSON(res, 200, {ok: true});
}, function (err) {
utils.sendError(res, err);
});
});

Expand Down
23 changes: 12 additions & 11 deletions lib/utils.js
Expand Up @@ -5,6 +5,7 @@ var rawBody = require('raw-body');
var Promise = require('pouchdb-promise');
var mkdirp = require('mkdirp');
var cleanFilename = require('./clean-filename');
var getOrCreateDB = require('./create-or-delete-dbs').getOrCreateDB;

//shared middleware

Expand Down Expand Up @@ -75,18 +76,18 @@ exports.setDBOnReq = function (dbName, dbWrapper, req, res, next) {
reason: 'no_db_file'
});
}
var db = new req.PouchDB(dbName);

// temporary workaround for https://github.com/pouchdb/pouchdb/issues/5668
// see also https://github.com/pouchdb/express-pouchdb/issues/274
if (/\//.test(dbName)) {
var path = db.__opts.prefix ? db.__opts.prefix + dbName : dbName;
mkdirp.sync(pathResolve(path));
}
getOrCreateDB(req.PouchDB, dbName).then(function (db) {
// temporary workaround for https://github.com/pouchdb/pouchdb/issues/5668
// see also https://github.com/pouchdb/express-pouchdb/issues/274
if (/\//.test(dbName)) {
var path = db.__opts.prefix ? db.__opts.prefix + dbName : dbName;
mkdirp.sync(pathResolve(path));
}

dbWrapper.wrap(dbName, db).then(function () {
req.db = db;
next();
dbWrapper.wrap(dbName, db).then(function () {
req.db = db;
next();
});
});
});
};
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -25,6 +25,7 @@
"on-finished": "^2.3.0",
"pouchdb-all-dbs": "^1.0.2",
"pouchdb-auth": "^2.1.1",
"pouchdb-collections": "6.1.2",
"pouchdb-find": "^0.10.3",
"pouchdb-list": "^1.1.0",
"pouchdb-promise": "6.1.2",
Expand Down

0 comments on commit 17cb28a

Please sign in to comment.