Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timeline: fix validation of timeline event changes #6462

Merged
merged 1 commit into from
Jul 7, 2022

Conversation

ganfra
Copy link
Member

@ganfra ganfra commented Jul 5, 2022

Fix #6461

@ganfra ganfra requested review from bmarty and ouchadam July 5, 2022 08:41
@ouchadam ouchadam added the Z-NextRelease For issues and PRs which should be included in the NextRelease. label Jul 5, 2022
val lastInsertion = results[range.startIndex + range.length - 1] ?: return false
if (firstBuiltEvent.displayIndex + 1 != lastInsertion.displayIndex) {
Timber.v("There is no continuation in the chunk, chunk is not fully loaded yet, skip insert.")
return false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of interest, what happens to these events, are they skipped forever?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they will be loaded when paginating manually!

@@ -558,6 +528,21 @@ internal class TimelineChunk(
}
}

private fun validateInsertion(range: OrderedCollectionChangeSet.Range, results: RealmResults<TimelineEventEntity>): Boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 for pulling out a function

Copy link
Member

@bmarty bmarty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can confirm that this fixes the crash from #6461, but I have another crash when closing the thread and going back to the main timeline.

Thread: DefaultTimeline_Thread, Exception: java.lang.IllegalStateException: Cannot create asynchronous query while in a write transaction in /tmp/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_OsResults.cpp line 243
at io.realm.internal.OsResults.nativeStartListening(Native Method)
at io.realm.internal.OsResults.addListener(OsResults.java:673)
at io.realm.RealmResults.addChangeListener(RealmResults.java:734)
at org.matrix.android.sdk.internal.session.room.timeline.TimelineChunk.(TimelineChunk.kt:117)
at org.matrix.android.sdk.internal.session.room.timeline.TimelineChunk.createTimelineChunk(TimelineChunk.kt:567)
at org.matrix.android.sdk.internal.session.room.timeline.TimelineChunk.chunkObjectListener$lambda-2(TimelineChunk.kt:96)
at org.matrix.android.sdk.internal.session.room.timeline.TimelineChunk.$r8$lambda$pCFJ5imq9fIZIR0Q2XoxgvbuKjU(Unknown Source:0)
at org.matrix.android.sdk.internal.session.room.timeline.TimelineChunk$$ExternalSyntheticLambda1.onChange(Unknown Source:4)

See https://github.com/matrix-org/element-android-rageshakes/issues/40144

}
}
}
if (!validateInsertion(range, results)) continue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for extracting

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jul 5, 2022

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

82.6% 82.6% Coverage
0.0% 0.0% Duplication

@ganfra
Copy link
Member Author

ganfra commented Jul 5, 2022

Yes, this is one of the other issues I was talking about. But it happens randomly and already exists before my fix.

val firstBuiltEvent = builtEvents.firstOrNull()
if (firstBuiltEvent != null) {
val lastInsertion = results[range.startIndex + range.length - 1] ?: return false
if (firstBuiltEvent.displayIndex + 1 != lastInsertion.displayIndex) {
Copy link
Contributor

@ouchadam ouchadam Jul 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for my understanding, is the only false case when the firstBuiltEvent exists and it doesn't have the same display index as the results[range.startIndex + range.length - 1]

it might be a little easier to read as a when rather than nested ifs

private fun validateInsertion(range: OrderedCollectionChangeSet.Range, results: RealmResults<TimelineEventEntity>): Boolean {
    // Insertion can only happen from LastForward chunk after a sync.
    val firstForwardEvent = isLastForward.get().takeIf { it }?.let { builtEvents.firstOrNull()  }
    return when {
        firstForwardEvent == null -> true
        firstForwardEvent.nextDisplayIndexDoesNotMatch(results.last(range)) -> {
            Timber.v("There is no continuation in the chunk, chunk is not fully loaded yet, skip insert.")
            false
        }
        else -> true
    }
}

private fun RealmResults<TimelineEventEntity>.last(range: OrderedCollectionChangeSet.Range): TimelineEventEntity? {
    return this[range.startIndex + range.length - 1]
}

private fun TimelineEvent.nextDisplayIndexDoesNotMatch(event: TimelineEventEntity?): Boolean {
    return (displayIndex + 1) != event?.displayIndex
}

not a blocker ^^^

@ouchadam ouchadam merged commit 67d5289 into develop Jul 7, 2022
@ouchadam ouchadam deleted the feature/fga/fix_6461 branch July 7, 2022 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Z-NextRelease For issues and PRs which should be included in the NextRelease.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crashes on Timeline [Thread] due to range validation
3 participants