Add locking to avoid index corruption

When a new room is added there's a fairly good chance that the other events being dispatched will happen in the middle of (for example) the room list being re-sorted. This commit wraps the entire handleRoomUpdate() function for the underlying algorithms in a lock so that if we're unlucky enough to get an update while we're sorting (as the ImportanceAlgorithm splices out what it is sorting) we won't scream about invalid index errors.
pull/21833/head
Travis Ralston 2020-06-24 21:41:11 -06:00
parent c7a83e65f0
commit 223ee0dbdb
3 changed files with 69 additions and 55 deletions

View File

@ -179,6 +179,9 @@ export class ImportanceAlgorithm extends OrderingAlgorithm {
}
public async handleRoomUpdate(room: Room, cause: RoomUpdateCause): Promise<boolean> {
try {
await this.updateLock.acquireAsync();
if (cause === RoomUpdateCause.NewRoom || cause === RoomUpdateCause.RoomRemoved) {
return this.handleSplice(room, cause);
}
@ -218,6 +221,9 @@ export class ImportanceAlgorithm extends OrderingAlgorithm {
await this.sortCategory(category);
return true; // change made
} finally {
await this.updateLock.release();
}
}
private async sortCategory(category: Category) {

View File

@ -38,6 +38,9 @@ export class NaturalAlgorithm extends OrderingAlgorithm {
}
public async handleRoomUpdate(room, cause): Promise<boolean> {
try {
await this.updateLock.acquireAsync();
const isSplice = cause === RoomUpdateCause.NewRoom || cause === RoomUpdateCause.RoomRemoved;
const isInPlace = cause === RoomUpdateCause.Timeline || cause === RoomUpdateCause.ReadReceipt;
if (!isSplice && !isInPlace) {
@ -56,5 +59,8 @@ export class NaturalAlgorithm extends OrderingAlgorithm {
this.cachedOrderedRooms = await sortRoomsWithAlgorithm(this.cachedOrderedRooms, this.tagId, this.sortingAlgorithm);
return true;
} finally {
await this.updateLock.release();
}
}
}

View File

@ -17,6 +17,7 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomUpdateCause, TagID } from "../../models";
import { SortAlgorithm } from "../models";
import AwaitLock from "await-lock";
/**
* Represents a list ordering algorithm. Subclasses should populate the
@ -25,6 +26,7 @@ import { SortAlgorithm } from "../models";
export abstract class OrderingAlgorithm {
protected cachedOrderedRooms: Room[];
protected sortingAlgorithm: SortAlgorithm;
protected readonly updateLock = new AwaitLock();
protected constructor(protected tagId: TagID, initialSortingAlgorithm: SortAlgorithm) {
// noinspection JSIgnoredPromiseFromCall