Skip to main content

Engine

Struct Engine 

Source
pub struct Engine {
    config: EngineConfig,
    sink: RwLock<Option<EventSink>>,
    volumes: RwLock<Vec<Arc<VolumeSlot>>>,
    threads: Mutex<Vec<JoinHandle<()>>>,
    metrics: MetricsHub,
    compile_cache: Mutex<Option<(String, QueryOptions, Arc<CompiledQuery>)>>,
    _diag_guard: Mutex<Option<SinkGuard>>,
    _writer_lock: File,
}
Expand description

The multi-volume engine: owns one index per NTFS volume, drives scans and USN tailing, and answers queries. Holds the single-writer lock for its whole lifetime.

Fields§

§config: EngineConfig§sink: RwLock<Option<EventSink>>§volumes: RwLock<Vec<Arc<VolumeSlot>>>§threads: Mutex<Vec<JoinHandle<()>>>§metrics: MetricsHub§compile_cache: Mutex<Option<(String, QueryOptions, Arc<CompiledQuery>)>>

Last (text, options) → compiled query. An identical re-issue — a USN- driven requery of the same text (the RefreshInPlace path) — then skips parse + compile, which matters most for a heavy regex. Always sound: the compiled query is a pure function of (text, options) (the date resolver maps civil dates to ticks independently of the wall clock). Keying on the whole QueryOptions over-approximates (only case + the regex mode/scope actually steer compilation) but stays trivially correct. Engine-wide because compilation is volume-independent.

§_diag_guard: Mutex<Option<SinkGuard>>

Keeps the diag→EngineError forwarding registered for our lifetime.

§_writer_lock: File

Exclusive-write handle on {index_dir}\.writer.lock for our whole lifetime — the OS releases it on process death, so no stale locks.

Implementations§

Source§

impl Engine

Source

pub fn query( &self, text: &str, opt: &QueryOptions, ) -> Result<(ResultSet, QueryTrace), EngineError>

Run a query against every Ready volume and merge the per-volume, already-sorted id lists into one ordered result set.

Per volume, the previous result is kept (VolumeSlot::last_query); when the new query provably narrows it and the index generation is unchanged, the candidate set is the previous hits instead of the whole index (query::refine) — typing one more letter costs O(previous hits), not O(index).

§Errors

Returns EngineError::Parse if text is not a valid query, or EngineError::Compile if a valid query fails to compile (e.g. a bad regex term).

§Panics

Panics if a Ready volume’s index is absent during the k-way merge — an invariant the volume thread upholds (a Ready slot always holds an index).

Source§

impl Engine

Source

pub fn list_ntfs_volumes() -> Vec<String>

Fixed NTFS volumes (“C:”, “D:”, …).

Source

pub(super) fn save_slot( &self, slot: &VolumeSlot, checkpoint: JournalCheckpoint, ) -> bool

Writes the slot’s snapshot (via its SnapshotStore) under the per-slot save lock and records the saved generations (the flush dirty check). Returns false on a failed write — already counted and logged here.

Source§

impl Engine

Source

pub(super) fn volume_thread(self: Arc<Self>, slot: Arc<VolumeSlot>)

Production wiring: the Windows journal seam (the snapshot seam lives on the slot, created by index_start).

Source

pub(super) fn volume_thread_with( self: Arc<Self>, slot: Arc<VolumeSlot>, journal: &mut dyn JournalSource, )

Panic firewall: a crashing volume thread must never leave the UI stuck on “Scanning” with no explanation. The panic itself is logged (with backtrace) by the diag hook; this converts it into a visible Failed state. Worker entry with an injectable journal seam — production passes the Win implementation; worker_tests.rs passes scripted fakes.

Source

fn volume_thread_inner( self: Arc<Self>, slot: Arc<VolumeSlot>, journal: &mut dyn JournalSource, )

Source

pub(super) fn maybe_compact(&self, slot: &VolumeSlot)

Compact once the tombstone/garbage thresholds trip (checked per applied USN batch). The copy builds under a read guard — this volume thread is the index’s only writer — and the write lock is held for the swap alone. install_index bumps the structural generation, hard-staling open result handles.

Source§

impl Engine

Source

pub fn new(config: EngineConfig) -> Result<Arc<Self>, EngineCreateError>

Create the engine and acquire the single-writer lock on the index directory.

§Errors

Returns EngineCreateError::Io if the index directory cannot be created, or EngineCreateError::Locked if another engine process already holds the writer lock (FMF_E_LOCKED).

Source

fn acquire_writer_lock(index_dir: &Path) -> Result<File, EngineCreateError>

Cross-process single-writer guard: exclusive write access on .writer.lock (readers allowed, so a losing process can report the holder’s pid). Held until drop; the OS frees it on process death.

Source

pub fn set_event_sink(&self, sink: Option<EventSink>)

Install (or clear with None) the callback that receives every EngineEvent.

Source

fn emit(&self, ev: EngineEvent)

Source

pub fn index_start(self: &Arc<Self>, volumes: &[String])

Begin indexing the given volumes (asynchronous; progress via events). Idempotent per volume label: clients re-send IndexStart on every (re)connect and the service also calls this at startup, so a volume already being indexed is skipped. A duplicate slot would make every query return that volume’s rows once per copy (search merges all Ready slots) — the source of the “each result appears N times” bug.

§Panics

Panics if a volume worker thread cannot be spawned.

Source

pub fn index_start_scope( self: &Arc<Self>, roots: &[String], excludes: &[String], )

Begin a non-elevated scope-mode index over roots (absolute base paths), folder-walked and watched in-process without elevation (ADR-0024). Unlike Self::index_start, the change source is ReadDirectoryChangesW, not the USN journal, and the snapshot lives under a single fixed scope label (so a hostile roots entry can never steer snapshot_path — only the fixed label does). Idempotent: a second call while the scope slot exists is a no-op.

§Panics

Panics if the volume worker thread cannot be spawned.

Source

pub fn status(&self) -> Vec<(String, VolumeState, u64)>

Per-volume status: (label, state, files scanned so far).

Source

pub const fn metrics(&self) -> &MetricsHub

The engine’s metrics hub (counters and the diagnostics ring).

Source

pub fn index_stats(&self) -> Vec<IndexStats>

Per-volume memory accounting (perf panel / fmf stats).

Source

pub fn metrics_snapshot(&self) -> MetricsSnapshot

Full observability snapshot (JSON-serializable).

Source

pub fn flush(&self) -> usize

Persist every Ready volume whose generations moved since its last save (“dirty”), using the tailing thread’s shared checkpoint. The checkpoint may trail the index by an in-flight batch — the USN replay on load covers that. Returns the number of snapshots written (failed writes are counted in snapshot_save_failures and excluded).

Source

pub fn shutdown(&self)

Signal every volume thread to stop and join them (bounded wait).

Source

pub fn insert_ready_volume(&self, label: &str, idx: VolumeIndex)

Test/dev helper: register an already-built index as a Ready volume. The zero checkpoint stands in for a journal position so flush can exercise the save path on injected volumes.

Source

pub fn replace_ready_volume(&self, label: &str, idx: VolumeIndex)

Test/dev helper: swap a rebuilt index into an existing Ready volume — the same structural replacement a journal-gone full rescan performs.

§Panics

Panics if no volume with the given label exists.

Auto Trait Implementations§

§

impl !Freeze for Engine

§

impl !RefUnwindSafe for Engine

§

impl Send for Engine

§

impl Sync for Engine

§

impl Unpin for Engine

§

impl UnsafeUnpin for Engine

§

impl !UnwindSafe for Engine

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more