Mutation Serialization & Concurrency
Relevant source files
The following files were used as context for generating this wiki page:
Mutation Serialization & Concurrency in Numan refers to the architectural safeguards and locking mechanisms that prevent data corruption during state-altering operations. This system ensures that concurrent Numan processes do not interleave destructive operations, such as package installations, lockfile updates, or Nushell configuration changes, on the same root directory. Sources: AGENTS.md:120-121, src/util/fs_safety.rs:1-10
The scope of this system covers advisory file locking for process serialization, atomic filesystem operations for state persistence, and safety checks to prevent unauthorized modification of managed files. These mechanisms collectively maintain the integrity of the $NUMAN_ROOT and ensure that the lockfile remains the ground truth for the system state. Sources: CONTRIBUTING.md:73-82, src/util/fs_safety.rs:13-26
Advisory Mutation Lock
Numan utilizes an advisory exclusive OS lock to serialize all state-mutating commands. This is primarily handled by the MutationLock RAII guard, which targets a specific lock file located at $NUMAN_ROOT/state/mutation.lock. Sources: src/util/fs_safety.rs:32-35, AGENTS.md:120-121
Locking Mechanism and Invariants
The mutation lock enforces three specific classes of invariants during its lifetime:
- Process Serialization: Prevents concurrent Numan invocations from performing destructive operations (install, update, gc, etc.) simultaneously. Sources: src/util/fs_safety.rs:16-18, CONTRIBUTING.md:77-77
- Symlink/Reparse Point Detection: Ensures Numan never follows symlinks or Windows reparse points when accessing managed paths to prevent path traversal or out-of-bounds writes. Sources: src/util/fs_safety.rs:20-22, REVIEW.md:23-23
- Root Containment: Lexically validates that relative paths derived from external metadata (like registries) remain strictly within the canonical Numan root. Sources: src/util/fs_safety.rs:24-26, src/nu/autoload.rs:81-90
The following diagram illustrates the flow of acquiring the mutation lock during a destructive command:
The diagram shows the lifecycle of a MutationLock from acquisition to automatic release via RAII. Sources: src/util/fs_safety.rs:49-80
Core Components
| Component | Description | Location |
|---|---|---|
MutationLock | RAII guard holding an exclusive advisory lock on the mutation file. | src/util/fs_safety.rs:38 |
acquire_mutation_lock | Function to attempt a non-blocking lock acquisition. | src/util/fs_safety.rs:56 |
setup_subcommand_lock | High-level wrapper for destructive subcommands (install, remove, use). | src/util/fs_safety.rs:104 |
mutation.lock | The physical file used for advisory locking. | $NUMAN_ROOT/state/mutation.lock |
Sources: src/util/fs_safety.rs:32-120, AGENTS.md:65-68
Atomic State Persistence
Concurrency safety extends to how Numan persists data to disk. To prevent partial-write corruption during system crashes or power failures, all critical JSON state files (lockfiles, journals, and paths caches) utilize atomic write patterns. Sources: AGENTS.md:131-132, CONTRIBUTING.md:78-78
The Atomic Write Pattern
Instead of overwriting files in place, Numan follows a "temp-and-move" strategy:
- Data is written to a temporary file in the same directory as the target. Sources: src/nu/autoload.rs:245-255
- The temporary file is flushed to disk. Sources: AGENTS.md:131-132
- An OS-level atomic rename (e.g.,
MoveFileExWon Windows) replaces the target file. Sources: src/nu/autoload.rs:328-333
This sequence ensures that even if the process is interrupted, the target file remains in a valid state (either the original version or the complete new version). Sources: src/nu/autoload.rs:328-340, AGENTS.md:131-132
Managed File Ownership & Safety
To coordinate safely with Nushell, Numan manages a specific vendor autoload file (numan.nu). Concurrency and safety rules prevent Numan from clobbering files it does not own. Sources: src/nu/autoload.rs:11-20
Ownership Verification
Before any mutation of numan.nu, Numan performs an ownership check using the OWNERSHIP_MARKER. This marker is a hardcoded two-line header:
pub const OWNERSHIP_MARKER: &str =
"# Generated and managed by Numan. Do not edit.\n# Numan autoload schema: 1\n";
Sources: src/util/fs_safety.rs:127-129
The system refuses to overwrite or delete the file if:
- The parent directory is a symlink or reparse point. Sources: src/util/fs_safety.rs:149-151
- The file itself is a symlink. Sources: src/util/fs_safety.rs:154-154
- The file exists but lacks the
OWNERSHIP_MARKER. Sources: src/util/fs_safety.rs:162-171
Module Autoload Concurrency
When updating the autoload file, Numan generates a "candidate" file first. This candidate is validated by invoking Nushell in "no-config" mode (nu -n <candidate>) before it is promoted to the live managed file. Sources: src/nu/autoload.rs:281-295, AGENTS.md:127-130
Summary
Mutation serialization in Numan is enforced through a combination of advisory OS-level locking (MutationLock), atomic filesystem operations to prevent corruption, and strict ownership markers. These mechanisms ensure that destructive commands are executed sequentially and that the Nushell environment remains stable even during concurrent usage or process failure. Sources: src/util/fs_safety.rs:13-30, AGENTS.md:118-132