зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1440334
- (part 2) Yield to the event loop more in SyncedBookmarksMirror. r=kitcambridge
MozReview-Commit-ID: LvtnFAbVZMD --HG-- extra : rebase_source : 86741b8d79f72c17c29b28c731b167afdcf0ec2b
This commit is contained in:
Родитель
e4c2bf7278
Коммит
a9cc0e90e4
|
@ -57,6 +57,7 @@ ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Async: "resource://services-common/async.js",
|
||||
AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
OS: "resource://gre/modules/osfile.jsm",
|
||||
|
@ -81,6 +82,12 @@ const SQLITE_MAX_VARIABLE_NUMBER = 999;
|
|||
// migration code to `migrateMirrorSchema`.
|
||||
const MIRROR_SCHEMA_VERSION = 1;
|
||||
|
||||
// Use a shared jankYielder in these functions
|
||||
XPCOMUtils.defineLazyGetter(this, "maybeYield", () => Async.jankYielder());
|
||||
function yieldingIterator(collection) {
|
||||
return Async.yieldingIterator(collection, maybeYield);
|
||||
}
|
||||
|
||||
/**
|
||||
* A mirror maintains a copy of the complete tree as stored on the Sync server.
|
||||
* It is persistent.
|
||||
|
@ -245,7 +252,7 @@ class SyncedBookmarksMirror {
|
|||
await this.db.executeBeforeShutdown(
|
||||
"SyncedBookmarksMirror: store",
|
||||
db => db.executeTransaction(async () => {
|
||||
for (let record of records) {
|
||||
for await (let record of yieldingIterator(records)) {
|
||||
switch (record.type) {
|
||||
case "bookmark":
|
||||
MirrorLog.trace("Storing bookmark in mirror", record.cleartext);
|
||||
|
@ -375,7 +382,7 @@ class SyncedBookmarksMirror {
|
|||
MirrorLog.debug("Building complete merged tree");
|
||||
let merger = new BookmarkMerger(localTree, newLocalContents,
|
||||
remoteTree, newRemoteContents);
|
||||
let mergedRoot = merger.merge();
|
||||
let mergedRoot = await merger.merge();
|
||||
for (let { value, extra } of merger.telemetryEvents) {
|
||||
this.recordTelemetryEvent("mirror", "merge", value, extra);
|
||||
}
|
||||
|
@ -391,11 +398,11 @@ class SyncedBookmarksMirror {
|
|||
// The merged tree should know about all items mentioned in the local
|
||||
// and remote trees. Otherwise, it's incomplete, and we'll corrupt
|
||||
// Places or lose data on the server if we try to apply it.
|
||||
if (!merger.subsumes(localTree)) {
|
||||
if (!await merger.subsumes(localTree)) {
|
||||
throw new SyncedBookmarksMirror.ConsistencyError(
|
||||
"Merged tree doesn't mention all items from local tree");
|
||||
}
|
||||
if (!merger.subsumes(remoteTree)) {
|
||||
if (!await merger.subsumes(remoteTree)) {
|
||||
throw new SyncedBookmarksMirror.ConsistencyError(
|
||||
"Merged tree doesn't mention all items from remote tree");
|
||||
}
|
||||
|
@ -613,6 +620,7 @@ class SyncedBookmarksMirror {
|
|||
let children = record.children;
|
||||
if (children && Array.isArray(children)) {
|
||||
for (let position = 0; position < children.length; ++position) {
|
||||
await maybeYield();
|
||||
let childRecordId = children[position];
|
||||
let childGuid = validateGuid(childRecordId);
|
||||
if (!childGuid) {
|
||||
|
@ -737,7 +745,7 @@ class SyncedBookmarksMirror {
|
|||
LEFT JOIN items v ON v.guid = s.guid
|
||||
WHERE v.guid IS NULL`);
|
||||
|
||||
for (let row of orphanRows) {
|
||||
for await (let row of yieldingIterator(orphanRows)) {
|
||||
let guid = row.getResultByName("guid");
|
||||
let missingParent = row.getResultByName("missingParent");
|
||||
if (missingParent) {
|
||||
|
@ -793,7 +801,7 @@ class SyncedBookmarksMirror {
|
|||
WHERE v.guid IS NULL`,
|
||||
{ syncStatus: PlacesUtils.bookmarks.SYNC_STATUS.NORMAL });
|
||||
|
||||
for (let row of problemRows) {
|
||||
for await (let row of yieldingIterator(problemRows)) {
|
||||
let guid = row.getResultByName("guid");
|
||||
let missingLocal = row.getResultByName("missingLocal");
|
||||
if (missingLocal) {
|
||||
|
@ -878,7 +886,7 @@ class SyncedBookmarksMirror {
|
|||
unfiledGuid: PlacesUtils.bookmarks.unfiledGuid });
|
||||
|
||||
let pseudoTree = new Map();
|
||||
for (let row of itemRows) {
|
||||
for await (let row of yieldingIterator(itemRows)) {
|
||||
let parentGuid = row.getResultByName("parentGuid");
|
||||
let node = BookmarkNode.fromRemoteRow(row, remoteTimeSeconds);
|
||||
if (pseudoTree.has(parentGuid)) {
|
||||
|
@ -894,7 +902,8 @@ class SyncedBookmarksMirror {
|
|||
// recursive query, with joins in the base and recursive clauses, takes
|
||||
// 10 seconds for a mirror with 5k items. Building the pseudo-tree and
|
||||
// the pseudo-tree and recursing in JS takes 30ms for 5k items.
|
||||
inflateTree(remoteTree, pseudoTree, PlacesUtils.bookmarks.rootGuid);
|
||||
// (Note: Timing was done before adding maybeYield calls)
|
||||
await inflateTree(remoteTree, pseudoTree, PlacesUtils.bookmarks.rootGuid);
|
||||
|
||||
// Note tombstones for remotely deleted items.
|
||||
let tombstoneRows = await this.db.execute(`
|
||||
|
@ -902,7 +911,7 @@ class SyncedBookmarksMirror {
|
|||
WHERE isDeleted AND
|
||||
needsMerge`);
|
||||
|
||||
for (let row of tombstoneRows) {
|
||||
for await (let row of yieldingIterator(tombstoneRows)) {
|
||||
let guid = row.getResultByName("guid");
|
||||
remoteTree.noteDeleted(guid);
|
||||
}
|
||||
|
@ -942,7 +951,7 @@ class SyncedBookmarksMirror {
|
|||
{ unfiledGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
rootGuid: PlacesUtils.bookmarks.rootGuid });
|
||||
|
||||
for (let row of rows) {
|
||||
for await (let row of yieldingIterator(rows)) {
|
||||
let guid = row.getResultByName("guid");
|
||||
let content = BookmarkContent.fromRow(row);
|
||||
newRemoteContents.set(guid, content);
|
||||
|
@ -1019,7 +1028,7 @@ class SyncedBookmarksMirror {
|
|||
folderKind: SyncedBookmarksMirror.KIND.FOLDER,
|
||||
separatorKind: SyncedBookmarksMirror.KIND.SEPARATOR });
|
||||
|
||||
for (let row of itemRows) {
|
||||
for await (let row of yieldingIterator(itemRows)) {
|
||||
let parentGuid = row.getResultByName("parentGuid");
|
||||
let node = BookmarkNode.fromLocalRow(row, localTimeSeconds);
|
||||
localTree.insert(parentGuid, node);
|
||||
|
@ -1029,7 +1038,7 @@ class SyncedBookmarksMirror {
|
|||
let tombstoneRows = await this.db.execute(`
|
||||
SELECT guid FROM moz_bookmarks_deleted`);
|
||||
|
||||
for (let row of tombstoneRows) {
|
||||
for await (let row of yieldingIterator(tombstoneRows)) {
|
||||
let guid = row.getResultByName("guid");
|
||||
localTree.noteDeleted(guid);
|
||||
}
|
||||
|
@ -1074,7 +1083,7 @@ class SyncedBookmarksMirror {
|
|||
rootGuid: PlacesUtils.bookmarks.rootGuid,
|
||||
syncStatus: PlacesUtils.bookmarks.SYNC_STATUS.NORMAL });
|
||||
|
||||
for (let row of rows) {
|
||||
for await (let row of yieldingIterator(rows)) {
|
||||
let guid = row.getResultByName("guid");
|
||||
let content = BookmarkContent.fromRow(row);
|
||||
newLocalContents.set(guid, content);
|
||||
|
@ -1306,7 +1315,7 @@ class SyncedBookmarksMirror {
|
|||
FROM itemsRemoved v
|
||||
LEFT JOIN moz_places h ON h.id = v.placeId
|
||||
ORDER BY v.level DESC, v.parentId, v.position`);
|
||||
for (let row of removedItemRows) {
|
||||
for await (let row of yieldingIterator(removedItemRows)) {
|
||||
let info = {
|
||||
id: row.getResultByName("id"),
|
||||
parentId: row.getResultByName("parentId"),
|
||||
|
@ -1328,7 +1337,7 @@ class SyncedBookmarksMirror {
|
|||
JOIN moz_bookmarks b ON b.id = c.itemId
|
||||
JOIN moz_bookmarks p ON p.id = b.parent
|
||||
ORDER BY c.level, p.id, b.position`);
|
||||
for (let row of changedGuidRows) {
|
||||
for await (let row of yieldingIterator(changedGuidRows)) {
|
||||
let info = {
|
||||
id: row.getResultByName("id"),
|
||||
lastModified: row.getResultByName("lastModified"),
|
||||
|
@ -1351,7 +1360,7 @@ class SyncedBookmarksMirror {
|
|||
JOIN moz_bookmarks p ON p.id = b.parent
|
||||
LEFT JOIN moz_places h ON h.id = b.fk
|
||||
ORDER BY n.level, p.id, b.position`);
|
||||
for (let row of newItemRows) {
|
||||
for await (let row of yieldingIterator(newItemRows)) {
|
||||
let info = {
|
||||
id: row.getResultByName("id"),
|
||||
parentId: row.getResultByName("parentId"),
|
||||
|
@ -1376,7 +1385,7 @@ class SyncedBookmarksMirror {
|
|||
JOIN moz_bookmarks b ON b.id = c.itemId
|
||||
JOIN moz_bookmarks p ON p.id = b.parent
|
||||
ORDER BY c.level, newParentId, newPosition`);
|
||||
for (let row of movedItemRows) {
|
||||
for await (let row of yieldingIterator(movedItemRows)) {
|
||||
let info = {
|
||||
id: row.getResultByName("id"),
|
||||
guid: row.getResultByName("guid"),
|
||||
|
@ -1404,7 +1413,7 @@ class SyncedBookmarksMirror {
|
|||
LEFT JOIN moz_places h ON h.id = b.fk
|
||||
LEFT JOIN moz_places i ON i.id = c.oldPlaceId
|
||||
ORDER BY c.level, p.id, b.position`);
|
||||
for (let row of changedItemRows) {
|
||||
for await (let row of yieldingIterator(changedItemRows)) {
|
||||
let info = {
|
||||
id: row.getResultByName("id"),
|
||||
guid: row.getResultByName("guid"),
|
||||
|
@ -1424,7 +1433,7 @@ class SyncedBookmarksMirror {
|
|||
let annoRows = await this.db.execute(`
|
||||
SELECT itemId, annoName, wasRemoved FROM annosChanged
|
||||
ORDER BY itemId`);
|
||||
for (let row of annoRows) {
|
||||
for await (let row of yieldingIterator(annoRows)) {
|
||||
let id = row.getResultByName("itemId");
|
||||
let name = row.getResultByName("annoName");
|
||||
if (row.getResultByName("wasRemoved")) {
|
||||
|
@ -1610,7 +1619,7 @@ class SyncedBookmarksMirror {
|
|||
IFNULL(parentTitle, "") AS parentTitle, dateAdded
|
||||
FROM itemsToUpload`);
|
||||
|
||||
for (let row of itemRows) {
|
||||
for await (let row of yieldingIterator(itemRows)) {
|
||||
let syncChangeCounter = row.getResultByName("syncChangeCounter");
|
||||
|
||||
let guid = row.getResultByName("guid");
|
||||
|
@ -2592,12 +2601,13 @@ function validateTag(rawTag) {
|
|||
|
||||
// Recursively inflates a bookmark tree from a pseudo-tree that maps
|
||||
// parents to children.
|
||||
function inflateTree(tree, pseudoTree, parentGuid) {
|
||||
async function inflateTree(tree, pseudoTree, parentGuid) {
|
||||
let nodes = pseudoTree.get(parentGuid);
|
||||
if (nodes) {
|
||||
for (let node of nodes) {
|
||||
await maybeYield();
|
||||
tree.insert(parentGuid, node);
|
||||
inflateTree(tree, pseudoTree, node.guid);
|
||||
await inflateTree(tree, pseudoTree, node.guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3026,7 +3036,7 @@ class MergedBookmarkNode {
|
|||
* @return {BookmarkNode}
|
||||
* A node containing the decided value and structure state.
|
||||
*/
|
||||
toBookmarkNode() {
|
||||
async toBookmarkNode() {
|
||||
if (MergedBookmarkNode.cachedBookmarkNodes.has(this)) {
|
||||
return MergedBookmarkNode.cachedBookmarkNodes.get(this);
|
||||
}
|
||||
|
@ -3042,8 +3052,8 @@ class MergedBookmarkNode {
|
|||
MergedBookmarkNode.cachedBookmarkNodes.set(this, newNode);
|
||||
|
||||
if (newNode.isFolder()) {
|
||||
for (let mergedChildNode of this.mergedChildren) {
|
||||
newNode.children.push(mergedChildNode.toBookmarkNode());
|
||||
for await (let mergedChildNode of yieldingIterator(this.mergedChildren)) {
|
||||
newNode.children.push(await mergedChildNode.toBookmarkNode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3166,22 +3176,22 @@ class BookmarkMerger {
|
|||
this.telemetryEvents = [];
|
||||
}
|
||||
|
||||
merge() {
|
||||
async merge() {
|
||||
let localRoot = this.localTree.nodeForGuid(PlacesUtils.bookmarks.rootGuid);
|
||||
let remoteRoot = this.remoteTree.nodeForGuid(PlacesUtils.bookmarks.rootGuid);
|
||||
let mergedRoot = this.mergeNode(PlacesUtils.bookmarks.rootGuid, localRoot,
|
||||
remoteRoot);
|
||||
let mergedRoot = await this.mergeNode(PlacesUtils.bookmarks.rootGuid, localRoot,
|
||||
remoteRoot);
|
||||
|
||||
// Any remaining deletions on one side should be deleted on the other side.
|
||||
// This happens when the remote tree has tombstones for items that don't
|
||||
// exist in Places, or Places has tombstones for items that aren't on the
|
||||
// server.
|
||||
for (let guid of this.localTree.deletedGuids) {
|
||||
for await (let guid of yieldingIterator(this.localTree.deletedGuids)) {
|
||||
if (!this.mentions(guid)) {
|
||||
this.deleteRemotely.add(guid);
|
||||
}
|
||||
}
|
||||
for (let guid of this.remoteTree.deletedGuids) {
|
||||
for await (let guid of yieldingIterator(this.remoteTree.deletedGuids)) {
|
||||
if (!this.mentions(guid)) {
|
||||
this.deleteLocally.add(guid);
|
||||
}
|
||||
|
@ -3189,8 +3199,8 @@ class BookmarkMerger {
|
|||
return mergedRoot;
|
||||
}
|
||||
|
||||
subsumes(tree) {
|
||||
for (let guid of tree.guids()) {
|
||||
async subsumes(tree) {
|
||||
for await (let guid of Async.yieldingIterator(tree.guids())) {
|
||||
if (!this.mentions(guid)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3215,7 +3225,8 @@ class BookmarkMerger {
|
|||
* @return {MergedBookmarkNode}
|
||||
* The merged node, with merged folder children.
|
||||
*/
|
||||
mergeNode(mergedGuid, localNode, remoteNode) {
|
||||
async mergeNode(mergedGuid, localNode, remoteNode) {
|
||||
await maybeYield();
|
||||
this.mergedGuids.add(mergedGuid);
|
||||
|
||||
if (localNode) {
|
||||
|
@ -3228,7 +3239,7 @@ class BookmarkMerger {
|
|||
MirrorLog.trace("Item ${mergedGuid} exists locally as ${localNode} " +
|
||||
"and remotely as ${remoteNode}; merging",
|
||||
{ mergedGuid, localNode, remoteNode });
|
||||
let mergedNode = this.twoWayMerge(mergedGuid, localNode, remoteNode);
|
||||
let mergedNode = await this.twoWayMerge(mergedGuid, localNode, remoteNode);
|
||||
return mergedNode;
|
||||
}
|
||||
|
||||
|
@ -3242,8 +3253,8 @@ class BookmarkMerger {
|
|||
// we still need to recursively walk and merge them. This method will
|
||||
// change the merge state from local to new if any children were moved
|
||||
// or deleted.
|
||||
this.mergeChildListsIntoMergedNode(mergedNode, localNode,
|
||||
/* remoteNode */ null);
|
||||
await this.mergeChildListsIntoMergedNode(mergedNode, localNode,
|
||||
/* remoteNode */ null);
|
||||
}
|
||||
return mergedNode;
|
||||
}
|
||||
|
@ -3258,8 +3269,8 @@ class BookmarkMerger {
|
|||
// As above, a remote folder's children might still exist locally, so we
|
||||
// need to merge them and update the merge state from remote to new if
|
||||
// any children were moved or deleted.
|
||||
this.mergeChildListsIntoMergedNode(mergedNode, /* localNode */ null,
|
||||
remoteNode);
|
||||
await this.mergeChildListsIntoMergedNode(mergedNode, /* localNode */ null,
|
||||
remoteNode);
|
||||
}
|
||||
return mergedNode;
|
||||
}
|
||||
|
@ -3281,7 +3292,7 @@ class BookmarkMerger {
|
|||
* @return {MergedBookmarkNode}
|
||||
* The merged node, with merged folder children.
|
||||
*/
|
||||
twoWayMerge(mergedGuid, localNode, remoteNode) {
|
||||
async twoWayMerge(mergedGuid, localNode, remoteNode) {
|
||||
let mergeState = this.resolveTwoWayValueConflict(mergedGuid, localNode,
|
||||
remoteNode);
|
||||
MirrorLog.trace("Merge state for ${mergedGuid} is ${mergeState}",
|
||||
|
@ -3296,7 +3307,7 @@ class BookmarkMerger {
|
|||
// structure changes.
|
||||
MirrorLog.trace("Merging folders ${localNode} and ${remoteNode}",
|
||||
{ localNode, remoteNode });
|
||||
this.mergeChildListsIntoMergedNode(mergedNode, localNode, remoteNode);
|
||||
await this.mergeChildListsIntoMergedNode(mergedNode, localNode, remoteNode);
|
||||
return mergedNode;
|
||||
}
|
||||
|
||||
|
@ -3401,8 +3412,8 @@ class BookmarkMerger {
|
|||
* `true` if the merged structure state changed because the remote
|
||||
* child was locally moved or deleted; `false` otherwise.
|
||||
*/
|
||||
mergeRemoteChildIntoMergedNode(mergedNode, remoteParentNode,
|
||||
remoteChildNode) {
|
||||
async mergeRemoteChildIntoMergedNode(mergedNode, remoteParentNode,
|
||||
remoteChildNode) {
|
||||
if (this.mergedGuids.has(remoteChildNode.guid)) {
|
||||
MirrorLog.trace("Remote child ${remoteChildNode} already seen in " +
|
||||
"another folder and merged", { remoteChildNode });
|
||||
|
@ -3414,7 +3425,7 @@ class BookmarkMerger {
|
|||
{ remoteChildNode, remoteParentNode, mergedNode });
|
||||
|
||||
// Make sure the remote child isn't locally deleted.
|
||||
let structureChange = this.checkForLocalStructureChangeOfRemoteNode(
|
||||
let structureChange = await this.checkForLocalStructureChangeOfRemoteNode(
|
||||
mergedNode, remoteParentNode, remoteChildNode);
|
||||
if (structureChange == BookmarkMerger.STRUCTURE.DELETED) {
|
||||
// If the remote child is locally deleted, we need to move all descendants
|
||||
|
@ -3435,12 +3446,12 @@ class BookmarkMerger {
|
|||
"locally; looking for content match",
|
||||
{ remoteChildNode });
|
||||
|
||||
let localChildNodeByContent = this.findLocalNodeMatchingRemoteNode(
|
||||
let localChildNodeByContent = await this.findLocalNodeMatchingRemoteNode(
|
||||
mergedNode, remoteChildNode);
|
||||
|
||||
let mergedChildNode = this.mergeNode(remoteChildNode.guid,
|
||||
localChildNodeByContent,
|
||||
remoteChildNode);
|
||||
let mergedChildNode = await this.mergeNode(remoteChildNode.guid,
|
||||
localChildNodeByContent,
|
||||
remoteChildNode);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return false;
|
||||
}
|
||||
|
@ -3466,8 +3477,8 @@ class BookmarkMerger {
|
|||
"local parent ${localParentNode} is deleted remotely",
|
||||
{ remoteChildNode, remoteParentNode, localParentNode });
|
||||
|
||||
let mergedChildNode = this.mergeNode(localChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
let mergedChildNode = await this.mergeNode(localChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return false;
|
||||
}
|
||||
|
@ -3506,8 +3517,8 @@ class BookmarkMerger {
|
|||
latestRemoteAge, localParentNode,
|
||||
latestLocalAge });
|
||||
|
||||
let mergedChildNode = this.mergeNode(remoteChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
let mergedChildNode = await this.mergeNode(remoteChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return false;
|
||||
}
|
||||
|
@ -3522,8 +3533,8 @@ class BookmarkMerger {
|
|||
"${remoteChildNode} in ${remoteParentNode}",
|
||||
{ remoteChildNode, remoteParentNode });
|
||||
|
||||
let mergedChildNode = this.mergeNode(remoteChildNode.guid, localChildNode,
|
||||
remoteChildNode);
|
||||
let mergedChildNode = await this.mergeNode(remoteChildNode.guid, localChildNode,
|
||||
remoteChildNode);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return false;
|
||||
}
|
||||
|
@ -3544,7 +3555,7 @@ class BookmarkMerger {
|
|||
* child doesn't exist remotely or was locally moved; `false`
|
||||
* otherwise.
|
||||
*/
|
||||
mergeLocalChildIntoMergedNode(mergedNode, localParentNode, localChildNode) {
|
||||
async mergeLocalChildIntoMergedNode(mergedNode, localParentNode, localChildNode) {
|
||||
if (this.mergedGuids.has(localChildNode.guid)) {
|
||||
// We already merged the child when we walked another folder.
|
||||
MirrorLog.trace("Local child ${localChildNode} already seen in " +
|
||||
|
@ -3558,7 +3569,7 @@ class BookmarkMerger {
|
|||
|
||||
// Now, we know we haven't seen the local child before, and it's not in
|
||||
// this folder on the server. Check if the child is remotely deleted.
|
||||
let structureChange = this.checkForRemoteStructureChangeOfLocalNode(
|
||||
let structureChange = await this.checkForRemoteStructureChangeOfLocalNode(
|
||||
mergedNode, localParentNode, localChildNode);
|
||||
if (structureChange == BookmarkMerger.STRUCTURE.DELETED) {
|
||||
// If the child is remotely deleted, we need to move any new local
|
||||
|
@ -3573,8 +3584,8 @@ class BookmarkMerger {
|
|||
if (!remoteChildNode) {
|
||||
// The local child doesn't exist remotely, but we still need to walk
|
||||
// its children.
|
||||
let mergedChildNode = this.mergeNode(localChildNode.guid, localChildNode,
|
||||
/* remoteChildNode */ null);
|
||||
let mergedChildNode = await this.mergeNode(localChildNode.guid, localChildNode,
|
||||
/* remoteChildNode */ null);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return true;
|
||||
}
|
||||
|
@ -3601,8 +3612,8 @@ class BookmarkMerger {
|
|||
"remote parent ${remoteParentNode} is deleted locally",
|
||||
{ localChildNode, localParentNode, remoteParentNode });
|
||||
|
||||
let mergedChildNode = this.mergeNode(localChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
let mergedChildNode = await this.mergeNode(localChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return true;
|
||||
}
|
||||
|
@ -3638,8 +3649,8 @@ class BookmarkMerger {
|
|||
latestLocalAge, remoteParentNode,
|
||||
latestRemoteAge });
|
||||
|
||||
let mergedChildNode = this.mergeNode(localChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
let mergedChildNode = await this.mergeNode(localChildNode.guid,
|
||||
localChildNode, remoteChildNode);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return true;
|
||||
}
|
||||
|
@ -3648,8 +3659,8 @@ class BookmarkMerger {
|
|||
"${localChildNode} in local parent ${localParentNode}",
|
||||
{ localChildNode, localParentNode });
|
||||
|
||||
let mergedChildNode = this.mergeNode(localChildNode.guid, localChildNode,
|
||||
remoteChildNode);
|
||||
let mergedChildNode = await this.mergeNode(localChildNode.guid, localChildNode,
|
||||
remoteChildNode);
|
||||
mergedNode.mergedChildren.push(mergedChildNode);
|
||||
return true;
|
||||
}
|
||||
|
@ -3675,7 +3686,7 @@ class BookmarkMerger {
|
|||
* The remote folder node. May be `null` if the folder only exists
|
||||
* locally.
|
||||
*/
|
||||
mergeChildListsIntoMergedNode(mergedNode, localNode, remoteNode) {
|
||||
async mergeChildListsIntoMergedNode(mergedNode, localNode, remoteNode) {
|
||||
let mergeStateChanged = false;
|
||||
|
||||
if (localNode && remoteNode) {
|
||||
|
@ -3683,30 +3694,30 @@ class BookmarkMerger {
|
|||
// The folder exists locally and remotely, and the local node is newer.
|
||||
// Walk and merge local children first, followed by remaining unmerged
|
||||
// remote children.
|
||||
if (this.mergeLocalChildrenIntoMergedNode(mergedNode, localNode)) {
|
||||
if (await this.mergeLocalChildrenIntoMergedNode(mergedNode, localNode)) {
|
||||
mergeStateChanged = true;
|
||||
}
|
||||
if (this.mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode)) {
|
||||
if (await this.mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode)) {
|
||||
mergeStateChanged = true;
|
||||
}
|
||||
} else {
|
||||
// The folder exists locally and remotely, and the remote node is newer.
|
||||
// Merge remote children first, then remaining local children.
|
||||
if (this.mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode)) {
|
||||
if (await this.mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode)) {
|
||||
mergeStateChanged = true;
|
||||
}
|
||||
if (this.mergeLocalChildrenIntoMergedNode(mergedNode, localNode)) {
|
||||
if (await this.mergeLocalChildrenIntoMergedNode(mergedNode, localNode)) {
|
||||
mergeStateChanged = true;
|
||||
}
|
||||
}
|
||||
} else if (localNode) {
|
||||
// The folder only exists locally, so no remote children to merge.
|
||||
if (this.mergeLocalChildrenIntoMergedNode(mergedNode, localNode)) {
|
||||
if (await this.mergeLocalChildrenIntoMergedNode(mergedNode, localNode)) {
|
||||
mergeStateChanged = true;
|
||||
}
|
||||
} else if (remoteNode) {
|
||||
// The folder only exists remotely, so local children to merge.
|
||||
if (this.mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode)) {
|
||||
if (await this.mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode)) {
|
||||
mergeStateChanged = true;
|
||||
}
|
||||
} else {
|
||||
|
@ -3720,7 +3731,7 @@ class BookmarkMerger {
|
|||
// orphans, but we also need to flag the containing folder so that it's
|
||||
// reuploaded to the server along with the new children.
|
||||
if (mergeStateChanged) {
|
||||
let newStructureNode = mergedNode.toBookmarkNode();
|
||||
let newStructureNode = await mergedNode.toBookmarkNode();
|
||||
let newMergeState = BookmarkMergeState.new(mergedNode.mergeState,
|
||||
newStructureNode);
|
||||
MirrorLog.trace("Merge state for ${mergedNode} has new structure " +
|
||||
|
@ -3745,13 +3756,13 @@ class BookmarkMerger {
|
|||
* `true` if the merge produced a new structure that should be
|
||||
* reuploaded to the server; `false` otherwise.
|
||||
*/
|
||||
mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode) {
|
||||
async mergeRemoteChildrenIntoMergedNode(mergedNode, remoteNode) {
|
||||
MirrorLog.trace("Merging remote children of ${remoteNode} into " +
|
||||
"${mergedNode}", { remoteNode, mergedNode });
|
||||
|
||||
let mergeStateChanged = false;
|
||||
for (let remoteChildNode of remoteNode.children) {
|
||||
let remoteChildrenChanged = this.mergeRemoteChildIntoMergedNode(
|
||||
for await (let remoteChildNode of yieldingIterator(remoteNode.children)) {
|
||||
let remoteChildrenChanged = await this.mergeRemoteChildIntoMergedNode(
|
||||
mergedNode, remoteNode, remoteChildNode);
|
||||
if (remoteChildrenChanged) {
|
||||
mergeStateChanged = true;
|
||||
|
@ -3772,13 +3783,13 @@ class BookmarkMerger {
|
|||
* `true` if the merge produced a new structure that should be
|
||||
* reuploaded to the server; `false` otherwise.
|
||||
*/
|
||||
mergeLocalChildrenIntoMergedNode(mergedNode, localNode) {
|
||||
async mergeLocalChildrenIntoMergedNode(mergedNode, localNode) {
|
||||
MirrorLog.trace("Merging local children of ${localNode} into " +
|
||||
"${mergedNode}", { localNode, mergedNode });
|
||||
|
||||
let mergeStateChanged = false;
|
||||
for (let localChildNode of localNode.children) {
|
||||
let remoteChildrenChanged = this.mergeLocalChildIntoMergedNode(
|
||||
for await (let localChildNode of yieldingIterator(localNode.children)) {
|
||||
let remoteChildrenChanged = await this.mergeLocalChildIntoMergedNode(
|
||||
mergedNode, localNode, localChildNode);
|
||||
if (remoteChildrenChanged) {
|
||||
mergeStateChanged = true;
|
||||
|
@ -3804,8 +3815,8 @@ class BookmarkMerger {
|
|||
* deleted or doesn't exist locally, `MOVED` if the node is moved
|
||||
* locally, or `DELETED` if the node is deleted locally.
|
||||
*/
|
||||
checkForLocalStructureChangeOfRemoteNode(mergedNode, remoteParentNode,
|
||||
remoteNode) {
|
||||
async checkForLocalStructureChangeOfRemoteNode(mergedNode, remoteParentNode,
|
||||
remoteNode) {
|
||||
if (!this.localTree.isDeleted(remoteNode.guid)) {
|
||||
let localNode = this.localTree.nodeForGuid(remoteNode.guid);
|
||||
if (!localNode) {
|
||||
|
@ -3855,9 +3866,9 @@ class BookmarkMerger {
|
|||
|
||||
this.deleteRemotely.add(remoteNode.guid);
|
||||
|
||||
let mergedOrphanNodes = this.processRemoteOrphansForNode(mergedNode,
|
||||
remoteNode);
|
||||
this.relocateOrphansTo(mergedNode, mergedOrphanNodes);
|
||||
let mergedOrphanNodes = await this.processRemoteOrphansForNode(mergedNode,
|
||||
remoteNode);
|
||||
await this.relocateOrphansTo(mergedNode, mergedOrphanNodes);
|
||||
MirrorLog.trace("Relocating remote orphans ${mergedOrphanNodes} to " +
|
||||
"${mergedNode}", { mergedOrphanNodes, mergedNode });
|
||||
|
||||
|
@ -3881,8 +3892,8 @@ class BookmarkMerger {
|
|||
* deleted or doesn't exist remotely, `MOVED` if the node is moved
|
||||
* remotely, or `DELETED` if the node is deleted remotely.
|
||||
*/
|
||||
checkForRemoteStructureChangeOfLocalNode(mergedNode, localParentNode,
|
||||
localNode) {
|
||||
async checkForRemoteStructureChangeOfLocalNode(mergedNode, localParentNode,
|
||||
localNode) {
|
||||
if (!this.remoteTree.isDeleted(localNode.guid)) {
|
||||
let remoteNode = this.remoteTree.nodeForGuid(localNode.guid);
|
||||
if (!remoteNode) {
|
||||
|
@ -3926,9 +3937,9 @@ class BookmarkMerger {
|
|||
|
||||
this.deleteLocally.add(localNode.guid);
|
||||
|
||||
let mergedOrphanNodes = this.processLocalOrphansForNode(mergedNode,
|
||||
localNode);
|
||||
this.relocateOrphansTo(mergedNode, mergedOrphanNodes);
|
||||
let mergedOrphanNodes = await this.processLocalOrphansForNode(mergedNode,
|
||||
localNode);
|
||||
await this.relocateOrphansTo(mergedNode, mergedOrphanNodes);
|
||||
MirrorLog.trace("Relocating local orphans ${mergedOrphanNodes} to " +
|
||||
"${mergedNode}", { mergedOrphanNodes, mergedNode });
|
||||
|
||||
|
@ -3941,11 +3952,11 @@ class BookmarkMerger {
|
|||
* bookmark to a folder on another device, and deletes that folder locally.
|
||||
* This is the inverse of `processLocalOrphansForNode`.
|
||||
*/
|
||||
processRemoteOrphansForNode(mergedNode, remoteNode) {
|
||||
async processRemoteOrphansForNode(mergedNode, remoteNode) {
|
||||
let remoteOrphanNodes = [];
|
||||
|
||||
for (let remoteChildNode of remoteNode.children) {
|
||||
let structureChange = this.checkForLocalStructureChangeOfRemoteNode(
|
||||
for await (let remoteChildNode of yieldingIterator(remoteNode.children)) {
|
||||
let structureChange = await this.checkForLocalStructureChangeOfRemoteNode(
|
||||
mergedNode, remoteNode, remoteChildNode);
|
||||
if (structureChange == BookmarkMerger.STRUCTURE.MOVED ||
|
||||
structureChange == BookmarkMerger.STRUCTURE.DELETED) {
|
||||
|
@ -3957,10 +3968,10 @@ class BookmarkMerger {
|
|||
}
|
||||
|
||||
let mergedOrphanNodes = [];
|
||||
for (let remoteOrphanNode of remoteOrphanNodes) {
|
||||
for await (let remoteOrphanNode of yieldingIterator(remoteOrphanNodes)) {
|
||||
let localOrphanNode = this.localTree.nodeForGuid(remoteOrphanNode.guid);
|
||||
let mergedOrphanNode = this.mergeNode(remoteOrphanNode.guid,
|
||||
localOrphanNode, remoteOrphanNode);
|
||||
let mergedOrphanNode = await this.mergeNode(remoteOrphanNode.guid,
|
||||
localOrphanNode, remoteOrphanNode);
|
||||
mergedOrphanNodes.push(mergedOrphanNode);
|
||||
}
|
||||
|
||||
|
@ -3972,15 +3983,15 @@ class BookmarkMerger {
|
|||
* haven't also been deleted locally. This is the inverse of
|
||||
* `processRemoteOrphansForNode`.
|
||||
*/
|
||||
processLocalOrphansForNode(mergedNode, localNode) {
|
||||
async processLocalOrphansForNode(mergedNode, localNode) {
|
||||
if (!localNode.isFolder()) {
|
||||
// The local node isn't a folder, so it won't have orphans.
|
||||
return [];
|
||||
}
|
||||
|
||||
let localOrphanNodes = [];
|
||||
for (let localChildNode of localNode.children) {
|
||||
let structureChange = this.checkForRemoteStructureChangeOfLocalNode(
|
||||
for await (let localChildNode of yieldingIterator(localNode.children)) {
|
||||
let structureChange = await this.checkForRemoteStructureChangeOfLocalNode(
|
||||
mergedNode, localNode, localChildNode);
|
||||
if (structureChange == BookmarkMerger.STRUCTURE.MOVED ||
|
||||
structureChange == BookmarkMerger.STRUCTURE.DELETED) {
|
||||
|
@ -3992,10 +4003,10 @@ class BookmarkMerger {
|
|||
}
|
||||
|
||||
let mergedOrphanNodes = [];
|
||||
for (let localOrphanNode of localOrphanNodes) {
|
||||
for await (let localOrphanNode of yieldingIterator(localOrphanNodes)) {
|
||||
let remoteOrphanNode = this.remoteTree.nodeForGuid(localOrphanNode.guid);
|
||||
let mergedNode = this.mergeNode(localOrphanNode.guid,
|
||||
localOrphanNode, remoteOrphanNode);
|
||||
let mergedNode = await this.mergeNode(localOrphanNode.guid,
|
||||
localOrphanNode, remoteOrphanNode);
|
||||
mergedOrphanNodes.push(mergedNode);
|
||||
}
|
||||
|
||||
|
@ -4012,9 +4023,9 @@ class BookmarkMerger {
|
|||
* @param {MergedBookmarkNode[]} mergedOrphanNodes
|
||||
* Merged orphans to relocate to the surviving ancestor.
|
||||
*/
|
||||
relocateOrphansTo(mergedNode, mergedOrphanNodes) {
|
||||
async relocateOrphansTo(mergedNode, mergedOrphanNodes) {
|
||||
for (let mergedOrphanNode of mergedOrphanNodes) {
|
||||
let newStructureNode = mergedOrphanNode.toBookmarkNode();
|
||||
let newStructureNode = await mergedOrphanNode.toBookmarkNode();
|
||||
let newMergeState = BookmarkMergeState.new(mergedOrphanNode.mergeState,
|
||||
newStructureNode);
|
||||
mergedOrphanNode.mergeState = newMergeState;
|
||||
|
@ -4035,7 +4046,7 @@ class BookmarkMerger {
|
|||
* A matching local child node, or `null` if there are no matching
|
||||
* local items.
|
||||
*/
|
||||
findLocalNodeMatchingRemoteNode(mergedNode, remoteChildNode) {
|
||||
async findLocalNodeMatchingRemoteNode(mergedNode, remoteChildNode) {
|
||||
let localParentNode = mergedNode.localNode;
|
||||
if (!localParentNode) {
|
||||
MirrorLog.trace("Merged node ${mergedNode} doesn't exist locally; no " +
|
||||
|
@ -4050,7 +4061,7 @@ class BookmarkMerger {
|
|||
return null;
|
||||
}
|
||||
let newLocalNode = null;
|
||||
for (let localChildNode of localParentNode.children) {
|
||||
for await (let localChildNode of yieldingIterator(localParentNode.children)) {
|
||||
if (this.mergedGuids.has(localChildNode.guid)) {
|
||||
MirrorLog.trace("Not deduping ${localChildNode}; already seen in " +
|
||||
"another folder", { localChildNode });
|
||||
|
@ -4189,8 +4200,8 @@ class BookmarkObserverRecorder {
|
|||
if (this.shouldInvalidateKeywords) {
|
||||
await PlacesUtils.keywords.invalidateCachedKeywords();
|
||||
}
|
||||
this.notifyBookmarkObservers();
|
||||
this.notifyAnnoObservers();
|
||||
await this.notifyBookmarkObservers();
|
||||
await this.notifyAnnoObservers();
|
||||
if (this.shouldInvalidateLivemarks) {
|
||||
await PlacesUtils.livemarks.invalidateCachedLivemarks();
|
||||
}
|
||||
|
@ -4290,12 +4301,12 @@ class BookmarkObserverRecorder {
|
|||
});
|
||||
}
|
||||
|
||||
notifyBookmarkObservers() {
|
||||
async notifyBookmarkObservers() {
|
||||
MirrorLog.debug("Notifying bookmark observers");
|
||||
let observers = PlacesUtils.bookmarks.getObservers();
|
||||
for (let observer of observers) {
|
||||
this.notifyObserver(observer, "onBeginUpdateBatch");
|
||||
for (let info of this.bookmarkObserverNotifications) {
|
||||
for await (let info of yieldingIterator(this.bookmarkObserverNotifications)) {
|
||||
if (info.isTagging && observer.skipTags) {
|
||||
continue;
|
||||
}
|
||||
|
@ -4305,11 +4316,12 @@ class BookmarkObserverRecorder {
|
|||
}
|
||||
}
|
||||
|
||||
notifyAnnoObservers() {
|
||||
async notifyAnnoObservers() {
|
||||
MirrorLog.debug("Notifying anno observers");
|
||||
let observers = PlacesUtils.annotations.getObservers();
|
||||
for (let observer of observers) {
|
||||
for (let { name, args } of this.annoObserverNotifications) {
|
||||
let wrapped = yieldingIterator(this.annoObserverNotifications);
|
||||
for await (let { name, args } of wrapped) {
|
||||
this.notifyObserver(observer, name, args);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче