Skip to content

Commit 8dcf776

Browse files
committed
Preview support for Linear read mode without snapshot attribute
Currently only available for BP5 engine, will be generalized into Linear read mode in #1291. If the backend does not support the snapshot attribute, then iterate in ascending order, skipping duplicate and non-linear iteration indices. Not possible if the Series is parsed ahead of time.
1 parent b70af3e commit 8dcf776

2 files changed

Lines changed: 187 additions & 27 deletions

File tree

src/ReadIterations.cpp

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ std::optional<SeriesIterator *> SeriesIterator::nextIterationInStep()
141141
{
142142
using ret_t = std::optional<SeriesIterator *>;
143143

144+
if (m_iterationsInCurrentStep.empty())
145+
{
146+
return ret_t{};
147+
}
144148
m_iterationsInCurrentStep.pop_front();
145149
if (m_iterationsInCurrentStep.empty())
146150
{
@@ -199,16 +203,55 @@ std::optional<SeriesIterator *> SeriesIterator::nextStep()
199203
auto itEnd = series.iterations.end();
200204
if (it == itEnd)
201205
{
202-
*this = end();
203-
return {this};
206+
if (status == AdvanceStatus::RANDOMACCESS ||
207+
status == AdvanceStatus::OVER)
208+
{
209+
*this = end();
210+
return {this};
211+
}
212+
else
213+
{
214+
/*
215+
* Stream still going but there was no iteration found in the
216+
* current IO step?
217+
* Might be a duplicate iteration resulting from appending,
218+
* will skip such iterations and hope to find something in a
219+
* later IO step. No need to finish right now.
220+
*/
221+
m_iterationsInCurrentStep = {};
222+
m_series->advance(AdvanceMode::ENDSTEP);
223+
}
204224
}
205-
++it;
206-
if (it == itEnd)
225+
else
207226
{
208-
*this = end();
209-
return {this};
227+
++it;
228+
229+
if (it == itEnd)
230+
{
231+
if (status == AdvanceStatus::RANDOMACCESS ||
232+
status == AdvanceStatus::OVER)
233+
{
234+
*this = end();
235+
return {this};
236+
}
237+
else
238+
{
239+
/*
240+
* Stream still going but there was no iteration found in
241+
* the current IO step? Might be a duplicate iteration
242+
* resulting from appending, will skip such iterations and
243+
* hope to find something in a later IO step. No need to
244+
* finish right now.
245+
*/
246+
m_iterationsInCurrentStep = {};
247+
m_series->advance(AdvanceMode::ENDSTEP);
248+
}
249+
}
250+
else
251+
{
252+
m_iterationsInCurrentStep = {it->first};
253+
}
210254
}
211-
m_iterationsInCurrentStep = {it->first};
212255
}
213256

214257
if (status == AdvanceStatus::OVER)

test/SerialIOTest.cpp

Lines changed: 137 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6345,9 +6345,48 @@ TEST_CASE("varying_zero_pattern", "[serial]")
63456345
}
63466346
}
63476347

