mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 16:46:47 +00:00
SDK: Add sync ChangeState and add msg to its result
This commit is contained in:
parent
a93840b240
commit
d70a203449
|
@ -22,43 +22,50 @@
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, AsyncOpResult v) -> std::ostream&
|
auto operator<<(std::ostream& os, AsyncOpResultCode v) -> std::ostream&
|
||||||
{
|
{
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case AsyncOpResult::Aborted:
|
case AsyncOpResultCode::Aborted:
|
||||||
return os << "Aborted";
|
return os << "Aborted";
|
||||||
case AsyncOpResult::Timeout:
|
case AsyncOpResultCode::Timeout:
|
||||||
return os << "Timeout";
|
return os << "Timeout";
|
||||||
case AsyncOpResult::Error:
|
case AsyncOpResultCode::Error:
|
||||||
return os << "Error";
|
return os << "Error";
|
||||||
case AsyncOpResult::Ok:
|
case AsyncOpResultCode::Ok:
|
||||||
default:
|
default:
|
||||||
return os << "Ok";
|
return os << "Ok";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto operator<<(std::ostream& os, AsyncOpResult v) -> std::ostream&
|
||||||
|
{
|
||||||
|
(void)(os << "[" << v.code << "]");
|
||||||
|
if (v.msg.empty()) {
|
||||||
|
(void)(os << " " << v.msg);
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
|
|
||||||
const std::unordered_map<DeviceTransition, DeviceState, tools::HashEnum<DeviceTransition>> Topology::fkExpectedState =
|
const std::unordered_map<DeviceTransition, DeviceState, tools::HashEnum<DeviceTransition>>
|
||||||
{
|
expectedState = {{Transition::InitDevice, DeviceState::InitializingDevice},
|
||||||
{ Transition::InitDevice, DeviceState::InitializingDevice },
|
{Transition::CompleteInit, DeviceState::Initialized},
|
||||||
{ Transition::CompleteInit, DeviceState::Initialized },
|
{Transition::Bind, DeviceState::Bound},
|
||||||
{ Transition::Bind, DeviceState::Bound },
|
{Transition::Connect, DeviceState::DeviceReady},
|
||||||
{ Transition::Connect, DeviceState::DeviceReady },
|
{Transition::InitTask, DeviceState::InitializingTask},
|
||||||
{ Transition::InitTask, DeviceState::InitializingTask },
|
{Transition::Run, DeviceState::Running},
|
||||||
{ Transition::Run, DeviceState::Running },
|
{Transition::Stop, DeviceState::Ready},
|
||||||
{ Transition::Stop, DeviceState::Ready },
|
{Transition::ResetTask, DeviceState::DeviceReady},
|
||||||
{ Transition::ResetTask, DeviceState::DeviceReady },
|
{Transition::ResetDevice, DeviceState::Idle},
|
||||||
{ Transition::ResetDevice, DeviceState::Idle },
|
{Transition::End, DeviceState::Exiting}};
|
||||||
{ Transition::End, DeviceState::Exiting }
|
|
||||||
};
|
|
||||||
|
|
||||||
Topology::Topology(DDSTopology topo, DDSSession session)
|
Topology::Topology(DDSTopology topo, DDSSession session)
|
||||||
: fDDSSession(std::move(session))
|
: fDDSSession(std::move(session))
|
||||||
, fDDSTopo(std::move(topo))
|
, fDDSTopo(std::move(topo))
|
||||||
, fTopologyState()
|
|
||||||
, fStateChangeOngoing(false)
|
, fStateChangeOngoing(false)
|
||||||
, fExecutionThread()
|
, fTargetState(DeviceState::Idle)
|
||||||
|
, fStateChangeTimeout(0)
|
||||||
, fShutdown(false)
|
, fShutdown(false)
|
||||||
{
|
{
|
||||||
std::vector<uint64_t> deviceList = fDDSTopo.GetDeviceList();
|
std::vector<uint64_t> deviceList = fDDSTopo.GetDeviceList();
|
||||||
|
@ -73,7 +80,6 @@ Topology::Topology(DDSTopology topo, DDSSession session)
|
||||||
|
|
||||||
for (unsigned int i = 0; i < parts.size(); ++i) {
|
for (unsigned int i = 0; i < parts.size(); ++i) {
|
||||||
boost::trim(parts.at(i));
|
boost::trim(parts.at(i));
|
||||||
LOG(info) << "parts[" << i << "]: " << parts.at(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parts[0] == "state-change") {
|
if (parts[0] == "state-change") {
|
||||||
|
@ -95,7 +101,7 @@ Topology::Topology(DDSTopology topo, DDSSession session)
|
||||||
fExecutionThread = std::thread(&Topology::WaitForState, this);
|
fExecutionThread = std::thread(&Topology::WaitForState, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Topology::ChangeState(fair::mq::Transition transition, ChangeStateCallback cb, std::chrono::milliseconds timeout) -> void
|
auto Topology::ChangeState(TopologyTransition transition, ChangeStateCallback cb, Duration timeout) -> void
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(fMtx);
|
std::lock_guard<std::mutex> guard(fMtx);
|
||||||
|
@ -103,17 +109,32 @@ auto Topology::ChangeState(fair::mq::Transition transition, ChangeStateCallback
|
||||||
LOG(error) << "State change already in progress, concurrent requested not yet supported";
|
LOG(error) << "State change already in progress, concurrent requested not yet supported";
|
||||||
return; // TODO call the callback with error msg
|
return; // TODO call the callback with error msg
|
||||||
}
|
}
|
||||||
LOG(info) << "Initiating ChangeState with " << transition << " to " << fkExpectedState.at(transition);
|
LOG(info) << "Initiating ChangeState with " << transition << " to " << expectedState.at(transition);
|
||||||
fStateChangeOngoing = true;
|
fStateChangeOngoing = true;
|
||||||
fChangeStateCallback = cb;
|
fChangeStateCallback = cb;
|
||||||
fStateChangeTimeout = timeout;
|
fStateChangeTimeout = timeout;
|
||||||
fTargetState = fkExpectedState.at(transition);
|
fTargetState = expectedState.at(transition);
|
||||||
|
|
||||||
fDDSSession.SendCommand(GetTransitionName(transition));
|
fDDSSession.SendCommand(GetTransitionName(transition));
|
||||||
}
|
}
|
||||||
fExecutionCV.notify_one();
|
fExecutionCV.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Topology::ChangeState(TopologyTransition t, Duration timeout) -> ChangeStateResult
|
||||||
|
{
|
||||||
|
fair::mq::tools::Semaphore blocker;
|
||||||
|
ChangeStateResult res;
|
||||||
|
ChangeState(
|
||||||
|
t,
|
||||||
|
[&blocker, &res](Topology::ChangeStateResult _res) {
|
||||||
|
res = _res;
|
||||||
|
blocker.Signal();
|
||||||
|
},
|
||||||
|
timeout);
|
||||||
|
blocker.Wait();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void Topology::WaitForState()
|
void Topology::WaitForState()
|
||||||
{
|
{
|
||||||
while (!fShutdown) {
|
while (!fShutdown) {
|
||||||
|
@ -150,10 +171,10 @@ void Topology::WaitForState()
|
||||||
}
|
}
|
||||||
} catch(std::exception& e) {
|
} catch(std::exception& e) {
|
||||||
LOG(error) << "Error while processing state request: " << e.what();
|
LOG(error) << "Error while processing state request: " << e.what();
|
||||||
fChangeStateCallback(ChangeStateResult{AsyncOpResult::Error, fTopologyState});
|
fChangeStateCallback({{AsyncOpResultCode::Error, ""}, fTopologyState});
|
||||||
}
|
}
|
||||||
|
|
||||||
fChangeStateCallback(ChangeStateResult{AsyncOpResult::Ok, fTopologyState});
|
fChangeStateCallback({{AsyncOpResultCode::Ok, ""}, fTopologyState});
|
||||||
} else {
|
} else {
|
||||||
std::unique_lock<std::mutex> lock(fExecutionMtx);
|
std::unique_lock<std::mutex> lock(fExecutionMtx);
|
||||||
fExecutionCV.wait(lock);
|
fExecutionCV.wait(lock);
|
||||||
|
|
|
@ -26,13 +26,21 @@
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
|
|
||||||
// TODO make this a struct with a readable string error msg
|
enum class AsyncOpResultCode {
|
||||||
enum class AsyncOpResult {
|
|
||||||
Ok,
|
Ok,
|
||||||
Timeout,
|
Timeout,
|
||||||
Error,
|
Error,
|
||||||
Aborted
|
Aborted
|
||||||
};
|
};
|
||||||
|
auto operator<<(std::ostream& os, AsyncOpResultCode v) -> std::ostream&;
|
||||||
|
|
||||||
|
using AsyncOpResultMessage = std::string;
|
||||||
|
|
||||||
|
struct AsyncOpResult {
|
||||||
|
AsyncOpResultCode code;
|
||||||
|
AsyncOpResultMessage msg;
|
||||||
|
operator AsyncOpResultCode() const { return code; }
|
||||||
|
};
|
||||||
auto operator<<(std::ostream& os, AsyncOpResult v) -> std::ostream&;
|
auto operator<<(std::ostream& os, AsyncOpResult v) -> std::ostream&;
|
||||||
|
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
|
@ -59,6 +67,12 @@ class Topology
|
||||||
/// @brief (Re)Construct a FairMQ topology from an existing DDS topology
|
/// @brief (Re)Construct a FairMQ topology from an existing DDS topology
|
||||||
/// @param topo Initialized DDS CTopology
|
/// @param topo Initialized DDS CTopology
|
||||||
explicit Topology(DDSTopology topo, DDSSession session = DDSSession());
|
explicit Topology(DDSTopology topo, DDSSession session = DDSSession());
|
||||||
|
|
||||||
|
explicit Topology(const Topology&) = delete;
|
||||||
|
Topology& operator=(const Topology&) = delete;
|
||||||
|
explicit Topology(Topology&&) = delete;
|
||||||
|
Topology& operator=(Topology&&) = delete;
|
||||||
|
|
||||||
~Topology();
|
~Topology();
|
||||||
|
|
||||||
struct ChangeStateResult {
|
struct ChangeStateResult {
|
||||||
|
@ -67,14 +81,21 @@ class Topology
|
||||||
friend auto operator<<(std::ostream& os, ChangeStateResult v) -> std::ostream&;
|
friend auto operator<<(std::ostream& os, ChangeStateResult v) -> std::ostream&;
|
||||||
};
|
};
|
||||||
using ChangeStateCallback = std::function<void(ChangeStateResult)>;
|
using ChangeStateCallback = std::function<void(ChangeStateResult)>;
|
||||||
|
using Duration = std::chrono::milliseconds;
|
||||||
|
|
||||||
/// @brief Initiate state transition on all FairMQ devices in this topology
|
/// @brief Initiate state transition on all FairMQ devices in this topology
|
||||||
/// @param t FairMQ device state machine transition
|
/// @param t FairMQ device state machine transition
|
||||||
/// @param cb Completion callback
|
/// @param cb Completion callback
|
||||||
auto ChangeState(TopologyTransition t, ChangeStateCallback cb, std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) -> void;
|
/// @param timeout Timeout in milliseconds, 0 means no timeout
|
||||||
|
auto ChangeState(TopologyTransition t, ChangeStateCallback cb, Duration timeout = std::chrono::milliseconds(0)) -> void;
|
||||||
|
|
||||||
static const std::unordered_map<DeviceTransition, DeviceState, tools::HashEnum<DeviceTransition>> fkExpectedState;
|
/// @brief Perform a state transition on all FairMQ devices in this topology
|
||||||
|
/// @param t FairMQ device state machine transition
|
||||||
|
/// @param timeout Timeout in milliseconds, 0 means no timeout
|
||||||
|
/// @return The result of the state transition
|
||||||
|
auto ChangeState(TopologyTransition t, Duration timeout = std::chrono::milliseconds(0)) -> ChangeStateResult;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DDSSession fDDSSession;
|
DDSSession fDDSSession;
|
||||||
DDSTopology fDDSTopo;
|
DDSTopology fDDSTopo;
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
* copied verbatim in the file "LICENSE" *
|
* copied verbatim in the file "LICENSE" *
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include <fairmq/sdk/Topology.h>
|
#include <fairmq/States.h>
|
||||||
#include <fairmq/StateMachine.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main(int /*argc*/, char ** /*argv*/)
|
int main(int /*argc*/, char ** /*argv*/)
|
||||||
|
|
|
@ -21,27 +21,39 @@ TEST_F(Topology, Construction)
|
||||||
fair::mq::sdk::Topology topo(mDDSTopo, mDDSSession);
|
fair::mq::sdk::Topology topo(mDDSTopo, mDDSSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(Topology, ChangeState)
|
TEST_F(Topology, ChangeState_async1)
|
||||||
{
|
{
|
||||||
using fair::mq::sdk::Topology;
|
using fair::mq::sdk::Topology;
|
||||||
using fair::mq::sdk::TopologyTransition;
|
using fair::mq::sdk::TopologyTransition;
|
||||||
|
|
||||||
Topology topo(mDDSTopo, mDDSSession);
|
Topology topo(mDDSTopo, mDDSSession);
|
||||||
Topology::ChangeStateResult r;
|
|
||||||
fair::mq::tools::Semaphore blocker;
|
fair::mq::tools::Semaphore blocker;
|
||||||
topo.ChangeState(TopologyTransition::Stop, [&](Topology::ChangeStateResult result) {
|
topo.ChangeState(TopologyTransition::Stop, [&blocker](Topology::ChangeStateResult result) {
|
||||||
LOG(info) << result;
|
LOG(info) << result;
|
||||||
r = result;
|
EXPECT_EQ(result.rc, fair::mq::AsyncOpResultCode::Ok);
|
||||||
|
// TODO add the helper to check state consistency
|
||||||
|
for (const auto& e : result.state) {
|
||||||
|
EXPECT_EQ(e.second.state, fair::mq::sdk::DeviceState::Ready);
|
||||||
|
}
|
||||||
blocker.Signal();
|
blocker.Signal();
|
||||||
});
|
});
|
||||||
blocker.Wait();
|
blocker.Wait();
|
||||||
EXPECT_EQ(r.rc, fair::mq::AsyncOpResult::Ok);
|
}
|
||||||
|
|
||||||
|
TEST_F(Topology, ChangeState_sync)
|
||||||
|
{
|
||||||
|
using fair::mq::sdk::Topology;
|
||||||
|
using fair::mq::sdk::TopologyTransition;
|
||||||
|
|
||||||
|
Topology topo(mDDSTopo, mDDSSession);
|
||||||
|
auto result(topo.ChangeState(TopologyTransition::Stop));
|
||||||
|
|
||||||
|
EXPECT_EQ(result.rc, fair::mq::AsyncOpResultCode::Ok);
|
||||||
// TODO add the helper to check state consistency
|
// TODO add the helper to check state consistency
|
||||||
for (const auto& e : r.state) {
|
for (const auto& e : result.state) {
|
||||||
EXPECT_EQ(e.second.state, fair::mq::sdk::DeviceState::Ready);
|
EXPECT_EQ(e.second.state, fair::mq::sdk::DeviceState::Ready);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TEST_F(Topology, Timeout)
|
// TEST_F(Topology, Timeout)
|
||||||
// {
|
// {
|
||||||
// using fair::mq::sdk::Topology;
|
// using fair::mq::sdk::Topology;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</decltask>
|
</decltask>
|
||||||
|
|
||||||
<decltask name="Sink">
|
<decltask name="Sink">
|
||||||
<exe reachable="true">fairmq-sink --id sink --color false --channel-config name=data,type=pull,method=connect -P dds</exe>
|
<exe reachable="true">fairmq-sink --id sink_%taskIndex% --color false --channel-config name=data,type=pull,method=connect -P dds</exe>
|
||||||
<requirements>
|
<requirements>
|
||||||
<name>SinkWorker</name>
|
<name>SinkWorker</name>
|
||||||
</requirements>
|
</requirements>
|
||||||
|
@ -27,7 +27,9 @@
|
||||||
|
|
||||||
<main name="main">
|
<main name="main">
|
||||||
<task>Sampler</task>
|
<task>Sampler</task>
|
||||||
<task>Sink</task>
|
<group name="SinkGroup" n="50">
|
||||||
|
<task>Sink</task>
|
||||||
|
</group>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
</topology>
|
</topology>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user