Skip to content
Merged
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
7 changes: 6 additions & 1 deletion include/openPMD/IO/ADIOS/ADIOS1IOHandlerImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ class OPENPMDAPI_EXPORT ADIOS1IOHandlerImpl : public AbstractIOHandlerImpl
m_openWriteFileHandles;
std::unordered_map<std::shared_ptr<std::string>, ADIOS_FILE *>
m_openReadFileHandles;
std::unordered_map<ADIOS_FILE *, std::vector<ADIOS_SELECTION *> >
struct ScheduledRead
{
ADIOS_SELECTION *selection;
std::shared_ptr<void> data; // needed to avoid early freeing
};
std::unordered_map<ADIOS_FILE *, std::vector<ScheduledRead> >
m_scheduledReads;
std::unordered_map<int64_t, std::unordered_map<std::string, Attribute> >
m_attributeWrites;
Expand Down
7 changes: 6 additions & 1 deletion include/openPMD/IO/ADIOS/ParallelADIOS1IOHandlerImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,12 @@ class OPENPMDAPI_EXPORT ParallelADIOS1IOHandlerImpl
m_openWriteFileHandles;
std::unordered_map<std::shared_ptr<std::string>, ADIOS_FILE *>
m_openReadFileHandles;
std::unordered_map<ADIOS_FILE *, std::vector<ADIOS_SELECTION *> >
struct ScheduledRead
{
ADIOS_SELECTION *selection;
std::shared_ptr<void> data; // needed to avoid early freeing
};
std::unordered_map<ADIOS_FILE *, std::vector<ScheduledRead> >
m_scheduledReads;
std::unordered_map<int64_t, std::unordered_map<std::string, Attribute> >
m_attributeWrites;
Expand Down
65 changes: 54 additions & 11 deletions include/openPMD/backend/Attributable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,37 @@ namespace internal
A_MAP m_attributes;
};

enum class SetAttributeMode : char
{
WhileReadingAttributes,
FromPublicAPICall
};

/** Verify values of attributes in the frontend
*
* verify string attributes are not empty (backend restriction, e.g., HDF5)
*/
template <typename T>
inline void attr_value_check(std::string const /* key */, T /* value */)
inline void attr_value_check(
std::string const /* key */, T /* value */, SetAttributeMode)
{}

template <>
inline void attr_value_check(std::string const key, std::string const value)
inline void attr_value_check(
std::string const key, std::string const value, SetAttributeMode mode)
{
if (value.empty())
throw std::runtime_error(
"[setAttribute] Value for string attribute '" + key +
"' must not be empty!");
switch (mode)
{
case SetAttributeMode::FromPublicAPICall:
if (value.empty())
throw std::runtime_error(
"[setAttribute] Value for string attribute '" + key +
"' must not be empty!");
break;
case SetAttributeMode::WhileReadingAttributes:
// no checks while reading
break;
}
}

} // namespace internal
Expand Down Expand Up @@ -267,6 +283,13 @@ class AttributableInterface
void seriesFlush(internal::FlushParams);

void flushAttributes(internal::FlushParams const &);

template <typename T>
bool setAttributeImpl(
std::string const &key, T value, internal::SetAttributeMode);
bool setAttributeImpl(
std::string const &key, char const value[], internal::SetAttributeMode);

enum ReadMode
{
/**
Expand Down Expand Up @@ -431,11 +454,29 @@ class LegacyAttributable : public AttributableInterface
}
};

// TODO explicitly instantiate Attributable::setAttribute for all T in Datatype
template <typename T>
inline bool AttributableInterface::setAttribute(std::string const &key, T value)
{
internal::attr_value_check(key, value);
return setAttributeImpl(
key, std::move(value), internal::SetAttributeMode::FromPublicAPICall);
}

inline bool
Attributable::setAttribute(std::string const &key, char const value[])
{
return setAttributeImpl(
key, value, internal::SetAttributeMode::FromPublicAPICall);
}

// note: we explicitly instantiate Attributable::setAttributeImpl for all T in
// Datatype in Attributable.cpp
template <typename T>
inline bool Attributable::setAttributeImpl(
std::string const &key,
T value,
internal::SetAttributeMode setAttributeMode)
{
internal::attr_value_check(key, value, setAttributeMode);

auto &attri = get();
if (IOHandler() && Access::READ_ONLY == IOHandler()->m_frontendAccess)
Expand Down Expand Up @@ -468,10 +509,12 @@ inline bool AttributableInterface::setAttribute(std::string const &key, T value)
}
}

inline bool
AttributableInterface::setAttribute(std::string const &key, char const value[])
inline bool Attributable::setAttributeImpl(
std::string const &key,
char const value[],
internal::SetAttributeMode setAttributeMode)
{
return this->setAttribute(key, std::string(value));
return this->setAttributeImpl(key, std::string(value), setAttributeMode);
}

template <typename T>
Expand Down
2 changes: 1 addition & 1 deletion src/IO/ADIOS/ADIOS1IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ std::future<void> ADIOS1IOHandlerImpl::flush()
"dataset reading");

for (auto &sel : file.second)
adios_selection_delete(sel);
adios_selection_delete(sel.selection);
}
m_scheduledReads.clear();

Expand Down
4 changes: 2 additions & 2 deletions src/IO/ADIOS/CommonADIOS1IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ void CommonADIOS1IOHandlerImpl::closeFile(
"dataset reading");

for (auto &sel : scheduled->second)
adios_selection_delete(sel);
adios_selection_delete(sel.selection);
m_scheduledReads.erase(scheduled);
}
close(handle_read->second);
Expand Down Expand Up @@ -1083,7 +1083,7 @@ void CommonADIOS1IOHandlerImpl::readDataset(
"[ADIOS1] Internal error: Failed to schedule ADIOS read during dataset "
"reading");

m_scheduledReads[f].push_back(sel);
m_scheduledReads[f].push_back({sel, parameters.data});
}

void CommonADIOS1IOHandlerImpl::readAttribute(
Expand Down
2 changes: 1 addition & 1 deletion src/IO/ADIOS/ParallelADIOS1IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ std::future<void> ParallelADIOS1IOHandlerImpl::flush()
"dataset reading");

for (auto &sel : file.second)
adios_selection_delete(sel);
adios_selection_delete(sel.selection);
}
m_scheduledReads.clear();

Expand Down
68 changes: 48 additions & 20 deletions src/IO/AbstractIOHandlerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,33 @@
#include "openPMD/IO/JSON/JSONIOHandler.hpp"
#include "openPMD/auxiliary/JSON.hpp"

#include <memory>
#include <utility>

namespace openPMD
{

namespace
{
template <typename Backend, bool enabled, typename... Args>
std::shared_ptr<Backend>
constructIOHandler(std::string const &backendName, Args &&...args)
{
if /* constexpr */ (enabled)
{
return std::make_shared<Backend>(std::forward<Args>(args)...);
}
else
{
throw std::runtime_error(
"openPMD-api built without support for "
"backend '" +
backendName + "'.");
}
throw "Unreachable";
}
} // namespace

