Skip to content
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

Add swmr mode #45

Merged
merged 24 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dd148e8
add swmr mode
stephprince Jul 31, 2024
dac45cb
update file access props to allow swmr mode
stephprince Aug 1, 2024
a954b9d
add isRecording flag for swmr mode
stephprince Aug 1, 2024
9355c05
add tests to turn on swmr mode
stephprince Aug 1, 2024
77a5298
add tests for isRecording flag
stephprince Aug 1, 2024
9d7b9b4
update test to create valid files
stephprince Aug 1, 2024
d509ada
Update readme to specify minimum HDF5 version
stephprince Aug 1, 2024
e6997d3
move isRecording to IO class
stephprince Aug 1, 2024
725126d
add stopRecording call to nwb finalize function
stephprince Aug 1, 2024
b071a23
update name of isRecording
stephprince Aug 2, 2024
74a8e7a
update tests
stephprince Aug 5, 2024
fda15bc
Merge branch 'main' into add-swmr-mode
stephprince Aug 5, 2024
7bdda16
add tests for swmr
stephprince Aug 5, 2024
30b404c
convert canModifyObjects to function
stephprince Aug 6, 2024
75c31a9
convert stopRecording to pauseRecording
stephprince Aug 6, 2024
e41258f
fix formatting
stephprince Aug 6, 2024
0408bac
add base class implementation of canModifyObjects
stephprince Aug 6, 2024
2266862
Update src/BaseIO.hpp
oruebel Aug 6, 2024
e47a460
add flush to pauseRecording
stephprince Aug 6, 2024
db3318f
make swmr mode optional
stephprince Aug 7, 2024
6410232
update docstring
stephprince Aug 7, 2024
1d96db0
Merge branch 'main' into add-swmr-mode
oruebel Aug 7, 2024
3a9aa90
Apply suggestions from code review
stephprince Aug 7, 2024
51d4c52
add additional tests and refactor io functions
stephprince Aug 7, 2024
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Below is a high-level overview of the project structure and capabilities we are
# Requirements
* A C++17-compliant compiler
* CMake `>= 3.15`
* HDF5
* HDF5 `>= 1.10`
* Boost
* Additional requirements for building the documentation (optional)
* Doxygen
Expand Down
5 changes: 5 additions & 0 deletions src/BaseIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ bool BaseIO::isReadyToOpen() const
return readyToOpen;
}

bool BaseIO::canModifyObjects()
{
return true;
}

