-
Notifications
You must be signed in to change notification settings - Fork 731
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
Feature/fga/simplify timeline logic #6318
Changes from 7 commits
af7fb5d
ad0447b
4278771
25f1ae4
e24db6c
70fe46b
d31da7d
6ca6ad6
2e16b1e
7b8b58e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fix loop in timeline and simplify management of chunks and timeline events. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright (c) 2022 The Matrix.org Foundation C.I.C. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.matrix.android.sdk.internal.database.migration | ||
|
||
import io.realm.DynamicRealm | ||
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields | ||
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields | ||
import org.matrix.android.sdk.internal.extensions.clearWith | ||
import org.matrix.android.sdk.internal.util.database.RealmMigrator | ||
|
||
/** | ||
* Migrating to: | ||
* Cleaning old chunks which may have broken links. | ||
*/ | ||
internal class MigrateSessionTo030(realm: DynamicRealm) : RealmMigrator(realm, 30) { | ||
|
||
override fun doMigrate(realm: DynamicRealm) { | ||
// Delete all previous chunks | ||
val chunks = realm.where("ChunkEntity") | ||
.equalTo(ChunkEntityFields.IS_LAST_FORWARD, false) | ||
.findAll() | ||
|
||
chunks.forEach { chunk -> | ||
chunk.getList(ChunkEntityFields.TIMELINE_EVENTS.`$`).clearWith { timelineEvent -> | ||
// Don't delete state events | ||
if (timelineEvent.isNull(TimelineEventEntityFields.ROOT.TYPE)) { | ||
ganfra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
timelineEvent.getObject(TimelineEventEntityFields.ROOT.`$`)?.deleteFromRealm() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see there may be also other entities attached to the event such as: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes we can keep them, they are kind of independent |
||
timelineEvent.deleteFromRealm() | ||
} | ||
} | ||
chunk.deleteFromRealm() | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,6 +70,7 @@ internal class TimelineChunk( | |
|
||
private val isLastForward = AtomicBoolean(chunkEntity.isLastForward) | ||
private val isLastBackward = AtomicBoolean(chunkEntity.isLastBackward) | ||
private val nextToken = chunkEntity.nextToken | ||
private var prevChunkLatch: CompletableDeferred<Unit>? = null | ||
private var nextChunkLatch: CompletableDeferred<Unit>? = null | ||
|
||
|
@@ -136,8 +137,10 @@ internal class TimelineChunk( | |
val prevEvents = prevChunk?.builtItems(includesNext = false, includesPrev = true).orEmpty() | ||
deepBuiltItems.addAll(prevEvents) | ||
} | ||
|
||
return deepBuiltItems | ||
// In some scenario (permalink) we might end up with duplicate timeline events, so we want to be sure we only expose one. | ||
return deepBuiltItems.distinctBy { | ||
it.eventId | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -154,10 +157,6 @@ internal class TimelineChunk( | |
val loadFromStorage = loadFromStorage(count, direction).also { | ||
logLoadedFromStorage(it, direction) | ||
} | ||
if (loadFromStorage.numberOfEvents == 6) { | ||
Timber.i("here") | ||
} | ||
|
||
val offsetCount = count - loadFromStorage.numberOfEvents | ||
|
||
return if (offsetCount == 0) { | ||
|
@@ -251,10 +250,6 @@ internal class TimelineChunk( | |
} | ||
|
||
fun getBuiltEventIndex(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): Int? { | ||
val builtEventIndex = builtEventsIndexes[eventId] | ||
if (builtEventIndex != null) { | ||
return getOffsetIndex() + builtEventIndex | ||
} | ||
if (searchInNext) { | ||
val nextBuiltEventIndex = nextChunk?.getBuiltEventIndex(eventId, searchInNext = true, searchInPrev = false) | ||
if (nextBuiltEventIndex != null) { | ||
|
@@ -267,7 +262,12 @@ internal class TimelineChunk( | |
return prevBuiltEventIndex | ||
} | ||
} | ||
return null | ||
val builtEventIndex = builtEventsIndexes[eventId] | ||
return if (builtEventIndex != null) { | ||
getOffsetIndex() + builtEventIndex | ||
} else { | ||
null | ||
} | ||
} | ||
|
||
fun getBuiltEvent(eventId: String, searchInNext: Boolean, searchInPrev: Boolean): TimelineEvent? { | ||
|
@@ -445,7 +445,7 @@ internal class TimelineChunk( | |
Timber.e(failure, "Failed to fetch from server") | ||
LoadMoreResult.FAILURE | ||
} | ||
return if (loadMoreResult == LoadMoreResult.SUCCESS) { | ||
return if (loadMoreResult != LoadMoreResult.FAILURE) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just checking, is it intended to call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the downside of linking the last permalink chunk to the lastForward chunk... I still don't know if we want this or just add timeline events from sync on both chunks instead |
||
latch?.await() | ||
loadMore(count, direction, fetchOnServerIfNeeded = false) | ||
} else { | ||
|
@@ -470,11 +470,15 @@ internal class TimelineChunk( | |
} | ||
|
||
private fun getOffsetIndex(): Int { | ||
if (nextToken == null) return 0 | ||
var offset = 0 | ||
var currentNextChunk = nextChunk | ||
while (currentNextChunk != null) { | ||
offset += currentNextChunk.builtEvents.size | ||
currentNextChunk = currentNextChunk.nextChunk | ||
currentNextChunk = currentNextChunk.nextChunk?.takeIf { | ||
// In case of permalink we can end up with a linked nextChunk (which is the lastForward Chunk) but no nextToken | ||
it.nextToken != null | ||
} | ||
} | ||
return offset | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this also close the following? They seem like duplicates of #5166 anway