wireshift-core 0.1.1

Core typed operations, buffers, and backend traits for wireshift
Documentation
//! Memory advice operations for sequential/random access hints.
//!
//! Issues `madvise(2)` to hint the kernel about expected file access patterns.
//! For sequential scans (warpscan's primary pattern), `MADV_SEQUENTIAL` doubles
//! the kernel readahead window, significantly improving NVMe throughput.

use std::fs::File;

use crate::error::Result;
use crate::op::{CompletionPayload, MadviseAdvice, Op, OpDescriptor};

/// Result of a successful madvise operation.
#[derive(Debug, Clone, Copy)]
pub struct MadviseResult {
    /// The advice that was applied.
    pub advice: MadviseAdvice,
}

/// Hint the kernel about expected access pattern for a file.
///
/// # Example
///
/// ```no_run
/// use wireshift_core::ops::Madvise;
/// use wireshift_core::op::MadviseAdvice;
/// use std::fs::File;
///
/// let file = File::open("data.bin").unwrap();
/// let op = Madvise::sequential(file);
/// ```
pub struct Madvise {
    file: File,
    advice: MadviseAdvice,
}

impl Madvise {
    /// Advise sequential access (aggressive readahead).
    pub fn sequential(file: File) -> Self {
        Self {
            file,
            advice: MadviseAdvice::Sequential,
        }
    }

    /// Advise random access (disable readahead).
    pub fn random(file: File) -> Self {
        Self {
            file,
            advice: MadviseAdvice::Random,
        }
    }

    /// Advise that data will not be needed (release pages).
    pub fn dont_need(file: File) -> Self {
        Self {
            file,
            advice: MadviseAdvice::DontNeed,
        }
    }

    /// Advise normal access pattern (reset to default).
    pub fn normal(file: File) -> Self {
        Self {
            file,
            advice: MadviseAdvice::Normal,
        }
    }
}

impl Op for Madvise {
    type Output = MadviseResult;

    fn name(&self) -> &'static str {
        "madvise"
    }

    fn into_descriptor(self) -> Result<OpDescriptor> {
        Ok(OpDescriptor::Madvise {
            file: self.file,
            advice: self.advice,
        })
    }

    fn map_completion(payload: CompletionPayload) -> Result<Self::Output> {
        match payload {
            CompletionPayload::Bytes(code) => {
                let advice = match code {
                    0 => MadviseAdvice::Sequential,
                    1 => MadviseAdvice::Random,
                    2 => MadviseAdvice::DontNeed,
                    _ => MadviseAdvice::Normal,
                };
                Ok(MadviseResult { advice })
            }
            // A non-Bytes payload means the completion was misrouted. Silently
            // returning `Normal` (the old `_` arm) told the caller the advice was
            // reset to Normal when the payload was actually invalid, masking the
            // routing bug (Law 10). Fail loud, matching the sibling ops. The
            // unknown-CODE fallback to Normal above is a legitimate advice mapping
            // and stays.
            other => Err(crate::error::Error::completion(
                format!("madvise received unexpected completion payload: {other:?}"),
                "ensure the backend routes madvise completions as byte-count payloads",
            )),
        }
    }
}