Skip to content

refactor(event cache): have the caches own the pagination task#6304

Open
bnjbvr wants to merge 11 commits intomainfrom
bnjbvr/single-background-pagination-request
Open

refactor(event cache): have the caches own the pagination task#6304
bnjbvr wants to merge 11 commits intomainfrom
bnjbvr/single-background-pagination-request

Conversation

@bnjbvr
Copy link
Member

@bnjbvr bnjbvr commented Mar 17, 2026

This opens the door for running paginations as background tasks. As such, it's a prerequisite for #6014.

The implementation follows the following scheme:

  • a pagination query will now create a shared() future, that can be polled from several tasks (and it will always return the same results for all the tasks awaiting upon it).
  • a task is also spawned, to immediately start polling the shared future, before it's returned to the caller
  • if a caller calls pagination while there's already a pagination happening, the shared future is returned to the caller: there's not a concurrent pagination happening. We simply wait on the current one to finish.

This changes a few test expectations in subtle ways, but that end up in the same timelines, so I didn't pay too much attention.


  • I've documented the public API Changes in the appropriate CHANGELOG.md files.
  • This PR was made with the help of AI.

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 17, 2026

Merging this PR will not alter performance

✅ 50 untouched benchmarks


Comparing bnjbvr/single-background-pagination-request (6159151) with main (daa1120)

Open in CodSpeed

@codecov
Copy link

codecov bot commented Mar 17, 2026

Codecov Report

❌ Patch coverage is 95.91837% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.82%. Comparing base (daa1120) to head (6159151).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...trix-sdk/src/event_cache/caches/room/pagination.rs 88.00% 3 Missing ⚠️
crates/matrix-sdk-ui/src/timeline/pagination.rs 87.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6304      +/-   ##
==========================================
- Coverage   89.83%   89.82%   -0.02%     
==========================================
  Files         376      376              
  Lines      102447   102508      +61     
  Branches   102447   102508      +61     
==========================================
+ Hits        92033    92077      +44     
- Misses       6836     6858      +22     
+ Partials     3578     3573       -5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

bnjbvr added a commit that referenced this pull request Mar 17, 2026
This makes it possible to share futures which output is a result that
has the error type set to `EventCacheError`. See also
#6304 for usage.
bnjbvr added a commit that referenced this pull request Mar 17, 2026
This makes it possible to share futures which output is a result that
has the error type set to `EventCacheError`. See also
#6304 for usage.
@bnjbvr bnjbvr force-pushed the bnjbvr/single-background-pagination-request branch from fea48b0 to 9e8ad72 Compare March 17, 2026 11:50
@bnjbvr bnjbvr marked this pull request as ready for review March 17, 2026 11:54
@bnjbvr bnjbvr requested a review from a team as a code owner March 17, 2026 11:54
@bnjbvr bnjbvr requested review from poljar and removed request for a team March 17, 2026 11:54
Copy link
Member

@Hywan Hywan left a comment

Choose a reason for hiding this comment

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

First review.


fn load_more_events_backwards(
&self,
) -> impl Future<Output = Result<LoadMoreEventsBackwardsOutcome>> + Send;
Copy link
Member

Choose a reason for hiding this comment

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

Why don't you write async fn load_more_events_backwards instead of return an impl Future?

Copy link
Member Author

Choose a reason for hiding this comment

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

async is only syntactic sugar for returns a Future which output is the return type; to imply that the returned future is Send, you need to have it appear in the function's signature explicitly. (In a subsequent commit, it even becomes SendOutsideWasm, fwiw.)

bnjbvr added a commit that referenced this pull request Mar 17, 2026
This makes it possible to share futures which output is a result that
has the error type set to `EventCacheError`. See also
#6304 for usage.
bnjbvr added a commit that referenced this pull request Mar 17, 2026
This makes it possible to share futures which output is a result that
has the error type set to `EventCacheError`. See also
#6304 for usage.
@bnjbvr bnjbvr force-pushed the bnjbvr/single-background-pagination-request branch from 78ff319 to e77b0b9 Compare March 17, 2026 15:42
@bnjbvr bnjbvr requested a review from Hywan March 17, 2026 15:49
Copy link
Member

@Hywan Hywan left a comment

Choose a reason for hiding this comment

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

We are progressing! I made a couple of suggestions, I believe we can simplify some parts.

I would love to see a bit more tests around this new shared mechanism. It works with the existing tests, but we are not testing concurrent pagination runs as far as I know.

pin_project! {
/// A subscriber to a [`PaginationStatus`].
///
/// This is a manual implementation of a map function on top of an internal type
Copy link
Member

Choose a reason for hiding this comment

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

I'm struggling to understand why we need a custom map implementation:

Did you consider this choice?

Copy link
Member Author

Choose a reason for hiding this comment

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

See comment below; the subscriber is used in more ways than just a stream.

Comment on lines +144 to +145
pub fn status(&self) -> PaginationStatusSubscriber {
PaginationStatusSubscriber { subscriber: self.0.cache.status().subscribe() }
Copy link
Member

Choose a reason for hiding this comment

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

With StreamExt::map, it might look like:

pub fn status(&self) -> impl Stream<Item = PaginationStatus> {
    self.0.cache.status().subscribe().map(From::from)
}

with a custom:

impl From<SharedPaginationStatus> for PaginationStatus {}

Copy link
Member Author

Choose a reason for hiding this comment

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

The thing is that status() is used in more ways: some callers will make use of get(), next() and next_now(), so we can't just replace with a stream and be done with it, unfortunately.

We could plain expose the raw Subscriber<SharedPaginationStatus>, but it seems wrong to have the callers having to call the From/Into implementations themselves?

@bnjbvr
Copy link
Member Author

bnjbvr commented Mar 18, 2026

Thanks for the review! A general comment, before I dive into the detailed comments:

but we are not testing concurrent pagination runs as far as I know.

Have you seen test_concurrent_backpagination? 😁

bnjbvr added 11 commits March 18, 2026 11:12
Even though the task which started the back-pagination is aborted, since
it's now the event cache owning it, it keeps on running in the
background.
- use the modern MatrixMockServer facilities
- provide a previous-batch token so as not to wait for the initial batch
token
- lower the delay for the /messages responses to 1 sec
…meline updates

My only guess for this semantic change, is that the pagination status
update and the end of the pagination now happen at different times, or
close enough that they're regrouped in the same stream update. This
doesn't fundamentally change the semantics, so we'll see if this holds
on slower machines (e.g. CI).
For some reason, the previous test didn't take the initial skip count
value into account, and now it does. Oh well.
@bnjbvr bnjbvr force-pushed the bnjbvr/single-background-pagination-request branch from e77b0b9 to 6159151 Compare March 18, 2026 10:13
@bnjbvr bnjbvr requested a review from Hywan March 18, 2026 10:13
@bnjbvr
Copy link
Member Author

bnjbvr commented Mar 18, 2026

@Hywan All the things for which you've requested tests are already tested, be it with tests that predated the PR, some of which have been tweaked, or new tests (test_concurrent_backpagination notably). PTAL!

@poljar poljar removed their request for review March 18, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants