Skip to main content

wasm_dbms_memory/
memory_access.rs

1// Rust guideline compliant 2026-04-27
2// X-WHERE-CLAUSE, M-CANONICAL-DOCS
3
4//! Trait abstracting page-level memory operations.
5//!
6//! [`MemoryAccess`] is the primary interface consumed by registry and
7//! ledger code in this crate. [`MemoryManager`](crate::MemoryManager)
8//! implements it with direct writes; the DBMS crate provides a
9//! journaled wrapper that records original bytes before each write.
10
11use wasm_dbms_api::prelude::{Encode, MemoryResult, Page, PageOffset};
12
13use crate::memory_manager::UNCLAIMED_PAGES_PAGE;
14use crate::unclaimed_pages::UnclaimedPages;
15
16/// Abstraction over page-level memory operations.
17///
18/// All table-registry and ledger functions are generic over this trait
19/// so that callers can transparently add write-ahead journaling or
20/// other interceptors without modifying the memory crate.
21pub trait MemoryAccess {
22    /// Returns the size of a single memory page.
23    fn page_size(&self) -> u64;
24
25    /// Grows the underlying memory by exactly one page and returns the
26    /// freshly allocated page number.
27    ///
28    /// The returned page is zero-initialized. This primitive is **not
29    /// journaled** — page growth cannot be rolled back, so a transaction
30    /// that aborts after a `grow_one_page` simply leaks the new page.
31    fn grow_one_page(&mut self) -> MemoryResult<Page>;
32
33    /// Zeros out an entire page. Used by [`MemoryAccess::unclaim_page`]
34    /// to scrub residual data before publishing the page to the
35    /// unclaimed-pages ledger.
36    fn zero_page(&mut self, page: Page) -> MemoryResult<()>;
37
38    /// Hands out a page for use by a caller.
39    ///
40    /// Reuses a page from the unclaimed-pages ledger when one is
41    /// available; otherwise grows the memory by one page.
42    fn claim_page(&mut self) -> MemoryResult<Page> {
43        let mut ledger: UnclaimedPages = self.read_at(UNCLAIMED_PAGES_PAGE, 0)?;
44        if let Some(page) = ledger.pop() {
45            self.write_at(UNCLAIMED_PAGES_PAGE, 0, &ledger)?;
46            return Ok(page);
47        }
48        self.grow_one_page()
49    }
50
51    /// Returns `page` to the unclaimed-pages ledger so it can be reused
52    /// by a future [`MemoryAccess::claim_page`] call.
53    ///
54    /// The page contents are zeroed before being published to the
55    /// ledger.
56    fn unclaim_page(&mut self, page: Page) -> MemoryResult<()> {
57        self.zero_page(page)?;
58        let mut ledger: UnclaimedPages = self.read_at(UNCLAIMED_PAGES_PAGE, 0)?;
59        ledger.push(page)?;
60        self.write_at(UNCLAIMED_PAGES_PAGE, 0, &ledger)
61    }
62
63    /// Reads a typed value from the specified page and offset.
64    fn read_at<D>(&mut self, page: Page, offset: PageOffset) -> MemoryResult<D>
65    where
66        D: Encode;
67
68    /// Writes a typed value at the specified page and offset.
69    fn write_at<E>(&mut self, page: Page, offset: PageOffset, data: &E) -> MemoryResult<()>
70    where
71        E: Encode;
72
73    /// Writes raw bytes at the specified page and offset, bypassing
74    /// alignment and encoding checks.
75    fn write_at_raw(&mut self, page: Page, offset: PageOffset, buf: &[u8]) -> MemoryResult<()>;
76
77    /// Zeros out the region occupied by `data` at the specified page
78    /// and offset.
79    fn zero<E>(&mut self, page: Page, offset: PageOffset, data: &E) -> MemoryResult<()>
80    where
81        E: Encode;
82
83    /// Zeros out `len` raw bytes at the specified page and offset.
84    ///
85    /// Used by the migration apply pipeline when scrubbing a record whose
86    /// size is known only at runtime (from a stored snapshot).
87    fn zero_raw(&mut self, page: Page, offset: PageOffset, len: PageOffset) -> MemoryResult<()>;
88
89    /// Reads raw bytes into `buf` at the specified page and offset.
90    ///
91    /// Returns the number of bytes actually read.
92    fn read_at_raw(
93        &mut self,
94        page: Page,
95        offset: PageOffset,
96        buf: &mut [u8],
97    ) -> MemoryResult<usize>;
98}