Improve performance of switching to rooms with lots of servers and ACLs (#8347)

* Improve performance of switching to rooms with lots of servers and ACLs

By not processing the *entire* list of servers and ACLs when determining
how to create permalinks, this shaves ~100 ms off of switches into
high-traffic rooms.

* Fix lint

* Ensure that permalink server candidates can't be duplicates
This commit is contained in:
Robin 2022-04-17 12:50:03 -04:00 committed by GitHub
parent 7c41b8612d
commit b114c5e239
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -166,9 +166,6 @@ export class RoomPermalinkCreator {
// updates, but they were on member events which can be very numerous, so the incremental // updates, but they were on member events which can be very numerous, so the incremental
// updates ended up being much slower than a full update. We now have the batch state update // updates ended up being much slower than a full update. We now have the batch state update
// event, so we just update in full, but on each batch of updates. // event, so we just update in full, but on each batch of updates.
// A full update takes about 120ms for me on Matrix HQ, which still feels like way too long
// to be spending worrying about how we might generate a permalink, but it's better than
// multiple seconds.
this.updateAllowedServers(); this.updateAllowedServers();
this.updateHighestPlUser(); this.updateHighestPlUser();
this.updatePopulationMap(); this.updatePopulationMap();
@ -241,24 +238,27 @@ export class RoomPermalinkCreator {
} }
private updateServerCandidates = () => { private updateServerCandidates = () => {
let candidates = []; const candidates = new Set<string>();
if (this.highestPlUserId) { if (this.highestPlUserId) {
candidates.push(getServerName(this.highestPlUserId)); candidates.add(getServerName(this.highestPlUserId));
} }
const serversByPopulation = Object.keys(this.populationMap) const serversByPopulation = Object.keys(this.populationMap)
.sort((a, b) => this.populationMap[b] - this.populationMap[a]) .sort((a, b) => this.populationMap[b] - this.populationMap[a]);
.filter(a => {
return !candidates.includes(a) &&
!isHostnameIpAddress(a) &&
!isHostInRegex(a, this.bannedHostsRegexps) &&
isHostInRegex(a, this.allowedHostsRegexps);
});
const remainingServers = serversByPopulation.slice(0, MAX_SERVER_CANDIDATES - candidates.length); for (let i = 0; i < serversByPopulation.length && candidates.size < MAX_SERVER_CANDIDATES; i++) {
candidates = candidates.concat(remainingServers); const server = serversByPopulation[i];
if (
!candidates.has(server) &&
!isHostnameIpAddress(server) &&
!isHostInRegex(server, this.bannedHostsRegexps) &&
isHostInRegex(server, this.allowedHostsRegexps)
) {
candidates.add(server);
}
}
this._serverCandidates = candidates; this._serverCandidates = [...candidates];
}; };
} }
@ -447,12 +447,12 @@ function getHostnameFromMatrixDomain(domain: string): string {
return new URL(`https://${domain}`).hostname; return new URL(`https://${domain}`).hostname;
} }
function isHostInRegex(hostname: string, regexps: RegExp[]) { function isHostInRegex(hostname: string, regexps: RegExp[]): boolean {
hostname = getHostnameFromMatrixDomain(hostname); hostname = getHostnameFromMatrixDomain(hostname);
if (!hostname) return true; // assumed if (!hostname) return true; // assumed
if (regexps.length > 0 && !regexps[0].test) throw new Error(regexps[0].toString()); if (regexps.length > 0 && !regexps[0].test) throw new Error(regexps[0].toString());
return regexps.filter(h => h.test(hostname)).length > 0; return regexps.some(h => h.test(hostname));
} }
function isHostnameIpAddress(hostname: string): boolean { function isHostnameIpAddress(hostname: string): boolean {