next.js/turbopack/crates/turbo-persistence/src/rc_bytes.rs
rc_bytes.rs127 lines2.9 KB
use std::{
    borrow::Borrow,
    fmt::{self, Debug, Formatter},
    ops::{Deref, Range},
    rc::Rc,
};

use memmap2::Mmap;

use crate::{
    compression::decompress_into_rc,
    shared_bytes::{SharedBytes, is_subslice_of},
};

/// The backing storage for an `RcBytes`.
///
/// Uses `Rc` for all refcounting, eliminating atomic operations.
#[derive(Clone)]
enum Backing {
    Rc { _backing: Rc<[u8]> },
    Mmap { _backing: Rc<Mmap> },
}

/// An owned byte slice backed by either an `Rc<[u8]>` or a memory-mapped file.
///
/// Identical to `ArcBytes` but uses `Rc` instead of `Arc`, eliminating atomic
/// refcount overhead. Use this in single-threaded contexts like SST iteration
/// during compaction.
#[derive(Clone)]
pub struct RcBytes {
    data: *const [u8],
    backing: Backing,
}

impl From<Rc<[u8]>> for RcBytes {
    fn from(rc: Rc<[u8]>) -> Self {
        Self {
            data: &*rc as *const [u8],
            backing: Backing::Rc { _backing: rc },
        }
    }
}

impl From<Box<[u8]>> for RcBytes {
    fn from(b: Box<[u8]>) -> Self {
        Self::from(Rc::from(b))
    }
}

impl Deref for RcBytes {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        unsafe { &*self.data }
    }
}

impl Borrow<[u8]> for RcBytes {
    fn borrow(&self) -> &[u8] {
        self
    }
}

impl PartialEq for RcBytes {
    fn eq(&self, other: &Self) -> bool {
        self.deref().eq(other.deref())
    }
}

impl Debug for RcBytes {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Debug::fmt(&**self, f)
    }
}

impl Eq for RcBytes {}

impl SharedBytes for RcBytes {
    type MmapHandle = Rc<Mmap>;

    fn slice(self, range: Range<usize>) -> Self {
        let data = &*self;
        let data = &data[range] as *const [u8];
        Self {
            data,
            backing: self.backing,
        }
    }

    unsafe fn slice_from_subslice(&self, subslice: &[u8]) -> Self {
        debug_assert!(
            is_subslice_of(
                subslice,
                match &self.backing {
                    Backing::Rc { _backing } => _backing,
                    Backing::Mmap { _backing } => _backing,
                }
            ),
            "slice_from_subslice: subslice is not within the backing storage"
        );
        Self {
            data: subslice as *const [u8],
            backing: self.backing.clone(),
        }
    }

    unsafe fn from_mmap(mmap: &Rc<Mmap>, subslice: &[u8]) -> Self {
        debug_assert!(
            is_subslice_of(subslice, mmap),
            "from_mmap: subslice is not within the mmap"
        );
        RcBytes {
            data: subslice as *const [u8],
            backing: Backing::Mmap {
                _backing: mmap.clone(),
            },
        }
    }

    fn from_decompressed(uncompressed_length: u32, block: &[u8]) -> anyhow::Result<Self> {
        Ok(RcBytes::from(decompress_into_rc(
            uncompressed_length,
            block,
        )?))
    }
}
Quest for Codev2.0.0
/
SIGN IN