Bug 1275878 - Part 1: move back clear history operations to History.clear(). r=adw draft
authorMarco Bonardo <mbonardo@mozilla.com>
Tue, 17 May 2016 09:35:45 +0200
changeset 614228 f257f99aff6eebc44fac46d0e2d2579dae50ace2
parent 614015 5928d905c0bc0b28f5488b236444c7d7991cf8d4
child 614229 6c9dd729c2aad0b5870f0cbf1e565a33376c4f56
push id69958
push usermak77@bonardo.net
push dateMon, 24 Jul 2017 09:35:11 +0000
reviewersadw
bugs1275878
milestone56.0a1
Bug 1275878 - Part 1: move back clear history operations to History.clear(). r=adw MozReview-Commit-ID: DbEJgKbTxd7
browser/components/downloads/test/browser/browser_indicatorDrop.js
browser/components/downloads/test/browser/browser_libraryDrop.js
browser/components/downloads/test/browser/head.js
toolkit/components/places/History.jsm
toolkit/components/places/nsPlacesExpiration.js
toolkit/components/places/tests/PlacesTestUtils.jsm
toolkit/components/places/tests/expiration/test_clearHistory.js
toolkit/components/places/tests/expiration/test_notifications.js
toolkit/components/places/tests/expiration/test_pref_interval.js
toolkit/components/places/tests/unit/test_history_clear.js
--- a/browser/components/downloads/test/browser/browser_indicatorDrop.js
+++ b/browser/components/downloads/test/browser/browser_indicatorDrop.js
@@ -3,17 +3,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
   "resource://testing-common/httpd.js");
 
 registerCleanupFunction(async function() {
   await task_resetState();
-  await task_clearHistory();
+  await PlacesUtils.history.clear();
 });
 
 add_task(async function test_indicatorDrop() {
   let downloadButton = document.getElementById("downloads-button");
   ok(downloadButton, "download button present");
 
   let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
       getService(Ci.mozIJSSubScriptLoader);
--- a/browser/components/downloads/test/browser/browser_libraryDrop.js
+++ b/browser/components/downloads/test/browser/browser_libraryDrop.js
@@ -3,17 +3,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
   "resource://testing-common/httpd.js");
 
 registerCleanupFunction(async function() {
   await task_resetState();
-  await task_clearHistory();
+  await PlacesUtils.history.clear();
 });
 
 add_task(async function test_indicatorDrop() {
   let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
       getService(Ci.mozIJSSubScriptLoader);
   let EventUtils = {};
   scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
 
--- a/browser/components/downloads/test/browser/head.js
+++ b/browser/components/downloads/test/browser/head.js
@@ -158,26 +158,16 @@ function startServer() {
   });
 }
 
 function httpUrl(aFileName) {
   return "http://localhost:" + gHttpServer.identity.primaryPort + "/" +
     aFileName;
 }
 
-function task_clearHistory() {
-  return new Promise(function(resolve) {
-    Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-      resolve();
-    }, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-    PlacesUtils.history.clear();
-  });
-}
-
 function openLibrary(aLeftPaneRoot) {
   let library = window.openDialog("chrome://browser/content/places/places.xul",
                                   "", "chrome,toolbar=yes,dialog=no,resizable",
                                   aLeftPaneRoot);
 
   return new Promise(resolve => {
     waitForFocus(resolve, library);
   });
--- a/toolkit/components/places/History.jsm
+++ b/toolkit/components/places/History.jsm
@@ -745,38 +745,66 @@ var invalidateFrecencies = async functio
      SET hidden = 0
      WHERE id in (${ ids })
      AND frecency <> 0`
   );
 };
 
 // Inner implementation of History.clear().
 var clear = async function(db) {
-  // Remove all history.
-  await db.execute("DELETE FROM moz_historyvisits");
+  await db.executeTransaction(async function() {
+    // Remove all non-bookmarked places entries first, this will speed up the
+    // triggers work.
+    await db.execute(`DELETE FROM moz_places WHERE foreign_count = 0`);
+    await db.execute(`DELETE FROM moz_updatehosts_temp`);
+
+    // Expire orphan icons.
+    await db.executeCached(`DELETE FROM moz_pages_w_icons
+                            WHERE page_url_hash NOT IN (SELECT url_hash FROM moz_places)`);
+    await db.executeCached(`DELETE FROM moz_icons
+                            WHERE root = 0 AND id NOT IN (SELECT icon_id FROM moz_icons_to_pages)`);
+
+    // Expire annotations.
+    await db.execute(`DELETE FROM moz_items_annos WHERE expiration = :expire_session`,
+                     { expire_session: Ci.nsIAnnotationService.EXPIRE_SESSION });
+    await db.execute(`DELETE FROM moz_annos WHERE id in (
+                        SELECT a.id FROM moz_annos a
+                        LEFT JOIN moz_places h ON a.place_id = h.id
+                        WHERE h.id IS NULL
+                           OR expiration = :expire_session
+                           OR (expiration = :expire_with_history
+                               AND h.last_visit_date ISNULL)
+                      )`, { expire_session: Ci.nsIAnnotationService.EXPIRE_SESSION,
+                            expire_with_history: Ci.nsIAnnotationService.EXPIRE_WITH_HISTORY });
+
+    // Expire inputhistory.
+    await db.execute(`DELETE FROM moz_inputhistory WHERE place_id IN (
+                        SELECT i.place_id FROM moz_inputhistory i
+                        LEFT JOIN moz_places h ON h.id = i.place_id
+                        WHERE h.id IS NULL)`);
+
+    // Remove all history.
+    await db.execute("DELETE FROM moz_historyvisits");
+
+    // Invalidate frecencies for the remaining places.
+    await db.execute(`UPDATE moz_places SET frecency =
+                        (CASE
+                          WHEN url_hash BETWEEN hash("place", "prefix_lo") AND
+                                                hash("place", "prefix_hi")
+                          THEN 0
+                          ELSE -1
+                          END)
+                        WHERE frecency > 0`);
+  });
 
   // Clear the registered embed visits.
   PlacesUtils.history.clearEmbedVisits();
 
-  // Expiration will take care of orphans.
   let observers = PlacesUtils.history.getObservers();
   notify(observers, "onClearHistory");
-
-  // Invalidate frecencies for the remaining places. This must happen
-  // after the notification to ensure it runs enqueued to expiration.
-  await db.execute(
-    `UPDATE moz_places SET frecency =
-     (CASE
-      WHEN url_hash BETWEEN hash("place", "prefix_lo") AND
-                            hash("place", "prefix_hi")
-      THEN 0
-      ELSE -1
-      END)
-     WHERE frecency > 0`);
-
   // Notify frecency change observers.
   notify(observers, "onManyFrecenciesChanged");
 };
 
 /**
  * Clean up pages whose history has been modified, by either
  * removing them entirely (if they are marked for removal,
  * typically because all visits have been removed and there
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -7,17 +7,16 @@
 /**
  * This component handles history and orphans expiration through asynchronous
  * Storage statements.
  * Expiration runs:
  * - At idle, but just once, we stop any other kind of expiration during idle
  *   to preserve batteries in portable devices.
  * - At shutdown, only if the database is dirty, we should still avoid to
  *   expire too heavily on shutdown.
- * - On ClearHistory we run a full expiration for privacy reasons.
  * - On a repeating timer we expire in small chunks.
  *
  * Expiration algorithm will adapt itself based on:
  * - Memory size of the device.
  * - Status of the database (clean or dirty).
  */
 
 const Cc = Components.classes;
@@ -104,21 +103,16 @@ const EXPIRE_AGGRESSIVITY_MULTIPLIER = 3
 // Used as a fall back value when it's not possible to calculate the real value.
 const URIENTRY_AVG_SIZE = 600;
 
 // Seconds of idle time before starting a larger expiration step.
 // Notice during idle we stop the expiration timer since we don't want to hurt
 // stand-by or mobile devices batteries.
 const IDLE_TIMEOUT_SECONDS = 5 * 60;
 
-// If a clear history ran just before we shutdown, we will skip most of the
-// expiration at shutdown.  This is maximum number of seconds from last
-// clearHistory to decide to skip expiration at shutdown.
-const SHUTDOWN_WITH_RECENT_CLEARHISTORY_TIMEOUT_SECONDS = 10;
-
 // If the number of pages over history limit is greater than this threshold,
 // expiration will be more aggressive, to bring back history to a saner size.
 const OVERLIMIT_PAGES_THRESHOLD = 1000;
 
 const MSECS_PER_DAY = 86400000;
 const ANNOS_EXPIRE_POLICIES = [
   { bind: "expire_days",
     type: Ci.nsIAnnotationService.EXPIRE_DAYS,
@@ -129,17 +123,17 @@ const ANNOS_EXPIRE_POLICIES = [
   { bind: "expire_months",
     type: Ci.nsIAnnotationService.EXPIRE_MONTHS,
     time: 180 * 1000 * MSECS_PER_DAY },
 ];
 
 // When we expire we can use these limits:
 // - SMALL for usual partial expirations, will expire a small chunk.
 // - LARGE for idle or shutdown expirations, will expire a large chunk.
-// - UNLIMITED for clearHistory, will expire everything.
+// - UNLIMITED will expire all the orphans.
 // - DEBUG will use a known limit, passed along with the debug notification.
 const LIMIT = {
   SMALL: 0,
   LARGE: 1,
   UNLIMITED: 2,
   DEBUG: 3,
 };
 
@@ -149,21 +143,20 @@ const STATUS = {
   DIRTY: 1,
   UNKNOWN: 2,
 };
 
 // Represents actions on which a query will run.
 const ACTION = {
   TIMED:           1 << 0, // happens every this._interval
   TIMED_OVERLIMIT: 1 << 1, // like TIMED but only when history is over limits
-  CLEAR_HISTORY:   1 << 2, // happens when history is cleared
-  SHUTDOWN_DIRTY:  1 << 3, // happens at shutdown for DIRTY state
-  IDLE_DIRTY:      1 << 4, // happens on idle for DIRTY state
-  IDLE_DAILY:      1 << 5, // happens once a day on idle
-  DEBUG:           1 << 6, // happens on TOPIC_DEBUG_START_EXPIRATION
+  SHUTDOWN_DIRTY:  1 << 2, // happens at shutdown for DIRTY state
+  IDLE_DIRTY:      1 << 3, // happens on idle for DIRTY state
+  IDLE_DAILY:      1 << 4, // happens once a day on idle
+  DEBUG:           1 << 5, // happens on TOPIC_DEBUG_START_EXPIRATION
 };
 
 // The queries we use to expire.
 const EXPIRATION_QUERIES = {
 
   // Some visits can be expired more often than others, cause they are less
   // useful to the user and can pollute awesomebar results:
   // 1. urls over 255 chars
@@ -235,161 +228,127 @@ const EXPIRATION_QUERIES = {
   QUERY_EXPIRE_URIS: {
     sql: `DELETE FROM moz_places WHERE id IN (
             SELECT p_id FROM expiration_notify WHERE p_id NOTNULL
           ) AND foreign_count = 0 AND last_visit_date ISNULL`,
     actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
              ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
-  // Expire orphan URIs from the database.
-  QUERY_SILENT_EXPIRE_ORPHAN_URIS: {
-    sql: `DELETE FROM moz_places WHERE id IN (
-            SELECT h.id
-            FROM moz_places h
-            LEFT JOIN moz_historyvisits v ON h.id = v.place_id
-            WHERE h.last_visit_date IS NULL
-              AND h.foreign_count = 0
-              AND v.id IS NULL
-            LIMIT :limit_uris
-          )`,
-    actions: ACTION.CLEAR_HISTORY
-  },
-
   // Hosts accumulated during the places delete are updated through a trigger
   // (see nsPlacesTriggers.h).
   QUERY_UPDATE_HOSTS: {
     sql: `DELETE FROM moz_updatehosts_temp`,
-    actions: ACTION.CLEAR_HISTORY | ACTION.TIMED | ACTION.TIMED_OVERLIMIT |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
+    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire orphan pages from the icons database.
   QUERY_EXPIRE_FAVICONS_PAGES: {
     sql: `DELETE FROM moz_pages_w_icons
           WHERE page_url_hash NOT IN (
             SELECT url_hash FROM moz_places
           )`,
-    actions: ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
+    actions: ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire orphan icons from the database.
   QUERY_EXPIRE_FAVICONS: {
     sql: `DELETE FROM moz_icons
           WHERE root = 0 AND id NOT IN (
             SELECT icon_id FROM moz_icons_to_pages
           )`,
-    actions: ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
+    actions: ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire orphan page annotations from the database.
   QUERY_EXPIRE_ANNOS: {
     sql: `DELETE FROM moz_annos WHERE id in (
             SELECT a.id FROM moz_annos a
             LEFT JOIN moz_places h ON a.place_id = h.id
             WHERE h.id IS NULL
             LIMIT :limit_annos
           )`,
-    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
+    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire page annotations based on expiration policy.
   QUERY_EXPIRE_ANNOS_WITH_POLICY: {
     sql: `DELETE FROM moz_annos
           WHERE (expiration = :expire_days
             AND :expire_days_time > MAX(lastModified, dateAdded))
              OR (expiration = :expire_weeks
             AND :expire_weeks_time > MAX(lastModified, dateAdded))
              OR (expiration = :expire_months
             AND :expire_months_time > MAX(lastModified, dateAdded))`,
-    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
+    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire items annotations based on expiration policy.
   QUERY_EXPIRE_ITEMS_ANNOS_WITH_POLICY: {
     sql: `DELETE FROM moz_items_annos
           WHERE (expiration = :expire_days
             AND :expire_days_time > MAX(lastModified, dateAdded))
              OR (expiration = :expire_weeks
             AND :expire_weeks_time > MAX(lastModified, dateAdded))
              OR (expiration = :expire_months
             AND :expire_months_time > MAX(lastModified, dateAdded))`,
-    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
+    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire page annotations based on expiration policy.
   QUERY_EXPIRE_ANNOS_WITH_HISTORY: {
     sql: `DELETE FROM moz_annos
           WHERE expiration = :expire_with_history
             AND NOT EXISTS (SELECT id FROM moz_historyvisits
                             WHERE place_id = moz_annos.place_id LIMIT 1)`,
-    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
+    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire item annos without a corresponding item id.
   QUERY_EXPIRE_ITEMS_ANNOS: {
     sql: `DELETE FROM moz_items_annos WHERE id IN (
             SELECT a.id FROM moz_items_annos a
             LEFT JOIN moz_bookmarks b ON a.item_id = b.id
             WHERE b.id IS NULL
             LIMIT :limit_annos
           )`,
-    actions: ACTION.CLEAR_HISTORY | ACTION.IDLE_DAILY | ACTION.DEBUG
+    actions: ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire all annotation names without a corresponding annotation.
   QUERY_EXPIRE_ANNO_ATTRIBUTES: {
     sql: `DELETE FROM moz_anno_attributes WHERE id IN (
             SELECT n.id FROM moz_anno_attributes n
             LEFT JOIN moz_annos a ON n.id = a.anno_attribute_id
             LEFT JOIN moz_items_annos t ON n.id = t.anno_attribute_id
             WHERE a.anno_attribute_id IS NULL
               AND t.anno_attribute_id IS NULL
             LIMIT :limit_annos
           )`,
-    actions: ACTION.CLEAR_HISTORY | ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY |
+    actions: ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY |
              ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Expire orphan inputhistory.
   QUERY_EXPIRE_INPUTHISTORY: {
     sql: `DELETE FROM moz_inputhistory WHERE place_id IN (
             SELECT i.place_id FROM moz_inputhistory i
             LEFT JOIN moz_places h ON h.id = i.place_id
             WHERE h.id IS NULL
             LIMIT :limit_inputhistory
           )`,
-    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.CLEAR_HISTORY |
-             ACTION.SHUTDOWN_DIRTY | ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY |
-             ACTION.DEBUG
-  },
-
-  // Expire all session annotations.  Should only be called at shutdown.
-  QUERY_EXPIRE_ANNOS_SESSION: {
-    sql: "DELETE FROM moz_annos WHERE expiration = :expire_session",
-    actions: ACTION.CLEAR_HISTORY | ACTION.DEBUG
-  },
-
-  // Expire all session item annotations.  Should only be called at shutdown.
-  QUERY_EXPIRE_ITEMS_ANNOS_SESSION: {
-    sql: "DELETE FROM moz_items_annos WHERE expiration = :expire_session",
-    actions: ACTION.CLEAR_HISTORY | ACTION.DEBUG
+    actions: ACTION.TIMED | ACTION.TIMED_OVERLIMIT | ACTION.SHUTDOWN_DIRTY |
+             ACTION.IDLE_DIRTY | ACTION.IDLE_DAILY | ACTION.DEBUG
   },
 
   // Select entries for notifications.
   // If p_id is set whole_entry = 1, then we have expired the full page.
   // Either p_id or v_id are always set.
   QUERY_SELECT_NOTIFICATIONS: {
     sql: `SELECT url, guid, MAX(visit_date) AS visit_date,
                  MAX(IFNULL(MIN(p_id, 1), MIN(v_id, 0))) AS whole_entry,
@@ -492,22 +451,19 @@ nsPlacesExpiration.prototype = {
       this._shuttingDown = true;
       this.expireOnIdle = false;
 
       if (this._timer) {
         this._timer.cancel();
         this._timer = null;
       }
 
-      // If we didn't ran a clearHistory recently and database is dirty, we
-      // want to expire some entries, to speed up the expiration process.
-      let hasRecentClearHistory =
-        Date.now() - this._lastClearHistoryTime <
-          SHUTDOWN_WITH_RECENT_CLEARHISTORY_TIMEOUT_SECONDS * 1000;
-      if (!hasRecentClearHistory && this.status == STATUS.DIRTY) {
+      // If the database is dirty, we want to expire some entries, to speed up
+      // the expiration process.
+      if (this.status == STATUS.DIRTY) {
         this._expireWithActionAndLimit(ACTION.SHUTDOWN_DIRTY, LIMIT.LARGE);
       }
 
       this._finalizeInternalStatements();
     } else if (aTopic == TOPIC_PREF_CHANGED) {
       this._loadPrefsPromise = this._loadPrefs().then(() => {
         if (aData == PREF_INTERVAL_SECONDS) {
           // Renew the timer with the new interval value.
@@ -572,22 +528,19 @@ nsPlacesExpiration.prototype = {
   onEndUpdateBatch: function PEX_onEndUpdateBatch() {
     this._inBatchMode = false;
 
     // Restore timer.
     if (!this._timer)
       this._newTimer();
   },
 
-  _lastClearHistoryTime: 0,
   onClearHistory: function PEX_onClearHistory() {
-    this._lastClearHistoryTime = Date.now();
-    // Expire orphans.  History status is clean after a clear history.
+    // History status is clean after a clear history.
     this.status = STATUS.CLEAN;
-    this._expireWithActionAndLimit(ACTION.CLEAR_HISTORY, LIMIT.UNLIMITED);
   },
 
   onVisit() {},
   onTitleChanged() {},
   onDeleteURI() {},
   onPageChanged() {},
   onDeleteVisits() {},
 
@@ -977,19 +930,16 @@ nsPlacesExpiration.prototype = {
         // Avoid expiring all visits in case of an unlimited debug expiration,
         // just remove orphans instead.
         params.limit_visits =
           aLimit == LIMIT.DEBUG && baseLimit == -1 ? 0 : baseLimit;
         break;
       case "QUERY_FIND_URIS_TO_EXPIRE":
         params.limit_uris = baseLimit;
         break;
-      case "QUERY_SILENT_EXPIRE_ORPHAN_URIS":
-        params.limit_uris = baseLimit;
-        break;
       case "QUERY_EXPIRE_ANNOS":
         // Each page may have multiple annos.
         params.limit_annos = baseLimit * EXPIRE_AGGRESSIVITY_MULTIPLIER;
         break;
       case "QUERY_EXPIRE_ANNOS_WITH_POLICY":
       case "QUERY_EXPIRE_ITEMS_ANNOS_WITH_POLICY":
         let microNow = Date.now() * 1000;
         ANNOS_EXPIRE_POLICIES.forEach(function(policy) {
@@ -1004,20 +954,16 @@ nsPlacesExpiration.prototype = {
         params.limit_annos = baseLimit;
         break;
       case "QUERY_EXPIRE_ANNO_ATTRIBUTES":
         params.limit_annos = baseLimit;
         break;
       case "QUERY_EXPIRE_INPUTHISTORY":
         params.limit_inputhistory = baseLimit;
         break;
-      case "QUERY_EXPIRE_ANNOS_SESSION":
-      case "QUERY_EXPIRE_ITEMS_ANNOS_SESSION":
-        params.expire_session = Ci.nsIAnnotationService.EXPIRE_SESSION;
-        break;
     }
 
     return stmt;
   },
 
   /**
    * Creates a new timer based on this._interval.
    *
--- a/toolkit/components/places/tests/PlacesTestUtils.jsm
+++ b/toolkit/components/places/tests/PlacesTestUtils.jsm
@@ -123,26 +123,21 @@ this.PlacesTestUtils = Object.freeze({
   },
 
   /**
    * Clear all history.
    *
    * @return {Promise}
    * @resolves When history was cleared successfully.
    * @rejects JavaScript exception.
+   *
+   * @deprecated New consumers should directly use PlacesUtils.history.clear().
    */
   clearHistory() {
-    let expirationFinished = new Promise(resolve => {
-      Services.obs.addObserver(function observe(subj, topic, data) {
-        Services.obs.removeObserver(observe, topic);
-        resolve();
-      }, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
-    });
-
-    return Promise.all([expirationFinished, PlacesUtils.history.clear()]);
+    return PlacesUtils.history.clear();
   },
 
   /**
    * Waits for all pending async statements on the default connection.
    *
    * @return {Promise}
    * @resolves When all pending async statements finished.
    * @rejects Never.
--- a/toolkit/components/places/tests/expiration/test_clearHistory.js
+++ b/toolkit/components/places/tests/expiration/test_clearHistory.js
@@ -6,79 +6,18 @@
 
 /**
  * What this is aimed to test:
  *
  * History.clear() should expire everything but bookmarked pages and valid
  * annos.
  */
 
-var as = PlacesUtils.annotations;
-
-/**
- * Creates an aged annotation.
- *
- * @param aIdentifier Either a page url or an item id.
- * @param aIdentifier Name of the annotation.
- * @param aValue Value for the annotation.
- * @param aExpirePolicy Expiration policy of the annotation.
- * @param aAgeInDays Age in days of the annotation.
- * @param [optional] aLastModifiedAgeInDays Age in days of the annotation, for lastModified.
- */
-var now = Date.now();
-function add_old_anno(aIdentifier, aName, aValue, aExpirePolicy,
-                      aAgeInDays, aLastModifiedAgeInDays) {
-  let expireDate = (now - (aAgeInDays * 86400 * 1000)) * 1000;
-  let lastModifiedDate = 0;
-  if (aLastModifiedAgeInDays)
-    lastModifiedDate = (now - (aLastModifiedAgeInDays * 86400 * 1000)) * 1000;
-
-  let sql;
-  if (typeof(aIdentifier) == "number") {
-    // Item annotation.
-    as.setItemAnnotation(aIdentifier, aName, aValue, 0, aExpirePolicy);
-    // Update dateAdded for the last added annotation.
-    sql = "UPDATE moz_items_annos SET dateAdded = :expire_date, lastModified = :last_modified " +
-          "WHERE id = ( " +
-            "SELECT a.id FROM moz_items_annos a " +
-            "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
-            "WHERE a.item_id = :id " +
-              "AND n.name = :anno_name " +
-            "ORDER BY a.dateAdded DESC LIMIT 1 " +
-          ")";
-  } else if (aIdentifier instanceof Ci.nsIURI) {
-    // Page annotation.
-    as.setPageAnnotation(aIdentifier, aName, aValue, 0, aExpirePolicy);
-    // Update dateAdded for the last added annotation.
-    sql = "UPDATE moz_annos SET dateAdded = :expire_date, lastModified = :last_modified " +
-          "WHERE id = ( " +
-            "SELECT a.id FROM moz_annos a " +
-            "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
-            "JOIN moz_places h on h.id = a.place_id " +
-            "WHERE h.url_hash = hash(:id) AND h.url = :id " +
-            "AND n.name = :anno_name " +
-            "ORDER BY a.dateAdded DESC LIMIT 1 " +
-          ")";
-  } else
-    do_throw("Wrong identifier type");
-
-  let stmt = DBConn().createStatement(sql);
-  stmt.params.id = (typeof(aIdentifier) == "number") ? aIdentifier
-                                                     : aIdentifier.spec;
-  stmt.params.expire_date = expireDate;
-  stmt.params.last_modified = lastModifiedDate;
-  stmt.params.anno_name = aName;
-  try {
-    stmt.executeStep();
-  } finally {
-    stmt.finalize();
-  }
-}
-
 add_task(async function test_historyClear() {
+  let as = PlacesUtils.annotations;
   // Set interval to a large value so we don't expire on it.
   setInterval(3600); // 1h
 
   // Expire all expirable pages.
   setMaxPages(0);
 
   // Add some bookmarked page with visit and annotations.
   for (let i = 0; i < 5; i++) {
@@ -94,48 +33,38 @@ add_task(async function test_historyClea
     // Will persist because it's an EXPIRE_NEVER item anno.
     as.setItemAnnotation(id, "persist", "test", 0, as.EXPIRE_NEVER);
     // Will persist because the page is bookmarked.
     as.setPageAnnotation(pageURI, "persist", "test", 0, as.EXPIRE_NEVER);
     // All EXPIRE_SESSION annotations are expected to expire on clear history.
     as.setItemAnnotation(id, "expire_session", "test", 0, as.EXPIRE_SESSION);
     as.setPageAnnotation(pageURI, "expire_session", "test", 0, as.EXPIRE_SESSION);
     // Annotations with timed policy will expire regardless bookmarked status.
-    add_old_anno(id, "expire_days", "test", as.EXPIRE_DAYS, 8);
-    add_old_anno(id, "expire_weeks", "test", as.EXPIRE_WEEKS, 31);
-    add_old_anno(id, "expire_months", "test", as.EXPIRE_MONTHS, 181);
-    add_old_anno(pageURI, "expire_days", "test", as.EXPIRE_DAYS, 8);
-    add_old_anno(pageURI, "expire_weeks", "test", as.EXPIRE_WEEKS, 31);
-    add_old_anno(pageURI, "expire_months", "test", as.EXPIRE_MONTHS, 181);
   }
 
   // Add some visited page and annotations for each.
   for (let i = 0; i < 5; i++) {
     // All page annotations related to these expired pages are expected to
     // expire as well.
     let pageURI = uri("http://page_anno." + i + ".mozilla.org/");
     await PlacesTestUtils.addVisits({ uri: pageURI });
     as.setPageAnnotation(pageURI, "expire", "test", 0, as.EXPIRE_NEVER);
     as.setPageAnnotation(pageURI, "expire_session", "test", 0, as.EXPIRE_SESSION);
-    add_old_anno(pageURI, "expire_days", "test", as.EXPIRE_DAYS, 8);
-    add_old_anno(pageURI, "expire_weeks", "test", as.EXPIRE_WEEKS, 31);
-    add_old_anno(pageURI, "expire_months", "test", as.EXPIRE_MONTHS, 181);
   }
 
   // Expire all visits for the bookmarks
   await PlacesTestUtils.clearHistory();
 
-  ["expire_days", "expire_weeks", "expire_months", "expire_session",
+  ["expire_session",
    "expire"].forEach(function(aAnno) {
     let pages = as.getPagesWithAnnotation(aAnno);
     do_check_eq(pages.length, 0);
   });
 
-  ["expire_days", "expire_weeks", "expire_months", "expire_session",
-   "expire"].forEach(function(aAnno) {
+  ["expire_session", "expire"].forEach(function(aAnno) {
     let items = as.getItemsWithAnnotation(aAnno);
     do_check_eq(items.length, 0);
   });
 
   let pages = as.getPagesWithAnnotation("persist");
   do_check_eq(pages.length, 5);
 
   let items = as.getItemsWithAnnotation("persist");
--- a/toolkit/components/places/tests/expiration/test_notifications.js
+++ b/toolkit/components/places/tests/expiration/test_notifications.js
@@ -20,17 +20,17 @@ var gObserver = {
   }
 };
 os.addObserver(gObserver, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
 
 function run_test() {
   // Set interval to a large value so we don't expire on it.
   setInterval(3600); // 1h
 
-  PlacesTestUtils.clearHistory();
+  promiseForceExpirationStep(1);
 
   do_timeout(2000, check_result);
   do_test_pending();
 }
 
 function check_result() {
   os.removeObserver(gObserver, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
   do_check_eq(gObserver.notifications, 1);
--- a/toolkit/components/places/tests/expiration/test_pref_interval.js
+++ b/toolkit/components/places/tests/expiration/test_pref_interval.js
@@ -12,50 +12,47 @@
 // PREF_INTERVAL_SECONDS_NOTSET in nsPlacesExpiration.
 const DEFAULT_TIMER_DELAY_SECONDS = 3 * 60;
 
 // Sync this with the const value in the component.
 const EXPIRE_AGGRESSIVITY_MULTIPLIER = 3;
 
 var tests = [
 
-  // This test should be the first, so the interval won't be influenced by
-  // status of history.
   { desc: "Set interval to 1s.",
     interval: 1,
-    expectedTimerDelay: 1
+    expectedTimerDelay: 1 * EXPIRE_AGGRESSIVITY_MULTIPLIER
   },
 
   { desc: "Set interval to a negative value.",
     interval: -1,
-    expectedTimerDelay: DEFAULT_TIMER_DELAY_SECONDS
+    expectedTimerDelay: DEFAULT_TIMER_DELAY_SECONDS * EXPIRE_AGGRESSIVITY_MULTIPLIER
   },
 
   { desc: "Set interval to 0.",
     interval: 0,
-    expectedTimerDelay: DEFAULT_TIMER_DELAY_SECONDS
+    expectedTimerDelay: DEFAULT_TIMER_DELAY_SECONDS * EXPIRE_AGGRESSIVITY_MULTIPLIER
   },
 
   { desc: "Set interval to a large value.",
     interval: 100,
-    expectedTimerDelay: 100
+    expectedTimerDelay: 100 * EXPIRE_AGGRESSIVITY_MULTIPLIER
   },
 
 ];
 
 add_task(async function test() {
   // The pref should not exist by default.
   Assert.throws(() => getInterval());
 
   // Force the component, so it will start observing preferences.
   force_expiration_start();
 
   for (let currentTest of tests) {
+    currentTest = tests.shift();
     print(currentTest.desc);
     let promise = promiseTopicObserved("test-interval-changed");
     setInterval(currentTest.interval);
     let [, data] = await promise;
-    Assert.equal(data, currentTest.expectedTimerDelay * EXPIRE_AGGRESSIVITY_MULTIPLIER);
+    Assert.equal(data, currentTest.expectedTimerDelay);
   }
-
   clearInterval();
 });
-
--- a/toolkit/components/places/tests/unit/test_history_clear.js
+++ b/toolkit/components/places/tests/unit/test_history_clear.js
@@ -1,41 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
 var mDBConn = DBConn();
 
-function promiseOnClearHistoryObserved() {
-  return new Promise(resolve => {
-
-    let historyObserver = {
-      onBeginUpdateBatch() {},
-      onEndUpdateBatch() {},
-      onVisit() {},
-      onTitleChanged() {},
-      onDeleteURI(aURI) {},
-      onPageChanged() {},
-      onDeleteVisits() {},
-
-      onClearHistory() {
-        PlacesUtils.history.removeObserver(this, false);
-        resolve();
-      },
-
-      QueryInterface: XPCOMUtils.generateQI([
-        Ci.nsINavHistoryObserver,
-      ])
-    }
-    PlacesUtils.history.addObserver(historyObserver);
-  });
-}
-
 add_task(async function test_history_clear() {
   await PlacesTestUtils.addVisits([
     { uri: uri("http://typed.mozilla.org/"),
       transition: TRANSITION_TYPED },
     { uri: uri("http://link.mozilla.org/"),
       transition: TRANSITION_LINK },
     { uri: uri("http://download.mozilla.org/"),
       transition: TRANSITION_DOWNLOAD },
@@ -73,24 +48,24 @@ add_task(async function test_history_cle
     { uri: uri("http://typed.mozilla.org/"),
       transition: TRANSITION_BOOKMARK },
     { uri: uri("http://frecency.mozilla.org/"),
       transition: TRANSITION_LINK },
   ]);
   await PlacesTestUtils.promiseAsyncUpdates();
 
   // Clear history and wait for the onClearHistory notification.
-  let promiseWaitClearHistory = promiseOnClearHistoryObserved();
+  let promiseClearHistory =
+    PlacesTestUtils.waitForNotification("onClearHistory", () => true, "history");
   PlacesUtils.history.clear();
-  await promiseWaitClearHistory;
+  await promiseClearHistory;
 
   // check browserHistory returns no entries
   do_check_eq(0, PlacesUtils.history.hasHistoryEntries);
 
-  await promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
   await PlacesTestUtils.promiseAsyncUpdates();
 
   // Check that frecency for not cleared items (bookmarks) has been converted
   // to -1.
   let stmt = mDBConn.createStatement(
     "SELECT h.id FROM moz_places h WHERE h.frecency > 0 ");
   do_check_false(stmt.executeStep());
   stmt.finalize();