Commit Graph

264 Commits

Author SHA1 Message Date
Jonas Platte 07808b4301 refactor: Enable extra code style clippy lints 2025-07-05 21:20:34 +02:00
Benjamin Bouvier 39d1ed9bc6 chore: exclude the room id / event id from the data to be sent to sentry
These are not included in Element's main privacy policy, and may
constitute PII (because the homeserver may include the name of some
user). We keep the information as separate log lines, so that
rageshakes/manual reports still include those.
2025-07-03 16:07:46 +02:00
Benjamin Bouvier 3d1d1c8f6d feat(state store): send deserialization errors to sentry \o/ 2025-07-03 16:07:46 +02:00
Benjamin Bouvier 5ad958722f feat(state store): include serde json error path when failing to deserialize in the state store 2025-07-03 16:07:46 +02:00
Benjamin Bouvier 31df84f5a1 feat(event cache): return the event's positions in find_event_relations 2025-06-30 16:10:49 +02:00
Benjamin Bouvier 1f89efb88d feat(event cache store): add a method to return the chunks' metadata 2025-06-30 11:09:11 +02:00
Kévin Commaille 06732ca71a refactor(common): Use a constant for the room version to use as a fallback
It avoids using different versions in several places for consistency. It
also allows to be able to change it in a single place when needed.

This also bumps the fallback to v11 everywhere, since it is the default
version for new rooms since Matrix 1.14 and it has the sanest redaction
rules.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2025-06-29 16:59:37 +02:00
Doug c74295c604 chore: Refactor ServerCapabilities into ServerInfo.
It has nothing to do with /capabilities so is confusing. We can use this new struct to combine the well-known response into a single cache too.
2025-06-19 17:40:04 +02:00
Stefan Ceriu f4e612ca9e feat: add thread support to the room message draft facilities
This patch adds optional thread root event id parameters to the drafting functions exposed on the room level
allowing unfinished messages to be managed for the main room as well as any inner thread.

