Skip to content

Commit 230afdd

Browse files
franzpoeschelax3lpre-commit-ci[bot]
authored
Fix append mode double attributes (#1302)
* Add failing test * Allow creating file-based Series with Append mode even if the specified directory does not exist * Add Mpi.hpp with MPI helpers Needed later for checking file presence in parallel situations * Add CHECK_FILE IO task and implement in the backends * Only write top-level attributes when really needed * Enable Series creation in Append mode * Add Windows CI workaround * Windows Workaround: Fallback to Create mode * Avoid MPI mocking, use ifdefs Also use parallel logical or for file existence check * Append mode: test in parallel * Don't alias sendbfr and recvbfr * Undo unused changes * Remove unused Mock_MPI_Comm * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Replace MPI specializations by if constexpr * Try making this constexpr I think that this won't work with every MPI implementation * Link ADIOS2 issue ornladios/ADIOS2#3358 Co-authored-by: Axel Huebl <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 273466e commit 230afdd

20 files changed

+608
-77
lines changed

include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ class ADIOS2IOHandlerImpl
150150
void
151151
createFile(Writable *, Parameter<Operation::CREATE_FILE> const &) override;
152152

153+
void checkFile(Writable *, Parameter<Operation::CHECK_FILE> &) override;
154+
155+
// MPI Collective
156+
bool checkFile(std::string fullFilePath) const;
157+
153158
void
154159
createPath(Writable *, Parameter<Operation::CREATE_PATH> const &) override;
155160

@@ -226,6 +231,9 @@ class ADIOS2IOHandlerImpl
226231

227232
private:
228233
adios2::ADIOS m_ADIOS;
234+
#if openPMD_HAVE_MPI
235+
std::optional<MPI_Comm> m_communicator;
236+
#endif
229237
/*
230238
* If the iteration encoding is variableBased, we default to using the
231239
* 2021_02_09 schema since it allows mutable attributes.
@@ -329,7 +337,7 @@ class ADIOS2IOHandlerImpl
329337
// use m_config
330338
std::optional<std::vector<ParameterizedOperator> > getOperators();
331339

332-
std::string fileSuffix() const;
340+
std::string fileSuffix(bool verbose = true) const;
333341

334342
/*
335343
* We need to give names to IO objects. These names are irrelevant

include/openPMD/IO/ADIOS/CommonADIOS1IOHandler.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class CommonADIOS1IOHandlerImpl : public AbstractIOHandlerImpl
5252
public:
5353
void
5454
createFile(Writable *, Parameter<Operation::CREATE_FILE> const &) override;
55+
void checkFile(Writable *, Parameter<Operation::CHECK_FILE> &) override;
5556
void
5657
createPath(Writable *, Parameter<Operation::CREATE_PATH> const &) override;
5758
void createDataset(

include/openPMD/IO/AbstractIOHandlerImpl.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ class AbstractIOHandlerImpl
5858
deref_dynamic_cast<Parameter<Operation::CREATE_FILE> >(
5959
i.parameter.get()));
6060
break;
61+
case O::CHECK_FILE:
62+
checkFile(
63+
i.writable,
64+
deref_dynamic_cast<Parameter<Operation::CHECK_FILE> >(
65+
i.parameter.get()));
66+
break;
6167
case O::CREATE_PATH:
6268
createPath(
6369
i.writable,
@@ -220,6 +226,17 @@ class AbstractIOHandlerImpl
220226
virtual void
221227
closeFile(Writable *, Parameter<Operation::CLOSE_FILE> const &) = 0;
222228

229+
/**
230+
* Check if the file specified by the parameter is already present on disk.
231+
* The Writable is irrelevant for this method.
232+
* A backend can choose to ignore this task and specify FileExists::DontKnow
233+
* in the out parameter.
234+
* The consequence will be that some top-level attributes might be defined
235+
* a second time when appending to an existing file, because the frontend
236+
* cannot be sure that the file already has these attributes.
237+
*/
238+
virtual void checkFile(Writable *, Parameter<Operation::CHECK_FILE> &) = 0;
239+
223240
/** Advance the file/stream that this writable belongs to.
224241
*
225242
* If the backend is based around usage of IO steps (especially streaming

include/openPMD/IO/HDF5/HDF5IOHandlerImpl.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class HDF5IOHandlerImpl : public AbstractIOHandlerImpl
4343

4444
void
4545
createFile(Writable *, Parameter<Operation::CREATE_FILE> const &) override;
46+
void checkFile(Writable *, Parameter<Operation::CHECK_FILE> &) override;
4647
void
4748
createPath(Writable *, Parameter<Operation::CREATE_PATH> const &) override;
4849
void createDataset(
@@ -92,6 +93,15 @@ class HDF5IOHandlerImpl : public AbstractIOHandlerImpl
9293
hid_t m_H5T_CDOUBLE;
9394
hid_t m_H5T_CLONG_DOUBLE;
9495

96+
protected:
97+
#if openPMD_HAVE_MPI
98+
/*
99+
* Not defined in ParallelHDF5IOHandlerImpl, so we don't have to write
100+
* some methods twice.
101+
*/
102+
std::optional<MPI_Comm> m_communicator;
103+
#endif
104+
95105
private:
96106
json::TracingJSON m_config;
97107
std::string m_chunks = "auto";

include/openPMD/IO/IOTask.hpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ Writable *getWritable(Attributable *);
4444
/** Type of IO operation between logical and persistent data.
4545
*/
4646
OPENPMDAPI_EXPORT_ENUM_CLASS(Operation){
47-
CREATE_FILE, OPEN_FILE, CLOSE_FILE, DELETE_FILE,
47+
CREATE_FILE, CHECK_FILE, OPEN_FILE, CLOSE_FILE,
48+
DELETE_FILE,
4849

4950
CREATE_PATH, CLOSE_PATH, OPEN_PATH, DELETE_PATH,
5051
LIST_PATHS,
@@ -118,6 +119,32 @@ struct OPENPMDAPI_EXPORT Parameter<Operation::CREATE_FILE>
118119
IterationEncoding encoding = IterationEncoding::groupBased;
119120
};
120121

122+
template <>
123+
struct OPENPMDAPI_EXPORT Parameter<Operation::CHECK_FILE>
124+
: public AbstractParameter
125+
{
126+
Parameter() = default;
127+
Parameter(Parameter const &p)
128+
: AbstractParameter(), name(p.name), fileExists(p.fileExists)
129+
{}
130+
131+
std::unique_ptr<AbstractParameter> clone() const override
132+
{
133+
return std::unique_ptr<AbstractParameter>(
134+
new Parameter<Operation::CHECK_FILE>(*this));
135+
}
136+
137+
std::string name = "";
138+
enum class FileExists
139+
{
140+
DontKnow,
141+
Yes,
142+
No
143+
};
144+
std::shared_ptr<FileExists> fileExists =
145+
std::make_shared<FileExists>(FileExists::DontKnow);
146+
};
147+
121148
template <>
122149
struct OPENPMDAPI_EXPORT Parameter<Operation::OPEN_FILE>
123150
: public AbstractParameter

include/openPMD/IO/JSON/JSONIOHandlerImpl.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ class JSONIOHandlerImpl : public AbstractIOHandlerImpl
160160
void
161161
createFile(Writable *, Parameter<Operation::CREATE_FILE> const &) override;
162162

163+
void checkFile(Writable *, Parameter<Operation::CHECK_FILE> &) override;
164+
163165
void
164166
createPath(Writable *, Parameter<Operation::CREATE_PATH> const &) override;
165167

include/openPMD/Series.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ OPENPMD_private
534534
bool hasExpansionPattern(std::string filenameWithExtension);
535535
bool reparseExpansionPattern(std::string filenameWithExtension);
536536
void init(std::shared_ptr<AbstractIOHandler>, std::unique_ptr<ParsedInput>);
537-
void initDefaults(IterationEncoding);
537+
void initDefaults(IterationEncoding, bool initAll = false);
538538
/**
539539
* @brief Internal call for flushing a Series.
540540
*

include/openPMD/auxiliary/Mpi.hpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/* Copyright 2022 Franz Poeschel
2+
*
3+
* This file is part of openPMD-api.
4+
*
5+
* openPMD-api is free software: you can redistribute it and/or modify
6+
* it under the terms of of either the GNU General Public License or
7+
* the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* openPMD-api is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License and the GNU Lesser General Public License
15+
* for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* and the GNU Lesser General Public License along with openPMD-api.
19+
* If not, see <http://www.gnu.org/licenses/>.
20+
*/
21+
#pragma once
22+
23+
#include "openPMD/config.hpp"
24+
25+
#if openPMD_HAVE_MPI
26+
#include <mpi.h>
27+
#endif
28+
29+
#include <type_traits>
30+
31+
namespace openPMD::auxiliary
32+
{
33+
#if openPMD_HAVE_MPI
34+
35+
namespace detail
36+
{
37+
namespace
38+
{
39+
// see https://en.cppreference.com/w/cpp/language/if
40+
template <typename>
41+
inline constexpr bool dependent_false_v = false;
42+
} // namespace
43+
} // namespace detail
44+
45+
namespace
46+
{
47+
template <typename T>
48+
constexpr MPI_Datatype openPMD_MPI_type()
49+
{
50+
using T_decay = std::decay_t<T>;
51+
if constexpr (std::is_same_v<T_decay, char>)
52+
{
53+
return MPI_CHAR;
54+
}
55+
else if constexpr (std::is_same_v<T_decay, unsigned>)
56+
{
57+
return MPI_UNSIGNED;
58+
}
59+
else if constexpr (std::is_same_v<T_decay, unsigned long>)
60+
{
61+
return MPI_UNSIGNED_LONG;
62+
}
63+
else if constexpr (std::is_same_v<T_decay, unsigned long long>)
64+
{
65+
return MPI_UNSIGNED_LONG_LONG;
66+
}
67+
else
68+
{
69+
static_assert(
70+
detail::dependent_false_v<T>,
71+
"openPMD_MPI_type: Unsupported type.");
72+
}
73+
}
74+
} // namespace
75+
76+
#endif
77+
} // namespace openPMD::auxiliary

src/IO/ADIOS/ADIOS1IOHandler.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ std::future<void> ADIOS1IOHandlerImpl::flush()
104104
deref_dynamic_cast<Parameter<Operation::CREATE_FILE> >(
105105
i.parameter.get()));
106106
break;
107+
case O::CHECK_FILE:
108+
checkFile(
109+
i.writable,
110+
deref_dynamic_cast<Parameter<Operation::CHECK_FILE> >(
111+
i.parameter.get()));
112+
break;
107113
case O::CREATE_PATH:
108114
createPath(
109115
i.writable,
@@ -346,6 +352,7 @@ void ADIOS1IOHandler::enqueue(IOTask const &i)
346352
switch (i.operation)
347353
{
348354
case Operation::CREATE_FILE:
355+
case Operation::CHECK_FILE:
349356
case Operation::CREATE_PATH:
350357
case Operation::OPEN_PATH:
351358
case Operation::CREATE_DATASET:

0 commit comments

Comments
 (0)