Skip to content

Commit 9f75045

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 6fa52c8 commit 9f75045

File tree

2 files changed

+185
-29
lines changed

2 files changed

+185
-29
lines changed

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
@@ -6069,9 +6069,46 @@ TEST_CASE("varying_zero_pattern", "[serial]")
60696069
}
60706070
}
60716071

6072+
enum class ParseMode
6073+
{
6074+
/*
6075+
* Conventional workflow. Just parse the whole thing and yield iterations
6076+
* in rising order.
6077+
*/
6078+
NoSteps,
6079+
/*
6080+
* The Series is parsed ahead of time upon opening, but it has steps.
6081+
* Parsing ahead of time is the conventional workflow to support
6082+
* random-access.
6083+
* Reading such a Series with the streaming API is only possible if all
6084+
* steps are in ascending order, otherwise the openPMD-api has no way of
6085+
* associating IO steps with interation indices.
6086+
* Reading such a Series with the Streaming API will become possible with
6087+
* the Linear read mode to be introduced by #1291.
6088+
*/
6089+
AheadOfTimeWithoutSnapshot,
6090+
/*
6091+
* A Series of the BP5 engine is not parsed ahead of time, but step-by-step,
6092+
* giving the openPMD-api a way to associate IO steps with iterations.
6093+
* No snapshot attribute exists, so the fallback mode is chosen:
6094+
* Iterations are returned in ascending order.
6095+
* If an IO step returns an iteration whose index is lower than the
6096+
* last one, it will be skipped.
6097+
* This mode of parsing will be generalized into the Linear read mode with
6098+
* PR #1291.
6099+
*/
6100+
LinearWithoutSnapshot,
6101+
/*
6102+
* Snapshot attribute exists and dictates the iteration index returned by
6103+
* an IO step. Duplicate iterations will be skipped.
6104+
*/
6105+
WithSnapshot
6106+
};
6107+
60726108
void append_mode(
60736109
std::string const &extension,
60746110
bool variableBased,
6111+
ParseMode parseMode,
60756112
std::string jsonConfig = "{}")
60766113
{
60776114

@@ -6179,26 +6216,60 @@ void append_mode(
61796216
}
61806217
{
61816218
Series read(filename, Access::READ_ONLY);
6182-
if (variableBased || extension == "bp5")
6219+
switch (parseMode)
61836220
{
6221+
case ParseMode::NoSteps: {
6222+
unsigned counter = 0;
6223+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 7, 10, 11};
6224+
for (auto const &iteration : read.readIterations())
6225+
{
6226+
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
6227+
++counter;
6228+
}
6229+
REQUIRE(counter == 8);
6230+
}
6231+
break;
6232+
case ParseMode::LinearWithoutSnapshot: {
6233+
unsigned counter = 0;
6234+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 11};
6235+
for (auto const &iteration : read.readIterations())
6236+
{
6237+
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
6238+
++counter;
6239+
}
6240+
REQUIRE(counter == 7);
6241+
}
6242+
break;
6243+
case ParseMode::WithSnapshot: {
61846244
// in variable-based encodings, iterations are not parsed ahead of
61856245
// time but as they go
61866246
unsigned counter = 0;
61876247
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 7, 11};
61886248
for (auto const &iteration : read.readIterations())
61896249
{
6190-
std::cout << "Seeing iteration " << iteration.iterationIndex
6191-
<< " of series " << filename << std::endl;
61926250
REQUIRE(iteration.iterationIndex == iterationOrder[counter]);
61936251
++counter;
61946252
}
61956253
REQUIRE(counter == 8);
61966254
// Cannot do listSeries here because the Series is already drained
61976255
REQUIRE_THROWS_AS(helper::listSeries(read), error::WrongAPIUsage);
61986256
}
6199-
else
6200-
{
6257+
break;
6258+
case ParseMode::AheadOfTimeWithoutSnapshot: {
62016259
REQUIRE(read.iterations.size() == 8);
6260+
unsigned counter = 0;
6261+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 7, 10, 11};
6262+
/*
6263+
* Use conventional read API since streaming API is not possible
6264+
* without Linear read mode.
6265+
* (See also comments inside ParseMode enum).
6266+
*/
6267+
for (auto const &iteration : read.iterations)
6268+
{
6269+
REQUIRE(iteration.first == iterationOrder[counter]);
6270+
++counter;
6271+
}
6272+
REQUIRE(counter == 8);
62026273
/*
62036274
* Roadmap: for now, reading this should work by ignoring the last
62046275
* duplicate iteration.
@@ -6208,6 +6279,8 @@ void append_mode(
62086279
*/
62096280
helper::listSeries(read);
62106281
}
6282+
break;
6283+
}
62116284
}
62126285
#if 100000000 * ADIOS2_VERSION_MAJOR + 1000000 * ADIOS2_VERSION_MINOR + \
62136286
10000 * ADIOS2_VERSION_PATCH + 100 * ADIOS2_VERSION_TWEAK >= \
@@ -6244,16 +6317,47 @@ void append_mode(
62446317
}
62456318
{
62466319
Series read(filename, Access::READ_ONLY);
6247-
// in variable-based encodings, iterations are not parsed ahead of
6248-
// time but as they go
6249-
unsigned counter = 0;
6250-
for (auto const &iteration : read.readIterations())
6320+
switch (parseMode)
62516321
{
6252-
REQUIRE(iteration.iterationIndex == counter);
6253-
++counter;
6322+
case ParseMode::LinearWithoutSnapshot: {
6323+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10};
6324+
unsigned counter = 0;
6325+
for (auto const &iteration : read.readIterations())
6326+
{
6327+
REQUIRE(
6328+
iteration.iterationIndex == iterationOrder[counter]);
6329+
++counter;
6330+
}
6331+
REQUIRE(counter == 6);
6332+
// Cannot do listSeries here because the Series is already
6333+
// drained
6334+
REQUIRE_THROWS_AS(
6335+
helper::listSeries(read), error::WrongAPIUsage);
6336+
}
6337+
break;
6338+
case ParseMode::WithSnapshot: {
6339+
// in variable-based encodings, iterations are not parsed ahead
6340+
// of time but as they go
6341+
unsigned counter = 0;
6342+
uint64_t iterationOrder[] = {0, 1, 2, 3, 4, 10, 7, 5};
6343+
for (auto const &iteration : read.readIterations())
6344+
{
6345+
REQUIRE(
6346+
iteration.iterationIndex == iterationOrder[counter]);
6347+
++counter;
6348+
}
6349+
REQUIRE(counter == 8);
6350+
// Cannot do listSeries here because the Series is already
6351+
// drained
6352+
REQUIRE_THROWS_AS(
6353+
helper::listSeries(read), error::WrongAPIUsage);
6354+
}
6355+
break;
6356+
case ParseMode::NoSteps:
6357+
case ParseMode::AheadOfTimeWithoutSnapshot:
6358+
throw std::runtime_error("Test configured wrong.");
6359+
break;
62546360
}
6255-
REQUIRE(counter == 6);
6256-
helper::listSeries(read);
62576361
}
62586362
}
62596363
#endif
@@ -6263,9 +6367,7 @@ TEST_CASE("append_mode", "[serial]")
62636367
{
62646368
for (auto const &t : testedFileExtensions())
62656369
{
6266-
if (t == "bp" || t == "bp4" || t == "bp5")
6267-
{
6268-
std::string jsonConfigOld = R"END(
6370+
std::string jsonConfigOld = R"END(
62696371
{
62706372
"adios2":
62716373
{
@@ -6276,7 +6378,7 @@ TEST_CASE("append_mode", "[serial]")
62766378
}
62776379
}
62786380
})END";
6279-
std::string jsonConfigNew = R"END(
6381+
std::string jsonConfigNew = R"END(
62806382
{
62816383
"adios2":
62826384
{
@@ -6287,14 +6389,25 @@ TEST_CASE("append_mode", "[serial]")
62876389
}
62886390
}
62896391
})END";
6290-
append_mode(t, false, jsonConfigOld);
6291-
append_mode(t, false, jsonConfigNew);
6292-
append_mode(t, true, jsonConfigOld);
6293-
append_mode(t, true, jsonConfigNew);
6392+
if (t == "bp5")
6393+
{
6394+
append_mode(
6395+
t, false, ParseMode::LinearWithoutSnapshot, jsonConfigOld);
6396+
append_mode(t, false, ParseMode::WithSnapshot, jsonConfigNew);
6397+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigOld);
6398+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigNew);
6399+
}
6400+
else if (t == "bp" || t == "bp4" || t == "bp5")
6401+
{
6402+
append_mode(
6403+
t, false, ParseMode::AheadOfTimeWithoutSnapshot, jsonConfigOld);
6404+
append_mode(t, false, ParseMode::WithSnapshot, jsonConfigNew);
6405+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigOld);
6406+
append_mode(t, true, ParseMode::WithSnapshot, jsonConfigNew);
62946407
}
62956408
else
62966409
{
6297-
append_mode(t, false);
6410+
append_mode(t, false, ParseMode::NoSteps);
62986411
}
62996412
}
63006413
}

0 commit comments

Comments
 (0)