From 6f6346d5c38de3bbcfdf5500e3a30fa3eede14ed Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 2 Mar 2021 19:29:55 +0100 Subject: [PATCH 1/3] detect when hitting beginning of timeline when loading timeline --- src/domain/session/room/timeline/TimelineViewModel.js | 4 ++-- src/matrix/room/timeline/Timeline.js | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/domain/session/room/timeline/TimelineViewModel.js b/src/domain/session/room/timeline/TimelineViewModel.js index b40a6dcb..a5dcee07 100644 --- a/src/domain/session/room/timeline/TimelineViewModel.js +++ b/src/domain/session/room/timeline/TimelineViewModel.js @@ -55,8 +55,8 @@ export class TimelineViewModel extends ViewModel { if (firstTile.shape === "gap") { return await firstTile.fill(); } else { - await this._timeline.loadAtTop(10); - return false; + const topReached = await this._timeline.loadAtTop(10); + return topReached; } } diff --git a/src/matrix/room/timeline/Timeline.js b/src/matrix/room/timeline/Timeline.js index 1b7c8a18..a737728c 100644 --- a/src/matrix/room/timeline/Timeline.js +++ b/src/matrix/room/timeline/Timeline.js @@ -74,13 +74,19 @@ export class Timeline { } // tries to prepend `amount` entries to the `entries` list. + /** + * [loadAtTop description] + * @param {[type]} amount [description] + * @return {boolean} true if the top of the timeline has been reached + * + */ async loadAtTop(amount) { if (this._disposables.isDisposed) { - return; + return true; } const firstEventEntry = this._remoteEntries.array.find(e => !!e.eventType); if (!firstEventEntry) { - return; + return true; } const readerRequest = this._disposables.track(this._timelineReader.readFrom( firstEventEntry.asEventKey(), @@ -90,6 +96,7 @@ export class Timeline { try { const entries = await readerRequest.complete(); this._remoteEntries.setManySorted(entries); + return entries.length < amount; } finally { this._disposables.disposeTracked(readerRequest); } From e1821b1753784b8f33180295902bdd9d14b18f46 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 2 Mar 2021 19:31:00 +0100 Subject: [PATCH 2/3] prevent linking fragment to itself when filling a gap this seems to happen when at the beginning of the timeline and make the timeline reader go into an infinite loop --- src/matrix/room/Room.js | 2 +- .../room/timeline/persistence/GapWriter.js | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index e626116e..dc730b2a 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -441,7 +441,7 @@ export class Room extends EventEmitter { storage: this._storage, fragmentIdComparer: this._fragmentIdComparer, }); - gapResult = await gapWriter.writeFragmentFill(fragmentEntry, response, txn); + gapResult = await gapWriter.writeFragmentFill(fragmentEntry, response, txn, log); } catch (err) { txn.abort(); throw err; diff --git a/src/matrix/room/timeline/persistence/GapWriter.js b/src/matrix/room/timeline/persistence/GapWriter.js index e9abded6..6b4f21df 100644 --- a/src/matrix/room/timeline/persistence/GapWriter.js +++ b/src/matrix/room/timeline/persistence/GapWriter.js @@ -26,7 +26,7 @@ export class GapWriter { this._fragmentIdComparer = fragmentIdComparer; } // events is in reverse-chronological order (last event comes at index 0) if backwards - async _findOverlappingEvents(fragmentEntry, events, txn) { + async _findOverlappingEvents(fragmentEntry, events, txn, log) { let expectedOverlappingEventId; if (fragmentEntry.hasLinkedFragment) { expectedOverlappingEventId = await this._findExpectedOverlappingEventId(fragmentEntry, txn); @@ -49,8 +49,12 @@ export class GapWriter { // TODO: check here that the neighbourEvent is at the correct edge of it's fragment // get neighbour fragment to link it up later on const neighbourEvent = await txn.timelineEvents.getByEventId(this._roomId, duplicateEventId); - const neighbourFragment = await txn.timelineFragments.get(this._roomId, neighbourEvent.fragmentId); - neighbourFragmentEntry = fragmentEntry.createNeighbourEntry(neighbourFragment); + if (neighbourEvent.fragmentId === fragmentEntry.fragmentId) { + log.log("hit #160, prevent fragment linking to itself", log.level.Warn); + } else { + const neighbourFragment = await txn.timelineFragments.get(this._roomId, neighbourEvent.fragmentId); + neighbourFragmentEntry = fragmentEntry.createNeighbourEntry(neighbourFragment); + } // trim overlapping events remainingEvents = null; } else { @@ -192,10 +196,11 @@ export class GapWriter { return changedFragments; } - async writeFragmentFill(fragmentEntry, response, txn) { + async writeFragmentFill(fragmentEntry, response, txn, log) { const {fragmentId, direction} = fragmentEntry; // chunk is in reverse-chronological order when backwards - const {chunk, start, end, state} = response; + const {chunk, start, state} = response; + let {end} = response; let entries; if (!Array.isArray(chunk)) { @@ -229,8 +234,11 @@ export class GapWriter { const { nonOverlappingEvents, neighbourFragmentEntry - } = await this._findOverlappingEvents(fragmentEntry, chunk, txn); - + } = await this._findOverlappingEvents(fragmentEntry, chunk, txn, log); + if (!neighbourFragmentEntry && nonOverlappingEvents.length === 0) { + log.log("hit #160, clearing token", log.level.Warn); + end = null; + } // create entries for all events in chunk, add them to entries entries = this._storeEvents(nonOverlappingEvents, lastKey, direction, state, txn); const fragments = await this._updateFragments(fragmentEntry, neighbourFragmentEntry, end, entries, txn); From 8208464653469e138a3688da41715b83967444dd Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 2 Mar 2021 19:37:11 +0100 Subject: [PATCH 3/3] only log and clear when actually needed --- src/matrix/room/timeline/persistence/GapWriter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/room/timeline/persistence/GapWriter.js b/src/matrix/room/timeline/persistence/GapWriter.js index 6b4f21df..899bc16a 100644 --- a/src/matrix/room/timeline/persistence/GapWriter.js +++ b/src/matrix/room/timeline/persistence/GapWriter.js @@ -235,7 +235,7 @@ export class GapWriter { nonOverlappingEvents, neighbourFragmentEntry } = await this._findOverlappingEvents(fragmentEntry, chunk, txn, log); - if (!neighbourFragmentEntry && nonOverlappingEvents.length === 0) { + if (!neighbourFragmentEntry && nonOverlappingEvents.length === 0 && typeof end === "string") { log.log("hit #160, clearing token", log.level.Warn); end = null; }