async-io-model
Explanations of common asynchronous patterns used in tursodb. Involves IOResult, state machines, re-entrancy pitfalls, CompletionGroup. Always use these patterns in `core` when doing anything IO
By tursodatabase · 1,176 installs
npx skills add tursodatabase/turso --skill async-io-model
Source repository · Upstream listing
Async I/O Model Guide
Turso uses cooperative yielding with explicit state machines instead of Rust async/await.
Core Types
Functions returning IOResult must be called repeatedly until Done .
Completion and CompletionGroup
A Completion tracks a single I/O operation:
To wait for multiple I/O operations, use CompletionGroup :
CompletionGroup features:
Aggregates multiple completions into one
Calls callback when all complete (or any errors)
Can nest groups (add a group's completion to another group)
Cancellable via group.cancel()
Helper Macros
return if io!
Unwraps IOResult , propagates IO variant up the call stack:
io yield one!
Yields a single completion:
State Machine Pattern
Operations that may yield use explicit state enums:
The function loops, matching on state and transitioning:
Re Entrancy: The Critical Pitfall
State mutations before yield points cause bugs on re entry.
Wrong
If something that might yield() returns IO , caller waits for completion, then calls bad example() again. counter gets incremented twice (or more).
Correct: Mutate After Yield
Correct: Use State Machine
Common Re Entrancy Bugs
Pattern Problem
vec.push(x); return if io!(...) Vec grows on each re entry
idx += 1; return if io!(...) Index advances multiple times
map.insert(k,v); return if io!(...) Duplicate inserts or overwrites
flag = true; return if io!(...) Usually ok, but check logic
State Enum Design
Encode progress in state variants:
Turso Implementation
Key files:
core/types.rs IOResult , IOCompletions , return if io! , return and restore if io!
core/io/completions.rs Completion , CompletionGroup
core/util.rs io yield one! macro
core/state machine.rs Generic StateMachine wrapper
core/storage/btree.rs Many state machine examples
core/storage/pager.rs CompletionGroup usage examples
Testing Async Code
Re entrancy bugs often only manifest under specific IO timing. Use:
Deterministic simulation ( testing/simulator/ )
Whopper concurrent DST ( testing/concurrent simulator/ )
Fault injection to force yields at different points
References
docs/manual.md section on I/O