mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-26 00:11:35 +00:00
gh-15091: Fixed race condition when syncing new space and container (gh-15106)
This commit is contained in:
@@ -141,12 +141,21 @@ export class ZenSpacesSyncEngine extends SyncEngine {
|
||||
return ZenSpacesSyncModel.computeChangedIDs();
|
||||
}
|
||||
|
||||
async _reconcile() {
|
||||
async _reconcile(item) {
|
||||
// Incoming records always apply, and any local divergence re-uploads afterwards
|
||||
// (see ZenSpacesSyncModel.noteApplied). The base reconciliation would
|
||||
// instead drop incoming changes whenever the id is also in the local
|
||||
// changed set, because the snapshot diff stamps its changes with "now"
|
||||
// and the local side would always win the age comparison.
|
||||
//
|
||||
// An id we accept must also leave the outgoing set. Projections only
|
||||
// reflect the applied state after the delayed session collection, so
|
||||
// uploading the id later in this same sync would overwrite the record
|
||||
// we just accepted with the stale pre-apply state (and the other
|
||||
// device would then apply that, endlessly trading states back and
|
||||
// forth). Divergence that survives the collection re-uploads on a
|
||||
// later sync through the snapshot diff.
|
||||
this._modified.delete(item.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,25 @@ class nsZenSpacesSyncApplier {
|
||||
return id ? win.document.getElementById(id) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a record's container guid to the local userContextId. A guid with
|
||||
* no local mapping (its container record hasn't applied here yet) throws,
|
||||
* failing the record so it redelivers once the container exists .
|
||||
*
|
||||
* @param {?string} containerGuid
|
||||
* @returns {number}
|
||||
*/
|
||||
#resolveContainerId(containerGuid) {
|
||||
if (!containerGuid) {
|
||||
return 0;
|
||||
}
|
||||
const mapped = ZenSpacesSyncModel.contextIdForGuid(containerGuid);
|
||||
if (mapped === null) {
|
||||
throw new Error(`unknown container guid ${containerGuid}`);
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} records - decrypted incoming records.
|
||||
* @returns {Array<string>} ids of records that failed to apply.
|
||||
@@ -259,8 +278,7 @@ class nsZenSpacesSyncApplier {
|
||||
name: data.name ?? "",
|
||||
icon: data.icon ?? undefined,
|
||||
theme: data.theme ?? null,
|
||||
containerTabId:
|
||||
ZenSpacesSyncModel.contextIdForGuid(data.containerGuid) ?? 0,
|
||||
containerTabId: this.#resolveContainerId(data.containerGuid),
|
||||
};
|
||||
// A space record re-syncs whenever its child ordering changes, so
|
||||
// only propagate (and especially repaint) when its own fields did.
|
||||
@@ -482,8 +500,7 @@ class nsZenSpacesSyncApplier {
|
||||
}
|
||||
|
||||
#createTab(win, tabId, data) {
|
||||
const userContextId =
|
||||
ZenSpacesSyncModel.contextIdForGuid(data.containerGuid) ?? 0;
|
||||
const userContextId = this.#resolveContainerId(data.containerGuid);
|
||||
const tab = win.gBrowser.addTrustedTab(data.url, {
|
||||
createLazyBrowser: true,
|
||||
inBackground: true,
|
||||
|
||||
Reference in New Issue
Block a user