Bug 869266 - Reduce number of SQL statements to record crashes; r=rnewman
authorGregory Szorc <gps@mozilla.com>
Wed, 08 May 2013 17:02:06 -0700
changeset 142190 dea5219d6b430c089a3a35edc3a6638fdf7ca09c
parent 142189 85804366a6833959248ebdd2c31895c5638b3dbf
child 142192 666b239772be4ccb558807f9cb139dda46b8cf19
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs869266
milestone23.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 869266 - Reduce number of SQL statements to record crashes; r=rnewman
services/healthreport/providers.jsm
services/healthreport/tests/xpcshell/test_provider_crashes.js
services/metrics/dataprovider.jsm
services/metrics/storage.jsm
services/metrics/tests/xpcshell/test_metrics_provider.js
services/metrics/tests/xpcshell/test_metrics_storage.js
--- a/services/healthreport/providers.jsm
+++ b/services/healthreport/providers.jsm
@@ -922,35 +922,49 @@ CrashesProvider.prototype = Object.freez
       lastCheck = parseInt(lastCheck, 10);
       if (Number.isNaN(lastCheck)) {
         lastCheck = getAgeLimit();
       }
     }
 
     let m = this.getMeasurement("crashes", 1);
 
+    // Aggregate counts locally to avoid excessive storage interaction.
+    let counts = {
+      pending: new Metrics.DailyValues(),
+      submitted: new Metrics.DailyValues(),
+    };
+
     // FUTURE detect mtimes in the future and react more intelligently.
     for (let filename in pending) {
       let modified = pending[filename].modified;
 
       if (modified.getTime() < lastCheck) {
         continue;
       }
 
-      yield m.incrementDailyCounter("pending", modified);
+      counts.pending.appendValue(modified, 1);
     }
 
     for (let filename in submitted) {
       let modified = submitted[filename].modified;
 
       if (modified.getTime() < lastCheck) {
         continue;
       }
 
-      yield m.incrementDailyCounter("submitted", modified);
+      counts.submitted.appendValue(modified, 1);
+    }
+
+    for (let [date, values] in counts.pending) {
+      yield m.incrementDailyCounter("pending", date, values.length);
+    }
+
+    for (let [date, values] in counts.submitted) {
+      yield m.incrementDailyCounter("submitted", date, values.length);
     }
 
     yield this.setState("lastCheck", "" + now.getTime());
   },
 });
 
 
 /**
--- a/services/healthreport/tests/xpcshell/test_provider_crashes.js
+++ b/services/healthreport/tests/xpcshell/test_provider_crashes.js
@@ -121,23 +121,27 @@ add_task(function test_collect() {
   currentState = yield provider.getState("lastCheck");
   do_check_neq(currentState, lastState);
   do_check_true(currentState > lastState);
 
   let now = new Date();
   let tomorrow = new Date(now.getTime() + MILLISECONDS_PER_DAY);
   let yesterday = new Date(now.getTime() - MILLISECONDS_PER_DAY);
 
-  let yesterdayID = createFakeCrash(false, yesterday);
-  let tomorrowID = createFakeCrash(false, tomorrow);
+  createFakeCrash(false, yesterday);
+
+  // Create multiple to test that multiple are handled properly.
+  createFakeCrash(false, tomorrow);
+  createFakeCrash(false, tomorrow);
+  createFakeCrash(false, tomorrow);
 
   yield provider.collectConstantData();
   values = yield m.getValues();
   do_check_eq(values.days.size, 11);
-  do_check_eq(values.days.getDay(tomorrow).get("pending"), 1);
+  do_check_eq(values.days.getDay(tomorrow).get("pending"), 3);
 
   for each (let date in gPending) {
     let day = values.days.getDay(date);
     do_check_eq(day.get("pending"), 1);
     do_check_eq(day.get("submitted"), 1);
   }
 
   yield provider.shutdown();
--- a/services/metrics/dataprovider.jsm
+++ b/services/metrics/dataprovider.jsm
@@ -228,21 +228,23 @@ Measurement.prototype = Object.freeze({
    * If the field is not known or is not a daily counter, this will throw.
    *
    *
    *
    * @param field
    *        (string) The name of the field whose value to increment.
    * @param date
    *        (Date) Day on which to increment the counter.
+   * @param by
+   *        (integer) How much to increment by.
    * @return Promise<>
    */
-  incrementDailyCounter: function (field, date=new Date()) {
+  incrementDailyCounter: function (field, date=new Date(), by=1) {
     return this.storage.incrementDailyCounterFromFieldID(this.fieldID(field),
-                                                         date);
+                                                         date, by);
   },
 
   /**
    * Record a new numeric value for a daily discrete numeric field.
    *
    * @param field
    *        (string) The name of the field to append a value to.
    * @param value
--- a/services/metrics/storage.jsm
+++ b/services/metrics/storage.jsm
@@ -486,17 +486,17 @@ const SQL = {
     "INSERT OR REPLACE INTO daily_counters VALUES (" +
       ":field_id, " +
       ":days, " +
       "COALESCE(" +
         "(SELECT value FROM daily_counters WHERE " +
           "field_id = :field_id AND day = :days " +
         "), " +
         "0" +
-      ") + 1)",
+      ") + :by)",
 
   deleteLastNumericFromFieldID:
     "DELETE FROM last_numeric WHERE field_id = :field_id",
 
   deleteLastTextFromFieldID:
     "DELETE FROM last_text WHERE field_id = :field_id",
 
   setLastNumeric:
@@ -1609,23 +1609,26 @@ MetricsStorageSqliteBackend.prototype = 
   /**
    * Increment a daily counter from a numeric field id.
    *
    * @param id
    *        (integer) Primary key of field to increment.
    * @param date
    *        (Date) When the increment occurred. This is typically "now" but can
    *        be explicitly defined for events that occurred in the past.
+   * @param by
+   *        (integer) How much to increment the value by. Defaults to 1.
    */
-  incrementDailyCounterFromFieldID: function (id, date=new Date()) {
+  incrementDailyCounterFromFieldID: function (id, date=new Date(), by=1) {
     this._ensureFieldType(id, this.FIELD_DAILY_COUNTER);
 
     let params = {
       field_id: id,
       days: dateToDays(date),
+      by: by,
     };
 
     return this._connection.executeCached(SQL.incrementDailyCounterFromFieldID,
                                           params);
   },
 
   /**
    * Obtain all counts for a specific daily counter.
--- a/services/metrics/tests/xpcshell/test_metrics_provider.js
+++ b/services/metrics/tests/xpcshell/test_metrics_provider.js
@@ -92,16 +92,20 @@ add_task(function test_measurement_stora
   yield m.incrementDailyCounter("daily-counter", now);
   yield m.incrementDailyCounter("daily-counter", yesterday);
   let count = yield provider.storage.getDailyCounterCountFromFieldID(counterID, now);
   do_check_eq(count, 2);
 
   count = yield provider.storage.getDailyCounterCountFromFieldID(counterID, yesterday);
   do_check_eq(count, 1);
 
+  yield m.incrementDailyCounter("daily-counter", now, 4);
+  count = yield provider.storage.getDailyCounterCountFromFieldID(counterID, now);
+  do_check_eq(count, 6);
+
   // Daily discrete numeric.
   let dailyDiscreteNumericID = m.fieldID("daily-discrete-numeric");
   yield m.addDailyDiscreteNumeric("daily-discrete-numeric", 5, now);
   yield m.addDailyDiscreteNumeric("daily-discrete-numeric", 6, now);
   yield m.addDailyDiscreteNumeric("daily-discrete-numeric", 7, yesterday);
 
   let values = yield provider.storage.getDailyDiscreteNumericFromFieldID(
     dailyDiscreteNumericID, now);
--- a/services/metrics/tests/xpcshell/test_metrics_storage.js
+++ b/services/metrics/tests/xpcshell/test_metrics_storage.js
@@ -440,16 +440,20 @@ add_task(function test_increment_daily_c
 
   let count = yield backend.getDailyCounterCountFromFieldID(fieldID, now);
   do_check_eq(count, 1);
 
   yield backend.incrementDailyCounterFromFieldID(fieldID, now);
   count = yield backend.getDailyCounterCountFromFieldID(fieldID, now);
   do_check_eq(count, 2);
 
+  yield backend.incrementDailyCounterFromFieldID(fieldID, now, 10);
+  count = yield backend.getDailyCounterCountFromFieldID(fieldID, now);
+  do_check_eq(count, 12);
+
   yield backend.close();
 });
 
 add_task(function test_increment_daily_counter_multiple_days() {
   let backend = yield Metrics.Storage("increment_daily_counter_multiple_days");
 
   let mID = yield backend.registerMeasurement("foo", "bar", 1);
   let fieldID = yield backend.registerField(mID, "baz",