Skip to content

Commit f4b0fca

Browse files
committed
refactor(segment): use the borrowed positional-read helper for metadata
Segment header/footer/index reads only borrow their file handle, so they were hand-rolling the same read-until-complete loop that read_exact_at already implements. Replace them with the read_exact_at_borrowed macro to remove the duplication.
1 parent 0368cd5 commit f4b0fca

3 files changed

Lines changed: 9 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ version, since none exists yet.
2929
- **Cross-platform VFS** — Linux (`io_uring`), Windows (IOCP), macOS/iOS
3030
(Grand Central Dispatch), Android, WASM/OPFS, and WASI backends, plus a
3131
tokio thread-pool fallback and an in-memory backend, with format-bit identity
32-
across targets.
32+
across targets. Backends may complete a positional read or write in several
33+
calls; PageDB finishes the caller's whole buffer before treating authenticated
34+
metadata as present or durable.
3335
- **Snapshots**`snapshot_to`, `restore_from`, and incremental apply, each
3436
authenticated against the exact state its manifest describes. Destinations
3537
must be empty; malformed or incomplete artifacts fail closed.

src/segment/authenticated_metadata.rs

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::pager::format::data_page::{body, extract_page_header_ids, open_data_p
1111
use crate::pager::format::page_kind::PageKind;
1212
use crate::pager::format::segment_footer::{SegmentFooterFields, decode_segment_footer};
1313
use crate::pager::format::structural_header::{SegmentHeaderFields, decode_segment_header};
14-
use crate::vfs::{Vfs, VfsFile, checked_read_progress};
14+
use crate::vfs::{Vfs, VfsFile, read_exact_at_borrowed};
1515

1616
use super::types::{EXTENT_INDEX_ENTRY_LEN, ExtentIndexEntry};
1717
use super::writer::{live_path, staging_path};
@@ -84,24 +84,12 @@ pub(crate) async fn authenticate_segment_metadata<V: Vfs + Clone>(
8484
let master_key = pager.mk_for(meta.mk_epoch, cipher_id)?;
8585
let hk = derive_hk(&master_key)?;
8686
let mut header_bytes = vec![0u8; page_size];
87-
let mut header_offset = 0;
88-
let mut header_remaining = &mut header_bytes[..];
89-
while !header_remaining.is_empty() {
90-
let read = file.read_at(header_offset, header_remaining).await?;
91-
checked_read_progress(&mut header_offset, read, header_remaining.len())?;
92-
header_remaining = header_remaining.split_at_mut(read).1;
93-
}
87+
read_exact_at_borrowed!(file, 0, &mut header_bytes[..])?;
9488
let header = decode_segment_header(&header_bytes, &hk, page_size)?;
9589
validate_header(&header, meta, parent_file_id, page_size)?;
9690

9791
let mut footer_bytes = vec![0u8; page_size];
98-
let mut next_footer_offset = footer_offset;
99-
let mut footer_remaining = &mut footer_bytes[..];
100-
while !footer_remaining.is_empty() {
101-
let read = file.read_at(next_footer_offset, footer_remaining).await?;
102-
checked_read_progress(&mut next_footer_offset, read, footer_remaining.len())?;
103-
footer_remaining = footer_remaining.split_at_mut(read).1;
104-
}
92+
read_exact_at_borrowed!(file, footer_offset, &mut footer_bytes[..])?;
10593
let (footer, manifest) = {
10694
let mut lru = pager.dek_lru().lock();
10795
let cipher = lru.get_or_derive(meta.realm_id, meta.mk_epoch, cipher_id, &master_key)?;
@@ -337,13 +325,7 @@ async fn collect_and_decode_index_page<V: Vfs + Clone>(
337325
.checked_mul(page_size_u64)
338326
.ok_or_else(|| PagedbError::segment_geometry_invalid("index.offset"))?;
339327
let mut page = vec![0u8; context.page_size];
340-
let mut read_offset = offset;
341-
let mut remaining = &mut page[..];
342-
while !remaining.is_empty() {
343-
let read = context.file.read_at(read_offset, remaining).await?;
344-
checked_read_progress(&mut read_offset, read, remaining.len())?;
345-
remaining = remaining.split_at_mut(read).1;
346-
}
328+
read_exact_at_borrowed!(context.file, offset, &mut page[..])?;
347329
let (cipher_id, mk_epoch) = extract_page_header_ids(&page)?;
348330
if cipher_id != context.cipher_id {
349331
return Err(PagedbError::segment_metadata_mismatch(

src/segment/reader.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::pager::Pager;
1414
use crate::pager::format::data_page::{body, extract_page_header_ids, open_data_page};
1515
use crate::pager::format::page_kind::PageKind;
1616
use crate::vfs::types::OpenMode;
17-
use crate::vfs::{Vfs, VfsFile, checked_read_progress};
17+
use crate::vfs::{Vfs, VfsFile, read_exact_at_borrowed};
1818

1919
use super::authenticated_metadata::{
2020
ExtentIndexDecodeContext, authenticate_segment_metadata, decode_extent_index,
@@ -228,13 +228,7 @@ impl<V: Vfs + Clone> SegmentReader<V> {
228228
.checked_mul(page_size)
229229
.ok_or_else(|| PagedbError::arithmetic_overflow("segment page offset"))?;
230230
let mut buf = vec![0u8; self.page_size];
231-
let mut read_offset = offset;
232-
let mut remaining = &mut buf[..];
233-
while !remaining.is_empty() {
234-
let read = self.file.read_at(read_offset, remaining).await?;
235-
checked_read_progress(&mut read_offset, read, remaining.len())?;
236-
remaining = remaining.split_at_mut(read).1;
237-
}
231+
read_exact_at_borrowed!(self.file, offset, &mut buf[..])?;
238232

239233
// Try each segment page kind; AAD binding rejects wrong ones.
240234
let try_kinds = [

0 commit comments

Comments
 (0)