Skip to content

Commit f9d2a4c

Browse files
committed
Lazy parsing
First attempt at an implementation of lazy parsing todo: * file-based layout * iterator access Basic file-based deferred parsing Remove changes to Container class Read eagerly by default Read iteration upon Iteration::open Expose to frontend and add some tests Use Builder Pattern for Series
1 parent def88c3 commit f9d2a4c

14 files changed

Lines changed: 470 additions & 141 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ set(CORE_SOURCE
348348
src/Record.cpp
349349
src/RecordComponent.cpp
350350
src/Series.cpp
351+
src/SeriesBuilder.cpp
351352
src/version.cpp
352353
src/WriteIterations.cpp
353354
src/auxiliary/Date.cpp

include/openPMD/Iteration.hpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
#pragma once
2222

23+
#include "openPMD/auxiliary/Option.hpp"
2324
#include "openPMD/auxiliary/Variant.hpp"
2425
#include "openPMD/backend/Attributable.hpp"
2526
#include "openPMD/backend/Container.hpp"
@@ -31,6 +32,11 @@
3132

3233
namespace openPMD
3334
{
35+
namespace traits
36+
{
37+
struct AccessIteration;
38+
}
39+
3440
/** @brief Logical compilation of data from one snapshot (e.g. a single simulation cycle).
3541
*
3642
* @see https://github.com/openPMD/openPMD-standard/blob/latest/STANDARD.md#required-attributes-for-the-basepath
@@ -46,6 +52,7 @@ class Iteration : public LegacyAttributable
4652
friend class SeriesImpl;
4753
friend class WriteIterations;
4854
friend class SeriesIterator;
55+
friend struct traits::AccessIteration;
4956

5057
public:
5158
Iteration( Iteration const & ) = default;
@@ -153,10 +160,21 @@ class Iteration : public LegacyAttributable
153160
private:
154161
Iteration();
155162

163+
struct DeferredRead
164+
{
165+
std::string index;
166+
bool fileBased = false;
167+
std::string filename;
168+
};
169+
156170
void flushFileBased(std::string const&, uint64_t);
157171
void flushGroupBased(uint64_t);
158172
void flush();
173+
void deferRead( DeferredRead );
159174
void read();
175+
void readFileBased( std::string filePath, std::string const & groupPath );
176+
void readGroupBased( std::string const & groupPath );
177+
void read_impl( std::string const & groupPath );
160178

161179
/**
162180
* @brief Whether an iteration has been closed yet.
@@ -194,6 +212,10 @@ class Iteration : public LegacyAttributable
194212
std::shared_ptr< StepStatus > m_stepStatus =
195213
std::make_shared< StepStatus >( StepStatus::NoStep );
196214

215+
std::shared_ptr< auxiliary::Option< DeferredRead > > m_deferredRead =
216+
std::make_shared< auxiliary::Option< DeferredRead > >(
217+
auxiliary::Option< DeferredRead >() );
218+
197219
/**
198220
* @brief Begin an IO step on the IO file (or file-like object)
199221
* containing this iteration. In case of group-based iteration
@@ -252,11 +274,33 @@ class Iteration : public LegacyAttributable
252274
* @param w The Writable representing the parent.
253275
*/
254276
virtual void linkHierarchy(Writable& w);
277+
278+
void accessLazily()
279+
{
280+
if( IOHandler()->m_frontendAccess == Access::CREATE )
281+
{
282+
return;
283+
}
284+
auto oldAccess = IOHandler()->m_frontendAccess;
285+
auto newAccess =
286+
const_cast< Access * >( &IOHandler()->m_frontendAccess );
287+
*newAccess = Access::READ_WRITE;
288+
try
289+
{
290+
read();
291+
}
292+
catch( ... )
293+
{
294+
*newAccess = oldAccess;
295+
throw;
296+
}
297+
*newAccess = oldAccess;
298+
}
255299
}; // Iteration
256300

257-
extern template
258-
float
259-
Iteration::time< float >() const;
301+
using Iterations_t = Container< Iteration, uint64_t >;
302+
303+
extern template float Iteration::time< float >() const;
260304

261305
extern template
262306
double

include/openPMD/Series.hpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class SeriesData : public AttributableData
6969
friend class openPMD::SeriesImpl;
7070
friend class openPMD::Iteration;
7171
friend class openPMD::Series;
72+
friend class SeriesInternal;
7273

7374
public:
7475
explicit SeriesData() = default;
@@ -81,7 +82,7 @@ class SeriesData : public AttributableData
8182

8283
virtual ~SeriesData() = default;
8384

84-
Container< Iteration, uint64_t > iterations{};
85+
Iterations_t iterations{};
8586

8687
OPENPMD_private :
8788
auxiliary::Option< WriteIterations > m_writeIterations;
@@ -99,6 +100,7 @@ OPENPMD_private :
99100
* one among both flags.
100101
*/
101102
StepStatus m_stepStatus = StepStatus::NoStep;
103+
bool m_parseLazily = false;
102104
}; // SeriesData
103105

