openPMD-api
AbstractIOHandler.hpp
1 /* Copyright 2017-2021 Fabian Koller, Axel Huebl
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 
29 #if openPMD_HAVE_MPI
30 #include <mpi.h>
31 #endif
32 
33 #include <future>
34 #include <memory>
35 #include <queue>
36 #include <stdexcept>
37 #include <string>
38 #include <type_traits>
39 
40 namespace openPMD
41 {
46 // do not write `enum class FlushLevel : unsigned char` here since NVHPC
47 // does not compile it correctly
48 enum class FlushLevel
49 {
55  UserFlush,
76 };
77 
78 namespace internal
79 {
85  struct FlushParams
86  {
88  std::string backendConfig = "{}";
89 
90  explicit FlushParams()
91  {}
92  FlushParams(FlushLevel flushLevel_in) : flushLevel(flushLevel_in)
93  {}
94  FlushParams(FlushLevel flushLevel_in, std::string backendConfig_in)
95  : flushLevel(flushLevel_in)
96  , backendConfig{std::move(backendConfig_in)}
97  {}
98  };
99 
100  /*
101  * To be used for reading
102  */
103  FlushParams const defaultFlushParams{};
104 
105  struct ParsedFlushParams;
106 
118  enum class SeriesStatus : unsigned char
119  {
120  Default,
123  Parsing
127  };
128 
129  // @todo put this somewhere else
130  template <typename Functor, typename... Args>
131  auto withRWAccess(SeriesStatus &status, Functor &&functor, Args &&...args)
132  -> decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
133  {
134  using Res = decltype(std::forward<Functor>(functor)(
135  std::forward<Args>(args)...));
136  if constexpr (std::is_void_v<Res>)
137  {
138  auto oldStatus = status;
140  try
141  {
142  std::forward<decltype(functor)>(functor)();
143  }
144  catch (...)
145  {
146  status = oldStatus;
147  throw;
148  }
149  status = oldStatus;
150  return;
151  }
152  else
153  {
154  auto oldStatus = status;
156  Res res;
157  try
158  {
159  res = std::forward<decltype(functor)>(functor)();
160  }
161  catch (...)
162  {
163  status = oldStatus;
164  throw;
165  }
166  status = oldStatus;
167  return res;
168  }
169  }
170 } // namespace internal
171 
172 namespace detail
173 {
174  class ADIOS2File;
175 }
176 
186 {
187  friend class Series;
188  friend class ADIOS2IOHandlerImpl;
189  friend class detail::ADIOS2File;
190 
191 private:
192  IterationEncoding m_encoding = IterationEncoding::groupBased;
193 
194  void setIterationEncoding(IterationEncoding encoding)
195  {
196  /*
197  * In file-based iteration encoding, the APPEND mode is handled entirely
198  * by the frontend, the backend should just treat it as CREATE mode
199  */
200  if (encoding == IterationEncoding::fileBased &&
201  m_backendAccess == Access::APPEND)
202  {
203  // do we really want to have those as const members..?
204  *const_cast<Access *>(&m_backendAccess) = Access::CREATE;
205  }
206 
207  m_encoding = encoding;
208  }
209 
210 public:
211 #if openPMD_HAVE_MPI
212  AbstractIOHandler(std::string path, Access at, MPI_Comm)
213  : directory{std::move(path)}, m_backendAccess{at}, m_frontendAccess{at}
214  {}
215 #endif
216  AbstractIOHandler(std::string path, Access at)
217  : directory{std::move(path)}, m_backendAccess{at}, m_frontendAccess{at}
218  {}
219  virtual ~AbstractIOHandler() = default;
220 
221  AbstractIOHandler(AbstractIOHandler const &) = default;
222  AbstractIOHandler(AbstractIOHandler &&) = default;
223 
224  AbstractIOHandler &operator=(AbstractIOHandler const &) = default;
225  AbstractIOHandler &operator=(AbstractIOHandler &&) = default;
226 
232  virtual void enqueue(IOTask const &iotask)
233  {
234  m_work.push(iotask);
235  }
236 
242  std::future<void> flush(internal::FlushParams const &);
243 
249  virtual std::future<void> flush(internal::ParsedFlushParams &) = 0;
250 
252  virtual std::string backendName() const = 0;
253 
254  std::string directory;
255  /*
256  * Originally, the reason for distinguishing these two was that during
257  * parsing in reading access modes, the access type would be temporarily
258  * const_cast'ed to an access type that would support modifying
259  * the openPMD object model. Then, it would be const_cast'ed back to
260  * READ_ONLY, to disable further modifications.
261  * Due to this approach's tendency to cause subtle bugs, and due to its
262  * difficult debugging properties, this was replaced by the SeriesStatus
263  * enum, defined in this file.
264  * The distinction of backendAccess and frontendAccess stays relevant, since
265  * the frontend can use it in order to pretend to the backend that another
266  * access type is being used. This is used by the file-based append mode,
267  * which is entirely implemented by the frontend, which internally uses
268  * the backend in CREATE mode.
269  */
270  Access m_backendAccess;
271  Access m_frontendAccess;
273  std::queue<IOTask> m_work;
281  bool m_lastFlushSuccessful = false;
282 }; // AbstractIOHandler
283 
284 } // namespace openPMD
Definition: ADIOS2IOHandler.hpp:94
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:186
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:28
bool m_lastFlushSuccessful
This is to avoid that the destructor tries flushing again if an error happened.
Definition: AbstractIOHandler.hpp:281
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:232
Self-contained description of a single IO operation.
Definition: IOTask.hpp:670
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:219
Definition: ADIOS2File.hpp:137
SeriesStatus
Some parts of the openPMD object model are read-only when accessing a Series in Access::READ_ONLY mod...
Definition: AbstractIOHandler.hpp:119
@ Default
Mutability of objects in the openPMD object model is determined by the open mode (Access enum),...
@ Parsing
All objects in the openPMD object model are temporarily mutable to allow inserting newly-parsed data.
Public definitions of openPMD-api.
Definition: Date.cpp:29
Access
File access mode to use during IO.
Definition: Access.hpp:30
@ CREATE
create new series and truncate existing (files)
@ APPEND
write new iterations to an existing series without reading
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:49
@ 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
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:86
Definition: FlushParametersInternal.hpp:32