Skip to content

Commit 97bcc32

Browse files
committed
refactor(api): shrink public surface to the supported crate root
Make every internal module (btree, catalog, crypto, pager, realm, recovery, segment, snapshot, txn) `pub(crate)` instead of `pub`, so embedders can only reach the curated set of re-exports at the crate root plus `options` and `vfs`. Update every dependent test, benchmark, and doc link to go through the new re-export paths, drop the unused `rekey_into_writer` stub that the narrower surface no longer needs, and mark the deep-walk report structs `#[non_exhaustive]` now that they're the only public window into recovery findings. Integration tests that relied on internal access no longer compile as a separate crate, so they move into `#[cfg(test)] mod tests` submodules alongside the code they exercise; the remaining `tests/` files are updated to use the public API only.
1 parent 758afbd commit 97bcc32

87 files changed

Lines changed: 546 additions & 561 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.config/nextest.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,16 @@ test-threads = "num-cpus"
1515
filter = """
1616
binary(crash_basic)
1717
| binary(recovery_basic)
18-
| binary(rekey_basic)
1918
| binary(fsck_deep)
2019
| binary(durability)
21-
| binary(snapshot_basic)
2220
| binary(compaction_basic)
2321
| binary(compaction_incremental)
2422
| binary(deferred_free_reclaim)
2523
| binary(reader_stall_policy)
2624
| (binary(pagedb) & (
2725
test(/crash/) | test(/recover/) | test(/rekey/)
2826
| test(/anchor/) | test(/torn/) | test(/journal/) | test(/replay/)
27+
| test(/snapshot/) | test(/metadata_errors/)
2928
))
3029
"""
3130
test-group = "serial"

benchmarks/engine-comparison/btree.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,10 @@ use fluxbench::prelude::*;
2121
use fluxbench::{bench, compare, synthetic, verify};
2222
use tokio::sync::Mutex as AsyncMutex;
2323

24-
use pagedb::crypto::CipherId;
25-
use pagedb::options::{OpenOptions, RetainPolicy};
2624
use pagedb::vfs::Vfs;
2725
use pagedb::vfs::memory::MemVfs;
2826
use pagedb::vfs::tokio_backend::TokioVfs;
29-
use pagedb::{Db, RealmId};
27+
use pagedb::{CipherId, Db, OpenOptions, RealmId, RetainPolicy};
3028

3129
const PAGE: usize = 4096;
3230
/// Working-set size: number of keys preloaded for read benches and the

src/btree/internal.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -125,19 +125,6 @@ impl Internal {
125125
Ok(())
126126
}
127127

128-
/// Descend selection: returns the child `page_id` covering `key`.
129-
#[must_use]
130-
pub fn child_for(&self, key: &[u8]) -> u64 {
131-
// Binary search for the rightmost entry where entry.key <= key.
132-
// Using partition_point: find the first index where entry.key > key.
133-
let pos = self.entries.partition_point(|e| e.key.as_slice() <= key);
134-
if pos == 0 {
135-
self.leftmost_child
136-
} else {
137-
self.entries[pos - 1].right_child
138-
}
139-
}
140-
141128
#[must_use]
142129
pub fn fits(&self, page_size: usize) -> bool {
143130
let cap = body_capacity(page_size);
@@ -222,8 +209,9 @@ impl<'a> InternalAccessor<'a> {
222209
read_u64_le(self.body, off + 2 + key_len)
223210
}
224211

225-
/// Descend selection: returns the child `page_id` covering `query`. Matches
226-
/// the semantics of [`Internal::child_for`] but operates on borrowed bytes.
212+
/// Descend selection: returns the child `page_id` covering `query`. Reads
213+
/// the slot directory in place, so descending a spine never materializes
214+
/// the node's keys.
227215
#[must_use]
228216
pub fn child_for(&self, query: &[u8]) -> u64 {
229217
// Rightmost index where entry.key <= query. Use partition_point logic

src/btree/leaf.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,6 @@ impl<'a> LeafAccessor<'a> {
301301
})
302302
}
303303

