Skip to content

Commit

Permalink
fixup! fix(event cache store): always use immediate mode when handlin…
Browse files Browse the repository at this point in the history
…g linked chunk updates
  • Loading branch information
bnjbvr committed Dec 12, 2024
1 parent 1b79fa6 commit cd16316
Showing 1 changed file with 39 additions and 13 deletions.
52 changes: 39 additions & 13 deletions crates/matrix-sdk-sqlite/src/event_cache_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,16 +378,7 @@ impl EventCacheStore for SqliteEventCacheStore {
let room_id = room_id.to_owned();
let this = self.clone();

self.acquire()
.await?
.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()?;

with_immediate_transaction(self.acquire().await?, move |txn| {
for up in updates {
match up {
Update::NewItemsChunk { previous, new, next } => {
Expand Down Expand Up @@ -539,11 +530,9 @@ impl EventCacheStore for SqliteEventCacheStore {
}
}

txn.commit()?;

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

Ok(())
}
Expand Down Expand Up @@ -718,6 +707,43 @@ impl EventCacheStore for SqliteEventCacheStore {
}
}

/// Like `deadpool::managed::Object::with_transaction`, but starts the
/// transaction in immediate (write) mode from the beginning, precluding errors
/// of the kind SQLITE_BUSY from happening, for transactions that may involve
/// both reads and writes, and start with a write.
async fn with_immediate_transaction<
T: Send + 'static,
F: FnOnce(&Transaction<'_>) -> Result<T, Error> + Send + 'static,
>(
conn: SqliteAsyncConn,
f: F,
) -> Result<T, Error> {
conn.interact(move |conn| -> Result<T, 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 code = || -> Result<T, Error> {
let txn = conn.transaction()?;
let res = f(&txn)?;
txn.commit()?;
Ok(res)
};

let res = code();

// Reset the transaction behavior to use Deferred, after this transaction has
// been run, whether it was successful or not.
conn.set_transaction_behavior(TransactionBehavior::Deferred);

res
})
.await
// SAFETY: same logic as in [`deadpool::managed::Object::with_transaction`].`
.unwrap()
}

fn insert_chunk(
txn: &Transaction<'_>,
room_id: &Key,
Expand Down

0 comments on commit cd16316

Please sign in to comment.