Bug 798353 - Make SettingsListener reuse the lock. r=fabrice
authorTim Chien <timdream@gmail.com>
Wed, 04 Sep 2013 08:28:28 -0400
changeset 145425 8e0c14f835917b9bd59c04a590ceeb0cf47c8b5f
parent 145424 ff2e4d8cb650a4eb55d54df683fc1295d4cc819c
child 145426 008139ec2abb425e1bc4c978e793bb7f1e2a618e
push id709
push userryanvm@gmail.com
push dateWed, 04 Sep 2013 12:31:11 +0000
treeherderb2g-inbound@c8c55f0fbd74 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfabrice
bugs798353
milestone26.0a1
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 ====================