304-
#[must_use]
305-
pub fn slot_count(&self) -> usize {
306-
self.slot_count
307-
}
308-
309304
fn prefix(&self) -> &'a [u8] {
310305
&self.body[HEADER_LEN..HEADER_LEN + self.prefix_len]
311306
}
@@ -361,23 +356,22 @@ impl<'a> LeafAccessor<'a> {
361356

362357
/// Decode the value at slot `idx`. Inline values borrow from the page body;
363358
/// overflow values return only the chain root + total length.
364-
pub fn value_at(&self, idx: usize) -> Result<LeafValueRef<'a>> {
359+
#[must_use]
360+
pub fn value_at(&self, idx: usize) -> LeafValueRef<'a> {
365361
let off = slot_offset(self.body, self.prefix_len, idx);
366362
let suffix_len = read_u16_le(self.body, off) as usize;
367363
let after_key = off + 2 + suffix_len;
368364
let value_len_raw = read_u16_le(self.body, after_key);
369365
if value_len_raw == OVERFLOW_SENTINEL {
370366
let total_len = read_u64_le(self.body, after_key + 2);
371367
let root_page_id = read_u64_le(self.body, after_key + 2 + 8);
372-
Ok(LeafValueRef::Overflow {
368+
LeafValueRef::Overflow {
373369
total_len,
374370
root_page_id,
375-
})
371+
}
376372
} else {
377373
let vlen = value_len_raw as usize;
378-
Ok(LeafValueRef::Inline(
379-
&self.body[after_key + 2..after_key + 2 + vlen],
380-
))
374+
LeafValueRef::Inline(&self.body[after_key + 2..after_key + 2 + vlen])
381375
}
382376
}
383377
}

src/btree/mod.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
//! `CoW` B+ tree (Layer 3a): sorted `bytes→bytes` table over the Pager.
22
3-
pub mod internal;
4-
pub mod leaf;
5-
pub mod node;
6-
pub mod overflow;
7-
pub mod scan;
8-
pub mod split;
9-
pub mod tree;
3+
pub(crate) mod internal;
4+
pub(crate) mod leaf;
5+
pub(crate) mod node;
6+
pub(crate) mod overflow;
7+
pub(crate) mod scan;
8+
pub(crate) mod split;
9+
#[cfg(test)]
10+
mod tests;
11+
pub(crate) mod tree;
1012

13+
// `pub` here is crate-scoped in effect: the `btree` module itself is
14+
// `pub(crate)`, so this does not escape the crate.
1115
pub use tree::BTree;

src/btree/overflow.rs

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
//! `next` pointer (page id, 0 = end of chain) followed by raw data bytes.
55
//!
66
//! - Root page (`PageKind::OverflowRoot`): `refcount[4] || next[8] || data_len[4] || data`.
7-
//! The `refcount: u32` enables shared chains — `increment_ref` CoW-copies the
8-
//! root with `refcount + 1`; `release` CoW-copies it with `refcount - 1` and,
9-
//! when it reaches 0, frees the entire chain.
7+
//! `release` CoW-copies the root with `refcount - 1` and, when it reaches 0,
8+
//! frees the entire chain. Snapshot lifetime does not rely on the count:
9+
//! copy-on-write leaves that still name a chain are protected because commit
10+
//! tags every freed page and reclamation waits until no retained root or live
11+
//! reader can reach it. Nothing in this crate raises a count above 1, so the
12+
//! decrement branch only fires for a root written by some other producer.
1013
//! - Chain page (`PageKind::Overflow`): `next[8] || data_len[4] || data`.
1114
//!
1215
//! The two layouts differ only in the root's 4-byte `refcount` prefix, so the
@@ -218,37 +221,11 @@ pub async fn write_chain<V: Vfs>(
218221
Ok(page_ids[0])
219222
}
220223