104106
class SeriesInternal;
@@ -312,8 +314,7 @@ class SeriesImpl : public AttributableImpl
312314
static constexpr char const * const BASEPATH = "/data/%T/";
313315

314316
struct ParsedInput;
315-
using iterations_t = decltype(internal::SeriesData::iterations);
316-
using iterations_iterator = iterations_t::iterator;
317+
using iterations_iterator = Iterations_t::iterator;
317318

318319
internal::SeriesData * m_series;
319320

@@ -337,6 +338,7 @@ class SeriesImpl : public AttributableImpl
337338
void flushMeshesPath();
338339
void flushParticlesPath();
339340
void readFileBased( );
341+
void readOneIterationFileBased( std::string const & filePath );
340342
/**
341343
* Note on re-parsing of a Series:
342344
* If init == false, the parsing process will seek for new
@@ -347,7 +349,6 @@ class SeriesImpl : public AttributableImpl
347349
*/
348350
void readGroupBased( bool init = true );
349351
void readBase();
350-
void read();
351352
std::string iterationFilename( uint64_t i );
352353
void openIteration( uint64_t index, Iteration iteration );
353354

@@ -393,13 +394,15 @@ class SeriesInternal : public SeriesData, public SeriesImpl
393394
std::string const & filepath,
394395
Access at,
395396
MPI_Comm comm,
396-
std::string const & options = "{}" );
397+
std::string const & options = "{}",
398+
bool parseLazily = false );
397399
#endif
398400

399401
SeriesInternal(
400402
std::string const & filepath,
401403
Access at,
402-
std::string const & options = "{}" );
404+
std::string const & options = "{}",
405+
bool parseLazily = false );
403406
// @todo make AttributableImpl<>::linkHierarchy non-virtual
404407
virtual ~SeriesInternal();
405408
};
@@ -423,17 +426,22 @@ class Series : public SeriesImpl
423426
std::string const & filepath,
424427
Access at,
425428
MPI_Comm comm,
426-
std::string const & options = "{}" );
429+
std::string const & options = "{}",
430+
bool parseLazily = false );
427431
#endif
428432

433+
/*
434+
* @todo Think it's time for a SeriesBuilder.
435+
*/
429436
Series(
430437
std::string const & filepath,
431438
Access at,
432-
std::string const & options = "{}" );
439+
std::string const & options = "{}",
440+
bool parseLazily = false );
433441

434442
virtual ~Series() = default;
435443

436-
Container< Iteration, uint64_t > iterations;
444+
Iterations_t iterations;
437445

