Skip to content

Commit bc11b93

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 7fe9548 commit bc11b93

2 files changed

Lines changed: 185 additions & 29 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: 135 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6345,9 +6345,46 @@ 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+
* The Series is parsed ahead of time upon opening, but it has steps.
6357+
* Parsing ahead of time is the conventional workflow to support
6358+
* random-access.
6359+
* Reading such a Series with the streaming API is only possible if all
6360+
* steps are in ascending order, otherwise the openPMD-api has no way of
6361+
* associating IO steps with interation indices.
6362+
* Reading such a Series with the Streaming API will become possible with
6363+
* the Linear read mode to be introduced by #1291.
6364+
*/
6365+
AheadOfTimeWithoutSnapshot,
6366+
/*
6367+
* A Series of the BP5 engine is not parsed ahead of time, but step-by-step,
6368+
* giving the openPMD-api a way to associate IO steps with iterations.
6369+
* No snapshot attribute exists, so the fallback mode is chosen:
6370+
* Iterations are returned in ascending order.
6371+
* If an IO step returns an iteration whose index is lower than the
6372+
* last one, it will be skipped.
6373+
* This mode of parsing will be generalized into the Linear read mode with
6374+
* PR #1291.
6375+
*/
6376+
LinearWithoutSnapshot,
6377+
/*
6378+
* Snapshot attribute exists and dictates the iteration index returned by
6379+
* an IO step. Duplicate iterations will be skipped.
6380+
*/
6381+
WithSnapshot
6382+
};
6383+
63486384
void append_mode(
63496385
std::string const &extension,
63506386
bool variableBased,
6387+
ParseMode parseMode,
63516388
std::string jsonConfig = "{}")
63526389
{
63536390

@@ -6455,26 +6492,60 @@ void append_mode(
64556492
}
64566493
{
64576494
Series read(filename, Access::READ_ONLY);
6458-
if (variableBased || extension == "bp5")
6495+
switch (parseMode)
64596496
{
6497+
case ParseMode::NoSteps: {
6498+
unsigned counter = 0;
6499+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 7, 10, 11};
6500+
for (auto const &iteration : read.readIterations())
6501+
{
6502+
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
6503+
++counter;
6504+
}
6505+
REQUIRE(counter == 8);
6506+
}
6507+
break;
6508+
case ParseMode::LinearWithoutSnapshot: {
6509+
unsigned counter = 0;
6510+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 11};
6511+
for (auto const &iteration : read.readIterations())
6512+
{
6513+
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
6514+
++counter;
6515+
}
6516+
REQUIRE(counter == 7);
6517+
}
6518+
break;
6519+
case ParseMode::WithSnapshot: {
64606520
// in variable-based encodings, iterations are not parsed ahead of
64616521
// time but as they go
64626522
unsigned counter = 0;
64636523
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 7, 11};
64646524
for (auto const &iteration : read.readIterations())
64656525
{
6466-
std::cout << "Seeing iteration " << iteration.iterationIndex
6467-
<< " of series " << filename << std::endl;
64686526
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
64696527
++counter;
64706528
}
64716529
REQUIRE(counter == 8);
64726530
// Cannot do listSeries here because the Series is already drained
64736531
REQUIRE_THROWS_AS(helper::listSeries(read), error::WrongAPIUsage);
64746532
}
6475-
else
6476-
{
6533+
break;
6534+
case ParseMode::AheadOfTimeWithoutSnapshot: {
64776535
REQUIRE(read.iterations.size() == 8);
6536+
unsigned counter = 0;
6537+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 7, 10, 11};
6538+
/*
6539+
* Use conventional read API since streaming API is not possible
6540+
* without Linear read mode.
6541+
* (See also comments inside ParseMode enum).
6542+
*/
6543+
for (auto const &iteration : read.iterations)
6544+
{
6545+
REQUIRE(iteration.first == iterationOrder[counter]);
6546+
++counter;
6547+
}
6548+
REQUIRE(counter == 8);
64786549
/*
64796550
* Roadmap: for now, reading this should work by ignoring the last
64806551
* duplicate iteration.
@@ -6484,6 +6555,8 @@ void append_mode(
64846555
*/
64856556
helper::listSeries(read);
64866557
}
6558+
break;
6559+
}
64876560
}
64886561
#if 100000000 * ADIOS2_VERSION_MAJOR + 1000000 * ADIOS2_VERSION_MINOR + \
64896562
10000 * ADIOS2_VERSION_PATCH + 100 * ADIOS2_VERSION_TWEAK >= \
@@ -6520,16 +6593,47 @@ void append_mode(
65206593
}
65216594
{
65226595
Series read(filename, Access::READ_ONLY);
6523-
// in variable-based encodings, iterations are not parsed ahead of
6524-
// time but as they go
6525-
unsigned counter = 0;
6526-
for (auto const &iteration : read.readIterations())
6596+
switch (parseMode)
65276597
{
6528-
REQUIRE(iteration.iterationIndex == counter);
6529-
++counter;
6598+
case ParseMode::LinearWithoutSnapshot: {
6599+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10};
6600+
unsigned counter = 0;
6601+
for (auto const &iteration : read.readIterations())
6602+
{
6603+
REQUIRE(
6604+
iteration.iterationIndex == iterationOrder[counter]);
6605+
++counter;
6606+
}
6607+
REQUIRE(counter == 6);
6608+
// Cannot do listSeries here because the Series is already
6609+
// drained
6610+
REQUIRE_THROWS_AS(
6611+
helper::listSeries(read), error::WrongAPIUsage);
6612+
}
6613+
break;
6614+
case ParseMode::WithSnapshot: {
6615+
// in variable-based encodings, iterations are not parsed ahead
6616+
// of time but as they go
6617+
unsigned counter = 0;
6618+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 7, 5};
6619+
for (auto const &iteration : read.readIterations())
6620+
{
6621+
REQUIRE(
6622+
iteration.iterationIndex == iterationOrder[counter]);
6623+
++counter;
6624+
}
6625+
REQUIRE(counter == 8);
6626+
// Cannot do listSeries here because the Series is already
6627+
// drained
6628+
REQUIRE_THROWS_AS(
6629+
helper::listSeries(read), error::WrongAPIUsage);
6630+
}
6631+
break;
6632+
case ParseMode::NoSteps:
6633+
case ParseMode::AheadOfTimeWithoutSnapshot:
6634+
throw std::runtime_error("Test configured wrong.");
6635+
break;
65306636
}
6531-
REQUIRE(counter == 6);
6532-
helper::listSeries(read);
65336637
}
65346638
}
65356639
#endif
@@ -6539,9 +6643,7 @@ TEST_CASE("append_mode", "[serial]")
65396643
{
65406644
for (auto const &t : testedFileExtensions())
65416645
{
6542-
if (t == "bp" || t == "bp4" || t == "bp5")
6543-
{
6544-
std::string jsonConfigOld = R"END(
6646+
std::string jsonConfigOld = R"END(
65456647
{
65466648
"adios2":
65476649
{
@@ -6552,7 +6654,7 @@ TEST_CASE("append_mode", "[serial]")
65526654
}
65536655
}
65546656
})END";
6555-
std::string jsonConfigNew = R"END(
6657+
std::string jsonConfigNew = R"END(
65566658
{
65576659
"adios2":
65586660
{
@@ -6563,14 +6665,25 @@ TEST_CASE("append_mode", "[serial]")
65636665
}
65646666
}
65656667
})END";
6566-
append_mode(t, false, jsonConfigOld);
6567-
append_mode(t, false, jsonConfigNew);
6568-
append_mode(t, true, jsonConfigOld);
6569-
append_mode(t, true, jsonConfigNew);
6668+
if (t == "bp5")
6669+
{
6670+
append_mode(
6671+
t, false, ParseMode::LinearWithoutSnapshot, jsonConfigOld);
6672+
append_mode(t, false, ParseMode::WithSnapshot, jsonConfigNew);
6673+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigOld);
6674+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigNew);
6675+
}
6676+
else if (t == "bp" || t == "bp4" || t == "bp5")
6677+
{
6678+
append_mode(
6679+
t, false, ParseMode::AheadOfTimeWithoutSnapshot, jsonConfigOld);
6680+
append_mode(t, false, ParseMode::WithSnapshot, jsonConfigNew);
6681+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigOld);
6682+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigNew);
65706683
}
65716684
else
65726685
{
6573-
append_mode(t, false);
6686+
append_mode(t, false, ParseMode::NoSteps);
65746687
}
65756688
}
65766689
}

0 commit comments

Comments
 (0)