6348+
enum class ParseMode
6349+
{
6350+
/*
6351+
* Conventional workflow. Just parse the whole thing and yield iterations
6352+
* in rising order.
6353+
*/
6354+
NoSteps,
6355+
/*
6356+
* NOTE: This mode is only temporary until the topic-linear-read PR,
6357+
* no longer necessary after that.
6358+
* The Series is parsed ahead of time upon opening, but it has steps.
6359+
* Parsing ahead of time is the conventional workflow to support
6360+
* random-access.
6361+
* Reading such a Series with the streaming API is only possible if all
6362+
* steps are in ascending order, otherwise the openPMD-api has no way of
6363+
* associating IO steps with interation indices.
6364+
* Reading such a Series with the Streaming API will become possible with
6365+
* the Linear read mode to be introduced by #1291.
6366+
*/
6367+
AheadOfTimeWithoutSnapshot,
6368+
/*
6369+
* A Series of the BP5 engine is not parsed ahead of time, but step-by-step,
6370+
* giving the openPMD-api a way to associate IO steps with iterations.
6371+
* No snapshot attribute exists, so the fallback mode is chosen:
6372+
* Iterations are returned in ascending order.
6373+
* If an IO step returns an iteration whose index is lower than the
6374+
* last one, it will be skipped.
6375+
* This mode of parsing will be generalized into the Linear read mode with
6376+
* PR #1291.
6377+
*/
6378+
LinearWithoutSnapshot,
6379+
/*
6380+
* Snapshot attribute exists and dictates the iteration index returned by
6381+
* an IO step. Duplicate iterations will be skipped.
6382+
*/
6383+
WithSnapshot
6384+
};
6385+
63486386
void append_mode(
63496387
std::string const &extension,
63506388
bool variableBased,
6389+
ParseMode parseMode,
63516390
std::string jsonConfig = "{}")
63526391
{
63536392

@@ -6455,8 +6494,31 @@ void append_mode(
64556494
}
64566495
{
64576496
Series read(filename, Access::READ_ONLY);
6458-
if (variableBased || extension == "bp5")
6497+
switch (parseMode)
64596498
{
6499+
case ParseMode::NoSteps: {
6500+
unsigned counter = 0;
6501+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 7, 10, 11};
6502+
for (auto const &iteration : read.readIterations())
6503+
{
6504+
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
6505+
++counter;
6506+
}
6507+
REQUIRE(counter == 8);
6508+
}
6509+
break;
6510+
case ParseMode::LinearWithoutSnapshot: {
6511+
unsigned counter = 0;
6512+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 11};
6513+
for (auto const &iteration : read.readIterations())
6514+
{
6515+
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
6516+
++counter;
6517+
}
6518+
REQUIRE(counter == 7);
6519+
}
6520+
break;
6521+
case ParseMode::WithSnapshot: {
64606522
// in variable-based encodings, iterations are not parsed ahead of
64616523
// time but as they go
64626524
unsigned counter = 0;
@@ -6470,9 +6532,22 @@ void append_mode(
64706532
// Cannot do listSeries here because the Series is already drained
64716533
REQUIRE_THROWS_AS(helper::listSeries(read), error::WrongAPIUsage);
64726534
}
6473-
else
6474-
{
6535+
break;
6536+
case ParseMode::AheadOfTimeWithoutSnapshot: {
64756537
REQUIRE(read.iterations.size() == 8);
6538+
unsigned counter = 0;
6539+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 7, 10, 11};
6540+
/*
6541+
* Use conventional read API since streaming API is not possible
6542+
* without Linear read mode.
6543+
* (See also comments inside ParseMode enum).
6544+
*/
6545+
for (auto const &iteration : read.iterations)
6546+
{
6547+
REQUIRE(iteration.first == iterationOrder[counter]);
6548+
++counter;
6549+
}
6550+
REQUIRE(counter == 8);
64766551
/*
64776552
* Roadmap: for now, reading this should work by ignoring the last
64786553
* duplicate iteration.
@@ -6482,6 +6557,8 @@ void append_mode(
64826557
*/
64836558
helper::listSeries(read);
64846559
}
6560+
break;
6561+
}
64856562
}
64866563
#if 100000000 * ADIOS2_VERSION_MAJOR + 1000000 * ADIOS2_VERSION_MINOR + \
64876564
10000 * ADIOS2_VERSION_PATCH + 100 * ADIOS2_VERSION_TWEAK >= \
@@ -6518,16 +6595,47 @@ void append_mode(
65186595
}
65196596
{
65206597
Series read(filename, Access::READ_ONLY);
6521-
// in variable-based encodings, iterations are not parsed ahead of
6522-
// time but as they go
6523-
unsigned counter = 0;
6524-
for (auto const &iteration : read.readIterations())
6598+
switch (parseMode)
65256599
{
6526-
REQUIRE(iteration.iterationIndex == counter);
6527-
++counter;
6600+
case ParseMode::LinearWithoutSnapshot: {
6601+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10};
6602+
unsigned counter = 0;
6603+
for (auto const &iteration : read.readIterations())
6604+
{
6605+
REQUIRE(
6606+
iteration.iterationIndex == iterationOrder[counter]);
6607+
++counter;
6608+
}
6609+
REQUIRE(counter == 6);
6610+
// Cannot do listSeries here because the Series is already
6611+
// drained
6612+
REQUIRE_THROWS_AS(
6613+
helper::listSeries(read), error::WrongAPIUsage);
6614+
}
6615+
break;
6616+
case ParseMode::WithSnapshot: {
6617+
// in variable-based encodings, iterations are not parsed ahead
6618+
// of time but as they go
6619+
unsigned counter = 0;
6620+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 7, 5};
6621+
for (auto const &iteration : read.readIterations())
6622+
{
6623+
REQUIRE(
6624+
iteration.iterationIndex == iterationOrder[counter]);
6625+
++counter;
6626+
}
6627+
REQUIRE(counter == 8);
6628+
// Cannot do listSeries here because the Series is already
6629+
// drained
6630+
REQUIRE_THROWS_AS(
6631+
helper::listSeries(read), error::WrongAPIUsage);
6632+
}
6633+
break;
6634+
case ParseMode::NoSteps:
6635+
case ParseMode::AheadOfTimeWithoutSnapshot:
6636+
throw std::runtime_error("Test configured wrong.");
6637+
break;
65286638
}
6529-
REQUIRE(counter == 6);
6530-
helper::listSeries(read);
65316639
}
65326640
}
65336641
#endif
@@ -6537,9 +6645,7 @@ TEST_CASE("append_mode", "[serial]")
65376645
{
65386646
for (auto const &t : testedFileExtensions())
65396647
{
6540-
if (t == "bp" || t == "bp4" || t == "bp5")
6541-
{
6542-
std::string jsonConfigOld = R"END(
6648+
std::string jsonConfigOld = R"END(
65436649
{
65446650
"adios2":
65456651
{
@@ -6550,7 +6656,7 @@ TEST_CASE("append_mode", "[serial]")
65506656
}
65516657
}
65526658
})END";
6553-
std::string jsonConfigNew = R"END(
6659+
std::string jsonConfigNew = R"END(
65546660
{
65556661
"adios2":
65566662
{
@@ -6561,14 +6667,25 @@ TEST_CASE("append_mode", "[serial]")
65616667
}
65626668
}
65636669
})END";
6564-
append_mode(t, false, jsonConfigOld);
6565-
append_mode(t, false, jsonConfigNew);
6566-
append_mode(t, true, jsonConfigOld);
6567-
append_mode(t, true, jsonConfigNew);
6670+
if (t == "bp5")
6671+
{
6672+
append_mode(
6673+
t, false, ParseMode::LinearWithoutSnapshot, jsonConfigOld);
6674+
append_mode(t, false, ParseMode::WithSnapshot, jsonConfigNew);
6675+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigOld);
6676+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigNew);
6677+
}
6678+
else if (t == "bp" || t == "bp4" || t == "bp5")
6679+
{
6680+
append_mode(
6681+
t, false, ParseMode::AheadOfTimeWithoutSnapshot, jsonConfigOld);
6682+
append_mode(t, false, ParseMode::WithSnapshot, jsonConfigNew);
6683+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigOld);
6684+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigNew);
65686685
}
65696686
else
65706687
{
6571-
append_mode(t, false);
6688+
append_mode(t, false, ParseMode::NoSteps);
65726689
}
65736690
}
65746691
}

0 commit comments

Comments
 (0)