Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions bindings/CXX/adios2/cxx/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ void Engine::PerformGets()
m_Engine->PerformGets();
}

std::unique_ptr<core::GetContext> Engine::NewGetContext()
{
helper::CheckForNullptr(m_Engine, "in call to Engine::NewGetContext");
return m_Engine->NewGetContext();
}

void Engine::PerformGets(core::GetContext &ctx)
{
helper::CheckForNullptr(m_Engine, "in call to Engine::PerformGets(GetContext&)");
m_Engine->PerformGets(ctx);
}

void Engine::LockWriterDefinitions()
{
helper::CheckForNullptr(m_Engine, "in call to Engine::LockWriterDefinitions");
Expand Down Expand Up @@ -334,6 +346,7 @@ Engine::AllStepsBlocksInfo(const VariableNT &variable) const
template void Engine::Get<T>(const std::string &, std::vector<T> &, const Mode); \
\
template void Engine::Get<T>(Variable<T>, T *, const Selection &, const Mode); \
template void Engine::Get<T>(core::GetContext &, Variable<T>, T *, const Selection &); \
template void Engine::Get<T>(Variable<T>, std::vector<T> &, const Selection &, const Mode); \
\
template void Engine::Get<T>(Variable<T>, typename Variable<T>::Info & info, const Mode); \
Expand Down
10 changes: 10 additions & 0 deletions bindings/CXX/adios2/cxx/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Selection; // for selection-based Get()
namespace core
{
class Engine; // private implementation
class GetContext;

}
/// \endcond
Expand Down Expand Up @@ -448,6 +449,15 @@ class Engine
/** Perform all Get calls in Deferred mode up to this point */
void PerformGets();

// Context-bearing Get / PerformGets — thread-safe pipeline (BP5 reader only).
// Returns nullptr if the engine doesn't support concurrent contexts.
std::unique_ptr<core::GetContext> NewGetContext();

template <class T>
void Get(core::GetContext &ctx, Variable<T> variable, T *data, const Selection &selection);

void PerformGets(core::GetContext &ctx);

/**
* Ends current step, by default calls PerformsPut/Get internally
* For most engines, this is an MPI collective function.
Expand Down
11 changes: 11 additions & 0 deletions bindings/CXX/adios2/cxx/Engine.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,17 @@ void Engine::Get(Variable<T> variable, std::vector<T> &dataV, const Selection &s
selection.GetCoreSelection(), launch);
}

template <class T>
void Engine::Get(core::GetContext &ctx, Variable<T> variable, T *data, const Selection &selection)
{
using IOType = typename TypeInfo<T>::IOType;
adios2::helper::CheckForNullptr(m_Engine, "in call to Engine::Get(GetContext &, ...)");
adios2::helper::CheckForNullptr(variable.m_Variable,
"for variable in call to Engine::Get(GetContext &, ...)");
m_Engine->Get(ctx, *variable.m_Variable, reinterpret_cast<IOType *>(data),
selection.GetCoreSelection());
}

} // end namespace adios2

#endif /* ADIOS2_BINDINGS_CXX_CXX_ENGINE_TCC_ */
5 changes: 5 additions & 0 deletions docs/user_guide/source/components/engine.rst
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,11 @@ PerformGets

Executes all pending ``Get`` calls in deferred mode.

A second overload, ``PerformGets(GetContext&)``, drains only the requests
queued on the supplied context, supporting concurrent ``Get`` pipelines on
a single engine. See `Thread-Safe Concurrent Reads with GetContext`_ in
the Selection chapter.


Engine usage example
--------------------
Expand Down
40 changes: 40 additions & 0 deletions docs/user_guide/source/components/selection.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,46 @@ Selection-based ``Get()`` is currently supported by the **BP5** and **SST**
(with BP5 marshalling) engines. Other engines will throw a runtime error if a
``Selection`` is passed to ``Get()``.

Thread-Safe Concurrent Reads with GetContext
--------------------------------------------

The Selection-based ``Get()`` shown above shares per-engine queue state with
every other ``Get()`` call on the same engine, so concurrent calls from
multiple threads are not safe. A second overload takes an explicit
``GetContext`` so each thread (or each independent reader) can queue and drain
``Get()`` requests on its own:

.. code-block:: c++

auto ctx = engine.NewGetContext();
if (!ctx) {
// Engine does not support concurrent contexts; fall back to the
// single-threaded Selection-based Get above.
}

auto sel = adios2::Selection::BoundingBox({0, 0}, {10, 20}).WithSteps(0, 1);
engine.Get(*ctx, var, data, sel);
engine.PerformGets(*ctx);

Each ``GetContext`` owns its own queue of pending requests, so
``PerformGets(ctxA)`` drains only ``ctxA`` and leaves any requests queued on
``ctxB`` untouched. A context is reusable after ``PerformGets``; the queue is
cleared on the success path. Calls in ctx-form are always deferred — there is
no ``Mode::Sync`` variant.

``NewGetContext()`` is a feature probe: it returns ``nullptr`` if the engine
does not support concurrent contexts. Currently only the **BP5** reader
supports them, and only when:

- the engine was opened in ``Mode::ReadRandomAccess`` (no step lifecycle to
race on), and
- the underlying file transport is reentrant for ``Read`` (the POSIX
transport is; ``fstream`` and others are not).

The legacy ``Selection``-less ``Get()``/``PerformGets()`` API and the
single-threaded Selection-based ``Get()`` are unchanged; the ctx-form is an
additional API for callers that need concurrency.

Compatibility
-------------

Expand Down
24 changes: 24 additions & 0 deletions docs/user_guide/source/introduction/whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@
What's new in Development
==============================

Thread-Safe Get with GetContext
-------------------------------

A new ``GetContext`` API extends the Selection-based ``Get()`` to support
concurrent read pipelines on a single engine. Each caller allocates its own
``GetContext`` via ``Engine::NewGetContext()`` and uses it as the first
argument to ``Get()`` and ``PerformGets()``; per-context queues mean two
threads can drive independent ``Get`` batches against the same open engine
without racing.

.. code-block:: c++

auto ctx = engine.NewGetContext();
if (ctx) {
engine.Get(*ctx, var, data, adios2::Selection::BoundingBox(start, count));
engine.PerformGets(*ctx);
}

``NewGetContext()`` returns ``nullptr`` when the engine does not support
concurrent contexts; callers feature-probe with the null check. Currently
only the **BP5** reader supports them, and only when opened in
``Mode::ReadRandomAccess`` with a reentrant file transport (POSIX). See the
Selection chapter for full details.

SST Mercury Data Plane
-----------------------

Expand Down
10 changes: 10 additions & 0 deletions source/adios2/core/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ void Engine::PerformPuts() { ThrowUp("PerformPuts"); }
void Engine::PerformGets() { ThrowUp("PerformGets"); }
void Engine::PerformDataWrite() { return; }

// Feature probe: null => engine doesn't support the ctx-form pipeline.
std::unique_ptr<GetContext> Engine::NewGetContext() { return nullptr; }
void Engine::PerformGets(GetContext &) { ThrowUp("PerformGets(GetContext&)"); }
void Engine::DoGetContextDeferred(GetContext &, VariableBase &, void *, const Selection &)
{
ThrowUp("DoGetContextDeferred");
}

void Engine::Close(const int transportIndex)
{
if (m_IsOpen)
Expand Down Expand Up @@ -375,6 +383,8 @@ std::vector<VariableStruct::BPInfo> Engine::BlocksInfoStruct(const VariableStruc
template void Engine::Get<T>(Variable<T> &, T *, const Selection &, const Mode); \
template void Engine::Get<T>(Variable<T> &, std::vector<T> &, const Selection &, const Mode); \
\
template void Engine::Get<T>(GetContext &, Variable<T> &, T *, const Selection &); \
\
template typename Variable<T>::BPInfo *Engine::Get<T>(Variable<T> &, const Mode); \
template typename Variable<T>::BPInfo *Engine::Get<T>(const std::string &, const Mode); \
\
Expand Down
12 changes: 12 additions & 0 deletions source/adios2/core/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "adios2/common/ADIOSMacros.h"
#include "adios2/common/ADIOSTypes.h"
#include "adios2/common/Selection.h"
#include "adios2/core/GetContext.h"
#include "adios2/core/IO.h"
#include "adios2/core/Variable.h"
#include "adios2/core/VariableStruct.h"
Expand Down Expand Up @@ -387,6 +388,15 @@ class Engine
void Get(Variable<T> &variable, std::vector<T> &dataV, const Selection &selection,
const Mode launch = Mode::Deferred);

// Context-bearing thread-safe Get pipeline (BP5 only).
// NewGetContext returns nullptr if the engine doesn't support it.
virtual std::unique_ptr<GetContext> NewGetContext();

template <class T>
void Get(GetContext &ctx, Variable<T> &variable, T *data, const Selection &selection);

virtual void PerformGets(GetContext &ctx);

/**
* Reader application indicates that no more data will be read from the
* current stream before advancing.
Expand Down Expand Up @@ -610,6 +620,8 @@ class Engine
ADIOS2_FOREACH_STDTYPE_1ARG(declare_type)
#undef declare_type

virtual void DoGetContextDeferred(GetContext &, VariableBase &, void *, const Selection &);

virtual void DoGetStructSync(VariableStruct &, void *);
virtual void DoGetStructDeferred(VariableStruct &, void *);

Expand Down
8 changes: 8 additions & 0 deletions source/adios2/core/Engine.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ void Engine::Get(Variable<T> &variable, T *data, const Selection &selection, con
}
}

template <class T>
void Engine::Get(GetContext &ctx, Variable<T> &variable, T *data, const Selection &selection)
{
CommonChecks(variable, data, {Mode::Read, Mode::ReadRandomAccess},
"in call to Get(GetContext &, Variable, T*, Selection)");
DoGetContextDeferred(ctx, variable, data, selection);
}

template <class T>
void Engine::Get(Variable<T> &variable, std::vector<T> &dataV, const Selection &selection,
const Mode launch)
Expand Down
25 changes: 25 additions & 0 deletions source/adios2/core/GetContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2026 Oak Ridge National Laboratory and Contributors
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ADIOS2_CORE_GETCONTEXT_H_
#define ADIOS2_CORE_GETCONTEXT_H_

namespace adios2
{
namespace core
{

// Opaque per-caller state for thread-safe Get/PerformGets.
class GetContext
{
public:
virtual ~GetContext() = default;
};

} // end namespace core
} // end namespace adios2

#endif /* ADIOS2_CORE_GETCONTEXT_H_ */
Loading
Loading