mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 08:41:16 +00:00
(WIP) SDK: Implement Topology::ChangeState
This commit is contained in:
parent
499ffcd300
commit
18dc536f3d
|
@ -46,6 +46,8 @@ bool Sampler::ConditionalRun()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this_thread::sleep_for(chrono::seconds(5));
|
||||||
|
|
||||||
if (fIterations > 0) {
|
if (fIterations > 0) {
|
||||||
++fCounter;
|
++fCounter;
|
||||||
if (fCounter >= fIterations) {
|
if (fCounter >= fIterations) {
|
||||||
|
|
|
@ -413,6 +413,7 @@ if(BUILD_FAIRMQ)
|
||||||
target_link_libraries(fairmq-splitter FairMQ)
|
target_link_libraries(fairmq-splitter FairMQ)
|
||||||
|
|
||||||
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
|
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
|
||||||
|
target_compile_definitions(fairmq-shmmonitor PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
||||||
target_link_libraries(fairmq-shmmonitor PUBLIC
|
target_link_libraries(fairmq-shmmonitor PUBLIC
|
||||||
Threads::Threads
|
Threads::Threads
|
||||||
$<$<PLATFORM_ID:Linux>:rt>
|
$<$<PLATFORM_ID:Linux>:rt>
|
||||||
|
|
|
@ -17,6 +17,7 @@ set(SDK_PUBLIC_HEADER_FILES
|
||||||
../SDK.h
|
../SDK.h
|
||||||
DDSEnvironment.h
|
DDSEnvironment.h
|
||||||
DDSSession.h
|
DDSSession.h
|
||||||
|
DDSTopology.h
|
||||||
Topology.h
|
Topology.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ set(SDK_PRIVATE_HEADER_FILES
|
||||||
set(SDK_SOURCE_FILES
|
set(SDK_SOURCE_FILES
|
||||||
DDSEnvironment.cxx
|
DDSEnvironment.cxx
|
||||||
DDSSession.cxx
|
DDSSession.cxx
|
||||||
|
DDSTopology.cxx
|
||||||
Topology.cxx
|
Topology.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -8,73 +8,119 @@
|
||||||
|
|
||||||
#include "DDSEnvironment.h"
|
#include "DDSEnvironment.h"
|
||||||
|
|
||||||
#include <DDS/Tools.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
|
#include <fairmq/sdk/DDSInfo.h>
|
||||||
|
|
||||||
|
#include <fairlogger/Logger.h>
|
||||||
|
|
||||||
|
#include <DDS/Tools.h>
|
||||||
|
#include <DDS/dds_intercom.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
|
|
||||||
// TODO https://github.com/FairRootGroup/DDS/issues/224
|
|
||||||
auto LoadDDSEnv(const boost::filesystem::path& config_home)
|
|
||||||
-> void
|
|
||||||
{
|
|
||||||
setenv("DDS_LOCATION", DDSInstallPrefix.c_str(), 1);
|
|
||||||
if (!config_home.empty()) {
|
|
||||||
setenv("HOME", config_home.c_str(), 1);
|
|
||||||
}
|
|
||||||
std::string path(std::getenv("PATH"));
|
|
||||||
path = DDSExecutableDir + std::string(":") + path;
|
|
||||||
setenv("PATH", path.c_str(), 1);
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
|
||||||
std::string ldVar("LD_LIBRARY_PATH");
|
|
||||||
std::string ld(std::getenv(ldVar.c_str()));
|
|
||||||
ld = DDSLibraryDir + std::string(":") + ld;
|
|
||||||
setenv(ldVar.c_str(), ld.c_str(), 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::istringstream cmd;
|
|
||||||
cmd.str("DDS_CFG=`dds-user-defaults --ignore-default-sid -p`\n"
|
|
||||||
"if [ -z \"$DDS_CFG\" ]; then\n"
|
|
||||||
" mkdir -p \"$HOME/.DDS\"\n"
|
|
||||||
" dds-user-defaults --ignore-default-sid -d -c \"$HOME/.DDS/DDS.cfg\"\n"
|
|
||||||
"fi");
|
|
||||||
std::system(cmd.str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DDSEnvironment::Impl
|
struct DDSEnvironment::Impl
|
||||||
{
|
{
|
||||||
explicit Impl(Path config_home)
|
explicit Impl(Path configHome)
|
||||||
: fCount()
|
: fLocation(DDSInstallPrefix)
|
||||||
, fConfigHome(std::move(config_home))
|
, fConfigHome(std::move(configHome))
|
||||||
{
|
{
|
||||||
LoadDDSEnv(fConfigHome);
|
SetupLocation();
|
||||||
if (fConfigHome.empty()) {
|
SetupDynamicLoader();
|
||||||
fConfigHome = std::getenv("HOME");
|
SetupPath();
|
||||||
|
SetupConfigHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SetupLocation() -> void
|
||||||
|
{
|
||||||
|
std::string location(GetEnv("DDS_LOCATION"));
|
||||||
|
if (location != DDSInstallPrefix) {
|
||||||
|
if (location.empty()) {
|
||||||
|
setenv("DDS_LOCATION", DDSInstallPrefix.c_str(), 1);
|
||||||
|
} else {
|
||||||
|
LOG(debug) << "$DDS_LOCATION appears to point to a different installation than this"
|
||||||
|
<< "program was linked against. Things might still work out, so not"
|
||||||
|
<< "touching it.";
|
||||||
|
fLocation = location;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto SetupConfigHome() -> void
|
||||||
|
{
|
||||||
|
if (fConfigHome.empty()) {
|
||||||
|
fConfigHome = GetEnv("HOME");
|
||||||
|
} else {
|
||||||
|
setenv("HOME", fConfigHome.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream cmd;
|
||||||
|
cmd.str("DDS_CFG=`dds-user-defaults --ignore-default-sid -p`\n"
|
||||||
|
"if [ -z \"$DDS_CFG\" ]; then\n"
|
||||||
|
" mkdir -p \"$HOME/.DDS\"\n"
|
||||||
|
" dds-user-defaults --ignore-default-sid -d -c \"$HOME/.DDS/DDS.cfg\"\n"
|
||||||
|
"fi");
|
||||||
|
std::system(cmd.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SetupPath() -> void
|
||||||
|
{
|
||||||
|
std::string path(GetEnv("PATH"));
|
||||||
|
Path ddsExecDir = (fLocation == DDSInstallPrefix) ? DDSExecutableDir : fLocation / Path("bin");
|
||||||
|
path = ddsExecDir.string() + std::string(":") + path;
|
||||||
|
setenv("PATH", path.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SetupDynamicLoader() -> void
|
||||||
|
{
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::string ldVar("DYLD_LIBRARY_PATH");
|
||||||
|
#else
|
||||||
|
std::string ldVar("LD_LIBRARY_PATH");
|
||||||
|
#endif
|
||||||
|
std::string ld(GetEnv(ldVar));
|
||||||
|
Path ddsLibDir = (fLocation == DDSInstallPrefix) ? DDSLibraryDir : fLocation / Path("lib");
|
||||||
|
ld = ddsLibDir.string() + std::string(":") + ld;
|
||||||
|
setenv(ldVar.c_str(), ld.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetEnv(const std::string& key) -> std::string
|
||||||
|
{
|
||||||
|
auto value = std::getenv(key.c_str());
|
||||||
|
if (value) {
|
||||||
|
return {value};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
struct Tag {};
|
struct Tag {};
|
||||||
friend auto operator<<(std::ostream& os, Tag) -> std::ostream& { return os << "DDSEnvironment"; }
|
friend auto operator<<(std::ostream& os, Tag) -> std::ostream& { return os << "DDSEnvironment"; }
|
||||||
tools::InstanceLimiter<Tag, 1> fCount;
|
tools::InstanceLimiter<Tag, 1> fCount;
|
||||||
|
|
||||||
|
Path fLocation;
|
||||||
Path fConfigHome;
|
Path fConfigHome;
|
||||||
};
|
};
|
||||||
|
|
||||||
DDSEnvironment::DDSEnvironment(Path config_home)
|
DDSEnvironment::DDSEnvironment()
|
||||||
: fImpl(std::make_shared<Impl>(std::move(config_home)))
|
: DDSEnvironment(Path())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
DDSEnvironment::DDSEnvironment(Path configHome)
|
||||||
|
: fImpl(std::make_shared<Impl>(std::move(configHome)))
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto DDSEnvironment::GetLocation() const -> Path { return fImpl->fLocation; }
|
||||||
|
|
||||||
auto DDSEnvironment::GetConfigHome() const -> Path { return fImpl->fConfigHome; }
|
auto DDSEnvironment::GetConfigHome() const -> Path { return fImpl->fConfigHome; }
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&
|
auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&
|
||||||
{
|
{
|
||||||
return os << "$DDS_LOCATION: " << DDSInstallPrefix << ", "
|
return os << "$DDS_LOCATION: " << env.GetLocation() << ", "
|
||||||
<< "$DDS_CONFIG_HOME: " << env.GetConfigHome() / DDSEnvironment::Path(".DDS");
|
<< "$DDS_CONFIG_HOME: " << env.GetConfigHome() / DDSEnvironment::Path(".DDS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#define FAIR_MQ_SDK_DDSENVIRONMENT_H
|
#define FAIR_MQ_SDK_DDSENVIRONMENT_H
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
|
@ -27,9 +26,10 @@ class DDSEnvironment
|
||||||
public:
|
public:
|
||||||
using Path = boost::filesystem::path;
|
using Path = boost::filesystem::path;
|
||||||
|
|
||||||
/// @brief See fair::mq::sdk::LoadDDSEnv
|
DDSEnvironment();
|
||||||
explicit DDSEnvironment(Path config_home = "");
|
explicit DDSEnvironment(Path);
|
||||||
|
|
||||||
|
auto GetLocation() const -> Path;
|
||||||
auto GetConfigHome() const -> Path;
|
auto GetConfigHome() const -> Path;
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&;
|
friend auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&;
|
||||||
|
@ -38,6 +38,8 @@ class DDSEnvironment
|
||||||
std::shared_ptr<Impl> fImpl;
|
std::shared_ptr<Impl> fImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using DDSEnv = DDSEnvironment;
|
||||||
|
|
||||||
} // namespace sdk
|
} // namespace sdk
|
||||||
} // namespace mq
|
} // namespace mq
|
||||||
} // namespace fair
|
} // namespace fair
|
||||||
|
|
|
@ -11,6 +11,20 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
namespace dds {
|
||||||
|
namespace tools_api {
|
||||||
|
|
||||||
|
class CSession;
|
||||||
|
|
||||||
|
} // namespace tools_api
|
||||||
|
|
||||||
|
namespace topology_api {
|
||||||
|
|
||||||
|
class CTopology;
|
||||||
|
|
||||||
|
} // namespace topology_api
|
||||||
|
} // namespace dds
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
|
|
|
@ -7,16 +7,19 @@
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include "DDSSession.h"
|
#include "DDSSession.h"
|
||||||
#include "DDSEnvironment.h"
|
|
||||||
|
#include <fairmq/sdk/DDSEnvironment.h>
|
||||||
|
#include <fairmq/Tools.h>
|
||||||
|
|
||||||
|
#include <fairlogger/Logger.h>
|
||||||
|
|
||||||
#include <DDS/Tools.h>
|
#include <DDS/Tools.h>
|
||||||
|
|
||||||
#include <boost/uuid/uuid_io.hpp>
|
#include <boost/uuid/uuid_io.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
#include <fairmq/Tools.h>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
|
@ -52,48 +55,76 @@ auto operator>>(std::istream& is, DDSRMSPlugin& plugin) -> std::istream&
|
||||||
|
|
||||||
struct DDSSession::Impl
|
struct DDSSession::Impl
|
||||||
{
|
{
|
||||||
Impl(DDSEnvironment env, DDSRMSPlugin plugin)
|
explicit Impl(DDSEnvironment env)
|
||||||
: fCount()
|
: fEnv(std::move(env))
|
||||||
, fEnv(std::move(env))
|
, fRMSPlugin(DDSRMSPlugin::localhost)
|
||||||
, fDefaultPlugin(std::move(plugin))
|
, fDDSService()
|
||||||
, fSession()
|
, fDDSCustomCmd(fDDSService)
|
||||||
, fId(to_string(fSession.create()))
|
, fId(to_string(fSession.create()))
|
||||||
|
, fStopOnDestruction(false)
|
||||||
{
|
{
|
||||||
setenv("DDS_SESSION_ID", fId.c_str(), 1);
|
setenv("DDS_SESSION_ID", fId.c_str(), 1);
|
||||||
|
|
||||||
|
fDDSService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& msg) {
|
||||||
|
std::cerr << "DDS error, error code: " << errorCode << ", error message: " << msg << std::endl;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Impl(DDSEnvironment env, DDSRMSPlugin plugin, Id existing_id)
|
explicit Impl(Id existing, DDSEnvironment env)
|
||||||
: fCount()
|
: fEnv(std::move(env))
|
||||||
, fEnv(std::move(env))
|
, fRMSPlugin(DDSRMSPlugin::localhost)
|
||||||
, fDefaultPlugin(std::move(plugin))
|
, fDDSService()
|
||||||
, fSession()
|
, fDDSCustomCmd(fDDSService)
|
||||||
, fId(std::move(existing_id))
|
, fId(std::move(existing))
|
||||||
|
, fStopOnDestruction(false)
|
||||||
{
|
{
|
||||||
fSession.attach(fId);
|
fSession.attach(fId);
|
||||||
std::string envId(std::getenv("DDS_SESSION_ID"));
|
std::string envId(std::getenv("DDS_SESSION_ID"));
|
||||||
if (envId != fId) {
|
if (envId != fId) {
|
||||||
setenv("DDS_SESSION_ID", fId.c_str(), 1);
|
setenv("DDS_SESSION_ID", fId.c_str(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fDDSService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& msg) {
|
||||||
|
std::cerr << "DDS error, error code: " << errorCode << ", error message: " << msg << std::endl;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~Impl()
|
||||||
|
{
|
||||||
|
if (fStopOnDestruction) {
|
||||||
|
fSession.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Impl() = delete;
|
||||||
|
Impl(const Impl&) = delete;
|
||||||
|
Impl& operator=(const Impl&) = delete;
|
||||||
|
Impl(Impl&&) = delete;
|
||||||
|
Impl& operator=(Impl&&) = delete;
|
||||||
|
|
||||||
struct Tag {};
|
struct Tag {};
|
||||||
friend auto operator<<(std::ostream& os, Tag) -> std::ostream& { return os << "DDSSession"; }
|
friend auto operator<<(std::ostream& os, Tag) -> std::ostream& { return os << "DDSSession"; }
|
||||||
tools::InstanceLimiter<Tag, 1> fCount;
|
tools::InstanceLimiter<Tag, 1> fCount;
|
||||||
|
|
||||||
const DDSEnvironment fEnv;
|
DDSEnvironment fEnv;
|
||||||
const DDSRMSPlugin fDefaultPlugin;
|
DDSRMSPlugin fRMSPlugin;
|
||||||
|
Path fRMSConfig;
|
||||||
dds::tools_api::CSession fSession;
|
dds::tools_api::CSession fSession;
|
||||||
const Id fId;
|
dds::intercom_api::CIntercomService fDDSService;
|
||||||
|
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
||||||
|
Id fId;
|
||||||
|
bool fStopOnDestruction;
|
||||||
};
|
};
|
||||||
|
|
||||||
DDSSession::DDSSession(DDSEnvironment env, DDSRMSPlugin default_plugin)
|
DDSSession::DDSSession(DDSEnvironment env)
|
||||||
: fImpl(std::make_shared<Impl>(std::move(env), std::move(default_plugin))) {}
|
: fImpl(std::make_shared<Impl>(env))
|
||||||
|
{}
|
||||||
|
|
||||||
DDSSession::DDSSession(DDSEnvironment env, Id existing_id)
|
DDSSession::DDSSession(Id existing, DDSEnvironment env)
|
||||||
: fImpl(std::make_shared<Impl>(std::move(env), DDSRMSPlugin::localhost, std::move(existing_id))) {}
|
: fImpl(std::make_shared<Impl>(std::move(existing), env))
|
||||||
|
{}
|
||||||
|
|
||||||
DDSSession::DDSSession(DDSEnvironment env, DDSRMSPlugin default_plugin, Id existing_id)
|
auto DDSSession::GetEnv() const -> DDSEnvironment { return fImpl->fEnv; }
|
||||||
: fImpl(std::make_shared<Impl>(std::move(env), std::move(default_plugin), std::move(existing_id))) {}
|
|
||||||
|
|
||||||
auto DDSSession::IsRunning() const -> bool { return fImpl->fSession.IsRunning(); }
|
auto DDSSession::IsRunning() const -> bool { return fImpl->fSession.IsRunning(); }
|
||||||
|
|
||||||
|
@ -101,36 +132,30 @@ auto DDSSession::GetId() const -> Id { return fImpl->fId; }
|
||||||
|
|
||||||
auto DDSSession::Stop() -> void { return fImpl->fSession.shutdown(); }
|
auto DDSSession::Stop() -> void { return fImpl->fSession.shutdown(); }
|
||||||
|
|
||||||
auto DDSSession::GetDefaultPlugin() const -> DDSRMSPlugin { return fImpl->fDefaultPlugin; }
|
auto DDSSession::GetRMSPlugin() const -> DDSRMSPlugin { return fImpl->fRMSPlugin; }
|
||||||
|
|
||||||
|
auto DDSSession::SetRMSPlugin(DDSRMSPlugin plugin) -> void { fImpl->fRMSPlugin = plugin; }
|
||||||
|
|
||||||
|
auto DDSSession::GetRMSConfig() const -> Path { return fImpl->fRMSConfig; }
|
||||||
|
|
||||||
|
auto DDSSession::SetRMSConfig(Path configFile) const -> void
|
||||||
|
{
|
||||||
|
fImpl->fRMSConfig = std::move(configFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto DDSSession::IsStoppedOnDestruction() const -> bool { return fImpl->fStopOnDestruction; }
|
||||||
|
|
||||||
|
auto DDSSession::StopOnDestruction(bool stop) -> void { fImpl->fStopOnDestruction = stop; }
|
||||||
|
|
||||||
auto DDSSession::SubmitAgents(Quantity agents) -> void
|
auto DDSSession::SubmitAgents(Quantity agents) -> void
|
||||||
{
|
|
||||||
SubmitAgents(agents, GetDefaultPlugin(), Path());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::SubmitAgents(Quantity agents, DDSRMSPlugin plugin) -> void
|
|
||||||
{
|
|
||||||
SubmitAgents(agents, plugin, Path());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::SubmitAgents(Quantity agents, const Path& config) -> void
|
|
||||||
{
|
|
||||||
SubmitAgents(agents, GetDefaultPlugin(), std::move(config));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::SubmitAgents(Quantity agents, DDSRMSPlugin plugin, const Path& config) -> void
|
|
||||||
{
|
{
|
||||||
// Requesting to submit 0 agents is not meaningful
|
// Requesting to submit 0 agents is not meaningful
|
||||||
assert(agents > 0);
|
assert(agents > 0);
|
||||||
// The config argument is required with all plugins except localhost
|
|
||||||
if (plugin != DDSRMSPlugin::localhost) {
|
|
||||||
assert(exists(config));
|
|
||||||
}
|
|
||||||
|
|
||||||
dds::tools_api::SSubmitRequestData submitInfo;
|
dds::tools_api::SSubmitRequestData submitInfo;
|
||||||
submitInfo.m_rms = tools::ToString(plugin);
|
submitInfo.m_rms = tools::ToString(GetRMSPlugin());
|
||||||
submitInfo.m_instances = agents;
|
submitInfo.m_instances = agents;
|
||||||
submitInfo.m_config = config.string();
|
submitInfo.m_config = GetRMSConfig().string();
|
||||||
|
|
||||||
tools::Semaphore blocker;
|
tools::Semaphore blocker;
|
||||||
auto submitRequest = dds::tools_api::SSubmitRequest::makeRequest(submitInfo);
|
auto submitRequest = dds::tools_api::SSubmitRequest::makeRequest(submitInfo);
|
||||||
|
@ -162,7 +187,28 @@ auto DDSSession::RequestAgentInfo() -> void
|
||||||
blocker.Wait();
|
blocker.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DDSSession::ActivateTopology(Path topologyFile) -> void
|
auto DDSSession::RequestCommanderInfo() -> void
|
||||||
|
{
|
||||||
|
dds::tools_api::SCommanderInfoRequestData commanderInfoInfo;
|
||||||
|
tools::Semaphore blocker;
|
||||||
|
auto commanderInfoRequest =
|
||||||
|
dds::tools_api::SCommanderInfoRequest::makeRequest(commanderInfoInfo);
|
||||||
|
commanderInfoRequest->setResponseCallback(
|
||||||
|
[&](const dds::tools_api::SCommanderInfoResponseData& _response) {
|
||||||
|
LOG(debug) << "pid: " << _response.m_pid;
|
||||||
|
LOG(debug) << "idle agents: " << _response.m_idleAgentsCount;
|
||||||
|
// LOG(debug) << "active topology: "
|
||||||
|
// << ((_response.m_hasActiveTopology) ? _response.m_activeTopologyName
|
||||||
|
// : "<none>");
|
||||||
|
});
|
||||||
|
commanderInfoRequest->setMessageCallback(
|
||||||
|
[](const dds::tools_api::SMessageResponseData& _message) { LOG(debug) << _message; });
|
||||||
|
commanderInfoRequest->setDoneCallback([&]() { blocker.Signal(); });
|
||||||
|
fImpl->fSession.sendRequest<dds::tools_api::SCommanderInfoRequest>(commanderInfoRequest);
|
||||||
|
blocker.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto DDSSession::ActivateTopology(const Path& topologyFile) -> void
|
||||||
{
|
{
|
||||||
dds::tools_api::STopologyRequestData topologyInfo;
|
dds::tools_api::STopologyRequestData topologyInfo;
|
||||||
topologyInfo.m_updateType = dds::tools_api::STopologyRequestData::EUpdateType::ACTIVATE;
|
topologyInfo.m_updateType = dds::tools_api::STopologyRequestData::EUpdateType::ACTIVATE;
|
||||||
|
@ -177,7 +223,16 @@ auto DDSSession::ActivateTopology(Path topologyFile) -> void
|
||||||
blocker.Wait();
|
blocker.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, DDSSession session) -> std::ostream&
|
void DDSSession::StartDDSService() { fImpl->fDDSService.start(fImpl->fId); }
|
||||||
|
|
||||||
|
void DDSSession::SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)> cb)
|
||||||
|
{
|
||||||
|
fImpl->fDDSCustomCmd.subscribe(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DDSSession::SendCommand(const std::string& cmd) { fImpl->fDDSCustomCmd.send(cmd, ""); }
|
||||||
|
|
||||||
|
auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&
|
||||||
{
|
{
|
||||||
return os << "$DDS_SESSION_ID: " << session.GetId();
|
return os << "$DDS_SESSION_ID: " << session.GetId();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,18 @@
|
||||||
#ifndef FAIR_MQ_SDK_DDSSESSION_H
|
#ifndef FAIR_MQ_SDK_DDSSESSION_H
|
||||||
#define FAIR_MQ_SDK_DDSSESSION_H
|
#define FAIR_MQ_SDK_DDSSESSION_H
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <fairmq/sdk/DDSEnvironment.h>
|
||||||
#include <cstdint>
|
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
#include <fairmq/sdk/DDSInfo.h>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
|
@ -47,23 +51,29 @@ class DDSSession
|
||||||
using Quantity = std::uint32_t;
|
using Quantity = std::uint32_t;
|
||||||
using Path = boost::filesystem::path;
|
using Path = boost::filesystem::path;
|
||||||
|
|
||||||
DDSSession() = delete;
|
explicit DDSSession(DDSEnvironment env = DDSEnvironment());
|
||||||
explicit DDSSession(DDSEnvironment env, DDSRMSPlugin default_plugin = DDSRMSPlugin::localhost);
|
explicit DDSSession(Id existing, DDSEnvironment env = DDSEnvironment());
|
||||||
explicit DDSSession(DDSEnvironment env, Id existing_id);
|
|
||||||
explicit DDSSession(DDSEnvironment env, DDSRMSPlugin default_plugin, Id existing_id);
|
|
||||||
|
|
||||||
|
auto GetEnv() const -> DDSEnvironment;
|
||||||
auto GetId() const -> Id;
|
auto GetId() const -> Id;
|
||||||
auto GetDefaultPlugin() const -> DDSRMSPlugin;
|
auto GetRMSPlugin() const -> DDSRMSPlugin;
|
||||||
|
auto SetRMSPlugin(DDSRMSPlugin) -> void;
|
||||||
|
auto GetRMSConfig() const -> Path;
|
||||||
|
auto SetRMSConfig(Path) const -> void;
|
||||||
|
auto IsStoppedOnDestruction() const -> bool;
|
||||||
|
auto StopOnDestruction(bool stop = true) -> void;
|
||||||
auto IsRunning() const -> bool;
|
auto IsRunning() const -> bool;
|
||||||
auto SubmitAgents(Quantity agents) -> void;
|
auto SubmitAgents(Quantity agents) -> void;
|
||||||
auto SubmitAgents(Quantity agents, DDSRMSPlugin plugin) -> void;
|
|
||||||
auto SubmitAgents(Quantity agents, DDSRMSPlugin plugin, const Path& config) -> void;
|
|
||||||
auto SubmitAgents(Quantity agents, const Path& config) -> void;
|
|
||||||
auto RequestAgentInfo() -> void;
|
auto RequestAgentInfo() -> void;
|
||||||
auto ActivateTopology(Path topologyFile) -> void;
|
auto RequestCommanderInfo() -> void;
|
||||||
|
auto ActivateTopology(const Path& topologyFile) -> void;
|
||||||
auto Stop() -> void;
|
auto Stop() -> void;
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, DDSSession session) -> std::ostream&;
|
void StartDDSService();
|
||||||
|
void SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)>);
|
||||||
|
void SendCommand(const std::string&);
|
||||||
|
|
||||||
|
friend auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&;
|
||||||
private:
|
private:
|
||||||
struct Impl;
|
struct Impl;
|
||||||
std::shared_ptr<Impl> fImpl;
|
std::shared_ptr<Impl> fImpl;
|
||||||
|
|
96
fairmq/sdk/DDSTopology.cxx
Normal file
96
fairmq/sdk/DDSTopology.cxx
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
|
* *
|
||||||
|
* This software is distributed under the terms of the *
|
||||||
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include "DDSTopology.h"
|
||||||
|
|
||||||
|
#include <fairmq/sdk/DDSEnvironment.h>
|
||||||
|
#include <fairmq/Tools.h>
|
||||||
|
|
||||||
|
#include <fairlogger/Logger.h>
|
||||||
|
|
||||||
|
#include <DDS/Topology.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace fair {
|
||||||
|
namespace mq {
|
||||||
|
namespace sdk {
|
||||||
|
|
||||||
|
struct DDSTopology::Impl
|
||||||
|
{
|
||||||
|
explicit Impl(Path topoFile, DDSEnvironment env)
|
||||||
|
: fEnv(std::move(env))
|
||||||
|
, fTopoFile(std::move(topoFile))
|
||||||
|
, fTopo(nullptr)
|
||||||
|
{
|
||||||
|
LOG(warn) << topoFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDSEnvironment fEnv;
|
||||||
|
Path fTopoFile;
|
||||||
|
std::unique_ptr<dds::topology_api::CTopology> fTopo;
|
||||||
|
};
|
||||||
|
|
||||||
|
DDSTopology::DDSTopology(Path topoFile, DDSEnvironment env)
|
||||||
|
: fImpl(std::make_shared<Impl>(std::move(topoFile), std::move(env)))
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto DDSTopology::GetEnv() const -> DDSEnvironment { return fImpl->fEnv; }
|
||||||
|
|
||||||
|
auto DDSTopology::GetTopoFile() const -> Path
|
||||||
|
{
|
||||||
|
auto file(fImpl->fTopoFile);
|
||||||
|
if (file.string().empty()) {
|
||||||
|
throw std::runtime_error("DDS topology xml spec file unknown");
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DDSTopology::CreateTopology(Path topoFile)
|
||||||
|
{
|
||||||
|
fImpl->fTopo = tools::make_unique<dds::topology_api::CTopology>(fImpl->fTopoFile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int DDSTopology::GetNumRequiredAgents()
|
||||||
|
{
|
||||||
|
return fImpl->fTopo->getRequiredNofAgents();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint64_t> DDSTopology::GetDeviceList()
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> taskIDs;
|
||||||
|
taskIDs.reserve(fImpl->fTopo->getRequiredNofAgents());
|
||||||
|
|
||||||
|
// TODO make sure returned tasks are actually devices
|
||||||
|
dds::topology_api::STopoRuntimeTask::FilterIteratorPair_t taskIt = fImpl->fTopo->getRuntimeTaskIterator([](const dds::topology_api::STopoRuntimeTask::FilterIterator_t::value_type& value) -> bool {
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto& it = taskIt.first; it != taskIt.second; ++it) {
|
||||||
|
LOG(debug) << "Found task " << it->first << " : " << it->second.m_task->getPath();
|
||||||
|
taskIDs.push_back(it->first);
|
||||||
|
}
|
||||||
|
|
||||||
|
return taskIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto DDSTopology::GetName() const -> std::string { return fImpl->fTopo.getName(); }
|
||||||
|
|
||||||
|
auto operator<<(std::ostream& os, const DDSTopology& t) -> std::ostream&
|
||||||
|
try {
|
||||||
|
return os << "DDS topology: " /*<< t.GetName() <<*/ " (loaded from " << t.GetTopoFile() << ")";
|
||||||
|
} catch (std::runtime_error&) {
|
||||||
|
return os << "DDS topology: " /*<< t.GetName()*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sdk
|
||||||
|
} // namespace mq
|
||||||
|
} // namespace fair
|
|
@ -9,18 +9,11 @@
|
||||||
#ifndef FAIR_MQ_SDK_DDSTOPOLOGY_H
|
#ifndef FAIR_MQ_SDK_DDSTOPOLOGY_H
|
||||||
#define FAIR_MQ_SDK_DDSTOPOLOGY_H
|
#define FAIR_MQ_SDK_DDSTOPOLOGY_H
|
||||||
|
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <fairmq/sdk/DDSEnvironment.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace dds {
|
|
||||||
namespace topology_api {
|
|
||||||
|
|
||||||
class CTopology;
|
|
||||||
|
|
||||||
} // namespace topology_api
|
|
||||||
} // namespace dds
|
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
|
@ -29,23 +22,44 @@ namespace sdk {
|
||||||
* @class DDSTopology DDSTopology.h <fairmq/sdk/DDSTopology.h>
|
* @class DDSTopology DDSTopology.h <fairmq/sdk/DDSTopology.h>
|
||||||
* @brief Represents a DDS topology
|
* @brief Represents a DDS topology
|
||||||
*/
|
*/
|
||||||
class DDSSession
|
class DDSTopology
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using CSessionPtr = std::shared_ptr<dds::tools_api::CSession>;
|
using Path = boost::filesystem::path;
|
||||||
|
|
||||||
explicit DDSSession();
|
DDSTopology() = delete;
|
||||||
explicit DDSSession(std::string existing_session_id);
|
|
||||||
|
/// @brief Construct from file
|
||||||
|
/// @param topoFile DDS topology xml file
|
||||||
|
/// @param env DDS environment
|
||||||
|
explicit DDSTopology(Path topoFile, DDSEnvironment env = DDSEnvironment());
|
||||||
|
|
||||||
|
/// @brief Get associated DDS environment
|
||||||
|
auto GetEnv() const -> DDSEnvironment;
|
||||||
|
|
||||||
|
/// @brief Get path to DDS topology xml, if it is known
|
||||||
|
/// @throw std::runtime_error
|
||||||
|
auto GetTopoFile() const -> Path;
|
||||||
|
|
||||||
|
void CreateTopology(Path);
|
||||||
|
|
||||||
|
/// @brief Get number of required agents for this topology
|
||||||
|
int GetNumRequiredAgents();
|
||||||
|
|
||||||
|
/// @brief Get list of devices
|
||||||
|
std::vector<uint64_t> GetDeviceList();
|
||||||
|
|
||||||
|
/// @brief Get the name of the topology
|
||||||
|
// auto GetName() const -> std::string;
|
||||||
|
|
||||||
|
friend auto operator<<(std::ostream&, const DDSTopology&) -> std::ostream&;
|
||||||
|
|
||||||
auto GetId() const -> const std::string&;
|
|
||||||
auto IsRunning() const -> bool;
|
|
||||||
private:
|
private:
|
||||||
CSessionPtr fSession;
|
struct Impl;
|
||||||
const std::string fId;
|
std::shared_ptr<Impl> fImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto LoadDDSEnv(const std::string& config_home = "", const std::string& prefix = DDSInstallPrefix)
|
using DDSTopo = DDSTopology;
|
||||||
-> void;
|
|
||||||
|
|
||||||
} // namespace sdk
|
} // namespace sdk
|
||||||
} // namespace mq
|
} // namespace mq
|
||||||
|
|
|
@ -8,25 +8,166 @@
|
||||||
|
|
||||||
#include "Topology.h"
|
#include "Topology.h"
|
||||||
|
|
||||||
#include <DDS/Topology.h>
|
#include <fairlogger/Logger.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include <boost/algorithm/string/trim.hpp>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <thread>
|
||||||
|
#include <future>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
|
|
||||||
|
auto operator<<(std::ostream& os, AsyncOpResult v) -> std::ostream&
|
||||||
|
{
|
||||||
|
switch (v) {
|
||||||
|
case AsyncOpResult::Aborted:
|
||||||
|
return os << "Aborted";
|
||||||
|
case AsyncOpResult::Timeout:
|
||||||
|
return os << "Timeout";
|
||||||
|
case AsyncOpResult::Error:
|
||||||
|
return os << "Error";
|
||||||
|
case AsyncOpResult::Ok:
|
||||||
|
default:
|
||||||
|
return os << "Ok";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
|
|
||||||
struct Topology::Impl
|
const std::unordered_map<DeviceTransition, DeviceState, tools::HashEnum<DeviceTransition>> Topology::fkExpectedState =
|
||||||
{
|
{
|
||||||
Impl(dds::topology_api::CTopology topo)
|
{ Transition::InitDevice, DeviceState::InitializingDevice },
|
||||||
: fDDSTopology(std::move(topo))
|
{ Transition::CompleteInit, DeviceState::Initialized },
|
||||||
{}
|
{ Transition::Bind, DeviceState::Bound },
|
||||||
|
{ Transition::Connect, DeviceState::DeviceReady },
|
||||||
dds::topology_api::CTopology fDDSTopology;
|
{ Transition::InitTask, DeviceState::InitializingTask },
|
||||||
|
{ Transition::Run, DeviceState::Running },
|
||||||
|
{ Transition::Stop, DeviceState::Ready },
|
||||||
|
{ Transition::ResetTask, DeviceState::DeviceReady },
|
||||||
|
{ Transition::ResetDevice, DeviceState::Idle },
|
||||||
|
{ Transition::End, DeviceState::Exiting }
|
||||||
};
|
};
|
||||||
|
|
||||||
Topology::Topology(dds::topology_api::CTopology topo)
|
Topology::Topology(DDSTopology topo, DDSSession session)
|
||||||
: fImpl(std::make_shared<Impl>(std::move(topo)))
|
: fDDSSession(std::move(session))
|
||||||
{}
|
, fDDSTopo(std::move(topo))
|
||||||
|
, fTopologyState()
|
||||||
|
, fStateChangeOngoing(false)
|
||||||
|
, fExecutionThread()
|
||||||
|
, fShutdown(false)
|
||||||
|
{
|
||||||
|
fDDSTopo.CreateTopology(fDDSTopo.GetTopoFile());
|
||||||
|
|
||||||
|
std::vector<uint64_t> deviceList = fDDSTopo.GetDeviceList();
|
||||||
|
for (const auto& d : deviceList) {
|
||||||
|
fTopologyState.emplace(d, DeviceStatus{ false, DeviceState::Ok });
|
||||||
|
}
|
||||||
|
fDDSSession.SubscribeToCommands([this](const std::string& msg, const std::string& condition, uint64_t senderId) {
|
||||||
|
LOG(info) << "Received from " << senderId << ": " << msg;
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
boost::algorithm::split(parts, msg, boost::algorithm::is_any_of(":,"));
|
||||||
|
if (parts[0] == "state-change") {
|
||||||
|
boost::trim(parts[2]);
|
||||||
|
AddNewStateEntry(senderId, parts[2]);
|
||||||
|
} else if (parts[0] == "state-changes-subscription") {
|
||||||
|
if (parts[2] != "OK") {
|
||||||
|
LOG(error) << "state-changes-subscription failed with return code: " << parts[2];
|
||||||
|
}
|
||||||
|
} else if (parts[0] == "state-changes-unsubscription") {
|
||||||
|
if (parts[2] != "OK") {
|
||||||
|
LOG(error) << "state-changes-unsubscription failed with return code: " << parts[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fDDSSession.StartDDSService();
|
||||||
|
fDDSSession.SendCommand("subscribe-to-state-changes");
|
||||||
|
|
||||||
|
fExecutionThread = std::thread(&Topology::WaitForState, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Topology::ChangeState(fair::mq::Transition transition, ChangeStateCallback cb, const std::chrono::milliseconds& timeout) -> void
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(fMtx);
|
||||||
|
if (fStateChangeOngoing) {
|
||||||
|
LOG(error) << "State change already in progress, concurrent requested not yet supported";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fStateChangeOngoing = true;
|
||||||
|
fChangeStateCallback = cb;
|
||||||
|
fStateChangeTimeout = timeout;
|
||||||
|
|
||||||
|
fDDSSession.SendCommand(GetTransitionName(transition));
|
||||||
|
|
||||||
|
fTargetState = fkExpectedState.at(transition);
|
||||||
|
}
|
||||||
|
fExecutionCV.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Topology::WaitForState()
|
||||||
|
{
|
||||||
|
while (!fShutdown) {
|
||||||
|
if (fStateChangeOngoing) {
|
||||||
|
auto condition = [&] { return fShutdown || std::all_of(fTopologyState.cbegin(),
|
||||||
|
fTopologyState.cend(),
|
||||||
|
[&](TopologyState::value_type i) {
|
||||||
|
return i.second.state == fTargetState;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(fMtx);
|
||||||
|
|
||||||
|
if (fStateChangeTimeout > std::chrono::milliseconds(0)) {
|
||||||
|
if (!fCV.wait_for(lock, fStateChangeTimeout, condition)) {
|
||||||
|
LOG(debug) << "timeout";
|
||||||
|
// TODO: catch this from another thread...
|
||||||
|
throw std::runtime_error("timeout");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fCV.wait(lock, condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fShutdown) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fStateChangeOngoing = false;
|
||||||
|
fChangeStateCallback(ChangeStateResult{AsyncOpResult::Ok, fTopologyState});
|
||||||
|
} else {
|
||||||
|
std::unique_lock<std::mutex> lock(fExecutionMtx);
|
||||||
|
fExecutionCV.wait(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void Topology::AddNewStateEntry(uint64_t senderId, const std::string& state)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(fMtx);
|
||||||
|
fTopologyState[senderId] = DeviceStatus{ true, fair::mq::GetState(state) };
|
||||||
|
}
|
||||||
|
fCV.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
Topology::~Topology()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(fMtx);
|
||||||
|
fShutdown = true;
|
||||||
|
}
|
||||||
|
fExecutionCV.notify_one();
|
||||||
|
fExecutionThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator<<(std::ostream& os, Topology::ChangeStateResult v) -> std::ostream&
|
||||||
|
{
|
||||||
|
return os << v.rc;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sdk
|
} // namespace sdk
|
||||||
} // namespace mq
|
} // namespace mq
|
||||||
|
|
|
@ -9,25 +9,45 @@
|
||||||
#ifndef FAIR_MQ_SDK_TOPOLOGY_H
|
#ifndef FAIR_MQ_SDK_TOPOLOGY_H
|
||||||
#define FAIR_MQ_SDK_TOPOLOGY_H
|
#define FAIR_MQ_SDK_TOPOLOGY_H
|
||||||
|
|
||||||
|
#include <fairmq/sdk/DDSInfo.h>
|
||||||
|
#include <fairmq/sdk/DDSSession.h>
|
||||||
|
#include <fairmq/sdk/DDSTopology.h>
|
||||||
#include <fairmq/States.h>
|
#include <fairmq/States.h>
|
||||||
|
#include <fairmq/Tools.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <chrono>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace dds {
|
|
||||||
namespace topology_api {
|
|
||||||
|
|
||||||
class CTopology;
|
|
||||||
|
|
||||||
} // namespace topology_api
|
|
||||||
} // namespace dds
|
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
|
|
||||||
|
enum class AsyncOpResult {
|
||||||
|
Ok,
|
||||||
|
Timeout,
|
||||||
|
Error,
|
||||||
|
Aborted
|
||||||
|
};
|
||||||
|
auto operator<<(std::ostream& os, AsyncOpResult v) -> std::ostream&;
|
||||||
|
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
|
|
||||||
|
using DeviceState = fair::mq::State;
|
||||||
|
using DeviceTransition = fair::mq::Transition;
|
||||||
|
|
||||||
|
struct DeviceStatus
|
||||||
|
{
|
||||||
|
bool initialized;
|
||||||
|
DeviceState state;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TopologyState = std::unordered_map<uint64_t, DeviceStatus>;
|
||||||
|
using TopologyTransition = fair::mq::Transition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Topology Topology.h <fairmq/sdk/Topology.h>
|
* @class Topology Topology.h <fairmq/sdk/Topology.h>
|
||||||
* @brief Represents a FairMQ topology
|
* @brief Represents a FairMQ topology
|
||||||
|
@ -35,16 +55,46 @@ namespace sdk {
|
||||||
class Topology
|
class Topology
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// @brief (Re)Construct a FairMQ topology from an existing DDS topology
|
||||||
|
/// @param topo Initialized DDS CTopology
|
||||||
|
explicit Topology(DDSTopology topo, DDSSession session = DDSSession());
|
||||||
|
~Topology();
|
||||||
|
|
||||||
/// @brief Construct a FairMQ topology from an existing DDS session via the dds::topology_api
|
struct ChangeStateResult {
|
||||||
/// @param topo An initialized CTopology object
|
AsyncOpResult rc;
|
||||||
explicit Topology(dds::topology_api::CTopology topo);
|
TopologyState state;
|
||||||
|
friend auto operator<<(std::ostream& os, ChangeStateResult v) -> std::ostream&;
|
||||||
|
};
|
||||||
|
using ChangeStateCallback = std::function<void(ChangeStateResult)>;
|
||||||
|
|
||||||
|
/// @brief Initiate state transition on all FairMQ devices in this topology
|
||||||
|
/// @param t FairMQ device state machine transition
|
||||||
|
/// @param cb Completion callback
|
||||||
|
auto ChangeState(TopologyTransition t, ChangeStateCallback cb, const std::chrono::milliseconds& timeout = std::chrono::milliseconds(0)) -> void;
|
||||||
|
|
||||||
|
static const std::unordered_map<DeviceTransition, DeviceState, tools::HashEnum<DeviceTransition>> fkExpectedState;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Impl;
|
DDSSession fDDSSession;
|
||||||
std::shared_ptr<Impl> fImpl;
|
DDSTopology fDDSTopo;
|
||||||
|
TopologyState fTopologyState;
|
||||||
|
bool fStateChangeOngoing;
|
||||||
|
DeviceState fTargetState;
|
||||||
|
std::mutex fMtx;
|
||||||
|
std::mutex fExecutionMtx;
|
||||||
|
std::condition_variable fCV;
|
||||||
|
std::condition_variable fExecutionCV;
|
||||||
|
std::thread fExecutionThread;
|
||||||
|
ChangeStateCallback fChangeStateCallback;
|
||||||
|
std::chrono::milliseconds fStateChangeTimeout;
|
||||||
|
bool fShutdown;
|
||||||
|
|
||||||
|
void WaitForState();
|
||||||
|
void AddNewStateEntry(uint64_t senderId, const std::string& state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Topo = Topology;
|
||||||
|
|
||||||
} // namespace sdk
|
} // namespace sdk
|
||||||
} // namespace mq
|
} // namespace mq
|
||||||
} // namespace fair
|
} // namespace fair
|
||||||
|
|
|
@ -287,7 +287,7 @@ if(BUILD_SDK)
|
||||||
add_testsuite(SDK
|
add_testsuite(SDK
|
||||||
SOURCES
|
SOURCES
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||||
# sdk/_dds.cxx
|
sdk/_dds.cxx
|
||||||
sdk/_topology.cxx
|
sdk/_topology.cxx
|
||||||
sdk/TopologyFixture.h
|
sdk/TopologyFixture.h
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,10 @@
|
||||||
#include <fairmq/SDK.h>
|
#include <fairmq/SDK.h>
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
|
|
||||||
#include <DDS/Topology.h>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
|
@ -45,14 +43,14 @@ struct LoggerConfig
|
||||||
struct TopologyFixture : ::testing::Test
|
struct TopologyFixture : ::testing::Test
|
||||||
{
|
{
|
||||||
TopologyFixture()
|
TopologyFixture()
|
||||||
: mLoggerConfig()
|
: mDDSTopoFile(tools::ToString(SDK_TESTSUITE_SOURCE_DIR, "/test_topo.xml"))
|
||||||
, mDDSTopologyFile(std::string(SDK_TESTSUITE_SOURCE_DIR) + "/test_topo.xml")
|
|
||||||
, mDDSEnv(CMAKE_CURRENT_BINARY_DIR)
|
, mDDSEnv(CMAKE_CURRENT_BINARY_DIR)
|
||||||
, mDDSSession(mDDSEnv)
|
, mDDSSession(mDDSEnv)
|
||||||
, mDDSTopology(mDDSTopologyFile)
|
, mDDSTopo(mDDSTopoFile, mDDSEnv)
|
||||||
{}
|
{
|
||||||
//
|
mDDSSession.StopOnDestruction();
|
||||||
//
|
}
|
||||||
|
|
||||||
// auto ActivateDDSTopology(const std::string& topology_file) -> void {
|
// auto ActivateDDSTopology(const std::string& topology_file) -> void {
|
||||||
// LOG(debug) << "ActivateDDSTopology(\"" << topology_file << "\")";
|
// LOG(debug) << "ActivateDDSTopology(\"" << topology_file << "\")";
|
||||||
// }
|
// }
|
||||||
|
@ -60,20 +58,22 @@ struct TopologyFixture : ::testing::Test
|
||||||
auto SetUp() -> void override {
|
auto SetUp() -> void override {
|
||||||
LOG(info) << mDDSEnv;
|
LOG(info) << mDDSEnv;
|
||||||
LOG(info) << mDDSSession;
|
LOG(info) << mDDSSession;
|
||||||
|
mDDSSession.RequestCommanderInfo();
|
||||||
mDDSSession.SubmitAgents(2);
|
mDDSSession.SubmitAgents(2);
|
||||||
|
mDDSSession.RequestCommanderInfo();
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1)); // TODO implement WaitForIdleAgents
|
std::this_thread::sleep_for(std::chrono::seconds(1)); // TODO implement WaitForIdleAgents
|
||||||
mDDSSession.ActivateTopology(mDDSTopologyFile);
|
mDDSSession.ActivateTopology(mDDSTopoFile);
|
||||||
|
mDDSSession.RequestCommanderInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto TearDown() -> void override {
|
auto TearDown() -> void override {
|
||||||
mDDSSession.Stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LoggerConfig mLoggerConfig;
|
LoggerConfig mLoggerConfig;
|
||||||
std::string mDDSTopologyFile;
|
std::string mDDSTopoFile;
|
||||||
sdk::DDSEnvironment mDDSEnv;
|
sdk::DDSEnvironment mDDSEnv;
|
||||||
sdk::DDSSession mDDSSession;
|
sdk::DDSSession mDDSSession;
|
||||||
dds::topology_api::CTopology mDDSTopology;
|
sdk::DDSTopology mDDSTopo;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace test */
|
} /* namespace test */
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
auto session_test() -> void
|
auto setup() -> void
|
||||||
{
|
{
|
||||||
fair::Logger::SetConsoleSeverity("debug");
|
fair::Logger::SetConsoleSeverity("debug");
|
||||||
fair::Logger::DefineVerbosity("user1",
|
fair::Logger::DefineVerbosity("user1",
|
||||||
|
@ -23,35 +23,24 @@ auto session_test() -> void
|
||||||
fair::VerbositySpec::Info::severity));
|
fair::VerbositySpec::Info::severity));
|
||||||
fair::Logger::SetVerbosity("user1");
|
fair::Logger::SetVerbosity("user1");
|
||||||
fair::Logger::SetConsoleColor();
|
fair::Logger::SetConsoleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DDS, Environment)
|
||||||
|
{
|
||||||
|
setup();
|
||||||
|
|
||||||
fair::mq::sdk::DDSEnvironment env(CMAKE_CURRENT_BINARY_DIR);
|
fair::mq::sdk::DDSEnvironment env(CMAKE_CURRENT_BINARY_DIR);
|
||||||
LOG(debug) << env;
|
LOG(debug) << env;
|
||||||
{
|
|
||||||
fair::mq::sdk::DDSSession session(env);
|
|
||||||
LOG(debug) << session;
|
|
||||||
session.SubmitAgents(5);
|
|
||||||
session.SubmitAgents(5);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
fair::mq::sdk::DDSSession session(env);
|
|
||||||
LOG(debug) << session;
|
|
||||||
session.SubmitAgents(5);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
fair::mq::sdk::DDSSession session(env);
|
|
||||||
LOG(debug) << session;
|
|
||||||
session.SubmitAgents(5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DDS, Session)
|
TEST(DDS, Session)
|
||||||
{
|
{
|
||||||
session_test();
|
setup();
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DDS, Session2)
|
fair::mq::sdk::DDSEnvironment env(CMAKE_CURRENT_BINARY_DIR);
|
||||||
{
|
fair::mq::sdk::DDSSession session(env);
|
||||||
session_test();
|
session.StopOnDestruction();
|
||||||
|
LOG(debug) << session;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
#include "TopologyFixture.h"
|
#include "TopologyFixture.h"
|
||||||
|
|
||||||
|
#include <DDS/Topology.h>
|
||||||
#include <fairmq/sdk/Topology.h>
|
#include <fairmq/sdk/Topology.h>
|
||||||
|
#include <fairmq/Tools.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -16,7 +18,21 @@ using Topology = fair::mq::test::TopologyFixture;
|
||||||
|
|
||||||
TEST_F(Topology, Construction)
|
TEST_F(Topology, Construction)
|
||||||
{
|
{
|
||||||
fair::mq::sdk::Topology topo(mDDSTopology);
|
fair::mq::sdk::Topology topo(mDDSTopo, mDDSSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Topology, ChangeState)
|
||||||
|
{
|
||||||
|
using fair::mq::sdk::Topology;
|
||||||
|
using fair::mq::sdk::TopologyTransition;
|
||||||
|
|
||||||
|
Topology topo(mDDSTopo, mDDSSession);
|
||||||
|
fair::mq::tools::Semaphore blocker;
|
||||||
|
topo.ChangeState(TopologyTransition::Stop, [&](Topology::ChangeStateResult result) {
|
||||||
|
LOG(info) << result;
|
||||||
|
blocker.Signal();
|
||||||
|
});
|
||||||
|
blocker.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue
Block a user