Gaps in timelines block older content loading from the event cache, massively undermining its benefits
Steps to reproduce
- Open the gallery for a room, and let it populate up the event & media cache for rapid access to the gallery. Could easily take a few minutes as it spiders the room.
- Use the app for a bit
- A few days later, go back to the room and open up its gallery again.
- A few pieces of recent content might appear instantly (if they just got downloaded on opening the room), but if there has been a gappy sync since you last viewed the room (which will likely be the case), then the cached events + content will not be displayed.
- Instead, the client presumably goes through filling in the gap by slowly calling /messages.
- The user feels that the cache isn't working (this might be what was happening in https://github.com/element-hq/element-x-ios/issues/3832)
- It's only once the gap has been filled in that the existing cached content gets rapidly loaded and displayed (although in practice i'm not sure that it's actually rapidly loading & displaying; it seems to be pulling it all back in from /messages again).
This is really bad on the gallery, as perceptually it feels like the cache got flushed, given as a user you end up staring at a blank gallery and a spinner while it paginates back through the gap. Even if eventually it hits the previously cached content and displays it rapidly.
The same problem exists on the normal timeline:
- Open a room
- Read a few pages of scrollback
- Go back to the room a while later
- If there's been a gap in the room history... we show the most recent message(s) in the room, but all the cached content isn't shown. (If it was, it'd seem like the client had lost messages in the gap)
- As a result, the user has to slowly wait while the client fills in the gap before they can see any of the prior history in the room - at which point the cache isn't fulfilling its function of letting users rapidly see information without having to talk to the server.
I suspect the solution may be to display a spinner in the timeline (or in the gallery) whenever there's a gap in the timeline which the client is currently 'filling in' via /messages. This lets the user see all the locally cached content asap, while being aware that there's a gap which is being populated - rather than being forced to hide the older cached content to avoid confusion while the gap is being populated.
Outcome
What did you expect?
Client should rapidly show me the messages & media in its cache so I can make good use of the cache
What happened instead?
Client blocks showing me older cached content in a gallery or room timeline until it has paginated through all the history that happened since I last looked at that room.
There may also be an additional bug where it doesn't retrieve older events from the cache at all after there's been a gap, but keeps paginating them in from the server (based on eyeballing performance in the gallery).
Application version
855
This is a known problem. We have formulated this problem since we are working on the event cache lazy-loader. Two solutions exist:
- automatic back pagination
- render gaps in the timeline.
These solutions are not mutually exclusive. Actually we need both for various reasons. Automatic back pagination is required to get a correct app badge counter and nice text search. On the other hand, rendering gaps allows to display what we have in the cache without blocking the timeline nor the media gallery (which is a timeline).
See Apollo e Dafne in https://github.com/matrix-org/matrix-rust-sdk/pull/4632
i guess the problem with automatic back pagination is that if hasn't kicked in yet to fill a gap for a given room (assuming automatic back pagination even existed), you'd still be stuck staring at the void rather than displaying the cached history.
cc @mxandreas just in case there's a quick fix to be had here by saying "sure, let's render timeline gaps as spinners"
I tend to agree that there's probably no better solution than to show the gap. It seems very confusing if suddenly you do not have a lot of messages that you used to have. I will check with the designers.
Automatic back-pagination + showing a gap in the timeline are two solutions that must be implemented anyway.
Right, but to be clear: "showing gaps" is needed irrespective of automatic back-pagination - they aren't really overlapping.
In terms of design, we already have a spinner UI showing backpagination happening; my proposal would be to show that spinner in the timeline at the point that the gap is (i.e. with msgs above it too).
For what it's worth: at this point the timeline will NOT show any gap that's NOT at the beginning of the timeline. i.e. we can't have this situation:
- some event
- a gap
- some event
As a matter of fact: if there's a gap, it MUST be at the beginning of the room, meaning that the beginning of the room is one of both:
- either the actual start of the room; there's nothing else to back-paginate
- or it's not the actual start of the room (and we should know about this, uh, modulo bugs), and in this case we can preemptively show a loading spinner, because there's going to be a pagination (either from the cache or from network). Only when the loading spinner is actually rendered and displayed on screen, can we trigger the back-pagination.
In the current state, described above, we don't have to think about rendering all gaps, in general. It would be nice to think about it for the future:
- then we could maximally reuse the event cache, and show older events even if we haven't resolved gaps in between (as in the initial example at the top of this comment)
- in offline mode, since we can't resolve a gap using network, we would display a spinner loading forever, which is bad (also note that in offline mode, we can't know where we have gaps, so we'd need to display some kind of banner "there might be missing events, since you're disconnected", to make it super clear).
So there are potentially two phases:
- show a spinner with "loading…" at the top of the timeline, if we're not at the start of the room yet
- think about how to render gaps, for offline mode + being able to display
events / gap / eventstimelines
I think implementing (1) would be a nice win in the short term, until we have design support for (2).
We had a small conversation with @amshakal yesterday and we would likely show the "placeholder" image (e.g. similar to what Slack does when it is trying to fetch the messages) so it would be a bit more subtle than spinner but @americanrefugee will take a deeper look when he is back. Besides being subtle, I think we need to choose something that works for both - the beginning of the timeline and the middle of timeline as 2 different ones is probably the worst option.
Adding a note that older content when the device is offline is only blocked when there is a bad timing: e.g. the app becomes aware that there is a gap but does not manage to fill this gap before the device goes offline. It is not that older content is never loaded whenever you're offline.
Technical Rust SDK note: supporting gaps in the timeline code will require taking into account the relative ordering of related events (that is, have an absolute idea of the relative position of two edits, for instance, to determine which is the "latest" one). Right now, we mostly don't need to do this, because either we're getting events from sync (so a related event has to be the latest one), or we're getting them from back-pagination (so we might see a related event before the event it relates to, in which case we stash it on the side, and apply it later when the related event's back).