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/config.hpp"
27 
28 #if openPMD_HAVE_MPI
29 #include <mpi.h>
30 #endif
31 
32 #include <future>
33 #include <memory>
34 #include <queue>
35 #include <stdexcept>
36 #include <string>
37 #include <type_traits>
38 
39 namespace openPMD
40 {
45 // do not write `enum class FlushLevel : unsigned char` here since NVHPC
46 // does not compile it correctly
47 enum class FlushLevel
48 {
54  UserFlush,
75 };
76 
77 namespace internal
78 {
84  struct FlushParams
85  {
87  std::string backendConfig = "{}";
88 
89  explicit FlushParams()
90  {}
91  FlushParams(FlushLevel flushLevel_in) : flushLevel(flushLevel_in)
92  {}
93  FlushParams(FlushLevel flushLevel_in, std::string backendConfig_in)
94  : flushLevel(flushLevel_in)
95  , backendConfig{std::move(backendConfig_in)}
96  {}
97  };
98 
99  /*
100  * To be used for reading
101  */
102  FlushParams const defaultFlushParams{};
103 
104  struct ParsedFlushParams;
105 
117  enum class SeriesStatus : unsigned char
118  {
119  Default,
120  Parsing
123  };
127 
128  // @todo put this somewhere else
129  template <typename Functor, typename... Args>
130  auto withRWAccess(SeriesStatus &status, Functor &&functor, Args &&...args)
131  -> decltype(std::forward<Functor>(functor)(std::forward<Args>(args)...))
132  {
133  using Res = decltype(std::forward<Functor>(functor)(
134  std::forward<Args>(args)...));
135  if constexpr (std::is_void_v<Res>)
136  {
137  auto oldStatus = status;
139  try
140  {
141  std::forward<decltype(functor)>(functor)();
142  }
143  catch (...)
144  {
145  status = oldStatus;
146  throw;
147  }
148  status = oldStatus;
149  return;
150  }
151  else
152  {
153  auto oldStatus = status;
155  Res res;
156  try
157  {
158  res = std::forward<decltype(functor)>(functor)();
159  }
160  catch (...)
161  {
162  status = oldStatus;
163  throw;
164  }
165  status = oldStatus;
166  return res;
167  }
168  }
169 } // namespace internal
170 
180 {
181  friend class Series;
182 
183 private:
184  void setIterationEncoding(IterationEncoding encoding)
185  {
186  /*
187  * In file-based iteration encoding, the APPEND mode is handled entirely
188  * by the frontend, the backend should just treat it as CREATE mode
189  */
190  if (encoding == IterationEncoding::fileBased &&
191  m_backendAccess == Access::APPEND)
192  {
193  // do we really want to have those as const members..?
194  *const_cast<Access *>(&m_backendAccess) = Access::CREATE;
195  }
196  }
197 
198 public:
199 #if openPMD_HAVE_MPI
200  AbstractIOHandler(std::string path, Access at, MPI_Comm)
201  : directory{std::move(path)}, m_backendAccess{at}, m_frontendAccess{at}
202  {}
203 #endif
204  AbstractIOHandler(std::string path, Access at)
205  : directory{std::move(path)}, m_backendAccess{at}, m_frontendAccess{at}
206  {}
207  virtual ~AbstractIOHandler() = default;
208 
214  virtual void enqueue(IOTask const &iotask)
215  {
216  m_work.push(iotask);
217  }
218 
224  std::future<void> flush(internal::FlushParams const &);
225 
231  virtual std::future<void> flush(internal::ParsedFlushParams &) = 0;
232 
234  virtual std::string backendName() const = 0;
235 
236  std::string const directory;
237  /*
238  * Originally, the reason for distinguishing these two was that during
239  * parsing in reading access modes, the access type would be temporarily
240  * const_cast'ed to an access type that would support modifying
241  * the openPMD object model. Then, it would be const_cast'ed back to
242  * READ_ONLY, to disable further modifications.
243  * Due to this approach's tendency to cause subtle bugs, and due to its
244  * difficult debugging properties, this was replaced by the SeriesStatus
245  * enum, defined in this file.
246  * The distinction of backendAccess and frontendAccess stays relevant, since
247  * the frontend can use it in order to pretend to the backend that another
248  * access type is being used. This is used by the file-based append mode,
249  * which is entirely implemented by the frontend, which internally uses
250  * the backend in CREATE mode.
251  */
252  Access const m_backendAccess;
253  Access const m_frontendAccess;
255  std::queue<IOTask> m_work;
256 }; // AbstractIOHandler
257 
258 } // namespace openPMD
FlushLevel
Determine what items should be flushed upon Series::flush()
Definition: AbstractIOHandler.hpp:47
Self-contained description of a single IO operation.
Definition: IOTask.hpp:695
Access
File access mode to use during IO.
Definition: Access.hpp:29
Only creates/opens files, nothing more.
virtual void enqueue(IOTask const &iotask)
Add provided task to queue according to FIFO.
Definition: AbstractIOHandler.hpp:214
create new series and truncate existing (files)
SeriesStatus
Some parts of the openPMD object model are read-only when accessing a Series in Access::READ_ONLY mod...
Definition: AbstractIOHandler.hpp:117
Restricted mode, ensures to set up the openPMD hierarchy (as far as defined so far) in the backend...
Implementation for the root level of the openPMD hierarchy.
Definition: Series.hpp:186
Interface for communicating between logical and physically persistent data.
Definition: AbstractIOHandler.hpp:179
Public definitions of openPMD-api.
write new iterations to an existing series without reading
Mutability of objects in the openPMD object model is determined by the open mode (Access enum)...
All objects in the openPMD object model are temporarily mutable to allow inserting newly-parsed data...
Parameters recursively passed through the openPMD hierarchy when flushing.
Definition: AbstractIOHandler.hpp:84
IterationEncoding
Encoding scheme of an Iterations Series&#39;.
Definition: IterationEncoding.hpp:32
Default mode, used when flushes are triggered internally, e.g.
Flush operation that was triggered by user code.
Definition: FlushParametersInternal.hpp:31