Backout 79296b6a6026 (bug 980549) for test failures, CLOSED TREE.
authorBen Turner <bent.mozilla@gmail.com>
Mon, 14 Apr 2014 18:37:34 -0700
changeset 178436 90a1ad39c6adbb32a9954de2f7d4aba70700f264
parent 178435 351382fc8e1fc7507332225afe34baa11dfa45ce
child 178437 4743c6a40048186d9a794ffeaf9036b9ee2e4d29
push id26586
push usercbook@mozilla.com
push dateTue, 15 Apr 2014 13:08:13 +0000
treeherdermozilla-central@56da72c95d48 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs980549
milestone31.0a1
backs out79296b6a6026b01c4e3efec3a31bb5007b30b0cb
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout 79296b6a6026 (bug 980549) for test failures, CLOSED TREE.
dom/base/IndexedDBHelper.jsm
dom/settings/SettingsManager.js
--- a/dom/base/IndexedDBHelper.jsm
+++ b/dom/base/IndexedDBHelper.jsm
@@ -14,21 +14,19 @@ if (DEBUG) {
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 this.EXPORTED_SYMBOLS = ["IndexedDBHelper"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
 Cu.importGlobalProperties(["indexedDB"]);
 
-XPCOMUtils.defineLazyModuleGetter(this, 'Services',
-  'resource://gre/modules/Services.jsm');
-
 this.IndexedDBHelper = function IndexedDBHelper() {}
 
 IndexedDBHelper.prototype = {
 
   // Cache the database
   _db: null,
 
   // Close the database
@@ -85,20 +83,17 @@ IndexedDBHelper.prototype = {
    * @param successCb
    *        Success callback to call.
    * @param failureCb
    *        Error callback to call when an error is encountered.
    */
   ensureDB: function ensureDB(aSuccessCb, aFailureCb) {
     if (this._db) {
       if (DEBUG) debug("ensureDB: already have a database, returning early.");
-      if (aSuccessCb) {
-        Services.tm.currentThread.dispatch(aSuccessCb,
-                                           Ci.nsIThread.DISPATCH_NORMAL);
-      }
+      aSuccessCb && aSuccessCb();
       return;
     }
     this.open(aSuccessCb, aFailureCb);
   },
 
   /**
    * Start a new transaction.
    *
--- a/dom/settings/SettingsManager.js
+++ b/dom/settings/SettingsManager.js
@@ -27,23 +27,16 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsIMemoryReporterManager");
 
 function SettingsLock(aSettingsManager) {
   this._open = true;
   this._isBusy = false;
   this._requests = new Queue();
   this._settingsManager = aSettingsManager;
   this._transaction = null;
-
-  let closeHelper = function() {
-    if (DEBUG) debug("closing lock");
-    this._open = false;
-  }.bind(this);
-
-  Services.tm.currentThread.dispatch(closeHelper, Ci.nsIThread.DISPATCH_NORMAL);
 }
 
 SettingsLock.prototype = {
   get closed() {
     return !this._open;
   },
 
   _wrap: function _wrap(obj) {
@@ -67,23 +60,21 @@ SettingsLock.prototype = {
             this._open = false;
           }.bind(lock);
           clearReq.onerror = function() {
             Services.DOMRequest.fireError(request, 0)
           };
           break;
         case "set":
           let keys = Object.getOwnPropertyNames(info.settings);
-          if (keys.length) {
-            lock._isBusy = true;
-          }
           for (let i = 0; i < keys.length; i++) {
             let key = keys[i];
             let last = i === keys.length - 1;
             if (DEBUG) debug("key: " + key + ", val: " + JSON.stringify(info.settings[key]) + ", type: " + typeof(info.settings[key]));
+            lock._isBusy = true;
             let checkKeyRequest = store.get(key);
 
             checkKeyRequest.onsuccess = function (event) {
               let defaultValue;
               let userValue = info.settings[key];
               if (event.target.result) {
                 defaultValue = event.target.result.defaultValue;
               } else {
@@ -91,46 +82,41 @@ SettingsLock.prototype = {
                 if (DEBUG) debug("MOZSETTINGS-SET-WARNING: " + key + " is not in the database.\n");
               }
 
               let obj = {settingName: key, defaultValue: defaultValue, userValue: userValue};
               if (DEBUG) debug("store1: " + JSON.stringify(obj));
               let setReq = store.put(obj);
 
               setReq.onsuccess = function() {
+                lock._isBusy = false;
                 cpmm.sendAsyncMessage("Settings:Changed", { key: key, value: userValue });
                 if (last && !request.error) {
                   lock._open = true;
                   Services.DOMRequest.fireSuccess(request, 0);
                   lock._open = false;
+                  if (!lock._requests.isEmpty()) {
+                    lock.process();
+                  }
                 }
               };
 
               setReq.onerror = function() {
                 if (!request.error) {
                   Services.DOMRequest.fireError(request, setReq.error.name)
                 }
               };
-
-              if (last) {
-                lock._isBusy = false;
-                if (!lock._requests.isEmpty()) {
-                  lock.process();
-                }
-              }
             };
             checkKeyRequest.onerror = function(event) {
               if (!request.error) {
                 Services.DOMRequest.fireError(request, checkKeyRequest.error.name)
               }
             };
           }
-          // Don't break here, instead return. Once the previous requests have
-          // finished this loop will start again.
-          return;
+          break;
         case "get":
           let getReq = (info.name === "*") ? store.mozGetAll()
                                            : store.mozGetAll(info.name);
 
           getReq.onsuccess = function(event) {
             if (DEBUG) debug("Request for '" + info.name + "' successful. " +
                              "Record count: " + event.target.result.length);
 
@@ -157,43 +143,45 @@ SettingsLock.prototype = {
             Services.DOMRequest.fireError(request, 0)
           };
           break;
       }
     }
   },
 
   createTransactionAndProcess: function() {
-    if (DEBUG) debug("database opened, creating transaction");
-
-    let manager = this._settingsManager;
-    let transactionType = manager.hasWritePrivileges ? "readwrite" : "readonly";
-
-    this._transaction =
-      manager._settingsDB._db.transaction(SETTINGSSTORE_NAME, transactionType);
-
-    this.process();
-  },
-
-  maybeProcess: function() {
-    if (this._transaction && !this._isBusy) {
-      this.process();
+    if (this._settingsManager._settingsDB._db) {
+      var lock;
+      while (lock = this._settingsManager._locks.dequeue()) {
+        if (!lock._transaction) {
+          let transactionType = this._settingsManager.hasWritePrivileges ? "readwrite" : "readonly";
+          lock._transaction = lock._settingsManager._settingsDB._db.transaction(SETTINGSSTORE_NAME, transactionType);
+        }
+        if (!lock._isBusy) {
+          lock.process();
+        } else {
+          this._settingsManager._locks.enqueue(lock);
+        }
+      }
+      if (!this._requests.isEmpty() && !this._isBusy) {
+        this.process();
+      }
     }
   },
 
   get: function get(aName) {
     if (!this._open) {
       dump("Settings lock not open!\n");
       throw Components.results.NS_ERROR_ABORT;
     }
 
     if (this._settingsManager.hasReadPrivileges) {
       let req = Services.DOMRequest.createRequest(this._settingsManager._window);
       this._requests.enqueue({ request: req, intent:"get", name: aName });
-      this.maybeProcess();
+      this.createTransactionAndProcess();
       return req;
     } else {
       if (DEBUG) debug("get not allowed");
       throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
     }
   },
 
   _serializePreservingBinaries: function _serializePreservingBinaries(aObject) {
@@ -228,72 +216,82 @@ SettingsLock.prototype = {
       throw "Settings lock not open";
     }
 
     if (this._settingsManager.hasWritePrivileges) {
       let req = Services.DOMRequest.createRequest(this._settingsManager._window);
       if (DEBUG) debug("send: " + JSON.stringify(aSettings));
       let settings = this._serializePreservingBinaries(aSettings);
       this._requests.enqueue({request: req, intent: "set", settings: settings});
-      this.maybeProcess();
+      this.createTransactionAndProcess();
       return req;
     } else {
       if (DEBUG) debug("set not allowed");
       throw "No permission to call set";
     }
   },
 
   clear: function clear() {
     if (!this._open) {
       throw "Settings lock not open";
     }
 
     if (this._settingsManager.hasWritePrivileges) {
       let req = Services.DOMRequest.createRequest(this._settingsManager._window);
       this._requests.enqueue({ request: req, intent: "clear"});
-      this.maybeProcess();
+      this.createTransactionAndProcess();
       return req;
     } else {
       if (DEBUG) debug("clear not allowed");
       throw "No permission to call clear";
     }
   },
 
   classID: Components.ID("{60c9357c-3ae0-4222-8f55-da01428470d5}"),
   contractID: "@mozilla.org/settingsLock;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
 };
 
 function SettingsManager() {
+  this._locks = new Queue();
   this._settingsDB = new SettingsDB();
   this._settingsDB.init();
 }
 
 SettingsManager.prototype = {
   _callbacks: null,
 
   _wrap: function _wrap(obj) {
     return Cu.cloneInto(obj, this._window);
   },
 
+  nextTick: function nextTick(aCallback, thisObj) {
+    if (thisObj)
+      aCallback = aCallback.bind(thisObj);
+
+    Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
+  },
+
   set onsettingchange(aHandler) {
     this.__DOM_IMPL__.setEventHandler("onsettingchange", aHandler);
   },
 
   get onsettingchange() {
     return this.__DOM_IMPL__.getEventHandler("onsettingchange");
   },
 
   createLock: function() {
     if (DEBUG) debug("get lock!");
     var lock = new SettingsLock(this);
+    this._locks.enqueue(lock);
     this._settingsDB.ensureDB(
       function() { lock.createTransactionAndProcess(); },
       function() { dump("Cannot open Settings DB. Trying to open an old version?\n"); }
     );
+    this.nextTick(function() { this._open = false; }, lock);
     return lock;
   },
 
   receiveMessage: function(aMessage) {
     if (DEBUG) debug("Settings::receiveMessage: " + aMessage.name);
     let msg = aMessage.json;
 
     switch (aMessage.name) {