Skip to content

Johnfreeman/file formats refactor#497

Draft
jcfreeman2 wants to merge 24 commits into
developfrom
johnfreeman/file_formats_refactor
Draft

Johnfreeman/file formats refactor#497
jcfreeman2 wants to merge 24 commits into
developfrom
johnfreeman/file_formats_refactor

Conversation

@jcfreeman2

@jcfreeman2 jcfreeman2 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Description

Addresses issue #496

As discussed during my talk at the Dataflow meeting on Wednesday morning (Jul-8-2026), I'm filing a draft PR which (with a couple small exceptions which I'll describe below) is a refactor of dfmodules. The main focus of the refactor has been to separate the file-format-specific parts of HDFDataStore (e.g., constructing hdf5libs' HDF5RawDataFile class directly, or hardwiring in the hdf5 extension to the output filename) from the file-format-agnostic parts (e.g., deciding when to close a file based on the number of bytes written to it).

Note that there are some finishing touches I've left out - e.g., reordering private vs. protected vs. public declarations to adhere to our standards, sticking implementation details in *.hxx files, etc. The logic there is that by not doing that, it's easier to compare the intermediate base class I've created, FileDataStoreImpl, with the original HDFDataStore on the develop branch.

Some of the changes made include:

  • Removing HDF5FileUtils.hpp and its unit tests. #included in HDF5DataStore on the develop branch, it was last touched in 2021 and none of its functions are used.
  • Moving the code in HDF5DataStore which doesn't concern hdf5 specifically into an intermediate base class, FileDataStoreImpl, which other file-format-specific implementations can inherit from. How to do this is described in the comment at the top of FileDataStoreImpl, but you can also see this "in action" by looking at plugins/HDF5DataStore.hpp
  • There's also a "stub" implementation of DataStore, StubDataStore which inherits from FileDataStoreImpl and writes a very simple one line output to a text file when its write function is called for either trigger records or time slices
  • Unit tests for StubDataStore are also added in StubWrite_test; they're basically the HDF5DataStore unit tests with hdf5-specific stuff stripped out, and are de-facto unit tests for DataStoreImpl.

Some of the decisions I made in this Draft PR I imagine (hope) are uncontroversial - getting rid of a no-longer-used header, refactoring the code from HDF5DataStore when it was moved into FileDataStoreImpl to avoid Don't Repeat Yourself, making logically-constant member data declared const, etc.

Others are open to discussion; I'll point some out here:

  • On the develop branch, hdf5libs::HDF5RawDataFile::write for a timeslice can throw a TimeSliceException. However, because I don't want every file-format-specific class to have to supply its own TimeSliceException (which would then need to be supplied as a template parameter to FileDataStoreImpl) I require that the class which satisfies the FileHandleConcept have a boolean telling you if you passed it a duplicate time slice.
  • I removed the section of the FileDataStoreImpl constructor where if the free space safety factor is below 1.1 it gets forced to 1.1. I did so thinking the configuration should tell you straightforwardly what's going on, and if we want to set a lower limit, have that enforced in the configuration or at least get the constructor to throw rather than continuing on with a different value than the one it was given
  • If the output path is invalid, a warning is issued, and only on the start transition (when prepare_for_run is called) is an exception thrown in this case. Curious why we don't just throw from the constructor?
  • I left HDF5Write_test with its original name, though it could be called HDFDataStore_test. Perhaps this raises the question, though, as to whether DataWrite wouldn't be a more accurate name than DataStore?
  • I know we discussed this at Dataflow but forget what answer was converged on - right now the run number is passed to DataStore::finish_with_run but HDFDataStore's implementation on the develop branch (and hence FileDataStoreImpl's implementation on this feature branch) don't use it. Do we want to keep this in the signature? Should we be using it right now?
  • In keeping with how it's done on the develop branch's HDF5DataStore::write function for the time slice - and the spirit of "this is just a refactor" - FileDataStoreImpl::write will check for duplicate time slices after determining whether to open a new file. Should this be before?

Also, moving forward, things to think about:

  • Kurt raised questions about if we want to adjust the logic we use for when to open a new file
  • Marco mentioned at Dataflow this week that the model of passing the configuration as a template parameter to the implementation of DataStore may not work long term, and that we'd need to literally just supply the instance of the ConfigurationManager; this is an issue that goes beyond the refactor and indeed beyond DataStore.
  • In FileDataStoreImpl::open_file_if_needed, m_file_handle.reset(); is wrapped in a try-catch block. However by default destructors are noexcept, meaning no throw would ever make it into the catch.

