Bug 1358907 Part 2 Wait for database load before shutting down r=mossop

Make sure the XPI database is fully loaded before running the
XPIDatabase.shutdown() logic.  This race has been present for a long
time but it suddenly became much more common when loading of the XPI
database was deferred until after startup.

MozReview-Commit-ID: 1llKuH3It19

--HG--
extra : rebase_source : de18515e0c38193d70953a49803fadb43be9286c
This commit is contained in:
Andrew Swan 2017-06-30 10:09:59 -07:00
Родитель bad78dd7d7
Коммит 453ee8a579
2 изменённых файлов: 36 добавлений и 22 удалений

Просмотреть файл

@ -658,7 +658,7 @@ this.XPIDatabase = {
* flush after the database is flushed and * flush after the database is flushed and
* all cleanup is done * all cleanup is done
*/ */
shutdown() { async shutdown() {
logger.debug("shutdown"); logger.debug("shutdown");
if (this.initialized) { if (this.initialized) {
// If our last database I/O had an error, try one last time to save. // If our last database I/O had an error, try one last time to save.
@ -676,28 +676,33 @@ this.XPIDatabase = {
"XPIDB_saves_late", this._deferredSave.dirty ? 1 : 0); "XPIDB_saves_late", this._deferredSave.dirty ? 1 : 0);
} }
// Return a promise that any pending writes of the DB are complete and we // If we're shutting down while still loading, finish loading
// are finished cleaning up // before everything else!
let flushPromise = this.flush(); if (this._dbPromise) {
flushPromise.catch(error => { await this._dbPromise;
logger.error("Flush of XPI database failed", error); }
AddonManagerPrivate.recordSimpleMeasure("XPIDB_shutdownFlush_failed", 1);
// If our last attempt to read or write the DB failed, force a new // Await and pending DB writes and finish cleaning up.
// extensions.ini to be written to disk on the next startup try {
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true); await this.flush();
}) } catch (error) {
.then(count => { logger.error("Flush of XPI database failed", error);
// Clear out the cached addons data loaded from JSON AddonManagerPrivate.recordSimpleMeasure("XPIDB_shutdownFlush_failed", 1);
delete this.addonDB; // If our last attempt to read or write the DB failed, force a new
delete this._dbPromise; // extensions.ini to be written to disk on the next startup
// same for the deferred save Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true);
delete this._deferredSave;
// re-enable the schema version setter throw error;
delete this._schemaVersionSet; }
});
return flushPromise; // Clear out the cached addons data loaded from JSON
delete this.addonDB;
delete this._dbPromise;
// same for the deferred save
delete this._deferredSave;
// re-enable the schema version setter
delete this._schemaVersionSet;
} }
return Promise.resolve(0);
}, },
/** /**

Просмотреть файл

@ -255,6 +255,15 @@ function run_test_1() {
gExtensionsJSON.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); gExtensionsJSON.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
startupManager(false); startupManager(false);
// Load the database.
awaitPromise(new Promise(resolve => {
Services.obs.addObserver(function listener() {
Services.obs.removeObserver(listener, "xpi-database-loaded");
resolve();
}, "xpi-database-loaded");
Services.obs.notifyObservers(null, "sessionstore-windows-restored");
}));
// Accessing the add-ons should open and recover the database // Accessing the add-ons should open and recover the database
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org", "addon2@tests.mozilla.org",