How to Configure io_uring for Asynchronous I/O in Turso on Linux
Enable the io_uring Cargo feature at compile time and select the "io_uring" VFS at runtime to replace Turso's default syscall backend with Linux's high-performance ring-based asynchronous I/O interface.
Turso, the edge-optimized database from tursodatabase/turso, provides an optional io_uring backend that replaces the standard synchronous VFS with a high-performance, ring-based interface. This Linux-only implementation, centered on the UringIO type in core/io/io_uring.rs, reduces system-call overhead through batched submissions and zero-copy buffers. Configuring it requires both compile-time feature selection and runtime VFS activation.
Prerequisites and Feature Gating
The io_uring backend is strictly Linux-only and gated behind the io_uring Cargo feature. In core/Cargo.toml, this feature pulls in the external io-uring crate and enables the rustix/io_uring implementation. The code is wrapped in conditional compilation: #[cfg(all(target_os = "linux", feature = "io_uring", not(miri)))].
If the target platform is not Linux, the code is excluded entirely. Attempting to use the "io_uring" VFS on non-Linux platforms results in a runtime error: "io_uring is only available on Linux targets" (see sdk-kit/src/rsapi.rs).
How the io_uring Backend Works
The architecture centers on the UringIO struct defined in core/io/io_uring.rs. When initialized via UringIO::new() (lines 95-134), it creates an io_uring::IoUring instance, registers a sparse buffer arena for fixed-buffer I/O, and probes kernel opcode support.
Submission and Completion Flow
All file operations—open_file, pread, pwrite, pwritev, sync, and truncate—build io_uring submission queue entries (SQEs) and push them into a shared RingState via submit_entry. A single leader thread serializes the submit_and_wait syscall while draining completion queue entries (CQEs).
When a CQE arrives, the user_data key maps back to a Completion via completion_from_key, waking the associated future. Write-vectors (pwritev) requiring multiple kernel calls are automatically resubmitted, and the future is woken with wake_user_data.
Performance Characteristics
The ring batches up to 512 entries (ENTRIES = 512) and waits for up to 4 completions (MAX_WAIT = 4) per syscall, significantly cutting io_uring_enter syscalls. Fixed-buffer registration allows the kernel to operate directly on pre-registered memory, eliminating extra copies for reads and writes.
Enabling the io_uring Backend
Follow these steps to configure the backend:
-
Compile with the feature flag. Build Turso using
cargo build --features=io_uringor addio_uring = trueto your workspace profile. On non-Linux targets, this code is excluded automatically. -
Select the VFS at runtime. Pass the string
"io_uring"to the database builder. Incore/lib.rs, the factory maps this string toArc::new(UringIO::new()?). The SDK exposes this asbuilder.with_io("io_uring".to_string()), while the CLI acceptstursodb --vfs io_uring. -
Verify initialization. Check the debug logs for the message
Using IO backend 'io-uring'emitted byUringIO::new. If this line does not appear, the system has fallen back to the default syscall VFS.
Fallback Behavior
If the kernel lacks support for specific opcodes (e.g., IORING_OP_FTRUNCATE), Turso logs a warning and executes the operation via synchronous POSIX syscalls, ensuring correctness on older kernels.
Code Examples
Rust SDK Configuration
use turso_sdk_kit::DatabaseBuilder;
fn main() -> turso_sdk_kit::Result<()> {
// Selects the io_uring VFS registered in core/lib.rs
let db = DatabaseBuilder::new()
.with_path("/var/lib/turso/my.db")
.with_io("io_uring".to_string())
.open()?;
// All subsequent I/O uses the io_uring ring via UringIO
let rows = db.query("SELECT * FROM users", ())?;
Ok(())
}
CLI Usage
tursodb \
--path /var/lib/turso/my.db \
--vfs io_uring \
repl
Integration Testing
// From tests/integration/query_processing/test_write_path.rs
let db = TestBuilder::new()
.with_io_uring(true)
.open();
db.execute("PRAGMA journal_mode=WAL").unwrap();
db.execute("INSERT INTO t (id) VALUES (1)").unwrap();
// Internally uses UringIO::pwritev for the write path
Summary
- The io_uring backend is available only on Linux and requires the
io_uringCargo feature. - The implementation lives in
core/io/io_uring.rsand registers the VFS name"io_uring"incore/lib.rsandcore/io/mod.rsunderBUILTIN_VFS_NAMES. - Runtime selection uses
.with_io("io_uring")in the SDK or--vfs io_uringin the CLI. - The backend batches up to 512 submissions and uses fixed buffers to minimize syscall overhead, gracefully falling back to POSIX syscalls for unsupported kernel opcodes.
Frequently Asked Questions
Is io_uring available on macOS or Windows?
No. The io_uring backend is strictly Linux-only. Attempting to use "io_uring" on other platforms triggers a runtime error stating that "io_uring is only available on Linux targets" as implemented in sdk-kit/src/rsapi.rs. Windows users should use the experimental_win_iocp VFS instead.
What happens if my kernel does not support io_uring?
If the kernel lacks support for specific io_uring opcodes (detected via the Probe during UringIO::new), Turso logs a warning and falls back to synchronous POSIX syscalls for those operations. The database remains functional but without the performance benefits of the ring-based interface.
How do I verify that Turso is actually using io_uring?
Check the debug logs for the message Using IO backend 'io-uring' emitted by UringIO::new in core/io/io_uring.rs. If this line does not appear, verify that you compiled with the io_uring feature and explicitly selected the "io_uring" VFS at runtime.
Does io_uring improve performance for all workloads?
io_uring primarily benefits workloads with high concurrent I/O or large batch operations by reducing syscall overhead and enabling zero-copy transfers via fixed-buffer registration. Single-threaded, low-concurrency workloads may see minimal improvement, though the batching of submissions still reduces context switches.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →