File-Space Strategy¶
A written HDF5 file can record how it manages free space: which allocation strategy it uses, whether freed regions are tracked across closes, and the page size used for paged allocation. This page covers FileBuilder::with_file_space_strategy and with_file_space_page_size, which mirror HDF5's H5Pset_file_space_strategy and H5Pset_file_space_page_size, and how the choice interacts with editing and repacking.
Recording a strategy¶
FileBuilder::with_file_space_strategy(strategy, persist, threshold) records the file-space management strategy, whether free space is persisted across closes, and the smallest free section the managers will track. with_file_space_page_size(size) sets the file-space page size used for paged allocation. Both are recorded in the file's superblock extension, so the reference HDF5 C library and a later reopen observe the choice.
use hdf5_pure::{File, FileBuilder, FileSpaceStrategy};
let mut b = FileBuilder::new();
b.create_dataset("keep").with_i32_data(&[1, 2, 3]);
b.with_file_space_strategy(FileSpaceStrategy::Page, false, 1) // strategy, persist, threshold
.with_file_space_page_size(8192);
b.write("out.h5").unwrap();
assert_eq!(
File::open("out.h5").unwrap().file_space_strategy(),
Some(FileSpaceStrategy::Page)
);
Strategy variants¶
The FileSpaceStrategy enum mirrors HDF5's H5F_fspace_strategy_t:
| Variant | HDF5 constant | Behavior |
|---|---|---|
FileSpaceStrategy::FsmAggr |
H5F_FSPACE_STRATEGY_FSM_AGGR |
Free-space managers, aggregators, and the virtual file driver — the HDF5 default. |
FileSpaceStrategy::Page |
H5F_FSPACE_STRATEGY_PAGE |
Paged aggregation backed by free-space managers. |
FileSpaceStrategy::Aggr |
H5F_FSPACE_STRATEGY_AGGR |
Aggregators and the virtual file driver only, no free-space managers. |
FileSpaceStrategy::None |
H5F_FSPACE_STRATEGY_NONE |
No free-space tracking; allocation only ever appends. |
The threshold parameter¶
The threshold argument is the smallest free-space section, in bytes, that the free-space managers will track. Sections below this size are not recorded. The C library's default is 1 (every freed section is eligible for tracking).
Reading the strategy back¶
The strategy lives in a superblock-extension message (a standalone object header the superblock points at), so it survives a reopen. File::file_space_strategy() returns the recorded FileSpaceStrategy, and File::file_space_info() returns the full FileSpaceInfo record (persist flag, threshold, page size, and the free-space manager addresses).
use hdf5_pure::File;
let file = File::open("out.h5").unwrap();
if let Some(info) = file.file_space_info() {
println!("strategy: {:?}", info.strategy);
println!("persist: {}", info.persist);
println!("threshold: {}", info.threshold);
println!("page size: {}", info.page_size);
}
file_space_strategy() (and file_space_info()) return None when the file records no strategy, which is what the C library also writes when the default is left in place.
Persisting free space across sessions¶
Passing persist = true records that freed space should be tracked on disk across closes. A brand-new file has nothing to track, so this only records the intent. When a later EditSession frees a region — for example by deleting a dataset — the freed region is recorded in on-disk free-space-manager blocks (FSHD/FSSE) rather than discarded. Later sessions, both this crate's and the reference C library's, recover and reuse those regions.
File::persisted_free_space() returns the tracked free regions as (address, length) pairs sorted by address, and EditSession::open seeds its free list from them so reuse spans sessions rather than just the open session.
use hdf5_pure::{EditSession, File, FileBuilder, FileSpaceStrategy};
let mut builder = FileBuilder::new();
builder.create_dataset("keep").with_i32_data(&[1, 2, 3]);
builder
.with_file_space_strategy(FileSpaceStrategy::Page, true, 1) // persist = true
.with_file_space_page_size(4096);
builder.write("managed.h5").unwrap();
// Create then delete a dataset; the freed region is recorded on disk.
let mut session = EditSession::open("managed.h5").unwrap();
session.create_dataset("scratch").with_f64_data(&vec![0.0; 4096]);
session.commit().unwrap();
let mut session = EditSession::open("managed.h5").unwrap();
session.delete("scratch");
session.commit().unwrap();
// Later opens can read the persisted free regions.
let file = File::open("managed.h5").unwrap();
let free = file.persisted_free_space();
let total_free: u64 = free.iter().map(|&(_, len)| len).sum();
println!("persisted free regions: {}", free.len());
println!("total persisted free bytes: {total_free}");
Note
persisted_free_space() is empty when the file does not persist free space, and for the streaming backend (which does not load the manager blocks). The addresses are file offsets relative to the base address; reading data is unaffected by the presence or absence of these managers.
When free space is not persisted, an EditSession still reuses space within a single session but does not carry a free list across closes. If churn has left a file with unused gaps and you want to reclaim them outright, repacking rewrites the file compactly.