# reactor
`src/core/reactor/api.rs`
The I/O abstraction trait. All storage engine I/O is routed through a `Reactor` implementation, enabling fully deterministic integration tests without mocking the file system.
---
## Trait
```rust
pub trait Reactor {
fn now(&self) -> SystemTime;
fn read_file(&self, path: &Path) -> io::Result<Vec<u8>>;
fn write_file(&self, path: &Path, data: &[u8]) -> io::Result<()>;
fn append_file(&self, path: &Path, data: &[u8]) -> io::Result<u64>;
fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
fn create_dir_all(&self, path: &Path) -> io::Result<()>;
fn metadata_len(&self, path: &Path) -> io::Result<u64>;
fn sleep(&self, duration: Duration);
fn random_u64(&self) -> u64;
}
```
---
## SystemReactor
```rust
pub struct SystemReactor;
```
The production implementation. Delegates directly to `std::fs` and `SystemTime::now`. `random_u64` derives entropy from the current nanosecond timestamp.
---
## DeterministicReactor
```rust
pub struct DeterministicReactor { /* ... */ }
impl DeterministicReactor {
pub fn new(now: SystemTime, seed: u64) -> Self
}
impl Default for DeterministicReactor {
// now: SystemTime::UNIX_EPOCH, seed: 0
}
```
The test implementation:
- **Time**: `now()` returns a fixed clock. `sleep()` advances the clock by the requested duration instead of blocking.
- **Randomness**: `random_u64()` uses a deterministic LCG seeded with `seed`. The same seed always produces the same sequence.
- **File I/O**: still delegates to `std::fs` — the reactor abstracts time and randomness, not the file system.
### Usage in tests
```rust
use std::time::{Duration, SystemTime};
use iridium::core::reactor::DeterministicReactor;
use iridium::features::storage::api::{open_store_with_reactor, StorageConfig};
use std::sync::Arc;
let reactor = Arc::new(DeterministicReactor::new(SystemTime::UNIX_EPOCH, 42));
let handle = open_store_with_reactor(config, reactor)?;
```
The deterministic reactor makes tests that involve time-based WAL rotation or HNSW rebuild scheduling stable and reproducible.