#if openPMD_HAVE_MPI
template <>
std::shared_ptr<AbstractIOHandler> createIOHandler<nlohmann::json>(
Expand All @@ -44,23 +69,24 @@ std::shared_ptr<AbstractIOHandler> createIOHandler<nlohmann::json>(
switch (format)
{
case Format::HDF5:
return std::make_shared<ParallelHDF5IOHandler>(
path, access, comm, std::move(options));
return constructIOHandler<ParallelHDF5IOHandler, openPMD_HAVE_HDF5>(
"HDF5", path, access, comm, std::move(options));
case Format::ADIOS1:
#if openPMD_HAVE_ADIOS1
return std::make_shared<ParallelADIOS1IOHandler>(path, access, comm);
return constructIOHandler<ParallelADIOS1IOHandler, openPMD_HAVE_ADIOS1>(
"ADIOS1", path, access, comm);
#else
throw std::runtime_error("openPMD-api built without ADIOS1 support");
#endif
case Format::ADIOS2:
return std::make_shared<ADIOS2IOHandler>(
path, access, comm, std::move(options), "bp4");
return constructIOHandler<ADIOS2IOHandler, openPMD_HAVE_ADIOS2>(
"ADIOS2", path, access, comm, std::move(options), "bp4");
case Format::ADIOS2_SST:
return std::make_shared<ADIOS2IOHandler>(
path, access, comm, std::move(options), "sst");
return constructIOHandler<ADIOS2IOHandler, openPMD_HAVE_ADIOS2>(
"ADIOS2", path, access, comm, std::move(options), "sst");
case Format::ADIOS2_SSC:
return std::make_shared<ADIOS2IOHandler>(
path, access, comm, std::move(options), "ssc");
return constructIOHandler<ADIOS2IOHandler, openPMD_HAVE_ADIOS2>(
"ADIOS2", path, access, comm, std::move(options), "ssc");
default:
throw std::runtime_error(
"Unknown file format! Did you specify a file ending?");
Expand All @@ -76,27 +102,29 @@ std::shared_ptr<AbstractIOHandler> createIOHandler<nlohmann::json>(
switch (format)
{
case Format::HDF5:
return std::make_shared<HDF5IOHandler>(
path, access, std::move(options));
return constructIOHandler<HDF5IOHandler, openPMD_HAVE_HDF5>(
"HDF5", path, access, std::move(options));
case Format::ADIOS1:
#if openPMD_HAVE_ADIOS1
return std::make_shared<ADIOS1IOHandler>(path, access);
return constructIOHandler<ADIOS1IOHandler, openPMD_HAVE_ADIOS1>(
"ADIOS1", path, access);
#else
throw std::runtime_error("openPMD-api built without ADIOS1 support");
#endif
#if openPMD_HAVE_ADIOS2
case Format::ADIOS2:
return std::make_shared<ADIOS2IOHandler>(
path, access, std::move(options), "bp4");
return constructIOHandler<ADIOS2IOHandler, openPMD_HAVE_ADIOS2>(
"ADIOS2", path, access, std::move(options), "bp4");
case Format::ADIOS2_SST:
return std::make_shared<ADIOS2IOHandler>(
path, access, std::move(options), "sst");
return constructIOHandler<ADIOS2IOHandler, openPMD_HAVE_ADIOS2>(
"ADIOS2", path, access, std::move(options), "sst");
case Format::ADIOS2_SSC:
return std::make_shared<ADIOS2IOHandler>(
path, access, std::move(options), "ssc");
#endif // openPMD_HAVE_ADIOS2
return constructIOHandler<ADIOS2IOHandler, openPMD_HAVE_ADIOS2>(
"ADIOS2", path, access, std::move(options), "ssc");
#endif
case Format::JSON:
return std::make_shared<JSONIOHandler>(path, access);
return constructIOHandler<JSONIOHandler, openPMD_HAVE_JSON>(
"JSON", path, access);
default:
throw std::runtime_error(
"Unknown file format! Did you specify a file ending?");
Expand Down
Loading