Bug 1436215 - Stage outgoing weak uploads in a separate table to avoid an expensive left join. r?markh draft
authorKit Cambridge <kit@yakshaving.ninja>
Tue, 06 Feb 2018 17:00:44 -0800
changeset 751883 00d018753b331995eb424247041064c8330fbb0a
parent 751882 d12603822ce65e58c91996a54d286f4eff22a895
child 751884 bf95b432396e5c73e0ba025a0fdc8404665d8440
push id98084
push userbmo:kit@mozilla.com
push dateWed, 07 Feb 2018 01:53:52 +0000
reviewersmarkh
bugs1436215
milestone60.0a1
Bug 1436215 - Stage outgoing weak uploads in a separate table to avoid an expensive left join. r?markh MozReview-Commit-ID: LrVDTCSPyDt
toolkit/components/places/SyncedBookmarksMirror.jsm
--- a/toolkit/components/places/SyncedBookmarksMirror.jsm
+++ b/toolkit/components/places/SyncedBookmarksMirror.jsm
@@ -409,16 +409,17 @@ class SyncedBookmarksMirror {
       await this.db.execute(`DELETE FROM mergeStates`);
       await this.db.execute(`DELETE FROM itemsAdded`);
       await this.db.execute(`DELETE FROM guidsChanged`);
       await this.db.execute(`DELETE FROM itemsChanged`);
       await this.db.execute(`DELETE FROM itemsRemoved`);
       await this.db.execute(`DELETE FROM itemsMoved`);
       await this.db.execute(`DELETE FROM annosChanged`);
       await this.db.execute(`DELETE FROM keywordsChanged`);
+      await this.db.execute(`DELETE FROM itemsToWeaklyReupload`);
       await this.db.execute(`DELETE FROM itemsToUpload`);
 
       return changeRecords;
     }, this.db.TRANSACTION_IMMEDIATE);
 
     MirrorLog.debug("Replaying recorded observer notifications");
     try {
       await observersToNotify.notifyAll();
@@ -1363,77 +1364,95 @@ class SyncedBookmarksMirror {
    * user moves many items between folders.
    *
    * Conceptually, `itemsToUpload` is a transient "view" of locally changed
    * items. The change counter in Places is the persistent record of items that
    * we need to upload, so, if upload is interrupted or fails, we'll stage the
    * items again on the next sync.
    */
   async stageItemsToUpload() {
-    // Stage all locally changed items for upload, along with any remotely
-    // changed records with older local creation dates. These are tracked
-    // "weakly", in the in-memory table only. If the upload is interrupted
-    // or fails, we won't reupload the record on the next sync.
+    // Stage remotely changed items with older local creation dates. These are
+    // tracked "weakly": if the upload is interrupted or fails, we won't
+    // reupload the record on the next sync.
+    await this.db.execute(`
+      INSERT INTO itemsToWeaklyReupload(id)
+      SELECT b.id FROM moz_bookmarks b
+      JOIN mergeStates r ON r.mergedGuid = b.guid
+      JOIN items v ON v.guid = r.mergedGuid
+      WHERE r.valueState = :valueState AND
+            b.dateAdded < v.dateAdded`,
+      { valueState: BookmarkMergeState.TYPE.REMOTE });
+
+    // Stage remaining locally changed items for upload.
     await this.db.execute(`
       WITH RECURSIVE
       syncedItems(id, level) AS (
         SELECT b.id, 0 AS level FROM moz_bookmarks b
         WHERE b.guid IN (:menuGuid, :toolbarGuid, :unfiledGuid, :mobileGuid)
         UNION ALL
         SELECT b.id, s.level + 1 AS level FROM moz_bookmarks b
         JOIN syncedItems s ON s.id = b.parent
-      ),
-      annos(itemId, name, content) AS (
-        SELECT a.item_id, n.name, a.content FROM moz_items_annos a
-        JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id
       )
       INSERT INTO itemsToUpload(guid, syncChangeCounter, parentGuid,
                                 parentTitle, dateAdded, type, title, isQuery,
                                 url, tags, description, loadInSidebar,
                                 smartBookmarkName, keyword, feedURL, siteURL,
                                 position)
       SELECT b.guid, b.syncChangeCounter, p.guid, p.title, b.dateAdded, b.type,
              b.title, IFNULL(SUBSTR(h.url, 1, 6) = 'place:', 0), h.url,
              (SELECT GROUP_CONCAT(t.title, ',') FROM moz_bookmarks e
               JOIN moz_bookmarks t ON t.id = e.parent
               JOIN moz_bookmarks r ON r.id = t.parent
-              WHERE r.guid = :tagsGuid AND
+              WHERE b.type = :bookmarkType AND
+                    r.guid = :tagsGuid AND
                     e.fk = h.id),
-             (SELECT content FROM annos WHERE itemId = b.id AND
-                                              name = :descriptionAnno),
-             IFNULL((SELECT content FROM annos WHERE itemId = b.id AND
-                                                     name = :sidebarAnno), 0),
-             (SELECT content FROM annos WHERE itemId = b.id AND
-                                              name = :smartBookmarkAnno),
+             (SELECT a.content FROM moz_items_annos a
+              JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id
+              WHERE b.type IN (:bookmarkType, :folderType) AND
+                    a.item_id = b.id AND
+                    n.name = :descriptionAnno),
+             IFNULL((SELECT a.content FROM moz_items_annos a
+                     JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id
+                     WHERE a.item_id = b.id AND
+                           n.name = :sidebarAnno), 0),
+             (SELECT a.content FROM moz_items_annos a
+              JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id
+              WHERE a.item_id = b.id AND
+                    n.name = :smartBookmarkAnno),
              (SELECT keyword FROM moz_keywords WHERE place_id = h.id),
-             (SELECT content FROM annos WHERE itemId = b.id AND
-                                              name = :feedURLAnno),
-             (SELECT content FROM annos WHERE itemId = b.id AND
-                                              name = :siteURLAnno),
+             (SELECT a.content FROM moz_items_annos a
+              JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id
+              WHERE b.type = :folderType AND
+                    a.item_id = b.id AND
+                    n.name = :feedURLAnno),
+             (SELECT a.content FROM moz_items_annos a
+              JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id
+              WHERE b.type = :folderType AND
+                    a.item_id = b.id AND
+                    n.name = :siteURLAnno),
              b.position
       FROM moz_bookmarks b
       JOIN moz_bookmarks p ON p.id = b.parent
       JOIN syncedItems s ON s.id = b.id
       LEFT JOIN moz_places h ON h.id = b.fk
-      JOIN mergeStates r ON r.mergedGuid = b.guid
-      LEFT JOIN items v ON v.guid = r.mergedGuid
+      LEFT JOIN itemsToWeaklyReupload w ON w.id = b.id
       WHERE b.syncChangeCounter >= 1 OR
-            (r.valueState = :valueState AND
-              b.dateAdded < v.dateAdded)`,
+            w.id NOT NULL`,
       { menuGuid: PlacesUtils.bookmarks.menuGuid,
         toolbarGuid: PlacesUtils.bookmarks.toolbarGuid,
         unfiledGuid: PlacesUtils.bookmarks.unfiledGuid,
         mobileGuid: PlacesUtils.bookmarks.mobileGuid,
+        bookmarkType: PlacesUtils.bookmarks.TYPE_BOOKMARK,
         tagsGuid: PlacesUtils.bookmarks.tagsGuid,
         descriptionAnno: PlacesSyncUtils.bookmarks.DESCRIPTION_ANNO,
         sidebarAnno: PlacesSyncUtils.bookmarks.SIDEBAR_ANNO,
         smartBookmarkAnno: PlacesSyncUtils.bookmarks.SMART_BOOKMARKS_ANNO,
+        folderType: PlacesUtils.bookmarks.TYPE_FOLDER,
         feedURLAnno: PlacesUtils.LMANNO_FEEDURI,
-        siteURLAnno: PlacesUtils.LMANNO_SITEURI,
-        valueState: BookmarkMergeState.TYPE.REMOTE });
+        siteURLAnno: PlacesUtils.LMANNO_SITEURI });
 
     // Record tag folder names for tag queries. Parsing query URLs one by one
     // is inefficient, but queries aren't common today, and we can remove this
     // logic entirely once bug 1293445 lands.
     let queryRows = await this.db.execute(`
       SELECT guid, url FROM itemsToUpload
       WHERE isQuery`);
 
@@ -2383,16 +2402,20 @@ async function initializeTempMirrorEntit
   // Note that an item may appear multiple times in this table, so `itemId` is
   // not a primary key.
   await db.execute(`CREATE TEMP TABLE keywordsChanged(
     itemId INTEGER NOT NULL,
     placeId INTEGER NOT NULL,
     keyword TEXT
   )`);
 
+  await db.execute(`CREATE TEMP TABLE itemsToWeaklyReupload(
+    id INTEGER PRIMARY KEY
+  )`);
+
   // Stores locally changed items staged for upload. See `stageItemsToUpload`
   // for an explanation of why these tables exists.
   await db.execute(`CREATE TEMP TABLE itemsToUpload(
     guid TEXT PRIMARY KEY,
     syncChangeCounter INTEGER NOT NULL,
     isDeleted BOOLEAN NOT NULL DEFAULT 0,
     parentGuid TEXT,
     parentTitle TEXT,
@@ -3928,16 +3951,17 @@ class BookmarkObserverRecorder {
     this.notifyAnnoObservers();
     if (this.shouldInvalidateLivemarks) {
       await PlacesUtils.livemarks.invalidateCachedLivemarks();
     }
     await this.updateFrecencies();
   }
 
   async updateFrecencies() {
+    MirrorLog.debug("Recalculating frecencies for new URLs");
     await this.db.execute(`
       UPDATE moz_places SET
         frecency = CALCULATE_FRECENCY(id)
       WHERE frecency = -1`);
   }
 
   noteItemAdded(info) {
     let uri = info.urlHref ? Services.io.newURI(info.urlHref) : null;