Status BaseIO::createCommonNWBAttributes(const std::string& path,
const std::string& objectNamespace,
const std::string& neurodataType,
Expand Down
21 changes: 21 additions & 0 deletions src/BaseIO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,27 @@ class BaseIO
virtual Status createReferenceDataSet(
const std::string& path, const std::vector<std::string>& references) = 0;

/**
* @brief Starts the recording process.
* @return The status of the operation.
*/
virtual Status startRecording() = 0;
stephprince marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief Stops the recording process.
oruebel marked this conversation as resolved.
Show resolved Hide resolved
* @return The status of the operation.
*/
virtual Status stopRecording() = 0;

/**
* @brief Returns true if the file is in a mode where objects can
* be added or deleted. Note, this does not apply to the modification
* of raw data on already existing objects. Derived classes should
* override this function to check if objects can be modified.
* @return True if the file is in a modification mode, false otherwise.
*/
virtual bool canModifyObjects();

/**
* @brief Creates an extendable dataset with a given base data type, size,
* chunking, and path.
Expand Down
58 changes: 55 additions & 3 deletions src/hdf5/HDF5IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "HDF5IO.hpp"

#include <H5Cpp.h>
#include <H5Fpublic.h>

#include "Utils.hpp"

Expand All @@ -17,8 +18,9 @@ using namespace AQNWB::HDF5;

HDF5IO::HDF5IO() {}

HDF5IO::HDF5IO(const std::string& fileName)
HDF5IO::HDF5IO(const std::string& fileName, const bool disableSWMRMode)
: filename(fileName)
, disableSWMRMode(disableSWMRMode)
{
}

Expand Down Expand Up @@ -48,15 +50,16 @@ Status HDF5IO::open(bool newfile)
if (opened)
return Status::Failure;

FileAccPropList props = FileAccPropList::DEFAULT;
FileAccPropList fapl = FileAccPropList::DEFAULT;
H5Pset_libver_bounds(fapl.getId(), H5F_LIBVER_LATEST, H5F_LIBVER_LATEST);
oruebel marked this conversation as resolved.
Show resolved Hide resolved

if (newfile)
accFlags = H5F_ACC_TRUNC;
else
accFlags = H5F_ACC_RDWR;

file = std::make_unique<H5::H5File>(
getFileName(), accFlags, FileCreatPropList::DEFAULT, props);
getFileName(), accFlags, FileCreatPropList::DEFAULT, fapl);
stephprince marked this conversation as resolved.
Show resolved Hide resolved
opened = true;

return Status::Success;
Expand Down Expand Up @@ -298,6 +301,9 @@ Status HDF5IO::createGroupIfDoesNotExist(const std::string& path)
/** Creates a link to another location in the file */
Status HDF5IO::createLink(const std::string& path, const std::string& reference)
{
if (!opened)
return Status::Failure;

herr_t error = H5Lcreate_soft(reference.c_str(),
file->getLocId(),
path.c_str(),
Expand All @@ -310,6 +316,9 @@ Status HDF5IO::createLink(const std::string& path, const std::string& reference)
Status HDF5IO::createReferenceDataSet(
const std::string& path, const std::vector<std::string>& references)
{
if (!opened)
return Status::Failure;

const hsize_t size = references.size();

hobj_ref_t* rdata = new hobj_ref_t[size * sizeof(hobj_ref_t)];
Expand Down Expand Up @@ -377,6 +386,49 @@ Status HDF5IO::createStringDataSet(const std::string& path,
return Status::Success;
}

Status HDF5IO::startRecording()
{
if (!opened)
return Status::Failure;

if (!disableSWMRMode) {
herr_t status = H5Fstart_swmr_write(this->file->getId());
return checkStatus(status);
}
return Status::Success;
}

Status HDF5IO::stopRecording()
{
// if SWMR mode is disabled, stopping the recording will leave the file open
if (!disableSWMRMode) {
close();
}
stephprince marked this conversation as resolved.
Show resolved Hide resolved
return Status::Success;
}

bool HDF5IO::canModifyObjects()
{
if (!opened)
return false;

// Get the file access intent
unsigned int intent;
herr_t status = H5Fget_intent(this->file->getId(), &intent);
if (status < 0) {
return false; // We could not access the file so modifying objects is not
// going to work
}

// Check if SWMR mode is enabled
if (intent & (H5F_ACC_SWMR_READ | H5F_ACC_SWMR_WRITE)) {
return false; // File is in SWMR mode
} else {
return true; // File is not in SWMR mode
}
return true;
}

stephprince marked this conversation as resolved.
Show resolved Hide resolved
std::unique_ptr<AQNWB::BaseRecordingData> HDF5IO::getDataSet(
const std::string& path)
{
Expand Down
23 changes: 22 additions & 1 deletion src/hdf5/HDF5IO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class HDF5IO : public BaseIO
* @brief Constructor for the HDF5IO class that takes a file name as input.
* @param fileName The name of the HDF5 file.
*/
HDF5IO(const std::string& fileName);
HDF5IO(const std::string& fileName, const bool disableSWMRMode = false);

/**
* @brief Destructor for the HDF5IO class.
Expand Down Expand Up @@ -176,6 +176,26 @@ class HDF5IO : public BaseIO
const std::string& path,
const std::vector<std::string>& references) override;

/**
* @brief Start SWMR write to start recording process
* @return The status of the start recording operation.
*/
Status startRecording() override;

/**
* @brief Stops the recording process.
* @return The status of the stop recording operation.
*/
Status stopRecording() override;

/**
* @brief Checks whether the file is in a mode where objects
* can be added or deleted. Note, this does not apply to the modification
* of raw data on already existing objects.
* @return Whether objects can be modified.
*/
bool canModifyObjects() override;

/**
* @brief Creates an extendable dataset with a given base data type, size,
* chunking, and path.
Expand Down Expand Up @@ -232,6 +252,7 @@ class HDF5IO : public BaseIO

private:
std::unique_ptr<H5::H5File> file;
bool disableSWMRMode;
stephprince marked this conversation as resolved.
Show resolved Hide resolved
};

/**
Expand Down
28 changes: 22 additions & 6 deletions src/nwb/NWBFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,28 @@ NWBFile::NWBFile(const std::string& idText, std::shared_ptr<BaseIO> io)

NWBFile::~NWBFile() {}

void NWBFile::initialize()
Status NWBFile::initialize()
stephprince marked this conversation as resolved.
Show resolved Hide resolved
{
if (std::filesystem::exists(io->getFileName())) {
io->open(false);
return io->open(false);
} else {
io->open(true);
createFileStructure();
return createFileStructure();
}
}

void NWBFile::finalize()
Status NWBFile::finalize()
{
recordingContainers.reset();
io->close();
return io->close();
stephprince marked this conversation as resolved.
Show resolved Hide resolved
oruebel marked this conversation as resolved.
Show resolved Hide resolved
}

Status NWBFile::createFileStructure()
{
if (!io->canModifyObjects()) {
return Status::Failure;
}

io->createCommonNWBAttributes("/", "core", "NWBFile", "");
io->createAttribute(NWBVersion, "/", "nwb_version");

Expand Down Expand Up @@ -82,6 +86,10 @@ Status NWBFile::createElectricalSeries(
std::vector<Types::ChannelVector> recordingArrays,
const BaseDataType& dataType)
{
if (!io->canModifyObjects()) {
return Status::Failure;
}

// store all recorded data in the acquisition group
std::string rootPath = "/acquisition/";

Expand Down Expand Up @@ -128,7 +136,15 @@ Status NWBFile::createElectricalSeries(
return Status::Success;
}

void NWBFile::stopRecording() {}
Status NWBFile::startRecording()
{
return io->startRecording();
}

void NWBFile::stopRecording()
{
io->stopRecording();
}
oruebel marked this conversation as resolved.
Show resolved Hide resolved

void NWBFile::cacheSpecifications(const std::string& specPath,
const std::string& versionNumber)
Expand Down
19 changes: 15 additions & 4 deletions src/nwb/NWBFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,22 @@ class NWBFile
* @brief Initializes the NWB file by opening and setting up the file
* structure.
*/
void initialize();
Status initialize();
stephprince marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief Finalizes the NWB file by closing it.
*/
void finalize();
Status finalize();

/**
* @brief Create ElectricalSeries objects to record data into.
* Created objects are stored in recordingContainers.
* Note, this function will fail if the file is in a mode where
* new objects cannot be added, which can be checked via
* nwbfile.io->canModifyObjects()
* @param recordingArrays vector of ChannelVector indicating the electrodes to
* record from. A separate ElectricalSeries will be
* created for each ChannelVector
* created for each ChannelVector.
* @param dataType The data type of the elements in the data block.
* @return Status The status of the object creation operation.
*/
Expand All @@ -67,7 +70,12 @@ class NWBFile
const BaseDataType& dataType = BaseDataType::I16);

/**
* @brief Closes the relevant datasets.
* @brief Starts the recording.
*/
Status startRecording();

/**
* @brief Stops the recording.
*/
void stopRecording();

Expand Down Expand Up @@ -95,6 +103,9 @@ class NWBFile
protected:
/**
* @brief Creates the default file structure.
* Note, this function will fail if the file is in a mode where
* new objects cannot be added, which can be checked via
* nwbfile.io->canModifyObjects()
* @return Status The status of the file structure creation.
*/
Status createFileStructure();
Expand Down
6 changes: 4 additions & 2 deletions src/nwb/NWBRecording.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ Status NWBRecording::openFile(const std::string& rootFolder,
createIO(IOType, filename));
nwbfile->initialize();

// create the datasets
nwbfile->createElectricalSeries(recordingArrays);

// start the new recording
return nwbfile->createElectricalSeries(recordingArrays);
return nwbfile->startRecording();
stephprince marked this conversation as resolved.
Show resolved Hide resolved
}

void NWBRecording::closeFile()
{
nwbfile->stopRecording();
nwbfile->finalize();
}

Expand Down
10 changes: 10 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ target_compile_features(aq-nwb_test PRIVATE cxx_std_17)

catch_discover_tests(aq-nwb_test)

# ---- Custom Executable ----

add_executable(reader_executable
reader.cpp)
target_link_libraries(
reader_executable PRIVATE
aq-nwb_lib
)
target_compile_features(reader_executable PRIVATE cxx_std_17)

# ---- End-of-file commands ----

add_folders(aq-nwbTests)
Loading
Loading