[TMP] Add some debugging to detect timeline inconsistencies

Note: may affect performance a little when loading the timeline, so
better revert when we are confident we have fixed the issue.

Change-Id: Ic4d31e47948984371a02ce51af7a8d56cb120234
This commit is contained in:
SpiritCroc 2022-03-10 12:36:00 +01:00
parent a132ee22cb
commit 7bfd3c8dca
2 changed files with 40 additions and 3 deletions

View file

@ -296,6 +296,10 @@ internal class DefaultTimeline(private val roomId: String,
private suspend fun postSnapshot() {
val snapshot = strategy.buildSnapshot()
Timber.v("Post snapshot of ${snapshot.size} events")
// Async debugging to not slow down things
timelineScope.launch(coroutineDispatchers.computation) {
checkTimelineConsistency("DefaultTimeline.postSnapshot", snapshot)
}
withContext(coroutineDispatchers.main) {
listeners.forEach {
tryOrNull { it.onTimelineUpdated(snapshot) }
@ -383,3 +387,32 @@ internal class DefaultTimeline(private val roomId: String,
initialEventIdOffset = offset
}
}
fun checkTimelineConsistency(location: String, events: List<TimelineEvent>) {
Timber.d("Check timeline consistency from $location for ${events.size} events")
try {
// Note that the "previous" event is actually newer than the currently looked at event,
// since the list is ordered from new to old
var prev: TimelineEvent? = null
for (i in events.indices) {
val event = events[i]
if (prev != null) {
if (prev.eventId == event.eventId) {
// This should never happen in a bug-free world, as far as I'm aware
Timber.e("Timeline inconsistency found at $location, $i/${events.size}: double event ${event.eventId}")
} else if (prev.displayIndex != event.displayIndex + 1 &&
// Jumps from -1 to 1 seem to be normal, have only seen index 0 for local echos yet
(prev.displayIndex != 1 || event.displayIndex != -1)) {
// Note that jumps in either direction may be normal for some scenarios:
// - Events between two chunks lead to a new indexing, so one may start at 1, or even something negative.
// - The list may omit unsupported events (I guess?), thus causing gaps in the indices.
Timber.w("Possible timeline inconsistency found at $location, $i/${events.size}: ${event.displayIndex}->${prev.displayIndex}, ${event.eventId} -> ${prev.eventId}")
}
}
prev = event
}
Timber.d("Done check timeline consistency from $location")
} catch (t: Throwable) {
Timber.e("Failed check timeline consistency from $location", t)
}
}

View file

@ -119,6 +119,7 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
val nextEvents = nextChunk?.builtItems(includesNext = true, includesPrev = false).orEmpty()
deepBuiltItems.addAll(nextEvents)
}
checkTimelineConsistency("TimelineChunk.builtItems", builtEvents)
deepBuiltItems.addAll(builtEvents)
if (includesPrev) {
val prevEvents = prevChunk?.builtItems(includesNext = false, includesPrev = true).orEmpty()
@ -294,6 +295,8 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
.offsets(direction, count, displayIndex)
.findAll()
.orEmpty()
val builtTimelineEvents = timelineEvents.map { it.buildAndDecryptIfNeeded() }
checkTimelineConsistency("TimelineChunk.loadFromStorage-raw-query", builtTimelineEvents)
if (timelineEvents.isEmpty()) return LoadedFromStorage()
// Disabled due to the new fallback
@ -303,9 +306,10 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
if (direction == Timeline.Direction.FORWARDS) {
builtEventsIndexes.entries.forEach { it.setValue(it.value + timelineEvents.size) }
}
timelineEvents
.mapIndexed { index, timelineEventEntity ->
val timelineEvent = timelineEventEntity.buildAndDecryptIfNeeded()
//timelineEvents
builtTimelineEvents
.mapIndexed { index, timelineEvent -> // timelineEventEntity ->
//val timelineEvent = timelineEventEntity.buildAndDecryptIfNeeded()
if (timelineEvent.root.type == EventType.STATE_ROOM_CREATE) {
isLastBackward.set(true)
}