Skip to content

Commit 937b313

Browse files
committed
FileStream writes BP5; mode-aware append; block-aware Variable::Start()
FileStream now resolves to BP5 on write, chosen by open mode without querying the filesystem for a version; read and append conform to the existing file. Fix the file/bp engine to conform to the on-disk version on append instead of forcing BP5. Give Variable::Start() the same engine-queried block-selection path as Count(), so SetBlockSelection reports the block's offset correctly. Add BP5 read-while-write coverage (StepsInSitu .BP5 variants) and verify FileStream/BPFile resolve to the expected engine via Engine::Type().
1 parent cee34db commit 937b313

15 files changed

Lines changed: 235 additions & 30 deletions

File tree

bindings/CXX/adios2/cxx/Variable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace adios2
150150
Dims Variable<T>::Start() const \
151151
{ \
152152
helper::CheckForNullptr(m_Variable, "in call to Variable<T>::Start"); \
153-
return m_Variable->m_Start; \
153+
return m_Variable->Start(); \
154154
} \
155155
\
156156
template <> \

bindings/CXX/adios2/cxx/Variable.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,20 @@ class Variable
292292
const size_t step = adios2::EngineCurrentStep) const;
293293

294294
/**
295-
* Inspects current start point
295+
* Returns the start offset of the variable's current selection: the box set
296+
* by SetSelection, or the selected block's global offset after
297+
* SetBlockSelection (queried from the engine; empty for a local-array block,
298+
* which has no global offset). For the variable's overall shape use Shape();
299+
* to enumerate every block use BlocksInfo().
296300
* @return start vector
297301
*/
298302
adios2::Dims Start() const;
299303

300304
/**
301-
* Inspects current count from start
305+
* Returns the count of the variable's current selection: the box set by
306+
* SetSelection, or the selected block's count after SetBlockSelection
307+
* (queried from the engine). For the variable's overall shape use Shape();
308+
* to enumerate every block use BlocksInfo().
302309
* @return count vector
303310
*/
304311
adios2::Dims Count() const;

bindings/CXX/adios2/cxx/VariableNT.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,21 @@ Dims VariableNT::Shape(const size_t step) const
154154
Dims VariableNT::Start() const
155155
{
156156
helper::CheckForNullptr(m_Variable, "in call to VariableNT::Start");
157-
return m_Variable->m_Start;
157+
auto type = m_Variable->m_Type;
158+
#define declare_type(T) \
159+
if (type == helper::GetDataType<T>()) \
160+
{ \
161+
return reinterpret_cast<core::Variable<T> *>(m_Variable)->Start(); \
162+
}
163+
ADIOS2_FOREACH_STDTYPE_1ARG(declare_type)
164+
#undef declare_type
165+
else if (type == DataType::Struct)
166+
{
167+
return reinterpret_cast<core::VariableStruct *>(m_Variable)->m_Start;
168+
}
169+
helper::Throw<std::runtime_error>("bindings::CXX", "VariableNT", "Start",
170+
"invalid data type " + ToString(type));
171+
return Dims();
158172
}
159173

160174
Dims VariableNT::Count() const

bindings/CXX/adios2/cxx/VariableNT.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,20 @@ class VariableNT
153153
adios2::Dims Shape(const size_t step = adios2::EngineCurrentStep) const;
154154

155155
/**
156-
* Inspects current start point
156+
* Returns the start offset of the variable's current selection: the box set
157+
* by SetSelection, or the selected block's global offset after
158+
* SetBlockSelection (queried from the engine; empty for a local-array block,
159+
* which has no global offset). For the variable's overall shape use Shape();
160+
* to enumerate every block use BlocksInfo().
157161
* @return start vector
158162
*/
159163
adios2::Dims Start() const;
160164

161165
/**
162-
* Inspects current count from start
166+
* Returns the count of the variable's current selection: the box set by
167+
* SetSelection, or the selected block's count after SetBlockSelection
168+
* (queried from the engine). For the variable's overall shape use Shape();
169+
* to enumerate every block use BlocksInfo().
163170
* @return count vector
164171
*/
165172
adios2::Dims Count() const;

docs/user_guide/source/components/variable.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,29 @@ Limitations of the ADIOS global array concept
236236
Technically, the content of the individual blocks is kept in the BP format (but not in HDF5 format) and in staging.
237237
If you really, really want to retrieve all the blocks, you need to handle this array as a Local Array and read the
238238
blocks one by one.
239+
240+
Inspecting a Variable's Selection
241+
---------------------------------
242+
243+
A ``Variable``'s current geometry can be read back through its accessors:
244+
245+
- ``Start()`` and ``Count()`` return the start offset and count of the
246+
variable's **current selection**. After ``SetSelection`` they echo the
247+
bounding box that was set; after ``SetBlockSelection`` they report the
248+
selected block's geometry, queried from the engine (``Start()`` is empty for a
249+
Local Array block, which has no global offset).
250+
- ``Shape()`` returns the variable's global shape, queried from the engine,
251+
independent of any selection.
252+
- ``BlocksInfo()`` and ``AllStepsBlocksInfo()`` enumerate the geometry of
253+
**every** block written at a step, for when you need more than the single
254+
currently selected block.
255+
256+
.. code-block:: c++
257+
258+
var.SetBlockSelection(3);
259+
adios2::Dims start = var.Start(); // block 3's offset in the global array
260+
adios2::Dims count = var.Count(); // block 3's size
261+
262+
``Start()`` and ``Count()`` describe the application's current selection, not
263+
engine-installed metadata; use ``Shape()`` for the overall shape and
264+
``BlocksInfo()`` to enumerate all blocks.

