Bug 1643194 - Do not build sync results if client has no listener r=Gijs

Building the sync event data has an extra cost on large collections. This bypasses iterations or records in case the client has no listener.

Differential Revision: https://phabricator.services.mozilla.com/D81046
This commit is contained in:
Mathieu Leplatre 2020-06-26 08:56:14 +00:00
parent 800ef13016
commit ceaf07c1e6

View File

@ -98,6 +98,10 @@ class EventEmitter {
} }
} }
hasListeners(event) {
return this._listeners.has(event) && this._listeners.get(event).length > 0;
}
on(event, callback) { on(event, callback) {
if (!this._listeners.has(event)) { if (!this._listeners.has(event)) {
throw new Error(`Unknown event type ${event}`); throw new Error(`Unknown event type ${event}`);
@ -566,23 +570,26 @@ class RemoteSettingsClient extends EventEmitter {
"duration" "duration"
); );
} }
// The records imported from the dump should be considered as "created" for the if (this.hasListeners("sync")) {
// listeners. // If we have listeners for the "sync" event, then compute the lists of changes.
const importedById = importedFromDump.reduce((acc, r) => { // The records imported from the dump should be considered as "created" for the
acc.set(r.id, r); // listeners.
return acc; const importedById = importedFromDump.reduce((acc, r) => {
}, new Map()); acc.set(r.id, r);
// Deleted records should not appear as created. return acc;
syncResult.deleted.forEach(r => importedById.delete(r.id)); }, new Map());
// Records from dump that were updated should appear in their newest form. // Deleted records should not appear as created.
syncResult.updated.forEach(u => { syncResult.deleted.forEach(r => importedById.delete(r.id));
if (importedById.has(u.old.id)) { // Records from dump that were updated should appear in their newest form.
importedById.set(u.old.id, u.new); syncResult.updated.forEach(u => {
} if (importedById.has(u.old.id)) {
}); importedById.set(u.old.id, u.new);
syncResult.created = syncResult.created.concat( }
Array.from(importedById.values()) });
); syncResult.created = syncResult.created.concat(
Array.from(importedById.values())
);
}
} }
} catch (e) { } catch (e) {
if (e instanceof InvalidSignatureError) { if (e instanceof InvalidSignatureError) {
@ -952,26 +959,29 @@ class RemoteSettingsClient extends EventEmitter {
console.warn(`${this.identifier} has signature disabled`); console.warn(`${this.identifier} has signature disabled`);
} }
// Compute the changes, comparing records before and after. if (this.hasListeners("sync")) {
syncResult.current = newRecords; // If we have some listeners for the "sync" event,
const oldById = new Map(localRecords.map(e => [e.id, e])); // Compute the changes, comparing records before and after.
for (const r of newRecords) { syncResult.current = newRecords;
const old = oldById.get(r.id); const oldById = new Map(localRecords.map(e => [e.id, e]));
if (old) { for (const r of newRecords) {
oldById.delete(r.id); const old = oldById.get(r.id);
if (r.last_modified != old.last_modified) { if (old) {
syncResult.updated.push({ old, new: r }); oldById.delete(r.id);
if (r.last_modified != old.last_modified) {
syncResult.updated.push({ old, new: r });
}
} else {
syncResult.created.push(r);
} }
} else {
syncResult.created.push(r);
} }
syncResult.deleted = syncResult.deleted.concat(
Array.from(oldById.values())
);
console.debug(
`${this.identifier} ${syncResult.created.length} created. ${syncResult.updated.length} updated. ${syncResult.deleted.length} deleted.`
);
} }
syncResult.deleted = syncResult.deleted.concat(
Array.from(oldById.values())
);
console.debug(
`${this.identifier} ${syncResult.created.length} created. ${syncResult.updated.length} updated. ${syncResult.deleted.length} deleted.`
);
return syncResult; return syncResult;
} }