From 6a8230239b13b52d6b2622afdffd4d56726964c3 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Mon, 21 Mar 2022 10:46:59 +0100 Subject: [PATCH] Avoid inconsistent timelines by db insertions before fully loaded chunk --- .../session/room/timeline/TimelineChunk.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt index 368979d73e..1bd541c2a9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineChunk.kt @@ -430,6 +430,31 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity, private fun handleDatabaseChangeSet(results: RealmResults, changeSet: OrderedCollectionChangeSet) { val insertions = changeSet.insertionRanges for (range in insertions) { + // Check if the insertion's displayIndices match our expectations - or skip this insertion. + // Inconsistencies (missing messages) can happen otherwise if we get insertions before having loaded all timeline events of the chunk. + if (builtEvents.isNotEmpty()) { + // Check consistency to item before insertions + if (range.startIndex > 0) { + val firstInsertion = results[range.startIndex]!! + val lastBeforeInsertion = builtEvents[range.startIndex-1] + if (firstInsertion.displayIndex+1 != lastBeforeInsertion.displayIndex) { + Timber.i("handleDatabaseChangeSet: skip insertion at ${range.startIndex}/${builtEvents.size}, " + + "displayIndex mismatch at ${range.startIndex}: ${firstInsertion.displayIndex} -> ${lastBeforeInsertion.displayIndex}") + continue + } + } + // Check consistency to item after insertions + if (range.startIndex < builtEvents.size) { + val lastInsertion = results[range.startIndex+range.length-1]!! + val firstAfterInsertion = builtEvents[range.startIndex] + if (firstAfterInsertion.displayIndex+1 != lastInsertion.displayIndex) { + Timber.i("handleDatabaseChangeSet: skip insertion at ${range.startIndex}/${builtEvents.size}, " + + "displayIndex mismatch at ${range.startIndex+range.length}: " + + "${firstAfterInsertion.displayIndex} -> ${lastInsertion.displayIndex}") + continue + } + } + } val newItems = results .subList(range.startIndex, range.startIndex + range.length) .map { it.buildAndDecryptIfNeeded() }