Internally it uses the room id or a tuple of the room id and the thread as keys for the various backing stores.
2025-06-13 14:41:10 +03:00
Damir Jelić 0e9ce0271e refactor: Create a store/types submodule 2025-06-10 13:53:09 +02:00
Benjamin Bouvier 7cdfb0d1c0 chore(sqlite): revert the busy_timeout pragmas
Internal Sentry reports tell us that enabling the busy_timeout seems to
have *increased* the number of "database is busy" errors, instead of
lowering those. As a result, we're going to disable the pragmas in all
the places where we enabled it before, and observe how the number of
"database is busy" errors evolves.
2025-06-10 11:13:28 +02:00
Benjamin Bouvier ebcb74a86d refactor!(event cache): introduce LinkedChunkId in the backends (#5182)
In a "soon" future, threads have their own linked chunk. All our code
has been written with the fact that a linked chunk belong to *a room* in
mind, so it needs some biggish update. Fortunately, most of the changes
are mechanical, so they should be rather easy to review.

Part of #4869, namely #5122.
2025-06-09 13:26:46 +00:00
Benjamin Bouvier 672bb9f460 feat: add the busy timeout pragma to the event cache store acquire() method too
It will tell us if this is sufficient to avoid locking the event cache
store database, now that we have some proof that this is happening in
the wild.
2025-06-03 16:17:36 +02:00
Daniel Salinas c6e55c1a36 Mechanical move from target_arch="wasm32" to target_family="wasm" 2025-06-02 17:27:34 +02:00
Jonas Platte 8eec683793 refactor: Use inline format arguments more
Automated with cargo clippy --fix --workspace --all-targets.
2025-05-29 13:19:59 +02:00
Damir Jelić 064fd6cb0b fix(sqlite): Use the correct column name for the sender of bundled room keys 2025-05-27 17:46:10 +02:00
Benjamin Bouvier 9e1ea5d7d3 feat(sdk): expose the state store database name 2025-05-27 08:59:59 +02:00
Benjamin Bouvier 56082f93d0 chore(sdk): forward "database is busy" errors to sentry 2025-05-22 11:50:13 +02:00
Benjamin Bouvier 341f9c267d feat(state store): enable the busy timeout to automatically retry operations on busy dbs
Under some very particular circumstances, the "database is locked" error
can still happen, even in WAL mode, even if the database connection is
not being upgraded from a read transaction to a write transaction.

We *think* this might be the reason behind errors like
github.com/element-hq/element-x-ios/issues/3582, so we're enabling the
sqlite busy_timeout, which will retry the operation after a short sleep,
until the busy timeout is being hit.
2025-05-14 13:27:54 +02:00
Denis Kasak fc071bafb2 docs: Various fixes for store-related comments.
- Doc comment for the SQLite-based state store incorrectly referred to
  it as a "cryptostore".
- Consistent capitalisation of SQLite.
- Consistent use of indefinite article "an" before SQLite.
- Fix line length.
2025-05-06 13:55:03 +02:00
Ivan Enderlin 83e4314645 fix(sqlite): Fix a UNIQUE constraint violation with Update::RemoveItem.
Imagine we have the following events:

| event_id | room_id | chunk_id | position |
|----------|---------|----------|----------|
| $ev0     | !r0     | 42       | 0        |
| $ev1     | !r0     | 42       | 1        |
| $ev2     | !r0     | 42       | 2        |
| $ev3     | !r0     | 42       | 3        |
| $ev4     | !r0     | 42       | 4        |

`$ev2` has been removed, then we end up in this state:

| event_id | room_id | chunk_id | position |
|----------|---------|----------|----------|
| $ev0     | !r0     | 42       | 0        |
| $ev1     | !r0     | 42       | 1        |
|          |         |          |          | <- no more `$ev2`
| $ev3     | !r0     | 42       | 3        |
| $ev4     | !r0     | 42       | 4        |

We need to shift the `position` of `$ev3` and `$ev4` to `position - 1`,
like so:

| event_id | room_id | chunk_id | position |
|----------|---------|----------|----------|
| $ev0     | !r0     | 42       | 0        |
| $ev1     | !r0     | 42       | 1        |
| $ev3     | !r0     | 42       | 2        |
| $ev4     | !r0     | 42       | 3        |

Usually, it boils down to run the following query:

```sql
UPDATE event_chunks
SET position = position - 1
WHERE position > 2 AND …
```

Okay. But `UPDATE` runs on rows in no particular order. It means that
it can update `$ev4` before `$ev3` for example. What happens in this
particular case? The `position` of `$ev4` becomes `3`, however `$ev3`
already has `position = 3`. Because there is a `UNIQUE` constraint
on `(room_id, chunk_id, position)`, it will result in a constraint
violation.

There is **no way** to control the execution order of `UPDATE` in
SQLite. To persuade yourself, try:

```sql
UPDATE event_chunks
SET position = position - 1
FROM (
    SELECT event_id
    FROM event_chunks
    WHERE position > 2 AND …
    ORDER BY position ASC
) as ordered
WHERE event_chunks.event_id = ordered.event_id
```

It will fail the same way.

Thus, we have 2 solutions:

1. Remove the `UNIQUE` constraint,
2. Be creative.

The `UNIQUE` constraint is a safe belt. Normally, we have
`event_cache::Deduplicator` that is responsible to ensure there is no
duplicated event. However, relying on this is “fragile” in the sense it
can contain bugs. Relying on the `UNIQUE` constraint from SQLite is more
robust. It's “braces and belt” as we say here.

So. We need to be creative.

Many solutions exist. Amongst the most popular, we see _dropping and
re-creating the index_, which is no-go for us, it's too expensive. I
(@hywan) have adopted the following one:

- Do `position = position - 1` but in the negative space, so
 `position = -(position - 1)`. A position cannot be negative; we are
  sure it is unique!
- Once all candidate rows are updated, do `position = -position` to move
  back to the positive space.

'told you it's gonna be creative.

This solution is a hack, **but** it is a small number of operations, and
we can keep the `UNIQUE` constraint in place.

This patch updates the `test_linked_chunk_remove_item` to handle
6 events. On _my_ system, with _my_ SQLite version, it triggers the
`UNIQUE` constraint violation without the bug fix.
2025-05-06 09:17:54 +02:00
Richard van der Hoff a3cb1cd6b5 Merge branch 'main' into rav/history_sharing/save_key_bundle_data 2025-04-24 12:07:21 +01:00
Johannes Marbach 1554e05d8a refactor(send_queue): generalize SentRequestKey::Media and DependentQueuedRequestKind::UploadFileWithThumbnail to prepare for MSC4274 gallery uploads (#4897)
This was broken out of
https://github.com/matrix-org/matrix-rust-sdk/pull/4838 and is a
preliminary step towards implementing
[MSC4274](https://github.com/matrix-org/matrix-spec-proposals/pull/4274).
`SentRequestKey::Media` and
`DependentQueuedRequestKind::UploadFileWithThumbnail` are generalized to
allow chaining dependent media uploads and accumulating sent media
sources.

- [x] Public API changes documented in changelogs (optional)

---------

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
2025-04-24 09:52:33 +00:00
Richard van der Hoff e89c45ba42 sqlite: store data on received room key bundles 2025-04-23 19:59:24 +01:00
Richard van der Hoff 00364d95af crypto: add methods for room key bundles to store traits 2025-04-23 19:59:24 +01:00
Damir Jelić 511cf78d51 chore: Bump the rusqlite version 2025-04-09 16:37:40 +02:00
Ivan Enderlin 52ec6a4539 feat(sqlite): Add SqliteStoreConfig::with_low_memory_config.
This patch adds a new constructor for `SqliteStoreConfig`, which sets
some defaults tailored for low memory usage.

This patch adds tests asserting the defaults for `new` and
`with_low_memory_config`.
2025-04-07 14:05:40 +02:00
Benjamin Bouvier d30dc7177f refactor(sqlite): rename gaps to gap_chunks / events_chunks to event_chunks
And some comments have been tweaked too.
2025-04-02 13:26:15 +02:00
Benjamin Bouvier e42be87798 test(event cache): add tests for save_event() and find_event_relations()
And fix the sql backend \o/
2025-04-02 13:26:15 +02:00
Benjamin Bouvier 524040b33c refactor(event cache): have EventCacheStore::clear_all_rooms_chunks delete all the events' contents 2025-04-02 13:26:15 +02:00
Benjamin Bouvier 0227b3f554 refactor(event cache): regroup code to compute the filter strings 2025-04-02 13:26:15 +02:00
Benjamin Bouvier 6a076b0989 refactor(event cache): don't return the event itself, in find_event_with_relations
And rename it `find_event_relations`.
2025-04-02 13:26:15 +02:00
Benjamin Bouvier 3489cbd5d7 feat(event cache): allow retrieving an event and all its relations 2025-04-02 13:26:15 +02:00
Benjamin Bouvier 65be779bb0 refactor(event cache): move relation extraction into common store helpers 2025-04-02 13:26:15 +02:00
Benjamin Bouvier 45f1dca6a3 refactor(event cache): don't return a position in find_event
Getting the position when reading an event is no longer required:

- the only use case for reading the position out of the event cache was
when we wanted to replace a redacted item into the linked chunk; now
with save_event(), we can replace it without having to know its
position.

As an extra measure of caution, I've also included the room_id in the
`events` table, next to the event_id, so that looking for an event is
still restricted to a single room.
2025-04-02 13:26:15 +02:00
Benjamin Bouvier 913b2a5f78 feat(event cache): allow to persist an out-of-band event into storage 2025-04-02 13:26:15 +02:00
Benjamin Bouvier 3d8af1b972 feat(event cache): extract an event's relationship before inserting it into the database 2025-04-02 13:26:15 +02:00
Benjamin Bouvier 03f5d0222e refactor(event cache): store the events' content independently of their position in a chunk 2025-04-02 13:26:15 +02:00
Benjamin Bouvier 231073c9c3 chore(sqlite): log underlying errors in many OpenStoreError variants
This would help understanding what's the underlying error each time.
2025-04-01 14:51:32 +02:00
Ivan Enderlin bb87a728ac doc(sqlite): Fix a broken link. 2025-04-01 11:50:20 +02:00
Ivan Enderlin 4112162092 feat(sqlite): Add SqliteStoreConfig::path() to override the path.
This patch adds `SqliteStoreConfig::path()` to override the path passed
to the constructor `new`.
2025-04-01 11:50:20 +02:00
Ivan Enderlin f341572616 feat(sqlite): SqliteStoreConfig implements Clone and Debug.
This patch implements `Clone` and `Debug` for `SqliteStoreConfig`.
2025-04-01 11:50:20 +02:00
Ivan Enderlin 2a67d7472a feat(base,sqlite,indexeddb): Use RoomLoadSettings to load all or one room.
This patch updates `BaseStateStore` and the `StateStore` trait along
with its implementors, to return all rooms or a single room from
`StateStore::get_room_infos`.

See the previous patch for more context.
2025-03-31 16:47:58 +02:00
Ivan Enderlin 8738c4dbfd test(sqlite): Add test for cache_size and journal_size_limit.
This patch adds tests for checking the `PRAGMA cache_size` and `PRAGMA
journal_size_limit`.
2025-03-28 13:36:32 +01:00
Ivan Enderlin 99436f8e79 test(sqlite): Test the new RuntimeConfig type. 2025-03-28 13:36:32 +01:00
Ivan Enderlin 339b220488 feat(sqlite): Introduce RuntimeConfig which includes cache_size
This patch updates `StoreOpenConfig` to hold a new type: `RuntimeConfig`.

This `RuntimeConfig` type is passed to a new `SqliteAsyncConnExt`
method, named `apply_runtime_config`. Depending on the values passed
here, the `optimize`, `cache_size` (new!) and `journal_size_limit`
methods will be called automatically.

The goal of this type is to automate a flow we keep repeating in
all the stores. This is error-prone. This type brings uniformity and
consistency.

This patch also makes all `open_with_pool` methods on the stores private
(they were public before):

1. they were never used as far as I know because getting a `SqlitePool`
   isn't possible since the `pool` attribute is private…
2. it's better to keep control of this flow.
2025-03-28 13:36:32 +01:00
Ivan Enderlin 660d4e7ccb feat(sqlite): Add StoreOpenConfig and open_with_config for all stores.
This patch adds a new `StoreOpenConfing` type to configure the store
when opening it and when creating the pool of connections to SQLite via
`deadpool_sqlite`.

This patch also adds a new `open_with_config` constructor on all
stores, namely `SqliteCryptoStore`, `SqliteEventCacheStore` and
`SqliteStateStore`.
2025-03-26 11:01:52 +01:00
Benjamin Bouvier 06d5fdb5ff fix(event cache): enable foreign keys on a connection basis
As opposed to WAL mode, foreign keys must be enabled for each database
connection, according to
https://www.sqlite.org/foreignkeys.html#fk_enable

Unfortunately, we can't track which connection objects have already
executed the pragma, so the safer we can do is enable it everytime we
try to acquire a connection from the pool.

Fixes #4785.
2025-03-11 15:03:42 +01:00
Benjamin Bouvier 961a893b8c test(event cache): double-check cascading happened in the clear linked chunk test 2025-03-11 15:03:42 +01:00
Ivan Enderlin 3d653d3fdc fix(sqlite): Design a new schema to get faster insertions.
This patch is twofold. First off, it provides a new schema allowing to
improve the performance of `SqliteEventCacheStore` for 100_000 events
from 6.7k events/sec to 284k events/sec on my machine.

Second, it now assumes that `EventCacheStore` does NOT store invalid
events. It was already the case, but the SQLite schema was not rejecting
invalid event in case some were handled. It's now explicitely forbidden.
2025-03-05 13:57:08 +01:00