Backed out changeset 1d200bf40a51 (bug 855015) for mochitest-2 failures. a=backokut
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 17 Apr 2013 16:12:53 -0400
changeset 119084 a5a89b7510cc8ddfd0597e86debaae7cd8021ae5
parent 119083 b81fce68ef67f2c354cd3a27aea678b2f1c03837
child 119085 2a03e41195bc4c6ec003f674019014d04bff8408
push id679
push userryanvm@gmail.com
push dateWed, 17 Apr 2013 20:21:22 +0000
reviewersbackokut
bugs855015
milestone18.0
backs out1d200bf40a511a6b2ad56ea848aa3769964d0884
Backed out changeset 1d200bf40a51 (bug 855015) for mochitest-2 failures. a=backokut
dom/contacts/ContactManager.js
dom/contacts/fallback/ContactDB.jsm
dom/contacts/fallback/ContactService.jsm
dom/contacts/tests/test_contacts_getall.html
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -18,18 +18,16 @@ Cu.import("resource://gre/modules/DOMReq
 XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
   return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
-const CONTACTS_SENDMORE_MINIMUM = 5;
-
 const nsIClassInfo            = Ci.nsIClassInfo;
 const CONTACTPROPERTIES_CID   = Components.ID("{f5181640-89e8-11e1-b0c4-0800200c9a66}");
 const nsIDOMContactProperties = Ci.nsIDOMContactProperties;
 
 // ContactProperties is not directly instantiated. It is used as interface.
 
 function ContactProperties(aProp) { if (DEBUG) debug("ContactProperties Constructor"); }
 
@@ -639,19 +637,16 @@ ContactManager.prototype = {
 
   handleContinue: function CM_handleContinue(aCursorId) {
     if (DEBUG) debug("handleContinue: " + aCursorId);
     let data = this._cursorData[aCursorId];
     if (data.cachedContacts.length > 0) {
       if (DEBUG) debug("contact in cache");
       let contact = data.cachedContacts.shift();
       this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));
-      if (data.cachedContacts.length < CONTACTS_SENDMORE_MINIMUM) {
-        cpmm.sendAsyncMessage("Contacts:GetAll:SendNow", { cursorId: aCursorId });
-      }
     } else {
       if (DEBUG) debug("waiting for contact");
       data.waitingForNext = true;
     }
   },
 
   remove: function removeContact(aRecord) {
     let request;
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -17,113 +17,25 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
 
 const DB_NAME = "contacts";
 const DB_VERSION = 8;
 const STORE_NAME = "contacts";
 const SAVED_GETALL_STORE_NAME = "getallcache";
 const CHUNK_SIZE = 20;
-const CHUNK_INTERVAL = 500;
-
-// This gives us >=2^30 unique timer IDs, enough for 1 per ms for 12.4 days.
-let gNextTimeoutId = 0;
-
-let gTimeoutTable = new Map(); // int -> nsITimer
-
-function setTimeout(aCallback, aMilliseconds) {
-  let id = gNextTimeoutId++;
-  let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-  timer.initWithCallback({
-    notify: function notify_callback() {
-        clearTimeout(id);
-        aCallback();
-      }
-    },
-    aMilliseconds,
-    timer.TYPE_ONE_SHOT);
-  gTimeoutTable.set(id, timer);
-  return id;
-}
-
-function clearTimeout(aId) {
-  let timer = gTimeoutTable.get(aId);
-  if (timer) {
-    timer.cancel();
-    gTimeoutTable.delete(aId);
-  }
-}
-
-function ContactDispatcher(aContacts, aFullContacts, aCallback, aNewTxn, aClearDispatcher) {
-  this.nextIndex = 0;
-
-  this.cancelTimeout = function() {
-    if (this.interval) {
-      clearTimeout(this.interval);
-      this.interval = null;
-    }
-  };
-
-  if (aFullContacts) {
-    this.sendChunk = function() {
-      if (aContacts.length > 0) {
-        aCallback(aContacts.splice(0, CHUNK_SIZE));
-        this.interval = setTimeout(this.sendChunk, CHUNK_INTERVAL);
-      } else {
-        aCallback(null);
-        this.cancelTimeout();
-        aClearDispatcher();
-      }
-    }.bind(this);
-  } else {
-    this.count = 0;
-    this.sendChunk = function() {
-      let chunk = [];
-      aNewTxn("readonly", STORE_NAME, function(txn, store) {
-        for (let i = this.nextIndex; i < Math.min(this.nextIndex+CHUNK_SIZE, aContacts.length); ++i) {
-          store.get(aContacts[i]).onsuccess = function(e) {
-            chunk.push(e.target.result);
-            this.count++;
-            if (this.count == aContacts.length) {
-              aCallback(chunk)
-              aCallback(null);
-              this.cancelTimeout();
-              aClearDispatcher();
-            } else if (chunk.length == CHUNK_SIZE) {
-              aCallback(chunk);
-              chunk.length = 0;
-              this.nextIndex += CHUNK_SIZE;
-              this.interval = setTimeout(this.sendChunk, CHUNK_INTERVAL);
-            }
-          }.bind(this);
-        }
-      }.bind(this));
-    }.bind(this);
-  }
-
-  this.sendChunk(0);
-}
-
-ContactDispatcher.prototype = {
-  sendNow: function() {
-    this.cancelTimeout();
-    this.interval = setTimeout(this.sendChunk, 0);
-  }
-};
 
 this.ContactDB = function ContactDB(aGlobal) {
   if (DEBUG) debug("Constructor");
   this._global = aGlobal;
 }
 
 ContactDB.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
-  _dispatcher: {},
-
   upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
     if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
     let db = aDb;
     let objectStore;
     for (let currVersion = aOldVersion; currVersion < aNewVersion; currVersion++) {
       if (currVersion == 0) {
         /**
          * Create the initial database schema.
@@ -604,41 +516,55 @@ ContactDB.prototype = {
   //TODO Use Timer.jsm (bug 840360) when it's available on b2g18
   nextTick: function nextTick(aCallback, thisObj) {
     if (thisObj)
       aCallback = aCallback.bind(thisObj);
 
     Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
   },
 
-  sendNow: function CDB_sendNow(aCursorId) {
-    if (aCursorId in this._dispatcher) {
-      this._dispatcher[aCursorId].sendNow();
-    }
-  },
-
-  _clearDispatcher: function CDB_clearDispatcher(aCursorId) {
-    if (aCursorId in this._dispatcher) {
-      delete this._dispatcher[aCursorId];
-    }
-  },
-
-  getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions, aCursorId) {
+  getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions) {
     if (DEBUG) debug("getAll")
     let optionStr = JSON.stringify(aOptions);
     this.getCacheForQuery(optionStr, function(aCachedResults, aFullContacts) {
       // aFullContacts is true if the cache didn't exist and had to be created.
       // In that case, we receive the full contacts since we already have them
-      // in memory to create the cache. This allows us to avoid accessing the
-      // object store again.
+      // in memory to create the cache anyway. This allows us to avoid accessing
+      // the main object store again.
       if (aCachedResults && aCachedResults.length > 0) {
-        let newTxnFn = this.newTxn.bind(this);
-        let clearDispatcherFn = this._clearDispatcher.bind(this, aCursorId);
-        this._dispatcher[aCursorId] = new ContactDispatcher(aCachedResults, aFullContacts,
-                                                            aSuccessCb, newTxnFn, clearDispatcherFn);
+        if (DEBUG) debug("query returned " + aCachedResults.length + " contacts");
+        if (aFullContacts) {
+          if (DEBUG) debug("full contacts: " + aCachedResults.length);
+          while(aCachedResults.length) {
+            aSuccessCb(aCachedResults.splice(0, CHUNK_SIZE));
+          }
+          aSuccessCb(null);
+        } else {
+          let count = 0;
+          let sendChunk = function(start) {
+            let chunk = [];
+            this.newTxn("readonly", STORE_NAME, function(txn, store) {
+              for (let i = start; i < Math.min(start+CHUNK_SIZE, aCachedResults.length); ++i) {
+                store.get(aCachedResults[i]).onsuccess = function(e) {
+                  chunk.push(e.target.result);
+                  count++;
+                  if (count == aCachedResults.length) {
+                    aSuccessCb(chunk);
+                    aSuccessCb(null);
+                  } else if (chunk.length == CHUNK_SIZE) {
+                    aSuccessCb(chunk);
+                    chunk.length = 0;
+                    this.nextTick(sendChunk.bind(this, start+CHUNK_SIZE));
+                  }
+                }.bind(this);
+              }
+            }.bind(this));
+          }.bind(this);
+          sendChunk(0);
+        }
       } else { // no contacts
         if (DEBUG) debug("query returned no contacts");
         aSuccessCb(null);
       }
     }.bind(this));
   },
 
   /*
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -36,17 +36,17 @@ XPCOMUtils.defineLazyGetter(this, "mRIL"
          getInterface(Ci.nsIRadioInterfaceLayer);
 });
 
 let myGlobal = this;
 
 this.DOMContactManager = {
   init: function() {
     if (DEBUG) debug("Init");
-    this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
+    this._messages = ["Contacts:Find", "Contacts:GetAll",
                       "Contacts:Clear", "Contact:Save",
                       "Contact:Remove", "Contacts:GetSimContacts",
                       "Contacts:RegisterForMessages", "child-process-shutdown"];
     this._children = [];
     this._messages.forEach(function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }.bind(this));
 
@@ -113,22 +113,17 @@ this.DOMContactManager = {
         if (!this.assertPermission(aMessage, "contacts-read")) {
           return null;
         }
         this._db.getAll(
           function(aContacts) {
             mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contacts: aContacts});
           },
           function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { errorMsg: aErrorMsg }); },
-          msg.findOptions, msg.cursorId);
-        break;
-      case "Contacts:GetAll:SendNow":
-        // sendNow is a no op if there isn't an existing cursor in the DB, so we
-        // don't need to assert the permission again.
-        this._db.sendNow(msg.cursorId);
+          msg.findOptions);
         break;
       case "Contact:Save":
         if (msg.options.reason === "create") {
           if (!this.assertPermission(aMessage, "contacts-create")) {
             return null;
           }
         } else {
           if (!this.assertPermission(aMessage, "contacts-write")) {
--- a/dom/contacts/tests/test_contacts_getall.html
+++ b/dom/contacts/tests/test_contacts_getall.html
@@ -56,26 +56,18 @@ function onUnwantedSuccess() {
   ok(false, "onUnwantedSuccess: shouldn't get here");
 }
 
 function onFailure() {
   ok(false, "in on Failure!");
 }
 
 function checkStr(str1, str2, msg) {
-  // comparing /[null(,null)+]/ and undefined should pass
-  function nonNull(e) {
-    return e != null;
-  }
-  if ((Array.isArray(str1) && str1.filter(nonNull).length == 0 && str2 == undefined)
-     ||(Array.isArray(str2) && str2.filter(nonNull).length == 0 && str1 == undefined)) {
-    ok(true, msg);
-  } else if (str1) {
-    is(JSON.stringify(typeof str1 == "string" ? [str1] : str1), JSON.stringify(typeof str2 == "string" ? [str2] : str2), msg);
-  }
+  if (str1)
+    ok(typeof str1 == "string" ? [str1] : str1, (typeof str2 == "string") ? [str2] : str2, msg);
 }
 
 function checkAddress(adr1, adr2) {
   checkStr(adr1.type, adr2.type, "Same type");
   checkStr(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
   checkStr(adr1.locality, adr2.locality, "Same locality");
   checkStr(adr1.region, adr2.region, "Same region");
   checkStr(adr1.postalCode, adr2.postalCode, "Same postalCode");
@@ -162,30 +154,28 @@ function clearDatabase() {
   req = mozContacts.clear();
   req.onsuccess = function() {
     ok(true, "Cleared the database");
     next();
   };
   req.onerror = onFailure;
 }
 
-function addContacts() {
-  ok(true, "Adding 40 contacts");
-  for (let i = 0; i < 39; ++i) {
+function add20Contacts() {
+  ok(true, "Adding 20 contacts");
+  for (let i=0; i<19; i++) {
     createResult1 = new mozContact();
-    properties1.familyName[0] = "Testname" + (i < 10 ? "0" + i : i);
     createResult1.init(properties1);
     req = mozContacts.save(createResult1);
     req.onsuccess = function() {
       ok(createResult1.id, "The contact now has an ID.");
     };
     req.onerror = onFailure;
   };
   createResult1 = new mozContact();
-  properties1.familyName[0] = "Testname39";
   createResult1.init(properties1);
   req = mozContacts.save(createResult1);
   req.onsuccess = function() {
     ok(createResult1.id, "The contact now has an ID.");
     ok(createResult1.name == properties1.name, "Same Name");
     next();
   };
   req.onerror = onFailure;
@@ -223,37 +213,29 @@ let steps = [
         is(count, 1, "last contact - only one contact returned");
         next();
       }
     };
     req.onerror = onFailure;
   },
 
   clearDatabase,
-  addContacts,
+  add20Contacts,
 
   function() {
-    ok(true, "Retrieving 40 contacts with getAll");
-    req = mozContacts.getAll({
-      sortBy: "familyName",
-      sortOrder: "ascending"
-    });
+    ok(true, "Retrieving 20 contacts with getAll");
+    req = mozContacts.getAll({});
     let count = 0;
-    let result;
-    let props;
     req.onsuccess = function(event) {
       if (req.result) {
         ok(true, "result is valid");
-        result = req.result;
-        properties1.familyName[0] = "Testname" + (count < 10 ? "0" + count : count);
-        is(result.familyName[0], properties1.familyName[0], "Same familyName");
         count++;
         req.continue();
       } else {
-        is(count, 40, "last contact - 40 contacts returned");
+        is(count, 20, "last contact - 20 contacts returned");
         next();
       }
     };
     req.onerror = onFailure;
   },
   function() {
     ok(true, "Deleting one contact");
     req = mozContacts.remove(createResult1);
@@ -268,25 +250,25 @@ let steps = [
     let count = 0;
     req.onsuccess = function(event) {
       ok(true, "on success");
       if (req.result) {
         ok(true, "result is valid");
         count++;
         req.continue();
       } else {
-        is(count, 39, "last contact - 39 contacts returned");
+        is(count, 19, "last contact - 19 contacts returned");
         next();
       }
     };
     req.onerror = onFailure;
   },
 
   clearDatabase,
-  addContacts,
+  add20Contacts,
 
   function() {
     ok(true, "Test cache consistency when deleting contact during getAll");
     req = mozContacts.find({});
     req.onsuccess = function(e) {
       let lastContact = e.target.result[e.target.result.length-1];
       req = mozContacts.getAll({});
       let count = 0;
@@ -303,26 +285,26 @@ let steps = [
             req.continue();
           };
         } else {
           if (req.result) {
             ok(true, "result is valid");
             count++;
             req.continue();
           } else {
-            is(count, 40, "last contact - 40 contacts returned");
+            is(count, 20, "last contact - 20 contacts returned");
             next();
           }
         }
       };
     };
   },
 
   clearDatabase,
-  addContacts,
+  add20Contacts,
 
   function() {
     ok(true, "Delete the current contact while iterating");
     req = mozContacts.getAll({});
     let count = 0;
     let previousId = null;
     req.onsuccess = function() {
       if (req.result) {
@@ -333,72 +315,72 @@ let steps = [
         previousId = req.result.id;
         count++;
         let delReq = mozContacts.remove(req.result);
         delReq.onsuccess = function() {
           ok(true, "deleted current contact");
           req.continue();
         };
       } else {
-        is(count, 40, "returned 40 contacts");
+        is(count, 20, "returned 20 contacts");
         next();
       }
     };
   },
 
   clearDatabase,
-  addContacts,
+  add20Contacts,
 
   function() {
     ok(true, "Iterating through the contact list inside a cursor callback");
     let count1 = 0, count2 = 0;
     let req1 = mozContacts.getAll({});
     let req2;
     req1.onsuccess = function() {
       if (count1 == 0) {
         count1++;
         req2 = mozContacts.getAll({});
         req2.onsuccess = function() {
           if (req2.result) {
             count2++;
             req2.continue();
           } else {
-            is(count2, 40, "inner cursor returned 40 contacts");
+            is(count2, 20, "inner cursor returned 20 contacts");
             req1.continue();
           }
         };
       } else {
         if (req1.result) {
           count1++;
           req1.continue();
         } else {
-          is(count1, 40, "outer cursor returned 40 contacts");
+          is(count1, 20, "outer cursor returned 20 contacts");
           next();
         }
       }
     };
   },
 
   clearDatabase,
-  addContacts,
+  add20Contacts,
 
   function() {
     ok(true, "20 concurrent cursors");
     const NUM_CURSORS = 20;
     let completed = 0;
     for (let i = 0; i < NUM_CURSORS; ++i) {
       mozContacts.getAll({}).onsuccess = (function(i) {
         let count = 0;
         return function(event) {
           let req = event.target;
           if (req.result) {
             count++;
             req.continue();
           } else {
-            is(count, 40, "cursor " + i + " returned 40 contacts");
+            is(count, 20, "cursor " + i + " returned 20 contacts");
             if (++completed == NUM_CURSORS) {
               next();
             }
           }
         };
       })(i);
     }
   },