openPMD-api
AbstractIOHandler.hpp
1 /* Copyright 2017-2025 Fabian Koller, Axel Huebl, 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/IO/Access.hpp"
24 #include "openPMD/IO/Format.hpp"
25 #include "openPMD/IO/IOTask.hpp"
26 #include "openPMD/IterationEncoding.hpp"
27 #include "openPMD/config.hpp"
28 #include "openPMD/version.hpp"
29 
30 #if openPMD_HAVE_MPI
31 #include <mpi.h>
32 #endif
33 
34 #include <future>
35 #include <memory>
36 #include <queue>
37 #include <stdexcept>
38 #include <string>
39 #include <type_traits>
40 
41 namespace openPMD
42 {
43 namespace json
44 {
45  class JsonMatcher;
46 }
47 
52 // do not write `enum class FlushLevel : unsigned char` here since NVHPC
53 // does not compile it correctly
54 enum class FlushLevel
55 {
61  UserFlush,
82 };
83 
84 enum class OpenpmdStandard
85 {
86  v_1_0_0,
87  v_1_0_1,
88  v_1_1_0,
89  v_2_0_0
90 };
91 
92 namespace auxiliary
93 {
94  auto parseStandard(std::string const &) -> OpenpmdStandard;
95  auto formatStandard(OpenpmdStandard) -> char const *;
96 } // namespace auxiliary
97 
98 namespace internal
99 {
105  struct FlushParams
106  {
108  std::string backendConfig = "{}";
109 
110  explicit FlushParams()
111  {}
112  FlushParams(FlushLevel flushLevel_in) : flushLevel(flushLevel_in)
113  {}
114  FlushParams(FlushLevel flushLevel_in, std::string backendConfig_in)
115  : flushLevel(flushLevel_in)
116  , backendConfig{std::move(backendConfig_in)}
117  {}
118  };
119 
120  /*
121  * To be used for reading
122  */
123  FlushParams const defaultFlushParams{};
124 
125  struct ParsedFlushParams;
126 
138  enum class SeriesStatus : unsigned char
139  {
140  Default,
143  Parsing
147  };
148 
149  // @todo put this somewhere else
150  template <typename Functor, typename... Args>
151  auto withRWAccess(SeriesStatus &status, Functor &&functor, Args &&...args)
152  -> decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
153  {
154  using Res = decltype(std::forward<Functor>(functor)(
155  std::forward<Args>(args)...));
156  if constexpr (std::is_void_v<Res>)
157  {
158  auto oldStatus = status;
159  status = internal::SeriesStatus::Parsing;
160  try
161  {
162  std::forward<decltype(functor)>(functor)();
163  }
164  catch (...)
165  {
166  status = oldStatus;
167  throw;
168  }
169  status = oldStatus;
170  return;
171  }
172  else
173  {
174  auto oldStatus = status;
175  status = internal::SeriesStatus::Parsing;
176  Res res;
177  try
178  {
179  res = std::forward<decltype(functor)>(functor)();
180  }
181  catch (...)
182  {
183  status = oldStatus;
184  throw;
185  }
186  status = oldStatus;
187  return res;
188  }
189  }
190 } // namespace internal
191 
192 namespace detail
193 {
194  class ADIOS2File;
195 }
196 
206 {
207  friend class Series;
208  friend class ADIOS2IOHandlerImpl;
209  friend class JSONIOHandlerImpl;
210  friend class HDF5IOHandlerImpl;
211  friend class detail::ADIOS2File;
212 
213 private:
214  void setIterationEncoding(IterationEncoding encoding);
215 
216 protected:
217  // Needs to be a pointer due to include structure, this header is
218  // transitively included in user code, but we don't reexport the JSON
219  // library
220  std::unique_ptr<json::JsonMatcher> jsonMatcher;
221 
222 public:
223 #if openPMD_HAVE_MPI
224  template <typename TracingJSON>
226  std::optional<std::unique_ptr<AbstractIOHandler>> initialize_from,
227  std::string path,
228  Access at,
229  TracingJSON &&jsonConfig,
230  MPI_Comm);
231 #endif
232 
233  template <typename TracingJSON>
235  std::optional<std::unique_ptr<AbstractIOHandler>> initialize_from,
236  std::string path,
237  Access at,
238  TracingJSON &&jsonConfig);
239 
240  AbstractIOHandler(std::optional<std::unique_ptr<AbstractIOHandler>>);
241 
242  virtual ~AbstractIOHandler();
243 
244  AbstractIOHandler(AbstractIOHandler const &) = delete;
245  // std::queue::queue(queue&&) is not noexcept
246  // NOLINTNEXTLINE(performance-noexcept-move-constructor)
247  AbstractIOHandler(AbstractIOHandler &&) noexcept(false);
248 
249  AbstractIOHandler &operator=(AbstractIOHandler const &) = delete;
250  AbstractIOHandler &operator=(AbstractIOHandler &&) noexcept;
251 
257  virtual void enqueue(IOTask const &iotask)
258  {
259  m_work.push(iotask);
260  }
261 
267  std::future<void> flush(internal::FlushParams const &);
268 
274  virtual std::future<void> flush(internal::ParsedFlushParams &) = 0;
275 
277  virtual std::string backendName() const = 0;
278  virtual bool fullSupportForVariableBasedEncoding() const;
279 
280  std::string directory;
281  /*
282  * Originally, the reason for distinguishing these two was that during
283  * parsing in reading access modes, the access type would be temporarily
284  * const_cast'ed to an access type that would support modifying
285  * the openPMD object model. Then, it would be const_cast'ed back to
286  * READ_ONLY, to disable further modifications.
287  * Due to this approach's tendency to cause subtle bugs, and due to its
288  * difficult debugging properties, this was replaced by the SeriesStatus
289  * enum, defined in this file.
290  * The distinction of backendAccess and frontendAccess stays relevant, since
291  * the frontend can use it in order to pretend to the backend that another
292  * access type is being used. This is used by the file-based append mode,
293  * which is entirely implemented by the frontend, which internally uses
294  * the backend in CREATE mode.
295  */
296  Access m_backendAccess;
297  Access m_frontendAccess;
298  std::queue<IOTask> m_work;
299 
300  /**************************************************************************
301  * Since the AbstractIOHandler is linked to every object of the frontend, *
302  * it stores a number of members that are needed by methods traversing *
303  * the object hierarchy. Those members are found below. *
304  **************************************************************************/
305 
313  bool m_lastFlushSuccessful = false;
314  internal::SeriesStatus m_seriesStatus = internal::SeriesStatus::Default;
315  IterationEncoding m_encoding = IterationEncoding::groupBased;
316  OpenpmdStandard m_standard = auxiliary::parseStandard(getStandardDefault());
317  bool m_verify_homogeneous_extents = true;
318 }; // AbstractIOHandler
319 
320 } // namespace openPMD
Definition: ADIOS2IOHandler.hpp:100
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:206
virtual std::future< void > flush(internal::ParsedFlushParams &)=0
Process operations in queue according to FIFO.
std::future< void > flush(internal::FlushParams const &)
Process operations in queue according to FIFO.
Definition: AbstractIOHandler.cpp:106
bool m_lastFlushSuccessful
This is to avoid that the destructor tries flushing again if an error happened.
Definition: AbstractIOHandler.hpp:313
virtual std::string backendName() const =0
The currently used backend.
virtual void enqueue(IOTask const &iotask)
Add provided task to queue according to FIFO.
Definition: AbstractIOHandler.hpp:257
Definition: HDF5IOHandlerImpl.hpp:41
Self-contained description of a single IO operation.
Definition: IOTask.hpp:836
Definition: JSONIOHandlerImpl.hpp:159
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:288
Definition: ADIOS2File.hpp:143
Public definitions of openPMD-api.
Definition: Date.cpp:29
Access
File access mode to use during IO.
Definition: Access.hpp:58
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:55
@ SkeletonOnly
Restricted mode, ensures to set up the openPMD hierarchy (as far as defined so far) in the backend.
@ CreateOrOpenFiles
Only creates/opens files, nothing more.
@ InternalFlush
Default mode, used when flushes are triggered internally, e.g.
@ UserFlush
Flush operation that was triggered by user code.
IterationEncoding
Encoding scheme of an Iterations Series'.
Definition: IterationEncoding.hpp:33
std::string getStandardDefault()
Return the default used version of the openPMD standard (read & write, run-time)
Definition: version.cpp:41
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:106
Definition: FlushParametersInternal.hpp:32