Bug 760243 - Fix shutdown errors and crash "Assertion failure: !connections[i]->ConnectionReady(), mozStorageService.cpp" r=philipp a=philipp
authorStefan Sitter <ssitter@gmail.com>
Wed, 10 Oct 2012 21:45:31 +0200
changeset 13472 ffe3ddad9bb8e2bf1b10677b65f1e35d85b02b2f
parent 13471 e6284105877656566837ba027e19ca8cbd6e5067
child 13473 46f13abb290a48c327a8e485223d65bf4fa1323f
child 13475 2fe681068001e1589ae22daed2123c2aa15614ab
push id706
push userssitter@gmail.com
push dateWed, 10 Oct 2012 19:45:53 +0000
treeherdercomm-beta@ffe3ddad9bb8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilipp, philipp
bugs760243
Bug 760243 - Fix shutdown errors and crash "Assertion failure: !connections[i]->ConnectionReady(), mozStorageService.cpp" r=philipp a=philipp
calendar/base/src/calCalendarManager.js
calendar/base/src/calDeletedItems.js
calendar/base/src/calTimezoneService.js
calendar/providers/storage/calStorageCalendar.js
--- a/calendar/base/src/calCalendarManager.js
+++ b/calendar/base/src/calCalendarManager.js
@@ -43,16 +43,17 @@ calCalendarManager.prototype = {
     get readOnlyCalendarCount() {
         return this.mReadonlyCalendarCount;
     },
 
     get calendarCount() {
         return this.mCalendarCount;
     },
 
+    // calIStartupService:
     startup: function ccm_startup(aCompleteListener) {
         AddonManager.addAddonListener(gCalendarManagerAddonListener);
         this.checkAndMigrateDB();
         this.mCache = null;
         this.mCalObservers = null;
         this.mRefreshTimer = {};
         this.setupOfflineObservers();
         if (cal.isSunbird()) {
@@ -75,18 +76,16 @@ calCalendarManager.prototype = {
 
     shutdown: function ccm_shutdown(aCompleteListener) {
         for each (var calendar in this.mCache) {
             calendar.removeObserver(this.mCalObservers[calendar.id]);
         }
 
         this.cleanupOfflineObservers();
 
-        Services.obs.removeObserver(this, "profile-after-change");
-        Services.obs.removeObserver(this, "profile-before-change");
         Services.obs.removeObserver(this, "http-on-modify-request");
 
         AddonManager.removeAddonListener(gCalendarManagerAddonListener);
 
         // Remove the observer if the pref is set. This might fail when the
         // user flips the pref, but we assume he is going to restart anyway
         // afterwards.
         if (cal.getPrefSafe("calendar.network.multirealm", false)) {
@@ -120,22 +119,16 @@ calCalendarManager.prototype = {
             }
         } catch (ex) {
             // If user cancels an exception is expected.
         }
     },
 
     observe: function ccm_observe(aSubject, aTopic, aData) {
         switch (aTopic) {
-            case "profile-after-change":
-                this.startup();
-                break;
-            case "profile-before-change":
-                this.shutdown();
-                break;
             case "timer-callback":
                 // Refresh all the calendars that can be refreshed.
                 var cals = this.getCalendars({});
                 for each (var calendar in cals) {
                     if (!calendar.getProperty("disabled") && calendar.canRefresh) {
                         calendar.refresh();
                     }
                 }
@@ -345,17 +338,17 @@ calCalendarManager.prototype = {
             selectPrefs.reset();
             selectCalendars.reset();
         }
     },
 
     checkAndMigrateDB: function calmgr_checkAndMigrateDB() {
         let storageSdb = Services.dirsvc.get("ProfD", Components.interfaces.nsILocalFile);
         storageSdb.append("storage.sdb");
-        db = Services.storage.openDatabase(storageSdb);
+        let db = Services.storage.openDatabase(storageSdb);
 
         db.beginTransactionAs(Components.interfaces.mozIStorageConnection.TRANSACTION_EXCLUSIVE);
         try {
             if (db.tableExists("cal_calendars_prefs")) {
                 // Check if we need to upgrade:
                 let version = this.getSchemaVersion(db);
                 //cal.LOG("*** Calendar schema version is: " + version);
                 if (version < DB_SCHEMA_VERSION) {
--- a/calendar/base/src/calDeletedItems.js
+++ b/calendar/base/src/calDeletedItems.js
@@ -126,35 +126,39 @@ calDeletedItems.prototype = {
             let stmt = "DELETE FROM cal_deleted_items WHERE id = :id";
             this.stmtUnmarkDelete = this.mDB.createStatement(stmt);
         }
         if (!this.stmtGetWithCal) {
             let stmt = "SELECT time_deleted FROM cal_deleted_items WHERE cal_id = :calId AND id = :id";
             this.stmtGetWithCal = this.mDB.createStatement(stmt);
         }
         if (!this.stmtGet) {
-            stmt = "SELECT time_deleted FROM cal_deleted_items WHERE id = :id";
+            let stmt = "SELECT time_deleted FROM cal_deleted_items WHERE id = :id";
             this.stmtGet = this.mDB.createStatement(stmt);
         }
         if (!this.stmtFlush) {
-            stmt = "DELETE FROM cal_deleted_items WHERE time_deleted < :stale_time";
+            let stmt = "DELETE FROM cal_deleted_items WHERE time_deleted < :stale_time";
             this.stmtFlush = this.mDB.createStatement(stmt);
         }
     },
 
     shutdown: function shutdown() {
-        if (this.stmtMarkDelete) this.stmtMarkDelete.finalize();
-        if (this.stmtUnmarkDelete) this.stmtUnmarkDelete.finalize();
-        if (this.stmtGet) this.stmtGet.finalize();
-        if (this.stmtGetWithCal) this.stmtGetWithCal.finalize();
-        if (this.stmtFlush) this.stmtFlush.finalize();
+        try {
+            if (this.stmtMarkDelete) this.stmtMarkDelete.finalize();
+            if (this.stmtUnmarkDelete) this.stmtUnmarkDelete.finalize();
+            if (this.stmtGet) this.stmtGet.finalize();
+            if (this.stmtGetWithCal) this.stmtGetWithCal.finalize();
+            if (this.stmtFlush) this.stmtFlush.finalize();
 
-        if (this.mDB) { this.mDB.close(); this.mDB = null; }
+            if (this.mDB) { this.mDB.asyncClose(); this.mDB = null; }
+        } catch (e) {
+            cal.ERROR("Error closing deleted items database: " + e);
+        }
 
-        cal.getCalendarManager.removeCalendarObserver(this);
+        cal.getCalendarManager().removeCalendarObserver(this);
     },
 
     // calIObserver
     onStartBatch: function() {},
     onEndBatch: function() {},
     onModifyItem: function() {},
     onError: function() {},
     onPropertyChanged: function() {},
--- a/calendar/base/src/calTimezoneService.js
+++ b/calendar/base/src/calTimezoneService.js
@@ -108,27 +108,27 @@ calTimezoneService.prototype = {
     },
     implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
     flags: Components.interfaces.nsIClassInfo.SINGLETON,
 
     QueryInterface: function calTimezoneService_QueryInterface(aIID) {
         return cal.doQueryInterface(this, calTimezoneService.prototype, aIID, null, this);
     },
 
-    // nsIStartupService
+    // calIStartupService:
     startup: function startup(aCompleteListener) {
         this.ensureInitialized(aCompleteListener);
     },
 
     shutdown: function shutdown(aCompleteListener) {
         Services.prefs.removeObserver("calendar.timezone.local", this);
 
         try {
-            this.mDb.close();
-            this.mDb = null;
+            if (this.mSelectByTzid) { this.mSelectByTzid.finalize(); }
+            if (this.mDb) { this.mDb.asyncClose(); this.mDb = null; }
         } catch (e) {
             cal.ERROR("Error closing timezone database: " + e);
         }
 
         aCompleteListener.onResult(null, Components.results.NS_OK);
     },
 
     get UTC() {
--- a/calendar/providers/storage/calStorageCalendar.js
+++ b/calendar/providers/storage/calStorageCalendar.js
@@ -355,27 +355,32 @@ calStorageCalendar.prototype = {
                 this.logError("prepareInitDB  moz-profile-calendar migration exception", exc);
                 this.mDB.rollbackTransaction();
                 throw exc;
             }
         } else if (this.uri.schemeIs("moz-storage-calendar")) {
             // New style uri, no need for migration here
             let localDB = cal.getCalendarDirectory();
             localDB.append("local.sqlite");
-            localDB = Services.storage.openDatabase(localDB);
-            cal.addObserver((function() localDB.close()),
-                            "profile-before-change", true);
 
-            this.mDB = localDB;
+            this.mDB = Services.storage.openDatabase(localDB);
             upgradeDB(this.mDB);
         } else {
             throw new Components.Exception("Invalid Scheme " + this.uri.spec);
         }
 
         this.initDB();
+        Services.obs.addObserver(this, "profile-before-change", false);
+    },
+
+    observe: function cSC_observe(aSubject, aTopic, aData) {
+        if (aTopic == "profile-before-change") {
+            Services.obs.removeObserver(this, "profile-before-change");
+            this.shutdownDB();
+        }
     },
 
     /**
      * Takes care of necessary preparations for most of our statements.
      *
      * @param aStmt         The statement to prepare.
      */
     prepareStatement: function cSC_prepareStatement(aStmt) {
@@ -1085,17 +1090,17 @@ calStorageCalendar.prototype = {
     // database handling
     //
 
     // database initialization
     // assumes mDB is valid
 
     initDB: function cSC_initDB() {
         cal.ASSERT(this.mDB, "Database has not been opened!", true);
-        
+
         try {
             this.mSelectEvent = this.mDB.createStatement(
                 "SELECT * FROM cal_events " +
                 "WHERE id = :id AND cal_id = :cal_id " +
                 " AND recurrence_id IS NULL " +
                 "LIMIT 1"
                 );
 
@@ -1425,16 +1430,75 @@ calStorageCalendar.prototype = {
                 "DELETE FROM cal_metadata" +
                 " WHERE cal_id = :cal_id"
                 );
         } catch (e) {
             this.logError("Error initializing statements.", e);
         }
     },
 
+    shutdownDB: function cSC_shutdownDB() {
+        try {
+            if (this.mDeleteAlarms) { this.mDeleteAlarms.finalize(); }
+            if (this.mDeleteAllEvents) { this.mDeleteAllEvents.finalize(); }
+            if (this.mDeleteAllMetaData) { this.mDeleteAllMetaData.finalize(); }
+            if (this.mDeleteAllTodos) { this.mDeleteAllTodos.finalize(); }
+            if (this.mDeleteAttachments) { this.mDeleteAttachments.finalize(); }
+            if (this.mDeleteAttendees) { this.mDeleteAttendees.finalize(); }
+            if (this.mDeleteEvent) { this.mDeleteEvent.finalize(); }
+            if (this.mDeleteMetaData) { this.mDeleteMetaData.finalize(); }
+            if (this.mDeleteProperties) { this.mDeleteProperties.finalize(); }
+            if (this.mDeleteRecurrence) { this.mDeleteRecurrence.finalize(); }
+            if (this.mDeleteRelations) { this.mDeleteRelations.finalize(); }
+            if (this.mDeleteTodo) { this.mDeleteTodo.finalize(); }
+            if (this.mEditEventOfflineFlag) { this.mEditEventOfflineFlag.finalize(); }
+            if (this.mEditTodoOfflineFlag) { this.mEditTodoOfflineFlag.finalize(); }
+            if (this.mInsertAlarm) { this.mInsertAlarm.finalize(); }
+            if (this.mInsertAttachment) { this.mInsertAttachment.finalize(); }
+            if (this.mInsertAttendee) { this.mInsertAttendee.finalize(); }
+            if (this.mInsertEvent) { this.mInsertEvent.finalize(); }
+            if (this.mInsertMetaData) { this.mInsertMetaData.finalize(); }
+            if (this.mInsertProperty) { this.mInsertProperty.finalize(); }
+            if (this.mInsertRecurrence) { this.mInsertRecurrence.finalize(); }
+            if (this.mInsertRelation) { this.mInsertRelation.finalize(); }
+            if (this.mInsertTodo) { this.mInsertTodo.finalize(); }
+            if (this.mSelectAlarmsForItem) { this.mSelectAlarmsForItem.finalize(); }
+            if (this.mSelectAlarmsForItemWithRecurrenceId) { this.mSelectAlarmsForItemWithRecurrenceId.finalize(); }
+            if (this.mSelectAllMetaData) { this.mSelectAllMetaData.finalize(); }
+            if (this.mSelectAttachmentsForItem) { this.mSelectAttachmentsForItem.finalize(); }
+            if (this.mSelectAttachmentsForItemWithRecurrenceId) { this.mSelectAttachmentsForItemWithRecurrenceId.finalize(); }
+            if (this.mSelectAttendeesForItem) { this.mSelectAttendeesForItem.finalize(); }
+            if (this.mSelectAttendeesForItemWithRecurrenceId) { this.mSelectAttendeesForItemWithRecurrenceId.finalize(); }
+            if (this.mSelectEvent) { this.mSelectEvent.finalize(); }
+            if (this.mSelectEventExceptions) { this.mSelectEventExceptions.finalize(); }
+            if (this.mSelectEventsWithRecurrence) { this.mSelectEventsWithRecurrence.finalize(); }
+            if (this.mSelectMetaData) { this.mSelectMetaData.finalize(); }
+            if (this.mSelectNonRecurringEventsByRange) { this.mSelectNonRecurringEventsByRange.finalize(); }
+            if (this.mSelectNonRecurringTodosByRange) { this.mSelectNonRecurringTodosByRange.finalize(); }
+            if (this.mSelectPropertiesForItem) { this.mSelectPropertiesForItem.finalize(); }
+            if (this.mSelectPropertiesForItemWithRecurrenceId) { this.mSelectPropertiesForItemWithRecurrenceId.finalize(); }
+            if (this.mSelectRecurrenceForItem) { this.mSelectRecurrenceForItem.finalize(); }
+            if (this.mSelectRelationsForItem) { this.mSelectRelationsForItem.finalize(); }
+            if (this.mSelectRelationsForItemWithRecurrenceId) { this.mSelectRelationsForItemWithRecurrenceId.finalize(); }
+            if (this.mSelectTodo) { this.mSelectTodo.finalize(); }
+            if (this.mSelectTodoExceptions) { this.mSelectTodoExceptions.finalize(); }
+            if (this.mSelectTodosWithRecurrence) { this.mSelectTodosWithRecurrence.finalize(); }
+            if (this.mDeleteEventExtras) {
+                for each (let stmt in this.mDeleteEventExtras) { stmt.finalize(); }
+            }
+            if (this.mDeleteTodoExtras) {
+                for each (let stmt in this.mDeleteTodoExtras) { stmt.finalize(); }
+            }
+
+            if (this.mDB) { this.mDB.asyncClose(); this.mDB = null; }
+        } catch (e) {
+            cal.ERROR("Error closing storage database: " + e);
+        }
+    },
+
     //
     // database reading functions
     //
 
     // read in the common ItemBase attributes from aDBRow, and stick
     // them on item
     getItemBaseFromRow: function cSC_getItemBaseFromRow(row, flags, item) {
         item.calendar = this.superCalendar;