refactor: sliding sync: convert to lists-as-keys rather than indexes

Sister PR to https://github.com/matrix-org/matrix-js-sdk/pull/3076
This commit is contained in:
Kegan Dougal 2023-01-18 17:19:12 +00:00
parent 4d2b27a96d
commit 21f0825703
4 changed files with 24 additions and 56 deletions

View file

@ -137,10 +137,10 @@ export class SlidingSyncManager {
this.listIdToIndex = {}; this.listIdToIndex = {};
// by default use the encrypted subscription as that gets everything, which is a safer // by default use the encrypted subscription as that gets everything, which is a safer
// default than potentially missing member events. // default than potentially missing member events.
this.slidingSync = new SlidingSync(proxyUrl, [], ENCRYPTED_SUBSCRIPTION, client, SLIDING_SYNC_TIMEOUT_MS); this.slidingSync = new SlidingSync(proxyUrl, new Map(), ENCRYPTED_SUBSCRIPTION, client, SLIDING_SYNC_TIMEOUT_MS);
this.slidingSync.addCustomSubscription(UNENCRYPTED_SUBSCRIPTION_NAME, UNENCRYPTED_SUBSCRIPTION); this.slidingSync.addCustomSubscription(UNENCRYPTED_SUBSCRIPTION_NAME, UNENCRYPTED_SUBSCRIPTION);
// set the space list // set the space list
this.slidingSync.setList(this.getOrAllocateListIndex(SlidingSyncManager.ListSpaces), { this.slidingSync.setList(SlidingSyncManager.ListSpaces, {
ranges: [[0, 20]], ranges: [[0, 20]],
sort: ["by_name"], sort: ["by_name"],
slow_get_all_rooms: true, slow_get_all_rooms: true,
@ -182,38 +182,16 @@ export class SlidingSyncManager {
return null; return null;
} }
/**
* Allocate or retrieve the list index for an arbitrary list ID. For example SlidingSyncManager.ListSpaces
* @param listId A string which represents the list.
* @returns The index to use when registering lists or listening for callbacks.
*/
public getOrAllocateListIndex(listId: string): number {
let index = this.listIdToIndex[listId];
if (index === undefined) {
// assign next highest index
index = -1;
for (const id in this.listIdToIndex) {
const listIndex = this.listIdToIndex[id];
if (listIndex > index) {
index = listIndex;
}
}
index++;
this.listIdToIndex[listId] = index;
}
return index;
}
/** /**
* Ensure that this list is registered. * Ensure that this list is registered.
* @param listIndex The list index to register * @param listKey The list key to register
* @param updateArgs The fields to update on the list. * @param updateArgs The fields to update on the list.
* @returns The complete list request params * @returns The complete list request params
*/ */
public async ensureListRegistered(listIndex: number, updateArgs: PartialSlidingSyncRequest): Promise<MSC3575List> { public async ensureListRegistered(listKey: string, updateArgs: PartialSlidingSyncRequest): Promise<MSC3575List> {
logger.debug("ensureListRegistered:::", listIndex, updateArgs); logger.debug("ensureListRegistered:::", listKey, updateArgs);
await this.configureDefer.promise; await this.configureDefer.promise;
let list = this.slidingSync.getList(listIndex); let list = this.slidingSync.getListParams(listKey);
if (!list) { if (!list) {
list = { list = {
ranges: [[0, 20]], ranges: [[0, 20]],
@ -252,14 +230,14 @@ export class SlidingSyncManager {
try { try {
// if we only have range changes then call a different function so we don't nuke the list from before // if we only have range changes then call a different function so we don't nuke the list from before
if (updateArgs.ranges && Object.keys(updateArgs).length === 1) { if (updateArgs.ranges && Object.keys(updateArgs).length === 1) {
await this.slidingSync.setListRanges(listIndex, updateArgs.ranges); await this.slidingSync.setListRanges(listKey, updateArgs.ranges);
} else { } else {
await this.slidingSync.setList(listIndex, list); await this.slidingSync.setList(listKey, list);
} }
} catch (err) { } catch (err) {
logger.debug("ensureListRegistered: update failed txn_id=", err); logger.debug("ensureListRegistered: update failed txn_id=", err);
} }
return this.slidingSync.getList(listIndex); return this.slidingSync.getListParams(listKey);
} }
public async setRoomVisible(roomId: string, visible: boolean): Promise<string> { public async setRoomVisible(roomId: string, visible: boolean): Promise<string> {
@ -304,7 +282,6 @@ export class SlidingSyncManager {
*/ */
public async startSpidering(batchSize: number, gapBetweenRequestsMs: number): Promise<void> { public async startSpidering(batchSize: number, gapBetweenRequestsMs: number): Promise<void> {
await sleep(gapBetweenRequestsMs); // wait a bit as this is called on first render so let's let things load await sleep(gapBetweenRequestsMs); // wait a bit as this is called on first render so let's let things load
const listIndex = this.getOrAllocateListIndex(SlidingSyncManager.ListSearch);
let startIndex = batchSize; let startIndex = batchSize;
let hasMore = true; let hasMore = true;
let firstTime = true; let firstTime = true;
@ -316,7 +293,7 @@ export class SlidingSyncManager {
[startIndex, endIndex], [startIndex, endIndex],
]; ];
if (firstTime) { if (firstTime) {
await this.slidingSync.setList(listIndex, { await this.slidingSync.setList(SlidingSyncManager.ListSearch, {
// e.g [0,19] [20,39] then [0,19] [40,59]. We keep [0,20] constantly to ensure // e.g [0,19] [20,39] then [0,19] [40,59]. We keep [0,20] constantly to ensure
// any changes to the list whilst spidering are caught. // any changes to the list whilst spidering are caught.
ranges: ranges, ranges: ranges,
@ -342,7 +319,7 @@ export class SlidingSyncManager {
}, },
}); });
} else { } else {
await this.slidingSync.setListRanges(listIndex, ranges); await this.slidingSync.setListRanges(SlidingSyncManager.ListSearch, ranges);
} }
// gradually request more over time // gradually request more over time
await sleep(gapBetweenRequestsMs); await sleep(gapBetweenRequestsMs);
@ -350,7 +327,7 @@ export class SlidingSyncManager {
// do nothing, as we reject only when we get interrupted but that's fine as the next // do nothing, as we reject only when we get interrupted but that's fine as the next
// request will include our data // request will include our data
} }
hasMore = endIndex + 1 < this.slidingSync.getListData(listIndex)?.joinedCount; hasMore = endIndex + 1 < this.slidingSync.getListData(SlidingSyncManager.ListSearch)?.joinedCount;
startIndex += batchSize; startIndex += batchSize;
firstTime = false; firstTime = false;
} }

View file

@ -340,9 +340,8 @@ export default class RoomSublist extends React.Component<IProps, IState> {
private onShowAllClick = async (): Promise<void> => { private onShowAllClick = async (): Promise<void> => {
if (this.slidingSyncMode) { if (this.slidingSyncMode) {
const slidingSyncIndex = SlidingSyncManager.instance.getOrAllocateListIndex(this.props.tagId);
const count = RoomListStore.instance.getCount(this.props.tagId); const count = RoomListStore.instance.getCount(this.props.tagId);
await SlidingSyncManager.instance.ensureListRegistered(slidingSyncIndex, { await SlidingSyncManager.instance.ensureListRegistered(this.props.tagId, {
ranges: [[0, count]], ranges: [[0, count]],
}); });
} }
@ -566,8 +565,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
let isAlphabetical = RoomListStore.instance.getTagSorting(this.props.tagId) === SortAlgorithm.Alphabetic; let isAlphabetical = RoomListStore.instance.getTagSorting(this.props.tagId) === SortAlgorithm.Alphabetic;
let isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance; let isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance;
if (this.slidingSyncMode) { if (this.slidingSyncMode) {
const slidingSyncIndex = SlidingSyncManager.instance.getOrAllocateListIndex(this.props.tagId); const slidingList = SlidingSyncManager.instance.slidingSync.getListParams(this.props.tagId);
const slidingList = SlidingSyncManager.instance.slidingSync.getList(slidingSyncIndex);
isAlphabetical = slidingList.sort[0] === "by_name"; isAlphabetical = slidingList.sort[0] === "by_name";
isUnreadFirst = slidingList.sort[0] === "by_notification_level"; isUnreadFirst = slidingList.sort[0] === "by_notification_level";
} }

View file

@ -34,7 +34,6 @@ export const useSlidingSyncRoomSearch = (): {
const [rooms, setRooms] = useState<Room[]>([]); const [rooms, setRooms] = useState<Room[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const listIndex = SlidingSyncManager.instance.getOrAllocateListIndex(SlidingSyncManager.ListSearch);
const [updateQuery, updateResult] = useLatestResult<{ term: string; limit?: number }, Room[]>(setRooms); const [updateQuery, updateResult] = useLatestResult<{ term: string; limit?: number }, Room[]>(setRooms);
@ -50,14 +49,14 @@ export const useSlidingSyncRoomSearch = (): {
try { try {
setLoading(true); setLoading(true);
await SlidingSyncManager.instance.ensureListRegistered(listIndex, { await SlidingSyncManager.instance.ensureListRegistered(SlidingSyncManager.ListSearch, {
ranges: [[0, limit]], ranges: [[0, limit]],
filters: { filters: {
room_name_like: term, room_name_like: term,
}, },
}); });
const rooms = []; const rooms = [];
const { roomIndexToRoomId } = SlidingSyncManager.instance.slidingSync.getListData(listIndex); const { roomIndexToRoomId } = SlidingSyncManager.instance.slidingSync.getListData(SlidingSyncManager.ListSearch);
let i = 0; let i = 0;
while (roomIndexToRoomId[i]) { while (roomIndexToRoomId[i]) {
const roomId = roomIndexToRoomId[i]; const roomId = roomIndexToRoomId[i];
@ -78,7 +77,7 @@ export const useSlidingSyncRoomSearch = (): {
// TODO: delete the list? // TODO: delete the list?
} }
}, },
[updateQuery, updateResult, listIndex], [updateQuery, updateResult, SlidingSyncManager.ListSearch],
); );
return { return {

View file

@ -89,15 +89,14 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
public async setTagSorting(tagId: TagID, sort: SortAlgorithm): Promise<void> { public async setTagSorting(tagId: TagID, sort: SortAlgorithm): Promise<void> {
logger.info("SlidingRoomListStore.setTagSorting ", tagId, sort); logger.info("SlidingRoomListStore.setTagSorting ", tagId, sort);
this.tagIdToSortAlgo[tagId] = sort; this.tagIdToSortAlgo[tagId] = sort;
const slidingSyncIndex = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
switch (sort) { switch (sort) {
case SortAlgorithm.Alphabetic: case SortAlgorithm.Alphabetic:
await this.context.slidingSyncManager.ensureListRegistered(slidingSyncIndex, { await this.context.slidingSyncManager.ensureListRegistered(tagId, {
sort: SlidingSyncSortToFilter[SortAlgorithm.Alphabetic], sort: SlidingSyncSortToFilter[SortAlgorithm.Alphabetic],
}); });
break; break;
case SortAlgorithm.Recent: case SortAlgorithm.Recent:
await this.context.slidingSyncManager.ensureListRegistered(slidingSyncIndex, { await this.context.slidingSyncManager.ensureListRegistered(tagId, {
sort: SlidingSyncSortToFilter[SortAlgorithm.Recent], sort: SlidingSyncSortToFilter[SortAlgorithm.Recent],
}); });
break; break;
@ -164,8 +163,7 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
// check all lists for each tag we know about and see if the room is there // check all lists for each tag we know about and see if the room is there
const tags: TagID[] = []; const tags: TagID[] = [];
for (const tagId in this.tagIdToSortAlgo) { for (const tagId in this.tagIdToSortAlgo) {
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId); const listData = this.context.slidingSyncManager.slidingSync.getListData(tagId);
const listData = this.context.slidingSyncManager.slidingSync.getListData(index);
if (!listData) { if (!listData) {
continue; continue;
} }
@ -259,11 +257,10 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
} }
private onSlidingSyncListUpdate( private onSlidingSyncListUpdate(
listIndex: number, tagId: string,
joinCount: number, joinCount: number,
roomIndexToRoomId: Record<number, string>, roomIndexToRoomId: Record<number, string>,
): void { ): void {
const tagId = this.context.slidingSyncManager.listIdForIndex(listIndex);
this.counts[tagId] = joinCount; this.counts[tagId] = joinCount;
this.refreshOrderedLists(tagId, roomIndexToRoomId); this.refreshOrderedLists(tagId, roomIndexToRoomId);
// let the UI update // let the UI update
@ -295,8 +292,7 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
if (room) { if (room) {
// resort it based on the slidingSync view of the list. This may cause this old sticky // resort it based on the slidingSync view of the list. This may cause this old sticky
// room to cease to exist. // room to cease to exist.
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId); const listData = this.context.slidingSyncManager.slidingSync.getListData(tagId);
const listData = this.context.slidingSyncManager.slidingSync.getListData(index);
if (!listData) { if (!listData) {
continue; continue;
} }
@ -334,9 +330,8 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
const sort = SortAlgorithm.Recent; // default to recency sort, TODO: read from config const sort = SortAlgorithm.Recent; // default to recency sort, TODO: read from config
this.tagIdToSortAlgo[tagId] = sort; this.tagIdToSortAlgo[tagId] = sort;
this.emit(LISTS_LOADING_EVENT, tagId, true); this.emit(LISTS_LOADING_EVENT, tagId, true);
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
this.context.slidingSyncManager this.context.slidingSyncManager
.ensureListRegistered(index, { .ensureListRegistered(tagId, {
filters: filter, filters: filter,
sort: SlidingSyncSortToFilter[sort], sort: SlidingSyncSortToFilter[sort],
}) })
@ -367,9 +362,8 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
); );
this.emit(LISTS_LOADING_EVENT, tagId, true); this.emit(LISTS_LOADING_EVENT, tagId, true);
const index = this.context.slidingSyncManager.getOrAllocateListIndex(tagId);
this.context.slidingSyncManager this.context.slidingSyncManager
.ensureListRegistered(index, { .ensureListRegistered(tagId, {
filters: filters, filters: filters,
}) })
.then(() => { .then(() => {