Skip to content

Conversation

@jgmontoya
Copy link
Contributor

@jgmontoya jgmontoya commented Jan 27, 2026

Problem

MdkSqliteStorage uses tokio::sync::Mutex for the SQLite connection and calls blocking_lock() to access it. This panics when called from within a tokio async runtime context:

Cannot block the current thread from within a runtime

This forces consumers (like whitenoise-rs) to wrap ALL MDK calls in std::thread::spawn() to escape the tokio runtime context, adding significant complexity and overhead.

Solution

Replace tokio::sync::Mutex with std::sync::Mutex. Since rusqlite operations are inherently synchronous, there's no benefit to using tokio's async Mutex. std::sync::Mutex::lock() does not panic in async contexts - it simply blocks until the lock is acquired.

Changes

  • Changed connection: Arc<tokio::sync::Mutex<Connection>> to Arc<std::sync::Mutex<Connection>>
  • Changed all .blocking_lock() calls to .lock().unwrap()

Impact

  • Consumers can now call MDK methods directly from async code without runtime panics
  • No architectural changes required
  • No API changes

This PR fixes runtime panics in MdkSqliteStorage by switching the SQLite connection synchronization from tokio::sync::Mutex to std::sync::Mutex, allowing blocking rusqlite operations to run from within a Tokio async runtime without triggering "Cannot block the current thread from within a runtime". Consumers can now call MDK storage methods directly from async contexts without spawning dedicated threads to avoid panics.

What changed:

  • Replaced the connection field type from Arc<tokio::sync::Mutex> to Arc<std::sync::Mutex> in mdk-sqlite-storage.
  • Replaced all usages of .blocking_lock() with .lock().unwrap() when acquiring the SQLite connection lock inside the crate.
  • Updated imports and internal code paths in crates/mdk-sqlite-storage to use std::sync::Mutex for synchronous DB access.

Security impact:

  • None: no changes to cryptography, key handling, SQLCipher configuration, file permissions, or secret management.

Protocol changes:

  • None.

API surface:

  • None: public types and method signatures are unchanged and no UniFFI/FFI boundaries or storage schema changes were introduced.

Testing:

  • No tests were added or modified as part of this change; existing tests that use storage APIs should continue to function without changes.

@coderabbitai
Copy link

coderabbitai bot commented Jan 27, 2026

📝 Walkthrough

Walkthrough

The pull request replaces the asynchronous mutex (tokio::sync::Mutex) with the standard library mutex (std::sync::Mutex) for the shared database connection in the SQLite storage module, updating all lock acquisition calls from blocking_lock() to lock().unwrap().

Changes

Cohort / File(s) Summary
Synchronization Primitive Replacement
crates/mdk-sqlite-storage/src/lib.rs
Replaced tokio::sync::Mutex with std::sync::Mutex for the connection field in MdkSqliteStorage. Updated all lock calls from blocking_lock() to lock().unwrap(), changing mutex poisoning/error-handling semantics. Import adjusted accordingly.
Changelog
crates/mdk-sqlite-storage/CHANGELOG.md
Added Unreleased entry noting the switch from tokio::sync::Mutex to std::sync::Mutex.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

storage

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately describes the main change: replacing tokio::sync::Mutex with std::sync::Mutex for the SQLite connection to prevent runtime panics.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
No Sensitive Identifier Leakage ✅ Passed PR changes only involve replacing tokio::sync::Mutex with std::sync::Mutex and updating blocking_lock() calls to lock().unwrap(). No sensitive identifiers found in logging, error messages, or Debug implementations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jgmontoya jgmontoya force-pushed the fix/use-std-mutex-for-sqlite-connection branch from eca9dec to fbe9052 Compare January 27, 2026 20:53
@github-actions
Copy link

✅ Coverage: 90.7% → 90.71% (+0.01%)

1 similar comment
@github-actions
Copy link

✅ Coverage: 90.7% → 90.71% (+0.01%)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/mdk-sqlite-storage/src/lib.rs`:
- Line 74: The use of std::sync::Mutex::lock() currently calls unwrap() and can
panic on a poisoned mutex; update all lock sites to handle PoisonError by
replacing unwrap() with unwrap_or_else(|e| e.into_inner()) so the code recovers
the inner guard instead of panicking—apply this change at all Mutex::lock()
calls in the file (notably inside the with_connection method and other methods
that acquire the same mutex) so every call (e.g., where
connection_mutex.lock().unwrap()) becomes
connection_mutex.lock().unwrap_or_else(|e| e.into_inner()).

…e panics

Replace tokio::sync::Mutex with std::sync::Mutex for the SQLite connection.
Since rusqlite operations are inherently synchronous, there's no benefit to
using tokio's async Mutex, and blocking_lock() panics when called from within
a tokio async runtime context ("Cannot block the current thread from within a runtime").

This allows consumers to call MDK methods directly from async code without
needing to wrap calls in std::thread::spawn() to escape the runtime context.
@jgmontoya jgmontoya force-pushed the fix/use-std-mutex-for-sqlite-connection branch from fbe9052 to 73d9a30 Compare January 27, 2026 21:07
@github-actions
Copy link

✅ Coverage: 90.7% → 90.71% (+0.01%)

use openmls_traits::storage::{StorageProvider, traits};
use rusqlite::Connection;
use tokio::sync::Mutex;
use std::sync::Mutex;
Copy link
Member

Choose a reason for hiding this comment

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

why not parking_lot?

I know I approved earlier but I think I actually want to take a close look into this before we move on it.

Copy link
Member

Choose a reason for hiding this comment

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

Ok - I've had a more thorough look and I'm happy.

use openmls_traits::storage::{StorageProvider, traits};
use rusqlite::Connection;
use tokio::sync::Mutex;
use std::sync::Mutex;
Copy link
Member

Choose a reason for hiding this comment

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

Ok - I've had a more thorough look and I'm happy.

@jgmontoya jgmontoya merged commit 4156904 into master Jan 28, 2026
12 checks passed
@jgmontoya jgmontoya deleted the fix/use-std-mutex-for-sqlite-connection branch January 28, 2026 14:00
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.

4 participants