Bug 798353 - Make SettingsListener reuse the lock. r=fabrice
authorTim Chien <timdream@gmail.com>
Wed, 04 Sep 2013 08:28:28 -0400
changeset 145532 8e0c14f835917b9bd59c04a590ceeb0cf47c8b5f
parent 145531 ff2e4d8cb650a4eb55d54df683fc1295d4cc819c
child 145533 008139ec2abb425e1bc4c978e793bb7f1e2a618e
push id25215
push userkwierso@gmail.com
push dateThu, 05 Sep 2013 00:22:19 +0000
treeherdermozilla-central@77ed46bf4c1a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs798353
milestone26.0a1
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
Bug 798353 - Make SettingsListener reuse the lock. r=fabrice
b2g/chrome/content/settings.js
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -1,72 +1,90 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-"use strict;"
+"use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
 
 #ifdef MOZ_WIDGET_GONK
 XPCOMUtils.defineLazyGetter(this, "libcutils", function () {
   Cu.import("resource://gre/modules/systemlibs.js");
   return libcutils;
 });
 #endif
 
-// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget
-// is resolved this helper could be removed.
 var SettingsListener = {
-  _callbacks: {},
+  // Timer to remove the lock.
+  _timer: null,
+
+  // lock stores here
+  _lock: null,
 
-  init: function sl_init() {
-    if ('mozSettings' in navigator && navigator.mozSettings) {
-      navigator.mozSettings.onsettingchange = this.onchange.bind(this);
-    }
-  },
+  /**
+   * getSettingsLock: create a lock or retrieve one that we saved.
+   * mozSettings.createLock() is expensive and lock should be reused
+   * whenever possible.
+   */
+  getSettingsLock: function sl_getSettingsLock() {
+    // Each time there is a getSettingsLock call, we postpone the removal.
+    clearTimeout(this._timer);
+    this._timer = setTimeout((function() {
+      this._lock = null;
+    }).bind(this), 0);
 
-  onchange: function sl_onchange(evt) {
-    var callback = this._callbacks[evt.settingName];
-    if (callback) {
-      callback(evt.settingValue);
+    // If there is a lock present we return that.
+    if (this._lock) {
+      return this._lock;
     }
+
+    // If there isn't we create a new one.
+    let settings = window.navigator.mozSettings;
+
+    return (this._lock = settings.createLock());
   },
 
   observe: function sl_observe(name, defaultValue, callback) {
-    var settings = window.navigator.mozSettings;
-    if (!settings) {
-      window.setTimeout(function() { callback(defaultValue); });
-      return;
+    let settings = window.navigator.mozSettings;
+
+    let req;
+    try {
+      req = this.getSettingsLock().get(name);
+    } catch (e) {
+      // It is possible (but rare) for getSettingsLock() to return
+      // a SettingsLock object that is no longer valid.
+      // Until https://bugzilla.mozilla.org/show_bug.cgi?id=793239
+      // is fixed, we just catch the resulting exception and try
+      // again with a fresh lock
+      console.warn('Stale lock in settings.js.',
+                   'See https://bugzilla.mozilla.org/show_bug.cgi?id=793239');
+      this._lock = null;
+      req = this.getSettingsLock().get(name);
     }
 
-    if (!callback || typeof callback !== 'function') {
-      throw new Error('Callback is not a function');
-    }
-
-    var req = settings.createLock().get(name);
     req.addEventListener('success', (function onsuccess() {
       callback(typeof(req.result[name]) != 'undefined' ?
         req.result[name] : defaultValue);
     }));
 
-    this._callbacks[name] = callback;
+    settings.addObserver(name, function settingChanged(evt) {
+      callback(evt.settingValue);
+    });
   }
 };
 
-SettingsListener.init();
-
 // =================== Console ======================
 
 SettingsListener.observe('debug.console.enabled', true, function(value) {
   Services.prefs.setBoolPref('consoleservice.enabled', value);
   Services.prefs.setBoolPref('layout.css.report_errors', value);
 });
 
 // =================== Languages ====================