Skip to content

Commit

Permalink
fix(event cache store): always use immediate mode when handling linke…
Browse files Browse the repository at this point in the history
…d chunk updates

If a linked chunk update starts with a RemoveChunk update, then the
transaction may start with a SELECT query and be considered a read
transaction. Soon enough, it will be upgraded into a write transaction,
because of the next UPDATE/DELETE operations that happen thereafter. If
there's another write transaction already happening, this may result in
a SQLITE_BUSY error, according to
https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions

One solution is to always start the transaction in immediate mode. This
may also fail with SQLITE_BUSY according to the documentation, but it's
unclear whether it will happen in general, since we're using WAL mode
too. Let's try it out.
  • Loading branch information
bnjbvr committed Dec 12, 2024
1 parent 0264e49 commit 1b79fa6
Showing 1 changed file with 14 additions and 5 deletions.
19 changes: 14 additions & 5 deletions crates/matrix-sdk-sqlite/src/event_cache_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use matrix_sdk_base::{
};
use matrix_sdk_store_encryption::StoreCipher;
use ruma::{MilliSecondsSinceUnixEpoch, RoomId};
use rusqlite::{OptionalExtension, Transaction};
use rusqlite::{OptionalExtension, Transaction, TransactionBehavior};
use tokio::fs;
use tracing::{debug, trace};

Expand Down Expand Up @@ -380,7 +380,14 @@ impl EventCacheStore for SqliteEventCacheStore {

self.acquire()
.await?
.with_transaction(move |txn| -> Result<_, Self::Error> {
.interact(move |conn| -> Result<_, Self::Error> {
// Start the transaction in IMMEDIATE mode since all updates may cause writes, to
// avoid read transactions upgrading to write mode and causing SQLITE_BUSY errors.
// See also: https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
conn.set_transaction_behavior(TransactionBehavior::Immediate);

let txn = conn.transaction()?;

for up in updates {
match up {
Update::NewItemsChunk { previous, new, next } => {
Expand All @@ -394,7 +401,7 @@ impl EventCacheStore for SqliteEventCacheStore {
);

insert_chunk(
txn,
&txn,
&hashed_room_id,
previous,
new,
Expand All @@ -418,7 +425,7 @@ impl EventCacheStore for SqliteEventCacheStore {

// Insert the chunk as a gap.
insert_chunk(
txn,
&txn,
&hashed_room_id,
previous,
new,
Expand Down Expand Up @@ -532,9 +539,11 @@ impl EventCacheStore for SqliteEventCacheStore {
}
}

txn.commit()?;

Ok(())
})
.await?;
.await.unwrap()?;

Ok(())
}
Expand Down

0 comments on commit 1b79fa6

Please sign in to comment.