--- 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;