Skip to content

base: Move media cache to new EventCacheStore trait#3858

Merged
bnjbvr merged 4 commits intomatrix-org:mainfrom
zecakeh:media-cache
Aug 22, 2024
Merged

base: Move media cache to new EventCacheStore trait#3858
bnjbvr merged 4 commits intomatrix-org:mainfrom
zecakeh:media-cache

Conversation

@zecakeh
Copy link
Copy Markdown
Collaborator

@zecakeh zecakeh commented Aug 20, 2024

Allows to save media in a different path than the state store.

This adds a "last_access" field to the SQLite implementation, to prepare for future work on a media retention policy.

This removes the IndexedDB media cache implementation, because as far as I know it is currently unused, and I have no idea how to implement efficiently the planned media retention policy with a key-value store.

Closes #1810.

  • Public API changes documented in changelogs (optional)

@zecakeh zecakeh requested a review from a team as a code owner August 20, 2024 10:00
@zecakeh zecakeh requested review from jmartinesp and removed request for a team August 20, 2024 10:00
@zecakeh zecakeh force-pushed the media-cache branch 2 times, most recently from d180536 to 7d963ad Compare August 20, 2024 10:17
Copy link
Copy Markdown
Contributor

@jmartinesp jmartinesp left a comment

Choose a reason for hiding this comment

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

The code LGTM in general, but since I'm not familiar with this part of the SDK maybe it would be better to have an extra pair of eyes on this? @bnjbvr , @Hywan maybe?

@zecakeh zecakeh force-pushed the media-cache branch 2 times, most recently from bacba74 to ec7060b Compare August 20, 2024 10:40
Allows to save media in a different path than the state store.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
@codecov
Copy link
Copy Markdown

codecov bot commented Aug 20, 2024

Codecov Report

Attention: Patch coverage is 93.47826% with 18 lines in your changes missing coverage. Please review.

Project coverage is 84.10%. Comparing base (3b34746) to head (8caa932).
Report is 22 commits behind head on main.

Files Patch % Lines
crates/matrix-sdk-sqlite/src/event_cache_store.rs 91.57% 8 Missing ⚠️
...es/matrix-sdk-base/src/event_cache_store/traits.rs 66.66% 4 Missing ⚠️
crates/matrix-sdk-sqlite/src/error.rs 0.00% 4 Missing ⚠️
...rates/matrix-sdk-base/src/event_cache_store/mod.rs 0.00% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3858   +/-   ##
=======================================
  Coverage   84.09%   84.10%           
=======================================
  Files         261      266    +5     
  Lines       27622    27689   +67     
=======================================
+ Hits        23229    23287   +58     
- Misses       4393     4402    +9     

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

@bnjbvr bnjbvr self-requested a review August 20, 2024 12:53
@bnjbvr
Copy link
Copy Markdown
Member

bnjbvr commented Aug 20, 2024

Thanks, I'll take over the review.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
@zecakeh zecakeh changed the title base: Move media cache to its own trait base: Move media cache to new EventCacheStore trait Aug 21, 2024
@zecakeh
Copy link
Copy Markdown
Collaborator Author

zecakeh commented Aug 21, 2024

As discussed in the matrix room, I renamed the trait to EventCacheStore.

Copy link
Copy Markdown
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Thanks! Would you be ok implementing the last access feature as a separate PR? I don't think it should be implemented only for the sqlite backend, and my proposal below should make it possible to implement for other backends too by tweaking the APIs.

let uri = self.encode_key(keys::MEDIA, request.source.unique_key());
let format = self.encode_key(keys::MEDIA, request.format.unique_key());
let data = self.encode_value(content)?;
self.acquire().await?.set_media(uri, format, data).await
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Out of curiosity, what's the reasoning behind having multiple layers to perform SQL queries? (i.e. having set_media somewhere else, and not inlined here)

In my recent works on the send queue, I've put all the code at the same layer, and it feels simpler to understand, and with fewer indirections.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I am not sure anymore. I mostly copy-pasted here what was in the StateStore implementation so we can definitely reduce the number of layers.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good, we can do this in a follow-up PR!

}

#[async_test]
async fn test_last_access() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we can introduce this feature in another PR, because I'd really like us to have it for all the EventCacheStore implementations, if we decide to go further down that road, and not only for a single backend, otherwise it may show at the use sites of the (abstract) event cache store.

Also I think for simplifying testing purposes and consistency of the backends, the timestamps should be provided by the caller; this will make it trivial to emulate time has spent without relying on tokio::time in tests, and will make it possible to implement this feature on the memory backend trivially too, I think.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It is planned to be for all the implementations in the next PR. The reasons I introduced it like that for the SQLite store is that:

  1. This is a brand new database and I know we'll need this column so it seemed like a waste to init the table without this only to have to write a migration in the next PR.
  2. Even if we only add the column without more logic, if a client uses that commit before the next PR is merged, the data will be wrong unless we decide to write a migration to clear the database.

So this is basically a placeholder implementation while we wait for the next PR.

Of course I didn't do this for the memory store because it's not persistent so we can change anything without migration.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sounds good!


tracing::info!("using event cache store @ {}", tmpdir_path.to_str().unwrap());

Ok(SqliteEventCacheStore::open(tmpdir_path.to_str().unwrap(), None).await.unwrap())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It seems sqlite supports in-memory backends too, and our code half supports it (the path is optional); is this something we could use in testing contexts, instead of having to create temporary directories and counting the number of temporaries we've created?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Where do you see the path as optional in our code?

We could use in-memory stores, but currently we rely heavily on deadpool-sqlite that requires a file. It's fine if we want to use in-memory store but we have to rewrite this to be able to interact with both deadpool-sqlite and rusqlite directly. In that case the layers we currently have (or something similar) might make more sense.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Where do you see the path as optional in our code?

path in the SqliteEventCacheStore impl; but it's probably a copy-pasto from the state store, which… never fills this path, and only uses it for debug purposes 🤦

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
@bnjbvr bnjbvr self-requested a review August 21, 2024 12:37
Copy link
Copy Markdown
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Thank you!

@bnjbvr bnjbvr merged commit 01e2db1 into matrix-org:main Aug 22, 2024
@zecakeh zecakeh deleted the media-cache branch August 22, 2024 08: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.

Split media caching from the StateStore trait

3 participants