438446
/**
439447
* @brief Entry point to the reading end of the streaming API.

include/openPMD/SeriesBuilder.hpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* Copyright 2017-2021 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+
22+
#pragma once
23+
24+
#include "openPMD/Series.hpp"
25+
26+
#include "openPMD/auxiliary/Option.hpp"
27+
#include "openPMD/config.hpp"
28+
29+
#if openPMD_HAVE_MPI
30+
31+
#include <mpi.h>
32+
33+
#endif
34+
35+
namespace openPMD
36+
{
37+
class SeriesBuilder
38+
{
39+
private:
40+
std::string m_filePath;
41+
std::string m_jsonOptions = "{}";
42+
Access m_access =
43+
Access::READ_ONLY; // use the most careful one for a default
44+
bool m_parseLazily = false;
45+
#if openPMD_HAVE_MPI
46+
auxiliary::Option< MPI_Comm > m_comm;
47+
#endif
48+
49+
public:
50+
explicit SeriesBuilder() = default;
51+
52+
Series build();
53+
54+
operator Series();
55+
56+
SeriesBuilder & filePath( std::string );
57+
SeriesBuilder & options( std::string );
58+
SeriesBuilder & access( Access );
59+
SeriesBuilder & parseEagerly();
60+
SeriesBuilder & parseLazily();
61+
#if openPMD_HAVE_MPI
62+
SeriesBuilder & comm( MPI_Comm );
63+
#endif
64+
};
65+
}

include/openPMD/WriteIterations.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,19 @@ class WriteIterations : private Container< Iteration, uint64_t >
4949
friend class Series;
5050

5151
private:
52-
using iterations_t = Container< Iteration, uint64_t >;
5352
struct SharedResources
5453
{
55-
iterations_t iterations;
54+
Iterations_t iterations;
5655
auxiliary::Option< uint64_t > currentlyOpen;
5756

58-
SharedResources( iterations_t );
57+
SharedResources( Iterations_t );
5958
~SharedResources();
6059
};
6160

62-
using key_type = typename iterations_t::key_type;
63-
using value_type = typename iterations_t::key_type;
64-
WriteIterations( iterations_t );
61+
using key_type = typename Iterations_t::key_type;
62+
// @todo: this is wrong
63+
using value_type = typename Iterations_t::key_type;
64+
WriteIterations( Iterations_t );
6565
explicit WriteIterations() = default;
6666
//! Index of the last opened iteration
6767
std::shared_ptr< SharedResources > shared;

include/openPMD/openPMD.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ namespace openPMD {}
2727
// IWYU pragma: begin_exports
2828
#include "openPMD/Dataset.hpp"
2929
#include "openPMD/Datatype.hpp"
30-
#include "openPMD/IterationEncoding.hpp"
3130
#include "openPMD/Iteration.hpp"
31+
#include "openPMD/IterationEncoding.hpp"
3232
#include "openPMD/Mesh.hpp"
3333
#include "openPMD/ParticlePatches.hpp"
3434
#include "openPMD/ParticleSpecies.hpp"
3535
#include "openPMD/ReadIterations.hpp"
36-
#include "openPMD/RecordComponent.hpp"
3736
#include "openPMD/Record.hpp"
37+
#include "openPMD/RecordComponent.hpp"
3838
#include "openPMD/Series.hpp"
39+
#include "openPMD/SeriesBuilder.hpp"
3940
#include "openPMD/UnitDimension.hpp"
4041
#include "openPMD/WriteIterations.hpp"
4142

src/Iteration.cpp

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "openPMD/backend/Writable.hpp"
2929

3030
#include <exception>
31+
#include <iostream>
3132
#include <tuple>
3233

3334

@@ -145,6 +146,7 @@ Iteration::close( bool _flush )
145146
Iteration &
146147
Iteration::open()
147148
{
149+
accessLazily();
148150
internal::SeriesInternal * s = &retrieveSeries();
149151
// figure out my iteration number
150152
auto begin = s->indexOf( *this );
@@ -291,9 +293,52 @@ Iteration::flush()
291293
}
292294
}
293295

294-
void
295-
Iteration::read()
296+
void Iteration::deferRead( DeferredRead dr )
297+
{
298+
*m_deferredRead = auxiliary::makeOption< DeferredRead >( std::move( dr ) );
299+
}
300+
301+
void Iteration::read()
296302
{
303+
if( !m_deferredRead->has_value() )
304+
{
305+
return;
306+
}
307+
auto const & deferred = m_deferredRead->get();
308+
if( deferred.fileBased )
309+
{
310+
readFileBased( deferred.filename, deferred.index );
311+
}
312+
else
313+
{
314+
readGroupBased( deferred.index );
315+
}
316+
// reset this thing
317+
*m_deferredRead = auxiliary::Option< DeferredRead >();
318+
}
319+
320+
void Iteration::readFileBased(
321+
std::string filePath, std::string const & groupPath )
322+
{
323+
auto & series = retrieveSeries();
324+
325+
series.readOneIterationFileBased( filePath );
326+
327+
read_impl( groupPath );
328+
}
329+
330+
void Iteration::readGroupBased( std::string const & groupPath )
331+
{
332+
333+
read_impl(groupPath );
334+
}
335+
336+
void Iteration::read_impl( std::string const & groupPath )
337+
{
338+
Parameter< Operation::OPEN_PATH > pOpen;
339+
pOpen.path = groupPath;
340+
IOHandler()->enqueue( IOTask( this, pOpen ) );
341+
297342
using DT = Datatype;
298343
Parameter< Operation::READ_ATT > aRead;
299344

@@ -356,7 +401,6 @@ Iteration::read()
356401

357402
if( hasMeshes )
358403
{
359-
Parameter< Operation::OPEN_PATH > pOpen;
360404
pOpen.path = s->meshesPath();
361405
IOHandler()->enqueue(IOTask(&meshes, pOpen));
362406

@@ -416,7 +460,6 @@ Iteration::read()
416460

417461
if( hasParticles )
418462
{
419-
Parameter< Operation::OPEN_PATH > pOpen;
420463
pOpen.path = s->particlesPath();
421464
IOHandler()->enqueue(IOTask(&particles, pOpen));
422465

0 commit comments

Comments
 (0)