221-
/// Increment the reference count of an overflow root page. Writes a new `CoW`
222-
/// copy of the root at `new_page_id` with `refcount + 1`. The caller is
223-
/// responsible for allocating `new_page_id` and freeing the old root page when
224-
/// appropriate.
225-
///
226-
/// Returns the new root page id (`new_page_id`).
227-
pub async fn increment_ref<V: Vfs>(
228-
pager: &Pager<V>,
229-
realm_id: RealmId,
230-
root_page_id: u64,
231-
new_page_id: u64,
232-
) -> Result<u64> {
233-
let page_size = pager.page_size();
234-
let info = read_root_page(pager, realm_id, root_page_id).await?;
235-
let new_refcount = info
236-
.refcount
237-
.checked_add(1)
238-
.ok_or_else(|| PagedbError::Io(std::io::Error::other("overflow refcount overflow")))?;
239-
let mut body = vec![0u8; page_size - ENVELOPE_OVERHEAD];
240-
encode_overflow_root(&mut body, new_refcount, info.next, &info.root_data)?;
241-
pager
242-
.write_main_page(new_page_id, realm_id, PageKind::OverflowRoot, &body)
243-
.await?;
244-
Ok(new_page_id)
245-
}
246-
247224
/// The result of a `release` call.
248225
pub enum ReleaseResult {
249-
/// Refcount decremented; new root page written at `new_root_page_id`.
250-
/// The caller must free `old_root_page_id`.
251-
Decremented { new_root_page_id: u64 },
226+
/// Refcount decremented; the decremented root was written to the caller's
227+
/// `new_page_id`. The caller must free the old root page.
228+
Decremented,
252229
/// Refcount reached 0; all chain pages are listed in `freed_pages`
253230
/// (including the original root). The caller must free them all.
254231
Freed { freed_pages: Vec<u64> },
@@ -297,9 +274,7 @@ pub async fn release<V: Vfs>(
297274
pager
298275
.write_main_page(new_page_id, realm_id, PageKind::OverflowRoot, &body)
299276
.await?;
300-
Ok(ReleaseResult::Decremented {
301-
new_root_page_id: new_page_id,
302-
})
277+
Ok(ReleaseResult::Decremented)
303278
}
304279

305280
/// Read a value's overflow chain via the Pager. Follows `next` pointers until 0.
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ use std::sync::Arc;
22
use std::sync::mpsc;
33
use std::time::Duration;
44

5-
use pagedb::btree::BTree;
6-
use pagedb::btree::internal::{Internal, InternalEntry};
7-
use pagedb::btree::leaf::{Leaf, LeafValue};
8-
use pagedb::btree::node::body_capacity;
9-
use pagedb::btree::overflow::encode_overflow;
10-
use pagedb::crypto::CipherId;
11-
use pagedb::crypto::kdf::derive_mk;
12-
use pagedb::errors::CorruptionDetail;
13-
use pagedb::pager::{PageKind, Pager, PagerConfig};
14-
use pagedb::vfs::memory::MemVfs;
15-
use pagedb::{PagedbError, RealmId};
5+
use crate::btree::BTree;
6+
use crate::btree::internal::{Internal, InternalEntry};
7+
use crate::btree::leaf::{Leaf, LeafValue};
8+
use crate::btree::node::body_capacity;
9+
use crate::btree::overflow::encode_overflow;
10+
use crate::crypto::CipherId;
11+
use crate::crypto::kdf::derive_mk;
12+
use crate::errors::CorruptionDetail;
13+
use crate::pager::{PageKind, Pager, PagerConfig};
14+
use crate::vfs::memory::MemVfs;
15+
use crate::{PagedbError, RealmId};
1616

1717
const PAGE: usize = 4096;
1818

@@ -377,7 +377,7 @@ async fn read_node_rejects_authenticated_envelope_body_kind_mismatch() {
377377
/// the body was structurally validated at parse time.
378378
#[tokio::test(flavor = "current_thread")]
379379
async fn malformed_node_body_reports_corruption_instead_of_panicking() {
380-
use pagedb::btree::node::{HEADER_LEN, NodeKind, write_header, write_slot_offset};
380+
use crate::btree::node::{HEADER_LEN, NodeKind, write_header, write_slot_offset};
381381

382382
let capacity = body_capacity(PAGE);
383383

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
//! out-of-bounds index. A `proptest` failure here is the panic being reported
1515
//! with the smallest input that still triggers it.
1616
17-
use pagedb::btree::internal::{Internal, InternalEntry};
18-
use pagedb::btree::leaf::{Leaf, LeafValue};
19-
use pagedb::btree::node::{
17+
use crate::btree::internal::{Internal, InternalEntry};
18+
use crate::btree::leaf::{Leaf, LeafValue};
19+
use crate::btree::node::{
2020
HEADER_LEN, NodeKind, OFF_PREFIX_LEN, OFF_SLOT_COUNT, body_capacity, validate_node_body,
2121
};
2222
use proptest::prelude::*;

tests/generated_overflow_chains.rs renamed to src/btree/tests/generated_overflow_chains.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ use std::sync::mpsc;
1616
use std::sync::{Arc, Mutex};
1717
use std::time::Duration;
1818

19-
use pagedb::RealmId;
20-
use pagedb::btree::overflow::{
19+
use crate::RealmId;
20+
use crate::btree::overflow::{
2121
OVERFLOW_ROOT_HEADER_LEN, collect_chain, decode_overflow, encode_overflow,
2222
overflow_page_capacity, overflow_root_capacity, read_chain, read_root_page,
2323
};
24-
use pagedb::crypto::CipherId;
25-
use pagedb::crypto::kdf::derive_mk;
26-
use pagedb::pager::format::data_page::ENVELOPE_OVERHEAD;
27-
use pagedb::pager::{PageKind, Pager, PagerConfig};
28-
use pagedb::vfs::memory::MemVfs;
24+
use crate::crypto::CipherId;
25+
use crate::crypto::kdf::derive_mk;
26+
use crate::pager::format::data_page::ENVELOPE_OVERHEAD;
27+
use crate::pager::{PageKind, Pager, PagerConfig};
28+
use crate::vfs::memory::MemVfs;
2929
use proptest::prelude::*;
3030
use proptest::test_runner::{TestCaseResult, TestRunner};
3131

tests/generated_structural_walks.rs renamed to src/btree/tests/generated_structural_walks.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ use std::sync::mpsc;
1717
use std::sync::{Arc, Mutex};
1818
use std::time::Duration;
1919

20-
use pagedb::RealmId;
21-
use pagedb::btree::BTree;
22-
use pagedb::btree::internal::{Internal, InternalEntry};
23-
use pagedb::btree::leaf::{Leaf, LeafValue};
24-
use pagedb::btree::node::body_capacity;
25-
use pagedb::crypto::CipherId;
26-
use pagedb::crypto::kdf::derive_mk;
27-
use pagedb::pager::{PageKind, Pager, PagerConfig};
28-
use pagedb::vfs::memory::MemVfs;
20+
use crate::RealmId;
21+
use crate::btree::BTree;
22+
use crate::btree::internal::{Internal, InternalEntry};
23+
use crate::btree::leaf::{Leaf, LeafValue};
24+
use crate::btree::node::body_capacity;
25+
use crate::crypto::CipherId;
26+
use crate::crypto::kdf::derive_mk;
27+
use crate::pager::{PageKind, Pager, PagerConfig};
28+
use crate::vfs::memory::MemVfs;
2929
use proptest::prelude::*;
3030
use proptest::test_runner::{TestCaseResult, TestRunner};
3131

0 commit comments

Comments
 (0)