To test, of course, check that this branch builds (it should be done alongside branches of the same name in hdf5libs and trigger, though in the case of trigger we're talking about a one-line change because I switched an argument in hdf5libs from a pointer to a reference).

The latest test build for this branch is DFRFD_DEV_260711_A9, which used commit 84843de915bc51 (Sat Jul 11 10:12:31 2026 -0500).

Type of change

  • Documentation (non-breaking change that adds or improves the documentation)
  • New feature or enhancement (non-breaking change which adds functionality)
  • [X ] Optimization (non-breaking change that improves code/performance)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (whatever its nature)

Testing checklist

  • [X ] Unit tests pass (e.g. dbt-build --unittest)
  • [X ] Minimal system quicktest passes (pytest -s minimal_system_quick_test.py)
  • [X ] Full set of integration tests pass (dunedaq_integtest_bundle.sh)
  • Python tests pass if applicable (e.g. python -m pytest)
  • Pre-commit hooks run successfully if applicable (e.g. pre-commit run --all-files)

Comments here on the testing

Further checks

  • [X ] Code is commented where needed, particularly in hard-to-understand areas
  • [X ] Code style is correct (dbt-build --lint, and/or see https://dune-daq-sw.readthedocs.io/en/latest/packages/styleguide/)
  • [X ] If applicable, new tests have been added or an issue has been opened to tackle that in the future.
    (Indicate issue here: # (issue))

Your Name added 21 commits June 23, 2026 12:51
…compile

I call this a "save-my-work" commit because I've basically done the
bare minimum to abstract out much of the functionality of
HDF5DataStore, but in a frankly sloppy, non-coding-standards-compliant
kind of way (e.g., I'm using protected data members in an intermediate
base class). Still, by committing this, it'll be clearer what
refinements I make moving forward (probably const getters for the
now-only-protected member data, e.g.)
… the less-bad name FileHandleClass, removing commented-out code, replacing std::numeric_limits<size_t>::max() with an explicit "the record is unset" static member
…pace used in both the trigger record and timeslice-writing functions
…index increment scenarios

Prior to this commit, increment_file_index_if_needed only incremented
the file index for reasons related to file size; (identical) logic for
incrementing the file index based on the timelice or trigger number
was implemented after the call to increment_file_index_if_needed in
both write() functions.

Note that resets of various tracking variables occur if the file index
is bumped for size reasons, but not record number reasons. This is
what's in the original code (i.e., this commit is a pure refactor),
but I should check to see if this is actually the logic that we want.
… a template parameter and not hardwired as the HDF5-specific appmodel::DataStoreConf
… own repeat-timeslice exception, put it in DataStoreImpl. Note for this to build you'll need to also build hdf5libs using its johnfreeman/file_formats_refactor branch
…ther than the body of the constructor; this enables logically-constant data to be declared const
…ke a DataStoreImpl-derived data store off of a null configuration
Beyond just the concept of "member data shouldn't directly be part of
a class's interface but should always be private and accessed through
getters", the advantage here is that variables which are non-constant
at the level of DataStoreImpl can be made constant for implementations
of open_new_file - e.g., the run number and the file index have const getters.

As you can see from this commit, this *does* require adding several
getter functions. An alternative would be to have a (very) long
signature to open_new_file.

Note that I didn't use [[nodiscard]] in the getter functions because
the cost of the lowered readability of the source code doesn't seem
worth protection against a fairly implausible scenario that a
developer would call a function called "get_XXXXX()" and then not do
anything with the return value.
…f a low-level class needed for writing data in a DataStoreImpl-derived class (e.g., HDF5RawDataFile from hdf5libs)
Rather than writing out a full trigger record or time slice to an HDF5
file, this will just write out
TriggerRecord #
or
TimeSlice #
to a text file. The real point of this is to test the DataStoreImpl
intermediate base class (soon to be renamed FileDataStoreImpl, btw).

Two things to think about moving forward:
* Some of the tests in HDF5Write_test may have been rendered redundant
* I should update the code to flexibly handle the extension; currently
  the text file also has the extension "hdf5"
…plementors of its derived class to deal with file opening flags
…tension to use be hdf5 and make it the passed-as-template-parameter file object's responsibility to define the extension
…ption of the DataStore interface into closer alignment with its current reality
@jcfreeman2 jcfreeman2 linked an issue Jul 10, 2026 that may be closed by this pull request
Your Name added 2 commits July 11, 2026 09:54
…unit testing purposes should still throw ERS exceptions
…t DataStore to throw; note this also prodded me to realize that GeneralDataStoreProblem isn't used, so I deleted it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Refactor of DataStore and its implementations

2 participants