source/adios2/core/IO.cpp

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -605,14 +605,31 @@ Engine &IO::Open(const std::string &name, const Mode mode, helper::Comm comm, co
605605
if (engineTypeLC == "filestream")
606606
{
607607
// FileStream streams BP4/BP5 file output only (not DAOS, timeseries,
608-
// etc.). A not-yet-created stream is normal, so BPVersionLocal returns
609-
// '4' for a missing path and the engine waits rather than erroring.
610-
char version = '4';
611-
if (comm.Rank() == 0)
608+
// etc.). The choice is mode-dependent: when writing a new file we
609+
// produce the latest streamable format (BP5) and do not query the
610+
// filesystem for a version (there is nothing to conform to). When
611+
// reading, or appending to, an existing stream we conform to the
612+
// file's version. A not-yet-created stream is normal (a reader may
613+
// open before the writer creates the file): BPVersionLocal reports
614+
// '0' (unknown), and we default to BP5, the format FileStream
615+
// writers produce, so the reader matches rather than guessing BP4.
616+
if (mode_to_use == Mode::Write)
612617
{
613-
version = helper::BPVersionLocal(name);
618+
engineTypeLC = "bp5";
619+
}
620+
else
621+
{
622+
char version = '5';
623+
if (comm.Rank() == 0)
624+
{
625+
char detected = helper::BPVersionLocal(name);
626+
if (detected != '0')
627+
{
628+
version = detected;
629+
}
630+
}
631+
engineTypeLC = std::string("bp") + comm.BroadcastValue(version);
614632
}
615-
engineTypeLC = std::string("bp") + comm.BroadcastValue(version);
616633
}
617634
else if (helper::EndsWith(name, ".h5", false))
618635
{
@@ -626,8 +643,11 @@ Engine &IO::Open(const std::string &name, const Mode mode, helper::Comm comm, co
626643
{
627644
engineTypeLC = "timeseries";
628645
}
629-
else if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess))
646+
else if ((mode_to_use == Mode::Read) || (mode_to_use == Mode::ReadRandomAccess) ||
647+
(mode_to_use == Mode::Append))
630648
{
649+
// Read and Append both conform to the on-disk file's version; only a
650+
// fresh Write (the final else) chooses the latest format outright.
631651
auto it = m_Parameters.find("TarInfo");
632652
if (it != m_Parameters.end())
633653
{
@@ -676,18 +696,30 @@ Engine &IO::Open(const std::string &name, const Mode mode, helper::Comm comm, co
676696
comm.BroadcastVector(selected);
677697
if (selected.empty())
678698
{
679-
// Built identically on every rank from 'name', so all ranks
680-
// throw together without broadcasting the message.
681-
std::string err = "Cannot determine the engine for reading \"" + name +
682-
"\": nothing exists at that location.";
683-
if (mode_to_use == Mode::Read)
699+
// Nothing on disk. Appending to a not-yet-created file creates
700+
// it in the latest format; reading is an error.
701+
if (mode_to_use == Mode::Append)
684702
{
685-
err += " If it is a stream that has not been created yet, select "
686-
"the engine explicitly with IO::SetEngine().";
703+
engineTypeLC = "bp5";
687704
}
688-
helper::Throw<std::runtime_error>("Core", "IO", "Open", err);
705+
else
706+
{
707+
// Built identically on every rank from 'name', so all ranks
708+
// throw together without broadcasting the message.
709+
std::string err = "Cannot determine the engine for reading \"" + name +
710+
"\": nothing exists at that location.";
711+
if (mode_to_use == Mode::Read)
712+
{
713+
err += " If it is a stream that has not been created yet, select "
714+
"the engine explicitly with IO::SetEngine().";
715+
}
716+
helper::Throw<std::runtime_error>("Core", "IO", "Open", err);
717+
}
718+
}
719+
else
720+
{
721+
engineTypeLC.assign(selected.begin(), selected.end());
689722
}
690-
engineTypeLC.assign(selected.begin(), selected.end());
691723
}
692724
}
693725
else

source/adios2/core/Variable.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ namespace core
6161
} \
6262
\
6363
template <> \
64+
Dims Variable<T>::Start() const \
65+
{ \
66+
return DoStart(); \
67+
} \
68+
\
69+
template <> \
6470
Dims Variable<T>::Count() const \
6571
{ \
6672
return DoCount(); \

source/adios2/core/Variable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ class Variable : public VariableBase
104104

105105
T *GetData() const noexcept;
106106

107+
Dims Start() const;
108+
107109
Dims Count() const;
108110

109111
size_t SelectionSize() const;
@@ -124,6 +126,8 @@ class Variable : public VariableBase
124126
std::vector<std::vector<typename Variable<T>::BPInfo>> AllStepsBlocksInfo() const;
125127

126128
private:
129+
Dims DoStart() const;
130+
127131
Dims DoCount() const;
128132

129133
size_t DoSelectionSize() const;

source/adios2/core/Variable.tcc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,80 @@ namespace adios2
1818
namespace core
1919
{
2020

21+
template <class T>
22+
Dims Variable<T>::DoStart() const
23+
{
24+
auto lf_Step = [&]() -> size_t {
25+
auto itStep = std::next(m_AvailableStepBlockIndexOffsets.begin(), m_StepsStart);
26+
if (itStep == m_AvailableStepBlockIndexOffsets.end())
27+
{
28+
auto it = m_AvailableStepBlockIndexOffsets.rbegin();
29+
helper::Throw<std::invalid_argument>(
30+
"Core", "Variable", "DoStart",
31+
"current relative step start for variable " + m_Name +
32+
" is outside the scope of available steps " + std::to_string(it->first - 1) +
33+
" in call to Start");
34+
}
35+
return itStep->first - 1;
36+
};
37+
38+
// A block selection reports the selected block's start, queried from the
39+
// engine (mirrors DoCount()). For a local-array block this is empty.
40+
if (m_Engine != nullptr && m_SelectionType == SelectionType::WriteBlock)
41+
{
42+
auto MVI = m_Engine->MinBlocksInfo(*this, m_StepsStart);
43+
if (MVI)
44+
{
45+
if (m_BlockID >= MVI->BlocksInfo.size())
46+
{
47+
helper::Throw<std::invalid_argument>(
48+
"Core", "Variable", "DoStart",
49+
"blockID " + std::to_string(m_BlockID) +
50+
" from SetBlockSelection is out of bounds for available "
51+
"blocks size " +
52+
std::to_string(MVI->BlocksInfo.size()) + " for variable " + m_Name +
53+
" for step " + std::to_string(m_StepsStart) +
54+
", in call to Variable<T>::Start()");
55+
}
56+
57+
const size_t *StartPtr = (MVI->BlocksInfo)[m_BlockID].Start;
58+
// Local values and local-array blocks have no global start offset
59+
if (MVI->WasLocalValue || StartPtr == nullptr)
60+
{
61+
delete MVI;
62+
return {};
63+
}
64+
Dims D;
65+
D.resize(MVI->Dims);
66+
for (int i = 0; i < MVI->Dims; i++)
67+
{
68+
D[i] = StartPtr[i];
69+
}
70+
delete MVI;
71+
return D;
72+
}
73+
74+
const size_t step = !m_FirstStreamingStep ? m_Engine->CurrentStep() : lf_Step();
75+
76+
const std::vector<typename Variable<T>::BPInfo> blocksInfo =
77+
m_Engine->BlocksInfo<T>(*this, step);
78+
79+
if (m_BlockID >= blocksInfo.size())
80+
{
81+
helper::Throw<std::invalid_argument>(
82+
"Core", "Variable", "DoStart",
83+
"blockID " + std::to_string(m_BlockID) +
84+
" from SetBlockSelection is out of bounds for available "
85+
"blocks size " +
86+
std::to_string(blocksInfo.size()) + " for variable " + m_Name + " for step " +
87+
std::to_string(step) + ", in call to Variable<T>::Start()");
88+
}
89+
90+
return blocksInfo[m_BlockID].Start;
91+
}
92+
return m_Start;
93+
}
94+
2195
template <class T>
2296
Dims Variable<T>::DoCount() const
2397
{

source/adios2/helper/adiosSystem.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,15 @@ bool IsHDF5File(const std::string &name, core::IO &io, helper::Comm &comm,
171171

172172
char BPVersionLocal(const std::string &name) noexcept
173173
{
174+
if (!adios2sys::SystemTools::PathExists(name))
175+
{
176+
// The dataset directory does not exist (yet). We cannot know which
177+
// version a future writer will produce, so report unknown ('0')
178+
// rather than guessing BP4. Callers decide how to handle a
179+
// not-yet-created stream. Only an existing directory that lacks the
180+
// mmd.0 metadata index is genuinely BP4.
181+
return '0';
182+
}
174183
const std::string mmdFileName = name + PathSeparator + "mmd.0";
175184
return adios2sys::SystemTools::PathExists(mmdFileName) ? '5' : '4';
176185
}

0 commit comments

Comments
 (0)