Skip to content

SWMR #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

SWMR #79

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Changelog

## hdf5 unreleased
## hdf5-types unreleased
## hdf5-derive unreleased
## hdf5-sys unreleased
## hdf5-src unreleased

## hdf5 unreleased
- Added support for Single Writer Multiple Readers (SWMR) (breaking change, OpenMode has extra variant)

## hdf5-types v0.10.1
Release date: Mar 19, 2025
- Fixed deref of null ptr in `VarLenAscii`/`VarLenUnicode`
Expand Down
49 changes: 49 additions & 0 deletions hdf5/examples/swmr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#[cfg(feature = "1.10.2")]
use hdf5_metno as hdf5;

#[cfg(feature = "1.10.2")]
fn reader() {
let file = hdf5::File::open_as("swmr.h5", hdf5::OpenMode::ReadSWMR).unwrap();
println!("Reader: Opened file");
let var = file.dataset("foo").unwrap();

for _ in 0..5 {
var.refresh().unwrap();
let shape = var.shape();
println!("Reader: Got shape: {shape:?}");
// If reading one should use the shape directly without
// using the convenience read_2d etc. functions which
// might get confused if the shape is changed during reading
std::thread::sleep(std::time::Duration::from_secs(5));
}
}

fn main() {
#[cfg(not(feature = "1.10.2"))]
println!("This examples requires hdf5 >= 1.10.2 to enable SWMR and set libver_bounds");

#[cfg(feature = "1.10.2")]
{
let file = hdf5::File::with_options()
.with_fapl(|fapl| fapl.libver_v110())
.create("swmr.h5")
.unwrap();

let var = file.new_dataset::<u8>().shape((0.., 5)).create("foo").unwrap();

file.start_swmr().unwrap();
println!("Writer: Wrote file");

let thread = std::thread::spawn(|| reader());

for i in 0..5 {
var.resize((i + 1, 5)).unwrap();
var.write_slice(&[i, i, i, i, i], (i, 0..)).unwrap();
var.flush().unwrap();
println!("Writer: Wrote {i}");
std::thread::sleep(std::time::Duration::from_secs(5));
}

thread.join().unwrap();
}
}
18 changes: 18 additions & 0 deletions hdf5/src/hl/dataset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use hdf5_sys::h5d::{
H5Dcreate2, H5Dcreate_anon, H5Dget_access_plist, H5Dget_create_plist, H5Dget_offset,
H5Dset_extent,
};
#[cfg(feature = "1.10.0")]
use hdf5_sys::h5d::{H5Dflush, H5Drefresh};
use hdf5_sys::h5l::H5Ldelete;
use hdf5_sys::h5p::H5P_DEFAULT;
use hdf5_sys::h5z::H5Z_filter_t;
Expand Down Expand Up @@ -154,6 +156,22 @@ impl Dataset {
pub fn filters(&self) -> Vec<Filter> {
self.dcpl().map_or(Vec::default(), |pl| pl.filters())
}

/// Flush the dataset metadata from the metadata cache to the file
#[cfg(feature = "1.10.0")]
pub fn flush(&self) -> Result<()> {
let id = self.id();
h5call!(H5Dflush(id))?;
Ok(())
}

/// Refresh metadata items assosicated with the dataset
#[cfg(feature = "1.10.0")]
pub fn refresh(&self) -> Result<()> {
let id = self.id();
h5call!(H5Drefresh(id))?;
Ok(())
}
}

pub struct Maybe<T>(Option<T>);
Expand Down
20 changes: 20 additions & 0 deletions hdf5/src/hl/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use hdf5_sys::h5f::{
H5Fget_freespace, H5Fget_intent, H5Fget_obj_count, H5Fget_obj_ids, H5Fopen, H5F_ACC_DEFAULT,
H5F_ACC_EXCL, H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_TRUNC, H5F_SCOPE_LOCAL,
};
#[cfg(feature = "1.10.0")]
use hdf5_sys::h5f::{H5Fstart_swmr_write, H5F_ACC_SWMR_READ};

use crate::hl::plist::{
file_access::{FileAccess, FileAccessBuilder},
Expand All @@ -17,9 +19,13 @@ use crate::internal_prelude::*;

/// File opening mode.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(not(feature = "1.10.0"), non_exhaustive)]
pub enum OpenMode {
/// Open a file as read-only, file must exist.
Read,
/// Open a file as read-only in SWMR mode, file must exist.
#[cfg(feature = "1.10.0")]
ReadSWMR,
/// Open a file as read/write, file must exist.
ReadWrite,
/// Create a file, truncate if exists.
Expand Down Expand Up @@ -178,6 +184,14 @@ impl File {
pub fn fcpl(&self) -> Result<FileCreate> {
self.create_plist()
}

#[cfg(feature = "1.10.0")]
/// Mark this file as ready for opening as SWMR
pub fn start_swmr(&self) -> Result<()> {
let id = self.id();
h5call!(H5Fstart_swmr_write(id))?;
Ok(())
}
}

/// File builder allowing to customize file access/creation property lists.
Expand Down Expand Up @@ -231,9 +245,13 @@ impl FileBuilder {
)?;
let flags = match mode {
OpenMode::Read => H5F_ACC_RDONLY,
#[cfg(feature = "1.10.0")]
OpenMode::ReadSWMR => H5F_ACC_RDONLY | H5F_ACC_SWMR_READ,
OpenMode::ReadWrite => H5F_ACC_RDWR,
OpenMode::Create => H5F_ACC_TRUNC,
OpenMode::CreateExcl | OpenMode::Append => H5F_ACC_EXCL,
#[cfg(not(feature = "1.10.0"))]
_ => unreachable!(),
};
let fname_ptr = filename.as_ptr();
h5lock!({
Expand All @@ -242,6 +260,8 @@ impl FileBuilder {
OpenMode::Read | OpenMode::ReadWrite => {
File::from_id(h5try!(H5Fopen(fname_ptr, flags, fapl.id())))
}
#[cfg(feature = "1.10.0")]
OpenMode::ReadSWMR => File::from_id(h5try!(H5Fopen(fname_ptr, flags, fapl.id()))),
_ => {
let fcpl = self.fcpl.finish()?;
File::from_id(h5try!(H5Fcreate(fname_ptr, flags, fcpl.id(), fapl.id())))
Expand Down
Loading