bblock
bblock wraps bstack allocators to provide
persistent, checksummed blocks. Every allocation carries a 4-byte CRC32 trailer;
verify() tells you at any time whether the stored bytes match the checksum.
Features
- Transparent checksumming — allocate as usual; the 4-byte CRC32 trailer is managed automatically by the safe API.
- Sub-range views —
BBlockView::subview(start, end)lets you operate on a named field of a record; writes still update the full-block checksum. - Cursor-based I/O —
BBlockReaderandBBlockWriterimplementio::Read/io::Write/io::Seekwith the same checksum guarantees. - Allocator-agnostic —
BBlockAllocator<A>works with anyA: BStackAllocator; no concrete allocator is imported by this crate.
Quick start
Add to Cargo.toml:
[]
= "0.1"
= { = ">=0.1.6", = ["alloc", "set"] }
use ;
use BBlockAllocator;
// Open (or create) a bstack file and wrap the allocator.
let stack = open.unwrap;
let alloc = new;
// Allocate a 16-byte block. On disk it occupies 20 bytes (16 + 4 checksum).
let block = alloc.alloc.unwrap;
let view = block.view;
view.write.unwrap;
assert!; // checksum is valid
// Sub-range views update the full-block checksum automatically.
view.subview.write.unwrap;
assert!; // still valid; full block was re-checksummed
// Cursor-based writer.
use Write;
let mut w = block.writer;
w.write_all.unwrap;
assert!;
API overview
| Type | Description |
|---|---|
BBlockAllocator<A> |
Wraps A: BStackAllocator; alloc, realloc, dealloc |
BBlock<'a, A> |
Checksummed block handle; Copy; source of views and cursors |
BBlockView<'a, A> |
Safe read/write window; supports subview |
BBlockReader<'a, A> |
io::Read + io::Seek over the view's data range |
BBlockWriter<'a, A> |
io::Write + io::Seek; recomputes checksum after every write |
CHECKSUM_LENGTH |
4 — the CRC32 trailer size in bytes |
BBlock<'a, A>
BBlockView<'a, A>
Limitations and caveats
This crate detects corruption; it does not repair it.
verify() returning false means the data should not be trusted, but bblock
provides no mechanism to restore a previous good value.
Checksumming is not part of the allocator's recovery strategy.
bstack's crash recovery operates on committed-length metadata, independently
of bblock's checksums. The recovery strategies of different allocators vary.
If you need checksum-based recovery baked into the allocator itself, use an
allocator that natively supports it.
unsafe code, direct bstack writes, and buggy allocators are not covered.
The checksum is maintained only when you write through the safe API
(BBlockView, BBlockWriter). Writing through a raw BStackSlice from
BBlock::into_slice, using bstack directly on the same region, or relying on
a buggy allocator will all produce stale or incorrect checksums.
If the checksum itself is corrupted, verify() cannot help you.
CRC32 catches the vast majority of real-world corruption scenarios, but it is
not a cryptographic guarantee. If both data and checksum are overwritten
consistently (e.g., a device returning all-zeros), verify() may return true
for corrupted data. For applications requiring strong consistency guarantees,
checksums are a useful building block but are not a substitute for write-ahead
logs, copy-on-write, two-phase commit, or other proper recovery strategies.
Avoid double-wrapping small blocks.
Embedding a serialised BBlock reference (16 bytes) inside another BBlock
is valid, but the 4-byte checksum overhead is proportionally significant for
small payloads. Prefer coarser-grained checksumming for small structures.
License
MIT — see LICENSE.