From d84bffb1c2fddfd409b7b090329595e894f0155b Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Fri, 13 Dec 2013 17:19:56 -0500 Subject: [PATCH] Fixes that should hopefully protect against database corruption - When opening the DB, always tell other Zotero instances to close it, regardless of whether they are holding the lock. - Don't let database re-open after it has been closed. This also fixes some issues with connector switching. --- chrome/content/zotero/xpcom/db.js | 11 +++++++++-- chrome/content/zotero/xpcom/ipc.js | 7 +++++-- chrome/content/zotero/xpcom/zotero.js | 9 +++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/chrome/content/zotero/xpcom/db.js b/chrome/content/zotero/xpcom/db.js index 18da2e9310..40376b2784 100644 --- a/chrome/content/zotero/xpcom/db.js +++ b/chrome/content/zotero/xpcom/db.js @@ -791,12 +791,17 @@ Zotero.DBConnection.prototype.checkException = function (e) { } -Zotero.DBConnection.prototype.closeDatabase = function () { +/** + * Close the database + * @param {Boolean} [permanent] If true, throw an error instead of + * allowing code to re-open the database again + */ +Zotero.DBConnection.prototype.closeDatabase = function (permanent) { if(this._connection) { this.stopDummyStatement(); var deferred = Q.defer(); this._connection.asyncClose(deferred.resolve); - this._connection = undefined; + this._connection = permanent ? false : null; return deferred.promise; } else { return Q(); @@ -1073,6 +1078,8 @@ Zotero.DBConnection.prototype.getSQLDataType = function(value) { Zotero.DBConnection.prototype._getDBConnection = function () { if (this._connection) { return this._connection; + } else if (this._connection === false) { + throw new Error("Database permanently closed; not re-opening"); } this._debug("Opening database '" + this._dbName + "'"); diff --git a/chrome/content/zotero/xpcom/ipc.js b/chrome/content/zotero/xpcom/ipc.js index 6f44247cd6..78b08b8822 100755 --- a/chrome/content/zotero/xpcom/ipc.js +++ b/chrome/content/zotero/xpcom/ipc.js @@ -62,10 +62,13 @@ Zotero.IPC = new function() { * has been received if it is already initialized, SA sends an initComplete message * to Z4Fx. */ - if(msg === "releaseLock" && !Zotero.isConnector) { + if(msg.substr(0, 11) === "releaseLock") { // Standalone sends this to the Firefox extension to tell the Firefox extension to // release its lock on the Zotero database - switchConnectorMode(true); + if(!Zotero.isConnector && (msg.length === 11 || + msg.substr(12) === Zotero.getZoteroDirectory().persistentDescriptor)) { + switchConnectorMode(true); + } } else if(msg === "lockReleased") { // The Firefox extension sends this to Standalone to let Standalone know that it has // released its lock diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index dd777d21d7..bb60b73450 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -759,6 +759,11 @@ Components.utils.import("resource://gre/modules/Services.jsm"); Zotero.DB.test(); var dbfile = Zotero.getZoteroDatabase(); + + // Tell any other Zotero instances to release their lock, + // in case we lost the lock on the database (how?) and it's + // now open in two places at once + Zotero.IPC.broadcast("releaseLock "+dbfile.persistentDescriptor); // Test write access on Zotero data directory if (!dbfile.parent.isWritable()) { @@ -886,8 +891,8 @@ Components.utils.import("resource://gre/modules/Services.jsm"); // Zotero.DBConnection.getStatement() explicitly Components.utils.forceGC(); - // unlock DB - return Zotero.DB.closeDatabase().then(function() { + // close DB + return Zotero.DB.closeDatabase(true).then(function() { // broadcast that DB lock has been released Zotero.IPC.broadcast("lockReleased"); });