mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-15 09:31:45 +00:00
Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f6e3183f45 | ||
|
71325828f6 | ||
|
9d30ff25c2 | ||
|
2ac8f98178 | ||
|
2c6f436858 | ||
|
dd191551ca | ||
|
88dbcbe4fd | ||
|
85a3a254d4 | ||
|
c34d1f0946 | ||
|
160ee9d064 | ||
|
040931fba7 | ||
|
0d46ffe010 | ||
|
72a8e9b33c | ||
|
caeee626a3 | ||
|
e1134321dd | ||
|
5fc1c47e2a | ||
|
2f69526c04 | ||
|
7502f4b424 | ||
|
1c1509af3e | ||
|
a53e95b5f6 | ||
|
ea9ad64664 | ||
|
b9720e5269 | ||
|
343605899f | ||
|
d64169a163 | ||
|
37c8041997 | ||
|
d8d293302d | ||
|
9544d9665b | ||
|
47d9e282d4 | ||
|
23423a86d9 | ||
|
dc72262af1 | ||
|
44bfbe02ed | ||
|
924320a0ac | ||
|
e3890a4033 | ||
|
fa394194e8 | ||
|
79bcb40c04 | ||
|
54719da645 | ||
|
4b78c472b1 | ||
|
92112c812f | ||
|
870d0deae1 | ||
|
acbf57d6f3 | ||
|
2973ce0352 | ||
|
e1b6b804bd | ||
|
456b65871a |
@@ -1,2 +1,3 @@
|
||||
comment:
|
||||
layout: "diff, files"
|
||||
behavior: once
|
||||
|
@@ -39,14 +39,16 @@ fairmq_build_option(BUILD_NANOMSG_TRANSPORT "Build nanomsg transport."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_SDK_COMMANDS "Build the FairMQ SDK commands."
|
||||
DEFAULT OFF)
|
||||
fairmq_build_option(BUILD_DDS_PLUGIN "Build DDS plugin."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
|
||||
fairmq_build_option(BUILD_PMIX_PLUGIN "Build PMIx plugin."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_EXAMPLES "Build FairMQ examples."
|
||||
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_SDK "Build the FairMQ controller SDK."
|
||||
DEFAULT OFF REQUIRES "BUILD_DDS_PLUGIN")
|
||||
DEFAULT OFF REQUIRES "BUILD_DDS_PLUGIN;BUILD_SDK_COMMANDS")
|
||||
fairmq_build_option(BUILD_DOCS "Build FairMQ documentation."
|
||||
DEFAULT OFF)
|
||||
fairmq_build_option(FAST_BUILD "Fast production build. Not recommended for development."
|
||||
@@ -89,6 +91,10 @@ else()
|
||||
set(required_dds_version 2.4)
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
find_package2(PRIVATE Flatbuffers REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_DDS_PLUGIN OR BUILD_SDK)
|
||||
find_package2(PRIVATE DDS REQUIRED
|
||||
VERSION ${required_dds_version}
|
||||
@@ -155,7 +161,7 @@ endif()
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
find_package2(PRIVATE ZeroMQ REQUIRED
|
||||
VERSION 4.1.5
|
||||
VERSION 4.1.4
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -230,6 +236,9 @@ endif()
|
||||
if(BUILD_SDK)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk)
|
||||
endif()
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk_commands)
|
||||
endif()
|
||||
################################################################################
|
||||
|
||||
|
||||
@@ -295,7 +304,7 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
message(STATUS " ")
|
||||
message(STATUS " ${Cyan}DEPENDENCY FOUND VERSION PREFIX${CR}")
|
||||
foreach(dep IN LISTS PROJECT_PACKAGE_DEPENDENCIES)
|
||||
if(${dep}_VERSION)
|
||||
if(${dep}_VERSION AND NOT ${dep}_VERSION STREQUAL "..")
|
||||
set(version_str "${BGreen}${${dep}_VERSION}${CR}")
|
||||
else()
|
||||
set(version_str "${BYellow}unknown${CR}")
|
||||
@@ -343,6 +352,13 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
elseif(${dep} STREQUAL fmt)
|
||||
get_target_property(fmt_include fmt::fmt INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${fmt_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL Flatbuffers)
|
||||
if(TARGET flatbuffers::flatbuffers)
|
||||
get_target_property(flatbuffers_include flatbuffers::flatbuffers INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
get_target_property(flatbuffers_include flatbuffers::flatbuffers_shared INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
get_filename_component(prefix ${flatbuffers_include}/.. ABSOLUTE)
|
||||
else()
|
||||
get_filename_component(prefix ${${dep}_INCLUDE_DIR}/.. ABSOLUTE)
|
||||
endif()
|
||||
@@ -410,6 +426,12 @@ else()
|
||||
set(sdk_summary "${BRed} NO${CR} EXPERIMENTAL (required C++14) (default, enable with ${BMagenta}-DBUILD_SDK=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}sdk${CR} ${sdk_summary}")
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
set(sdk_commands_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_SDK_COMMANDS=OFF${CR})")
|
||||
else()
|
||||
set(sdk_commands_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_SDK_COMMANDS=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}sdk_commands${CR} ${sdk_commands_summary}")
|
||||
message(STATUS " ")
|
||||
if(RUN_STATIC_ANALYSIS)
|
||||
list(LENGTH PROJECT_STATIC_ANALYSERS size)
|
||||
|
@@ -29,13 +29,14 @@ Set(configure_options "${configure_options};-DCMAKE_PREFIX_PATH=$ENV{SIMPATH}")
|
||||
Set(configure_options "${configure_options};-DBUILD_NANOMSG_TRANSPORT=ON")
|
||||
# Set(configure_options "${configure_options};-DBUILD_OFI_TRANSPORT=ON")
|
||||
Set(configure_options "${configure_options};-DBUILD_DDS_PLUGIN=ON")
|
||||
Set(configure_options "${configure_options};-DBUILD_SDK=OFF")
|
||||
Set(configure_options "${configure_options};-DBUILD_SDK=ON")
|
||||
Set(configure_options "${configure_options};-DBUILD_SDK_COMMANDS=ON")
|
||||
Set(configure_options "${configure_options};-DFAST_BUILD=ON")
|
||||
Set(configure_options "${configure_options};-DCOTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES=-j$ENV{number_of_processors}")
|
||||
|
||||
Set(EXTRA_FLAGS $ENV{EXTRA_FLAGS})
|
||||
If(EXTRA_FLAGS)
|
||||
Set(configure_options "${configure_options};${EXTRA_FLAGS}")
|
||||
Set(configure_options "${configure_options};${EXTRA_FLAGS}")
|
||||
EndIf()
|
||||
|
||||
If($ENV{ctest_model} MATCHES Profile)
|
||||
@@ -43,6 +44,7 @@ If($ENV{ctest_model} MATCHES Profile)
|
||||
If(GCOV_COMMAND)
|
||||
Message("Found GCOV: ${GCOV_COMMAND}")
|
||||
Set(CTEST_COVERAGE_COMMAND ${GCOV_COMMAND})
|
||||
set(CTEST_COVERAGE_EXTRA_FLAGS "-p")
|
||||
EndIf(GCOV_COMMAND)
|
||||
EndIf()
|
||||
|
||||
@@ -58,7 +60,7 @@ Ctest_Configure(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
|
||||
Ctest_Build(BUILD "${CTEST_BINARY_DIRECTORY}")
|
||||
|
||||
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
# PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
RETURN_VALUE _ctest_test_ret_val
|
||||
@@ -78,7 +80,7 @@ If("$ENV{do_codecov_upload}")
|
||||
EndIf()
|
||||
|
||||
Ctest_Submit()
|
||||
|
||||
|
||||
if (_ctest_test_ret_val)
|
||||
Message(FATAL_ERROR "Some tests failed.")
|
||||
endif()
|
||||
|
16
Jenkinsfile
vendored
16
Jenkinsfile
vendored
@@ -22,11 +22,11 @@ def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc8/) {
|
||||
if (os =~ /Debian/ && compiler =~ /gcc9/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/8" >> Dart.cfg
|
||||
echo "module load compiler/gcc/9.1.0" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /MacOS/) {
|
||||
@@ -49,6 +49,10 @@ def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
deleteDir()
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS')
|
||||
} catch (e) {
|
||||
def tarball = "${prefix}_${label}_dds_logs.tar.gz"
|
||||
sh "tar czvf ${tarball} -C \${WORKSPACE}/build/test/ .DDS/"
|
||||
archiveArtifacts tarball
|
||||
|
||||
deleteDir()
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR')
|
||||
throw e
|
||||
@@ -65,16 +69,16 @@ pipeline{
|
||||
stage("Run CI Matrix") {
|
||||
steps{
|
||||
script {
|
||||
def build_jobs = jobMatrix('alfa-ci/build', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
def build_jobs = jobMatrix('build', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc9.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.14', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
sh './Dart.sh alfa_ci Dart.cfg'
|
||||
}
|
||||
|
||||
def profile_jobs = jobMatrix('alfa-ci/codecov', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
def profile_jobs = jobMatrix('codecov', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc9.1.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
withCredentials([string(credentialsId: 'fairmq_codecov_token', variable: 'CODECOV_TOKEN')]) {
|
||||
sh './Dart.sh codecov Dart.cfg'
|
||||
|
@@ -21,11 +21,11 @@ def buildMatrix(List specs, Closure callback) {
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc8/) {
|
||||
if (os =~ /Debian/ && compiler =~ /gcc9/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/8" >> Dart.cfg
|
||||
echo "module load compiler/gcc/9.1.0" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /MacOS/) {
|
||||
@@ -46,6 +46,10 @@ def buildMatrix(List specs, Closure callback) {
|
||||
|
||||
deleteDir()
|
||||
} catch (e) {
|
||||
def tarball = "${label}_dds_logs.tar.gz"
|
||||
sh "tar czvf ${tarball} -C \${WORKSPACE}/build/test/ .DDS/"
|
||||
archiveArtifacts tarball
|
||||
|
||||
deleteDir()
|
||||
throw e
|
||||
}
|
||||
@@ -63,7 +67,7 @@ pipeline{
|
||||
steps{
|
||||
script {
|
||||
parallel(buildMatrix([
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc9.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.14', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
|
@@ -181,4 +181,5 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
|
||||
3. [Provided Plugins](docs/Plugins.md#73-provided-plugins)
|
||||
1. [DDS](docs/Plugins.md#731-dds)
|
||||
2. [PMIx](docs/Plugins.md#732-pmix)
|
||||
8. [Controller SDK](docs/SDK.md)
|
||||
|
||||
|
@@ -194,6 +194,13 @@ macro(set_fairmq_defaults)
|
||||
endif()
|
||||
list(APPEND PROJECT_STATIC_ANALYSERS "${analyser}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_GENERATOR STREQUAL Ninja AND ENABLE_CCACHE)
|
||||
find_program(CCACHE ccache)
|
||||
if(CCACHE)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(join VALUES GLUE OUTPUT)
|
||||
@@ -445,6 +452,23 @@ macro(exec cmd)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(exec_source cmd)
|
||||
join("${ARGN}" " " args)
|
||||
file(APPEND ${${package}_BUILD_LOGFILE} ">>> ${cmd} ${args}\n")
|
||||
|
||||
execute_process(COMMAND ${cmd} ${ARGN}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE log
|
||||
ERROR_VARIABLE log
|
||||
RESULT_VARIABLE res
|
||||
)
|
||||
file(APPEND ${${package}_BUILD_LOGFILE} ${log})
|
||||
|
||||
if(res)
|
||||
message(FATAL_ERROR "${res} \nSee also \"${${package}_BUILD_LOGFILE}\"")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(build_bundled package bundle)
|
||||
message(STATUS "Building bundled ${package}")
|
||||
|
||||
@@ -455,7 +479,7 @@ function(build_bundled package bundle)
|
||||
file(REMOVE ${${package}_BUILD_LOGFILE})
|
||||
|
||||
if(Git_FOUND)
|
||||
exec(${GIT_EXECUTABLE} submodule update --init --recursive -- ${${package}_SOURCE_DIR})
|
||||
exec_source(${GIT_EXECUTABLE} submodule update --init -- ${${package}_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
if(${package} STREQUAL GTest)
|
||||
@@ -482,7 +506,7 @@ function(build_bundled package bundle)
|
||||
endfunction()
|
||||
|
||||
macro(fairmq_build_option option description)
|
||||
cmake_parse_arguments(ARGS "" "DEFAULT;REQUIRES" "" ${ARGN})
|
||||
cmake_parse_arguments(ARGS "" "DEFAULT" "REQUIRES" ${ARGN})
|
||||
|
||||
if(ARGS_DEFAULT)
|
||||
set(__default__ ON)
|
||||
@@ -493,19 +517,21 @@ macro(fairmq_build_option option description)
|
||||
if(ARGS_REQUIRES)
|
||||
include(CMakeDependentOption)
|
||||
set(__requires__ ${ARGS_REQUIRES})
|
||||
string(REGEX REPLACE " +" ";" __requires_condition__ "${__requires__}")
|
||||
if(${__requires_condition__})
|
||||
else()
|
||||
if(${option})
|
||||
message(WARNING "Cannot enable build option ${option}, depending options are not set: ${__requires_condition__}.")
|
||||
foreach(d ${__requires__})
|
||||
string(REGEX REPLACE " +" ";" __requires_condition__ "${d}")
|
||||
if(${__requires_condition__})
|
||||
else()
|
||||
if(${option})
|
||||
message(WARNING "Cannot enable build option ${option}, depending option is not set: ${__requires_condition__}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
set(__requires__)
|
||||
endif()
|
||||
|
||||
if(__requires__)
|
||||
cmake_dependent_option(${option} ${description} ${__default__} ${__requires__} OFF)
|
||||
cmake_dependent_option(${option} ${description} ${__default__} "${__requires__}" OFF)
|
||||
else()
|
||||
option(${option} ${description} ${__default__})
|
||||
endif()
|
||||
|
34
docs/SDK.md
Normal file
34
docs/SDK.md
Normal file
@@ -0,0 +1,34 @@
|
||||
← [Back](../README.md)
|
||||
|
||||
# 8. Controller SDK
|
||||
|
||||
The FairMQ Controller Software Development Kit (`-DBUILD_SDK=ON`) contains a (as of today still experimental) set of C++ APIs that provide essential functionality to the implementer of a global controller.
|
||||
|
||||
The FairMQ core library only provides two local controllers - `static` (a fixed sequence of state transitions) and `interactive` (a read-eval-print-loop which reads keyboard commands from standard input). A local controller only knows how steer a single [FairMQ device](Device.md) - in fact, it runs in a thread within the device process.
|
||||
|
||||
A global controller has knowledge about the full topology of connected FairMQ devices. Its responsibility is to facilitate the lifecycle of a distributed FairMQ-based application (*executing a topology*), such as
|
||||
|
||||
* allocating/releasing compute resources from a resource management system,
|
||||
* launching/setting up the run-time environment and the FairMQ devices,
|
||||
* driving the device state machines in lock-step across the full topology,
|
||||
* pushing the device configuration,
|
||||
* monitoring (some aspects of the application's) operation,
|
||||
* and handling/reporting (some) error cases.
|
||||
|
||||
The low-level hook to integrate FairMQ devices with such a global contoller is the [plugin mechanism](Plugins.md) in the FairMQ core library. The FairMQ Controller SDK provides C++ APIs that communicate to the endpoints exposed by such a FairMQ plugin.
|
||||
|
||||
At the moment, the Controller SDK only supports [DDS](https://dds.gsi.de) as resource manager and run-time environment. A second implementation based on [PMIx](https://pmix.org/) (targeting its implementation in [Slurm](https://slurm.schedmd.com/documentation.html) and [OpenRTE](https://www-lb.open-mpi.org/papers/euro-pvmmpi-2005-orte/)) is in development.
|
||||
|
||||
The following section give a short overview on the APIs provided.
|
||||
|
||||
## RMS and run-time environment
|
||||
|
||||
The classes [`fair::mq::sdk::DDSEnvironment`](../fairmq/sdk/DDSEnvironment.h), [`fair::mq::sdk::DDSSession`](../fairmq/sdk/DDSSession.h), and [`fair::mq::sdk::DDSTopology`](../fairmq/sdk/DDSTopology.h) are thin wrappers of most of the synchronous APIs exposed by DDS ([`dds::tools_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1tools__api.html) and [`dds::topology_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1topology__api.html)). E.g. they allow to [start a DDS session](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L26-L28), [allocate resources](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L34) and [launch a topology](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L39) from a C++ program.
|
||||
|
||||
## Driving the global state machine
|
||||
|
||||
The class [`fair::mq::sdk::Topology`](../fairmq/sdk/Topology.h) adds a FairMQ-specific view on an existing DDS session that is executing a topology of FairMQ devices. One can e.g. [initiate a state transition on all devices in the topology simultaneously](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L48-L49). This topology transition completes once a topology-wide barrier is passed (all devices completed the transition). This effectively exposes the device state machine as a topology state machine. The implementation is based on remote procedure calls over the [DDS intercom service](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1intercom__api.html) between the controller and the DDS plugin shipped with FairMQ (`-DBUILD_DDS_PLUGIN=ON`).
|
||||
|
||||
For future versions of the SDK new APIs are planned to inspect and modify the device configurations and also operate only on subsets of a given topology.
|
||||
|
||||
← [Back](../README.md)
|
@@ -6,9 +6,6 @@
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <thread> // this_thread::sleep_for
|
||||
#include <chrono>
|
||||
|
||||
#include "Sampler.h"
|
||||
|
||||
using namespace std;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<topology name="ExampleDDS">
|
||||
|
||||
<property name="data1" />
|
||||
<property name="data2" />
|
||||
<property name="fmqchan_data1" />
|
||||
<property name="fmqchan_data2" />
|
||||
|
||||
<declrequirement name="SamplerWorker" type="wnname" value="sampler"/>
|
||||
<declrequirement name="ProcessorWorker" type="wnname" value="processor"/>
|
||||
@@ -14,7 +14,7 @@
|
||||
<name>SamplerWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="write">data1</name>
|
||||
<name access="write">fmqchan_data1</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
<name>ProcessorWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="read">data1</name>
|
||||
<name access="read">data2</name>
|
||||
<name access="read">fmqchan_data1</name>
|
||||
<name access="read">fmqchan_data2</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<name>SinkWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="write">data2</name>
|
||||
<name access="write">fmqchan_data2</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<topology name="ExampleDDS">
|
||||
|
||||
<property name="data1" />
|
||||
<property name="data2" />
|
||||
<property name="fmqchan_data1" />
|
||||
<property name="fmqchan_data2" />
|
||||
|
||||
<declrequirement name="SamplerWorker" type="wnname" value="sampler"/>
|
||||
<declrequirement name="ProcessorWorker" type="wnname" value="processor"/>
|
||||
@@ -14,7 +14,7 @@
|
||||
<name>SamplerWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="write">data1</name>
|
||||
<name access="write">fmqchan_data1</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
<name>ProcessorWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="read">data1</name>
|
||||
<name access="read">data2</name>
|
||||
<name access="read">fmqchan_data1</name>
|
||||
<name access="read">fmqchan_data2</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<name>SinkWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="write">data2</name>
|
||||
<name access="write">fmqchan_data2</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
|
@@ -32,19 +32,19 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multipart.sh.in ${CMA
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multipart.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh)
|
||||
|
||||
add_test(NAME Example.Multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
|
||||
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.Multipart.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
|
||||
set_tests_properties(Example.Multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
set_tests_properties(Example.Multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.Multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
|
||||
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
add_test(NAME Example.Multipart.ofi COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh ofi)
|
||||
set_tests_properties(Example.Multipart.ofi PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
set_tests_properties(Example.Multipart.ofi PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
|
||||
endif()
|
||||
|
||||
# install
|
||||
|
@@ -40,8 +40,7 @@ bool Sampler::ConditionalRun()
|
||||
header.stopFlag = 0;
|
||||
|
||||
// Set stopFlag to 1 for last message.
|
||||
if (fMaxIterations > 0 && fNumIterations == fMaxIterations - 1)
|
||||
{
|
||||
if (fMaxIterations > 0 && fNumIterations == fMaxIterations - 1) {
|
||||
header.stopFlag = 1;
|
||||
}
|
||||
LOG(info) << "Sending header with stopFlag: " << header.stopFlag;
|
||||
@@ -60,13 +59,20 @@ bool Sampler::ConditionalRun()
|
||||
assert(auxData.Size() == 0);
|
||||
assert(parts.Size() == 5);
|
||||
|
||||
parts.AddPart(NewMessage());
|
||||
|
||||
assert(parts.Size() == 6);
|
||||
|
||||
parts.AddPart(NewMessage(100));
|
||||
|
||||
assert(parts.Size() == 7);
|
||||
|
||||
LOG(info) << "Sending body of size: " << parts.At(1)->GetSize();
|
||||
|
||||
Send(parts, "data");
|
||||
|
||||
// Go out of the sending loop if the stopFlag was sent.
|
||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations)
|
||||
{
|
||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
|
||||
return false;
|
||||
}
|
||||
@@ -77,8 +83,4 @@ bool Sampler::ConditionalRun()
|
||||
return true;
|
||||
}
|
||||
|
||||
Sampler::~Sampler()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace example_multipart
|
||||
|
@@ -24,7 +24,7 @@ class Sampler : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Sampler();
|
||||
virtual ~Sampler();
|
||||
virtual ~Sampler() {}
|
||||
|
||||
protected:
|
||||
virtual void InitTask();
|
||||
|
@@ -20,23 +20,28 @@ using namespace std;
|
||||
namespace example_multipart
|
||||
{
|
||||
|
||||
Sink::Sink()
|
||||
{
|
||||
OnData("data", &Sink::HandleData);
|
||||
}
|
||||
|
||||
bool Sink::HandleData(FairMQParts& parts, int /*index*/)
|
||||
{
|
||||
LOG(info) << "Received message with " << parts.Size() << " parts";
|
||||
|
||||
Header header;
|
||||
header.stopFlag = (static_cast<Header*>(parts.At(0)->GetData()))->stopFlag;
|
||||
|
||||
LOG(info) << "Received message with " << parts.Size() << " parts";
|
||||
LOG(info) << "Received part 1 (header) with stopFlag: " << header.stopFlag;
|
||||
LOG(info) << "Received part 2 of size: " << parts.At(1)->GetSize();
|
||||
assert(parts.At(1)->GetSize() == 1000);
|
||||
LOG(info) << "Received part 3 of size: " << parts.At(2)->GetSize();
|
||||
assert(parts.At(2)->GetSize() == 500);
|
||||
LOG(info) << "Received part 4 of size: " << parts.At(3)->GetSize();
|
||||
assert(parts.At(3)->GetSize() == 600);
|
||||
LOG(info) << "Received part 5 of size: " << parts.At(4)->GetSize();
|
||||
assert(parts.At(4)->GetSize() == 700);
|
||||
LOG(info) << "Received part 6 of size: " << parts.At(5)->GetSize();
|
||||
assert(parts.At(5)->GetSize() == 0);
|
||||
LOG(info) << "Received part 7 of size: " << parts.At(6)->GetSize();
|
||||
assert(parts.At(6)->GetSize() == 100);
|
||||
|
||||
LOG(info) << "Received header with stopFlag: " << header.stopFlag;
|
||||
LOG(info) << "Received body of size: " << parts.At(1)->GetSize();
|
||||
|
||||
if (header.stopFlag == 1)
|
||||
{
|
||||
if (header.stopFlag == 1) {
|
||||
LOG(info) << "stopFlag is 1, going IDLE";
|
||||
return false;
|
||||
}
|
||||
@@ -44,8 +49,4 @@ bool Sink::HandleData(FairMQParts& parts, int /*index*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
Sink::~Sink()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,8 +23,8 @@ namespace example_multipart
|
||||
class Sink : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Sink();
|
||||
virtual ~Sink();
|
||||
Sink() { OnData("data", &Sink::HandleData); }
|
||||
virtual ~Sink() {}
|
||||
|
||||
protected:
|
||||
bool HandleData(FairMQParts&, int);
|
||||
|
@@ -2,12 +2,24 @@
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
transport="zeromq"
|
||||
|
||||
if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
SAMPLER="fairmq-ex-multipart-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
|
||||
SINK="fairmq-ex-multipart-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --session $SESSION"
|
||||
SINK+=" --channel-config name=data,type=pull,method=bind,rateLogging=0,address=tcp://127.0.0.1:5555"
|
||||
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$SINK &
|
||||
|
@@ -31,10 +31,12 @@ SENDER="fairmq-ex-readout-sender"
|
||||
SENDER+=" --id sender1"
|
||||
SENDER+=" --input-name ps"
|
||||
SENDER+=" --channel-config name=ps,type=pair,method=bind,address=tcp://localhost:7779,transport=shmem"
|
||||
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7780,transport=ofi"
|
||||
#SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7780,transport=ofi"
|
||||
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7780,transport=zeromq"
|
||||
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SENDER &
|
||||
|
||||
RECEIVER="fairmq-ex-readout-receiver"
|
||||
RECEIVER+=" --id receiver1"
|
||||
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7780,transport=ofi"
|
||||
#RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7780,transport=ofi"
|
||||
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7780,transport=zeromq"
|
||||
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &
|
||||
|
@@ -25,10 +25,12 @@ SENDER="fairmq-ex-readout-sender"
|
||||
SENDER+=" --id sender1"
|
||||
SENDER+=" --input-name bs"
|
||||
SENDER+=" --channel-config name=bs,type=pair,method=bind,address=tcp://localhost:7778,transport=shmem"
|
||||
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7779,transport=ofi"
|
||||
# SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7779,transport=ofi"
|
||||
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7779,transport=zeromq"
|
||||
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SENDER &
|
||||
|
||||
RECEIVER="fairmq-ex-readout-receiver"
|
||||
RECEIVER+=" --id receiver1"
|
||||
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7779,transport=ofi"
|
||||
# RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7779,transport=ofi"
|
||||
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7779,transport=zeromq"
|
||||
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &
|
||||
|
@@ -460,6 +460,10 @@ if(BUILD_FAIRMQ)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
add_subdirectory(sdk/commands)
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK)
|
||||
add_subdirectory(sdk)
|
||||
endif()
|
||||
|
@@ -12,12 +12,10 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
@@ -7,7 +7,8 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "FairMQChannel.h"
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <fairmq/Properties.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp> // join/split
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#define FAIRMQCHANNEL_H_
|
||||
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <FairMQUnmanagedRegion.h>
|
||||
#include <FairMQSocket.h>
|
||||
#include <fairmq/Transports.h>
|
||||
#include <FairMQLogger.h>
|
||||
@@ -17,15 +18,14 @@
|
||||
#include <fairmq/Properties.h>
|
||||
#include <FairMQMessage.h>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory> // unique_ptr, shared_ptr
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <utility> // std::move
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // int64_t
|
||||
|
||||
class FairMQChannel
|
||||
{
|
||||
|
@@ -8,19 +8,15 @@
|
||||
|
||||
#include <FairMQDevice.h>
|
||||
|
||||
#include <fairmq/tools/RateLimit.h>
|
||||
#include <fairmq/tools/Network.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp> // join/split
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <future>
|
||||
#include <algorithm> // std::max
|
||||
|
@@ -14,7 +14,6 @@
|
||||
#include <fairmq/Transports.h>
|
||||
#include <fairmq/StateQueue.h>
|
||||
|
||||
#include <FairMQSocket.h>
|
||||
#include <FairMQChannel.h>
|
||||
#include <FairMQMessage.h>
|
||||
#include <FairMQParts.h>
|
||||
@@ -24,21 +23,19 @@
|
||||
|
||||
#include <vector>
|
||||
#include <memory> // unique_ptr
|
||||
#include <algorithm> // std::sort()
|
||||
#include <algorithm> // find
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <assert.h> // static_assert
|
||||
#include <type_traits> // is_trivially_copyable
|
||||
#include <stdexcept>
|
||||
#include <queue>
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <utility> // pair
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/Version.h>
|
||||
|
||||
using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
|
||||
|
||||
@@ -149,15 +146,6 @@ class FairMQDevice
|
||||
return GetChannel(channel, index).Receive(msg, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
int SendAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msg, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return GetChannel(channel, index).Send(msg, 0);
|
||||
}
|
||||
int ReceiveAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msg, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return GetChannel(channel, index).Receive(msg, 0);
|
||||
}
|
||||
|
||||
/// Shorthand method to send FairMQParts on `chan` at index `i`
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
@@ -180,15 +168,6 @@ class FairMQDevice
|
||||
return GetChannel(channel, index).Receive(parts.fParts, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
int64_t SendAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(parts, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return GetChannel(channel, index).Send(parts.fParts, 0);
|
||||
}
|
||||
int64_t ReceiveAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(parts, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return GetChannel(channel, index).Receive(parts.fParts, 0);
|
||||
}
|
||||
|
||||
/// @brief Getter for default transport factory
|
||||
auto Transport() const -> FairMQTransportFactory*
|
||||
{
|
||||
@@ -292,9 +271,6 @@ class FairMQDevice
|
||||
return channels.at(0)->Transport()->CreatePoller(channels);
|
||||
}
|
||||
|
||||
/// Waits for the first initialization run to finish
|
||||
void WaitForInitialValidation() __attribute__((deprecated("This method will have no effect in future versions and will be removed. Instead subscribe for state changes and inspect configuration values."))) {}
|
||||
|
||||
/// Adds a transport to the device if it doesn't exist
|
||||
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
|
||||
std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
|
||||
|
@@ -33,7 +33,7 @@ class FairMQParts
|
||||
FairMQParts& operator=(const FairMQParts&) = delete;
|
||||
/// Constructor from argument pack of std::unique_ptr<FairMQMessage> rvalues
|
||||
template <typename... Ts>
|
||||
FairMQParts(Ts&&... messages) : fParts() {AddPart(std::forward<Ts>(messages)...);}
|
||||
FairMQParts(Ts&&... messages) : fParts() { AddPart(std::forward<Ts>(messages)...); }
|
||||
/// Default destructor
|
||||
~FairMQParts() {};
|
||||
|
||||
@@ -63,10 +63,10 @@ class FairMQParts
|
||||
/// Add content of another object by move
|
||||
void AddPart(FairMQParts&& other)
|
||||
{
|
||||
container parts = std::move(other.fParts);
|
||||
for (auto& part : parts) {
|
||||
fParts.push_back(std::move(part));
|
||||
}
|
||||
container parts = std::move(other.fParts);
|
||||
for (auto& part : parts) {
|
||||
fParts.push_back(std::move(part));
|
||||
}
|
||||
}
|
||||
|
||||
/// Get reference to part in the container at index (without bounds check)
|
||||
|
@@ -16,11 +16,10 @@
|
||||
#include <fairmq/ofi/TransportFactory.h>
|
||||
#endif
|
||||
#include <FairMQLogger.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/Unique.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
FairMQTransportFactory::FairMQTransportFactory(const std::string& id)
|
||||
: fkId(id)
|
||||
|
@@ -12,7 +12,6 @@
|
||||
#include <FairMQLogger.h>
|
||||
#include <FairMQMessage.h>
|
||||
#include <FairMQPoller.h>
|
||||
#include <fairmq/ProgOptionsFwd.h>
|
||||
#include <FairMQSocket.h>
|
||||
#include <FairMQUnmanagedRegion.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
@@ -22,8 +21,11 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
#include <cstddef> // size_t
|
||||
|
||||
class FairMQChannel;
|
||||
namespace fair { namespace mq { class ProgOptions; } }
|
||||
|
||||
class FairMQTransportFactory
|
||||
{
|
||||
|
@@ -23,11 +23,7 @@ class FairMQTransportFactory;
|
||||
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
|
||||
#include <boost/container/pmr/polymorphic_allocator.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
|
@@ -9,7 +9,8 @@
|
||||
#ifndef FAIR_MQ_PLUGIN_H
|
||||
#define FAIR_MQ_PLUGIN_H
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/CppSTL.h>
|
||||
#include <fairmq/tools/Version.h>
|
||||
#include <fairmq/PluginServices.h>
|
||||
|
||||
#include <boost/dll/alias.hpp>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <fairmq/plugins/Builtin.h>
|
||||
#include <fairmq/PluginManager.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
@@ -11,8 +11,9 @@
|
||||
|
||||
#include <fairmq/Plugin.h>
|
||||
#include <fairmq/PluginServices.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <FairMQDevice.h>
|
||||
#include <fairmq/tools/CppSTL.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define BOOST_FILESYSTEM_NO_DEPRECATED
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -21,13 +22,14 @@
|
||||
#include <boost/dll/import.hpp>
|
||||
#include <boost/dll/shared_library.hpp>
|
||||
#include <boost/dll/runtime_symbol_info.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <utility> // forward
|
||||
|
||||
namespace fair
|
||||
{
|
||||
|
@@ -7,6 +7,7 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include <fairmq/PluginServices.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
using namespace fair::mq;
|
||||
using namespace std;
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#ifndef FAIR_MQ_PLUGINSERVICES_H
|
||||
#define FAIR_MQ_PLUGINSERVICES_H
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/States.h>
|
||||
#include <FairMQDevice.h>
|
||||
#include <fairmq/ProgOptions.h>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
#include "FairMQLogger.h"
|
||||
#include <fairmq/ProgOptions.h>
|
||||
|
||||
#include "tools/Unique.h"
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
@@ -14,7 +14,7 @@
|
||||
#include <fairmq/EventManager.h>
|
||||
#include <fairmq/ProgOptionsFwd.h>
|
||||
#include <fairmq/Properties.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#ifndef FAIR_MQ_TRANSPORTS_H
|
||||
#define FAIR_MQ_TRANSPORTS_H
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/CppSTL.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@@ -8,10 +8,9 @@
|
||||
|
||||
#include "FairMQBenchmarkSampler.h"
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include "tools/RateLimit.h"
|
||||
#include "../FairMQLogger.h"
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
@@ -27,10 +26,6 @@ FairMQBenchmarkSampler::FairMQBenchmarkSampler()
|
||||
{
|
||||
}
|
||||
|
||||
FairMQBenchmarkSampler::~FairMQBenchmarkSampler()
|
||||
{
|
||||
}
|
||||
|
||||
void FairMQBenchmarkSampler::InitTask()
|
||||
{
|
||||
fMultipart = fConfig->GetProperty<bool>("multipart");
|
||||
|
@@ -10,8 +10,10 @@
|
||||
#define FAIRMQBENCHMARKSAMPLER_H_
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint64_t
|
||||
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
@@ -23,7 +25,7 @@ class FairMQBenchmarkSampler : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
FairMQBenchmarkSampler();
|
||||
virtual ~FairMQBenchmarkSampler();
|
||||
virtual ~FairMQBenchmarkSampler() {}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
|
@@ -17,7 +17,6 @@
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "FairMQPoller.h"
|
||||
#include "FairMQChannel.h"
|
||||
|
@@ -427,6 +427,9 @@ auto Control::RunShutdownSequence() -> void
|
||||
case DeviceState::Idle:
|
||||
ChangeDeviceState(DeviceStateTransition::End);
|
||||
break;
|
||||
case DeviceState::InitializingDevice:
|
||||
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
||||
break;
|
||||
case DeviceState::Initialized:
|
||||
case DeviceState::Bound:
|
||||
case DeviceState::DeviceReady:
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
set(plugin FairMQPlugin_dds)
|
||||
add_library(${plugin} SHARED ${CMAKE_CURRENT_SOURCE_DIR}/DDS.cxx ${CMAKE_CURRENT_SOURCE_DIR}/DDS.h)
|
||||
target_link_libraries(${plugin} FairMQ DDS::dds_intercom_lib DDS::dds_protocol_lib)
|
||||
target_link_libraries(${plugin} PUBLIC FairMQ StateMachine DDS::dds_intercom_lib DDS::dds_protocol_lib Boost::boost PRIVATE Commands)
|
||||
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_target_properties(${plugin} PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
set_target_properties(${plugin} PROPERTIES
|
||||
@@ -19,7 +19,7 @@ set_target_properties(${plugin} PROPERTIES
|
||||
|
||||
set(exe fairmq-dds-command-ui)
|
||||
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
||||
target_link_libraries(${exe} FairMQ DDS::dds_intercom_lib DDS::dds_protocol_lib)
|
||||
target_link_libraries(${exe} FairMQ Commands StateMachine DDS::dds_intercom_lib DDS::dds_protocol_lib)
|
||||
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
install(TARGETS ${plugin} ${exe}
|
||||
|
@@ -8,18 +8,18 @@
|
||||
|
||||
#include "DDS.h"
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
|
||||
#include <termios.h> // for the interactive mode
|
||||
#include <poll.h> // for the interactive mode
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using fair::mq::tools::ToString;
|
||||
@@ -54,19 +54,20 @@ DDS::DDS(const string& name,
|
||||
, fExitingAckedByLastExternalController(false)
|
||||
, fHeartbeatInterval(100)
|
||||
, fUpdatesAllowed(false)
|
||||
, fWorkGuard(fWorkerQueue.get_executor())
|
||||
{
|
||||
try {
|
||||
TakeDeviceControl();
|
||||
|
||||
fHeartbeatThread = thread(&DDS::HeartbeatSender, this);
|
||||
|
||||
std::string deviceId(GetProperty<std::string>("id"));
|
||||
string deviceId(GetProperty<string>("id"));
|
||||
if (deviceId.empty()) {
|
||||
SetProperty<std::string>("id", dds::env_prop<dds::task_path>());
|
||||
SetProperty<string>("id", dds::env_prop<dds::task_path>());
|
||||
}
|
||||
std::string sessionId(GetProperty<std::string>("session"));
|
||||
string sessionId(GetProperty<string>("session"));
|
||||
if (sessionId == "default") {
|
||||
SetProperty<std::string>("session", dds::env_prop<dds::dds_session_id>());
|
||||
SetProperty<string>("session", dds::env_prop<dds::dds_session_id>());
|
||||
}
|
||||
|
||||
auto control = GetProperty<string>("control");
|
||||
@@ -83,7 +84,6 @@ DDS::DDS(const string& name,
|
||||
|
||||
SubscribeForCustomCommands();
|
||||
SubscribeForConnectingChannels();
|
||||
fDDS.Start();
|
||||
|
||||
// subscribe to device state changes, pushing new state changes into the event queue
|
||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
||||
@@ -99,11 +99,16 @@ DDS::DDS(const string& name,
|
||||
PublishBoundChannels();
|
||||
break;
|
||||
case DeviceState::ResettingDevice: {
|
||||
std::lock_guard<std::mutex> lk(fUpdateMutex);
|
||||
fUpdatesAllowed = false;
|
||||
{
|
||||
lock_guard<mutex> lk(fUpdateMutex);
|
||||
fUpdatesAllowed = false;
|
||||
}
|
||||
|
||||
EmptyChannelContainers();
|
||||
break;
|
||||
}
|
||||
case DeviceState::Exiting:
|
||||
fWorkGuard.reset();
|
||||
fDeviceTerminationRequested = true;
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
ReleaseDeviceControl();
|
||||
@@ -116,15 +121,22 @@ DDS::DDS(const string& name,
|
||||
string id = GetProperty<string>("id");
|
||||
fLastState = fCurrentState;
|
||||
fCurrentState = newState;
|
||||
using namespace sdk::cmd;
|
||||
for (auto subscriberId : fStateChangeSubscribers) {
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
||||
fDDS.Send("state-change: " + id + "," + ToString(dds::env_prop<dds::task_id>()) + "," + ToStr(fLastState) + "->" + ToStr(newState), to_string(subscriberId));
|
||||
|
||||
Cmds cmds(make<StateChange>(id, dds::env_prop<dds::task_id>(), fLastState, fCurrentState));
|
||||
fDDS.Send(cmds.Serialize(), to_string(subscriberId));
|
||||
}
|
||||
});
|
||||
|
||||
if (staticMode) {
|
||||
fControllerThread = thread(&DDS::StaticControl, this);
|
||||
} else {
|
||||
StartWorkerThread();
|
||||
}
|
||||
|
||||
fDDS.Start();
|
||||
} catch (PluginServices::DeviceControlError& e) {
|
||||
LOG(debug) << e.what();
|
||||
} catch (exception& e) {
|
||||
@@ -132,6 +144,19 @@ DDS::DDS(const string& name,
|
||||
}
|
||||
}
|
||||
|
||||
void DDS::EmptyChannelContainers()
|
||||
{
|
||||
fBindingChans.clear();
|
||||
fConnectingChans.clear();
|
||||
}
|
||||
|
||||
auto DDS::StartWorkerThread() -> void
|
||||
{
|
||||
fWorkerThread = thread([this]() {
|
||||
fWorkerQueue.run();
|
||||
});
|
||||
}
|
||||
|
||||
auto DDS::WaitForExitingAck() -> void
|
||||
{
|
||||
unique_lock<mutex> lock(fStateChangeSubscriberMutex);
|
||||
@@ -156,7 +181,7 @@ auto DDS::StaticControl() -> void
|
||||
ReleaseDeviceControl();
|
||||
} catch (exception& e) {
|
||||
ReleaseDeviceControl();
|
||||
LOG(error) << "Error: " << e.what() << endl;
|
||||
LOG(error) << "Error: " << e.what() << "\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -227,7 +252,7 @@ auto DDS::FillChannelContainers() -> void
|
||||
fIofN.insert(make_pair(chanName, IofN(i, n)));
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(fUpdateMutex);
|
||||
lock_guard<mutex> lk(fUpdateMutex);
|
||||
fUpdatesAllowed = true;
|
||||
}
|
||||
fUpdateCondition.notify_one();
|
||||
@@ -240,60 +265,70 @@ auto DDS::SubscribeForConnectingChannels() -> void
|
||||
{
|
||||
LOG(debug) << "Subscribing for DDS properties.";
|
||||
|
||||
fDDS.SubscribeKeyValue([&] (const string& propertyId, const string& value, uint64_t senderTaskID) {
|
||||
try {
|
||||
LOG(debug) << "Received update for " << propertyId << ": value=" << value << ", senderTaskID=" << senderTaskID;
|
||||
fDDS.SubscribeKeyValue([&] (const string& key, const string& value, uint64_t senderTaskID) {
|
||||
LOG(debug) << "Received property: key=" << key << ", value=" << value << ", senderTaskID=" << senderTaskID;
|
||||
|
||||
std::unique_lock<std::mutex> lk(fUpdateMutex);
|
||||
fUpdateCondition.wait(lk, [&]{ return fUpdatesAllowed; });
|
||||
|
||||
string val = value;
|
||||
// check if it is to handle as one out of multiple values
|
||||
auto it = fIofN.find(propertyId);
|
||||
if (it != fIofN.end()) {
|
||||
it->second.fEntries.push_back(value);
|
||||
if (it->second.fEntries.size() == it->second.fN) {
|
||||
sort(it->second.fEntries.begin(), it->second.fEntries.end());
|
||||
val = it->second.fEntries.at(it->second.fI);
|
||||
} else {
|
||||
LOG(debug) << "received " << it->second.fEntries.size() << " values for " << propertyId << ", expecting total of " << it->second.fN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> connectionStrings;
|
||||
boost::algorithm::split(connectionStrings, val, boost::algorithm::is_any_of(","));
|
||||
if (connectionStrings.size() > 1) { // multiple bound channels received
|
||||
auto it2 = fI.find(propertyId);
|
||||
if (it2 != fI.end()) {
|
||||
LOG(debug) << "adding connecting channel " << propertyId << " : " << connectionStrings.at(it2->second);
|
||||
fConnectingChans.at(propertyId).fDDSValues.insert({senderTaskID, connectionStrings.at(it2->second).c_str()});
|
||||
} else {
|
||||
LOG(error) << "multiple bound channels received, but no task index specified, only assigning the first";
|
||||
fConnectingChans.at(propertyId).fDDSValues.insert({senderTaskID, connectionStrings.at(0).c_str()});
|
||||
}
|
||||
} else { // only one bound channel received
|
||||
fConnectingChans.at(propertyId).fDDSValues.insert({senderTaskID, val.c_str()});
|
||||
}
|
||||
|
||||
// update channels and remove them from unfinished container
|
||||
for (auto mi = fConnectingChans.begin(); mi != fConnectingChans.end(); /* no increment */) {
|
||||
if (mi->second.fSubChannelAddresses.size() == mi->second.fDDSValues.size()) {
|
||||
// when multiple subChannels are used, their order on every device should be the same, irregardless of arrival order from DDS.
|
||||
sort(mi->second.fSubChannelAddresses.begin(), mi->second.fSubChannelAddresses.end());
|
||||
auto it3 = mi->second.fDDSValues.begin();
|
||||
for (unsigned int i = 0; i < mi->second.fSubChannelAddresses.size(); ++i) {
|
||||
SetProperty<string>(string{"chans." + mi->first + "." + to_string(i) + ".address"}, it3->second);
|
||||
++it3;
|
||||
}
|
||||
fConnectingChans.erase(mi++);
|
||||
} else {
|
||||
++mi;
|
||||
}
|
||||
}
|
||||
} catch (const exception& e) {
|
||||
LOG(error) << "Error on handling DDS property update for " << propertyId << ": value=" << value << ", senderTaskID=" << senderTaskID << ": " << e.what();
|
||||
if (key.compare(0, 8, "fmqchan_") != 0) {
|
||||
LOG(debug) << "property update is not a channel info update: " << key;
|
||||
return;
|
||||
}
|
||||
string channelName = key.substr(8);
|
||||
LOG(info) << "Update for channel name: " << channelName;
|
||||
|
||||
boost::asio::post(fWorkerQueue, [=]() {
|
||||
try {
|
||||
{
|
||||
unique_lock<mutex> lk(fUpdateMutex);
|
||||
fUpdateCondition.wait(lk, [&]{ return fUpdatesAllowed; });
|
||||
}
|
||||
string val = value;
|
||||
// check if it is to handle as one out of multiple values
|
||||
auto it = fIofN.find(channelName);
|
||||
if (it != fIofN.end()) {
|
||||
it->second.fEntries.push_back(value);
|
||||
if (it->second.fEntries.size() == it->second.fN) {
|
||||
sort(it->second.fEntries.begin(), it->second.fEntries.end());
|
||||
val = it->second.fEntries.at(it->second.fI);
|
||||
} else {
|
||||
LOG(debug) << "received " << it->second.fEntries.size() << " values for " << channelName << ", expecting total of " << it->second.fN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> connectionStrings;
|
||||
boost::algorithm::split(connectionStrings, val, boost::algorithm::is_any_of(","));
|
||||
if (connectionStrings.size() > 1) { // multiple bound channels received
|
||||
auto it2 = fI.find(channelName);
|
||||
if (it2 != fI.end()) {
|
||||
LOG(debug) << "adding connecting channel " << channelName << " : " << connectionStrings.at(it2->second);
|
||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, connectionStrings.at(it2->second).c_str()});
|
||||
} else {
|
||||
LOG(error) << "multiple bound channels received, but no task index specified, only assigning the first";
|
||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, connectionStrings.at(0).c_str()});
|
||||
}
|
||||
} else { // only one bound channel received
|
||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, val.c_str()});
|
||||
}
|
||||
|
||||
// update channels and remove them from unfinished container
|
||||
for (auto mi = fConnectingChans.begin(); mi != fConnectingChans.end(); /* no increment */) {
|
||||
if (mi->second.fSubChannelAddresses.size() == mi->second.fDDSValues.size()) {
|
||||
// when multiple subChannels are used, their order on every device should be the same, irregardless of arrival order from DDS.
|
||||
sort(mi->second.fSubChannelAddresses.begin(), mi->second.fSubChannelAddresses.end());
|
||||
auto it3 = mi->second.fDDSValues.begin();
|
||||
for (unsigned int i = 0; i < mi->second.fSubChannelAddresses.size(); ++i) {
|
||||
SetProperty<string>(string{"chans." + mi->first + "." + to_string(i) + ".address"}, it3->second);
|
||||
++it3;
|
||||
}
|
||||
fConnectingChans.erase(mi++);
|
||||
} else {
|
||||
++mi;
|
||||
}
|
||||
}
|
||||
} catch (const exception& e) {
|
||||
LOG(error) << "Error handling DDS property: key=" << key << ", value=" << value << ", senderTaskID=" << senderTaskID << ": " << e.what();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -301,13 +336,14 @@ auto DDS::PublishBoundChannels() -> void
|
||||
{
|
||||
for (const auto& chan : fBindingChans) {
|
||||
string joined = boost::algorithm::join(chan.second, ",");
|
||||
LOG(debug) << "Publishing " << chan.first << " bound addresses (" << chan.second.size() << ") to DDS under '" << chan.first << "' property name.";
|
||||
fDDS.PutValue(chan.first, joined);
|
||||
LOG(debug) << "Publishing bound addresses (" << chan.second.size() << ") of channel '" << chan.first << "' to DDS under '" << "fmqchan_" + chan.first << "' property name.";
|
||||
fDDS.PutValue("fmqchan_" + chan.first, joined);
|
||||
}
|
||||
}
|
||||
|
||||
auto DDS::HeartbeatSender() -> void
|
||||
{
|
||||
using namespace sdk::cmd;
|
||||
string id = GetProperty<string>("id");
|
||||
|
||||
while (!fDeviceTerminationRequested) {
|
||||
@@ -315,7 +351,7 @@ auto DDS::HeartbeatSender() -> void
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
|
||||
for (const auto subscriberId : fHeartbeatSubscribers) {
|
||||
fDDS.Send("heartbeat: " + id , to_string(subscriberId));
|
||||
fDDS.Send(Cmds(make<Heartbeat>(id)).Serialize(), to_string(subscriberId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,86 +361,100 @@ auto DDS::HeartbeatSender() -> void
|
||||
|
||||
auto DDS::SubscribeForCustomCommands() -> void
|
||||
{
|
||||
using namespace sdk::cmd;
|
||||
LOG(debug) << "Subscribing for DDS custom commands.";
|
||||
|
||||
string id = GetProperty<string>("id");
|
||||
|
||||
fDDS.SubscribeCustomCmd([id, this](const string& cmd, const string& cond, uint64_t senderId) {
|
||||
LOG(info) << "Received command: '" << cmd << "' from " << senderId;
|
||||
fDDS.SubscribeCustomCmd([id, this](const string& cmdStr, const string& cond, uint64_t senderId) {
|
||||
// LOG(info) << "Received command: '" << cmdStr << "' from " << senderId;
|
||||
|
||||
if (cmd == "check-state") {
|
||||
fDDS.Send(id + ": " + ToStr(GetCurrentDeviceState()), to_string(senderId));
|
||||
} else if (fTransitions.find(cmd) != fTransitions.end()) {
|
||||
if (ChangeDeviceState(ToDeviceStateTransition(cmd))) {
|
||||
fDDS.Send(id + ": queued, " + cmd, to_string(senderId));
|
||||
} else {
|
||||
fDDS.Send(id + ": could not queue, " + cmd, to_string(senderId));
|
||||
}
|
||||
if (cmd == "END" && ToStr(GetCurrentDeviceState()) == "EXITING") {
|
||||
unique_lock<mutex> lock(fStopMutex);
|
||||
fStopCondition.notify_one();
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fLastExternalController = senderId;
|
||||
}
|
||||
} else if (cmd == "dump-config") {
|
||||
stringstream ss;
|
||||
for (const auto pKey: GetPropertyKeys()) {
|
||||
ss << id << ": " << pKey << " -> " << GetPropertyAsString(pKey) << endl;
|
||||
}
|
||||
fDDS.Send(ss.str(), to_string(senderId));
|
||||
} else if (cmd == "subscribe-to-heartbeats") {
|
||||
{
|
||||
// auto size = fHeartbeatSubscribers.size();
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
fHeartbeatSubscribers.insert(senderId);
|
||||
}
|
||||
fDDS.Send("heartbeat-subscription: " + id + ",OK", to_string(senderId));
|
||||
} else if (cmd == "unsubscribe-from-heartbeats") {
|
||||
{
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
fHeartbeatSubscribers.erase(senderId);
|
||||
}
|
||||
fDDS.Send("heartbeat-unsubscription: " + id + ",OK", to_string(senderId));
|
||||
} else if (cmd == "state-change-exiting-received") {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
if (fLastExternalController == senderId) {
|
||||
fExitingAckedByLastExternalController = true;
|
||||
Cmds inCmds;
|
||||
inCmds.Deserialize(cmdStr);
|
||||
|
||||
for (const auto& cmd : inCmds) {
|
||||
switch (cmd->GetType()) {
|
||||
case Type::check_state: {
|
||||
fDDS.Send(Cmds(make<CurrentState>(id, GetCurrentDeviceState())).Serialize(), to_string(senderId));
|
||||
}
|
||||
}
|
||||
fExitingAcked.notify_one();
|
||||
} else if (cmd == "subscribe-to-state-changes") {
|
||||
{
|
||||
// auto size = fStateChangeSubscribers.size();
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.insert(senderId);
|
||||
if (!fControllerThread.joinable()) {
|
||||
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
||||
break;
|
||||
case Type::change_state: {
|
||||
Transition transition = static_cast<ChangeState&>(*cmd).GetTransition();
|
||||
if (ChangeDeviceState(transition)) {
|
||||
Cmds outCmds(make<TransitionStatus>(id, Result::Ok, transition));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} else {
|
||||
Cmds outCmds(make<TransitionStatus>(id, Result::Failure, transition));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::dump_config: {
|
||||
stringstream ss;
|
||||
for (const auto pKey: GetPropertyKeys()) {
|
||||
ss << id << ": " << pKey << " -> " << GetPropertyAsString(pKey) << "\n";
|
||||
}
|
||||
Cmds outCmds(make<Config>(id, ss.str()));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::subscribe_to_heartbeats: {
|
||||
{
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
fHeartbeatSubscribers.insert(senderId);
|
||||
}
|
||||
Cmds outCmds(make<HeartbeatSubscription>(id, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_heartbeats: {
|
||||
{
|
||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
||||
fHeartbeatSubscribers.erase(senderId);
|
||||
}
|
||||
Cmds outCmds(make<HeartbeatUnsubscription>(id, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::state_change_exiting_received: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
if (fLastExternalController == senderId) {
|
||||
fExitingAckedByLastExternalController = true;
|
||||
}
|
||||
}
|
||||
fExitingAcked.notify_one();
|
||||
}
|
||||
break;
|
||||
case Type::subscribe_to_state_change: {
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.insert(senderId);
|
||||
if (!fControllerThread.joinable()) {
|
||||
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
||||
}
|
||||
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << senderId;
|
||||
|
||||
Cmds outCmds(make<StateChangeSubscription>(id, Result::Ok), make<StateChange>(id, dds::env_prop<dds::task_id>(), fLastState, fCurrentState));
|
||||
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_state_change: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.erase(senderId);
|
||||
}
|
||||
Cmds outCmds(make<StateChangeUnsubscription>(id, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(warn) << "Unexpected/unknown command received: " << cmdStr;
|
||||
LOG(warn) << "Origin: " << senderId;
|
||||
LOG(warn) << "Destination: " << cond;
|
||||
break;
|
||||
}
|
||||
fDDS.Send("state-changes-subscription: " + id + ",OK", to_string(senderId));
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << senderId;
|
||||
// fDDSCustomCmd.send("state-change: " + id + "," + ToStr(fLastState) + "->" + ToStr(fCurrentState), to_string(senderId));
|
||||
fDDS.Send("state-change: " + id + "," + ToString(dds::env_prop<dds::task_id>()) + "," + ToStr(fLastState) + "->" + ToStr(fCurrentState), to_string(senderId));
|
||||
}
|
||||
} else if (cmd == "unsubscribe-from-state-changes") {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.erase(senderId);
|
||||
}
|
||||
fDDS.Send("state-changes-unsubscription: " + id + ",OK", to_string(senderId));
|
||||
} else if (cmd == "SHUTDOWN") {
|
||||
TransitionDeviceStateTo(DeviceState::Exiting);
|
||||
} else if (cmd == "STARTUP") {
|
||||
TransitionDeviceStateTo(DeviceState::Running);
|
||||
} else {
|
||||
LOG(warn) << "Unknown command: " << cmd;
|
||||
LOG(warn) << "Origin: " << senderId;
|
||||
LOG(warn) << "Destination: " << cond;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -421,6 +471,11 @@ DDS::~DDS()
|
||||
if (fHeartbeatThread.joinable()) {
|
||||
fHeartbeatThread.join();
|
||||
}
|
||||
|
||||
fWorkGuard.reset();
|
||||
if (fWorkerThread.joinable()) {
|
||||
fWorkerThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace plugins */
|
||||
|
@@ -9,19 +9,24 @@
|
||||
#ifndef FAIR_MQ_PLUGINS_DDS
|
||||
#define FAIR_MQ_PLUGINS_DDS
|
||||
|
||||
#include <DDS/dds_env_prop.h>
|
||||
#include <DDS/dds_intercom.h>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <fairmq/Plugin.h>
|
||||
#include <fairmq/StateQueue.h>
|
||||
#include <fairmq/Version.h>
|
||||
#include <functional>
|
||||
|
||||
#include <DDS/dds_env_prop.h>
|
||||
#include <DDS/dds_intercom.h>
|
||||
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -130,8 +135,11 @@ class DDS : public Plugin
|
||||
private:
|
||||
auto StaticControl() -> void;
|
||||
auto WaitForExitingAck() -> void;
|
||||
auto StartWorkerThread() -> void;
|
||||
|
||||
auto FillChannelContainers() -> void;
|
||||
auto EmptyChannelContainers() -> void;
|
||||
|
||||
auto SubscribeForConnectingChannels() -> void;
|
||||
auto PublishBoundChannels() -> void;
|
||||
auto SubscribeForCustomCommands() -> void;
|
||||
@@ -172,6 +180,10 @@ class DDS : public Plugin
|
||||
bool fUpdatesAllowed;
|
||||
std::mutex fUpdateMutex;
|
||||
std::condition_variable fUpdateCondition;
|
||||
|
||||
std::thread fWorkerThread;
|
||||
boost::asio::io_context fWorkerQueue;
|
||||
boost::asio::executor_work_guard<boost::asio::executor> fWorkGuard;
|
||||
};
|
||||
|
||||
Plugin::ProgOptions DDSProgramOptions()
|
||||
|
@@ -6,27 +6,26 @@
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
#include <fairmq/States.h>
|
||||
|
||||
#include <DDS/dds_intercom.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <cstdlib>
|
||||
#include <DDS/dds_intercom.h>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <termios.h> // raw mode console input
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <termios.h> // raw mode console input
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dds::intercom_api;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
struct TerminalConfig
|
||||
@@ -50,7 +49,8 @@ struct TerminalConfig
|
||||
}
|
||||
};
|
||||
|
||||
struct StateSubscription {
|
||||
struct StateSubscription
|
||||
{
|
||||
const string& fTopologyPath;
|
||||
CCustomCmd& fDdsCustomCmd;
|
||||
|
||||
@@ -58,11 +58,11 @@ struct StateSubscription {
|
||||
: fTopologyPath(topologyPath)
|
||||
, fDdsCustomCmd(ddsCustomCmd)
|
||||
{
|
||||
fDdsCustomCmd.send("subscribe-to-state-changes", fTopologyPath);
|
||||
fDdsCustomCmd.send(Cmds(make<SubscribeToStateChange>()).Serialize(), fTopologyPath);
|
||||
}
|
||||
|
||||
~StateSubscription() {
|
||||
fDdsCustomCmd.send("unsubscribe-from-state-changes", fTopologyPath);
|
||||
fDdsCustomCmd.send(Cmds(make<UnsubscribeFromStateChange>()).Serialize(), fTopologyPath);
|
||||
this_thread::sleep_for(chrono::milliseconds(100)); // give dds a chance to complete request
|
||||
}
|
||||
};
|
||||
@@ -74,7 +74,7 @@ void printControlsHelp()
|
||||
cout << "To quit press Ctrl+C" << endl;
|
||||
}
|
||||
|
||||
void commandMode(const string& commandIn, const string& topologyPath, CCustomCmd& ddsCustomCmd) {
|
||||
void sendCommand(const string& commandIn, const string& topologyPath, CCustomCmd& ddsCustomCmd) {
|
||||
char c;
|
||||
string command(commandIn);
|
||||
TerminalConfig tconfig;
|
||||
@@ -88,52 +88,43 @@ void commandMode(const string& commandIn, const string& topologyPath, CCustomCmd
|
||||
while (true) {
|
||||
if (command == "c") {
|
||||
cout << "> checking state of the devices" << endl;
|
||||
ddsCustomCmd.send("check-state", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<CheckState>()).Serialize(), topologyPath);
|
||||
} else if (command == "o") {
|
||||
cout << "> dumping config of the devices" << endl;
|
||||
ddsCustomCmd.send("dump-config", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<DumpConfig>()).Serialize(), topologyPath);
|
||||
} else if (command == "i") {
|
||||
cout << "> init devices" << endl;
|
||||
ddsCustomCmd.send("INIT DEVICE", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::InitDevice)).Serialize(), topologyPath);
|
||||
} else if (command == "k") {
|
||||
cout << "> complete init" << endl;
|
||||
ddsCustomCmd.send("COMPLETE INIT", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::CompleteInit)).Serialize(), topologyPath);
|
||||
} else if (command == "b") {
|
||||
cout << "> bind devices" << endl;
|
||||
ddsCustomCmd.send("BIND", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Bind)).Serialize(), topologyPath);
|
||||
} else if (command == "x") {
|
||||
cout << "> connect devices" << endl;
|
||||
ddsCustomCmd.send("CONNECT", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Connect)).Serialize(), topologyPath);
|
||||
} else if (command == "j") {
|
||||
cout << "> init tasks" << endl;
|
||||
ddsCustomCmd.send("INIT TASK", topologyPath);
|
||||
} else if (command == "p") {
|
||||
cout << "> pause devices" << endl;
|
||||
ddsCustomCmd.send("PAUSE", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::InitTask)).Serialize(), topologyPath);
|
||||
} else if (command == "r") {
|
||||
cout << "> run tasks" << endl;
|
||||
ddsCustomCmd.send("RUN", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Run)).Serialize(), topologyPath);
|
||||
} else if (command == "s") {
|
||||
cout << "> stop devices" << endl;
|
||||
ddsCustomCmd.send("STOP", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Stop)).Serialize(), topologyPath);
|
||||
} else if (command == "t") {
|
||||
cout << "> reset tasks" << endl;
|
||||
ddsCustomCmd.send("RESET TASK", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::ResetTask)).Serialize(), topologyPath);
|
||||
} else if (command == "d") {
|
||||
cout << "> reset devices" << endl;
|
||||
ddsCustomCmd.send("RESET DEVICE", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::ResetDevice)).Serialize(), topologyPath);
|
||||
} else if (command == "h") {
|
||||
cout << "> help" << endl;
|
||||
printControlsHelp();
|
||||
} else if (command == "q") {
|
||||
cout << "> end" << endl;
|
||||
ddsCustomCmd.send("END", topologyPath);
|
||||
} else if (command == "q!") {
|
||||
cout << "> shutdown" << endl;
|
||||
ddsCustomCmd.send("SHUTDOWN", topologyPath);
|
||||
} else if (command == "r!") {
|
||||
cout << "> startup" << endl;
|
||||
ddsCustomCmd.send("STARTUP", topologyPath);
|
||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::End)).Serialize(), topologyPath);
|
||||
} else {
|
||||
cout << "\033[01;32mInvalid input: [" << c << "]\033[0m" << endl;
|
||||
printControlsHelp();
|
||||
@@ -152,33 +143,36 @@ void commandMode(const string& commandIn, const string& topologyPath, CCustomCmd
|
||||
struct WaitMode
|
||||
{
|
||||
explicit WaitMode(const string& targetState)
|
||||
: fTargetState(targetState)
|
||||
{}
|
||||
: fTransitionedCount(0)
|
||||
{
|
||||
if (targetState != "") {
|
||||
size_t n = targetState.find("->");
|
||||
if (n == string::npos) {
|
||||
fTargetStatePair.first = fair::mq::State::Ok;
|
||||
fTargetStatePair.second = fair::mq::GetState(targetState);
|
||||
} else {
|
||||
fTargetStatePair.first = fair::mq::GetState(targetState.substr(0, n));
|
||||
fTargetStatePair.second = fair::mq::GetState(targetState.substr(n + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Run(const chrono::milliseconds& timeout,
|
||||
const string& topologyPath,
|
||||
CCustomCmd& ddsCustomCmd,
|
||||
unsigned int numberDevices,
|
||||
const string& command = "")
|
||||
void Run(const chrono::milliseconds& timeout, const string& topologyPath, CCustomCmd& ddsCustomCmd, unsigned int numDevices, const string& command = "")
|
||||
{
|
||||
StateSubscription stateSubscription(topologyPath, ddsCustomCmd);
|
||||
|
||||
if (command != "") {
|
||||
commandMode(command, topologyPath, ddsCustomCmd);
|
||||
sendCommand(command, topologyPath, ddsCustomCmd);
|
||||
}
|
||||
|
||||
// TODO once DDS provides an API to retrieve actual number of tasks, use it here
|
||||
auto condition = [&] {
|
||||
bool res(!fTargetStates.empty()
|
||||
&& all_of(fTargetStates.cbegin(),
|
||||
fTargetStates.cend(),
|
||||
[&](unordered_map<uint64_t, string>::value_type i) {
|
||||
return boost::algorithm::ends_with(i.second, fTargetState);
|
||||
}));
|
||||
if (numberDevices > 0) {
|
||||
res = res && (fTargetStates.size() == numberDevices);
|
||||
bool res = fTransitionedCount == numDevices;
|
||||
if (fTargetStatePair.first == fair::mq::State::Ok) {
|
||||
cout << "Waiting for " << numDevices << " devices to reach " << fTargetStatePair.second << ", condition check: " << res << endl;
|
||||
} else {
|
||||
cout << "Waiting for " << numDevices << " devices to reach " << fTargetStatePair.first << "->" << fTargetStatePair.second << ", condition check: " << res << endl;
|
||||
}
|
||||
cout << "waiting for " << numberDevices << " devices to reach " << fTargetState << ", condition check: " << res << endl;
|
||||
return res;
|
||||
};
|
||||
|
||||
@@ -191,21 +185,33 @@ struct WaitMode
|
||||
} else {
|
||||
fCV.wait(lock, condition);
|
||||
}
|
||||
|
||||
// cout << "WaitMode.Run() finished" << endl;
|
||||
}
|
||||
|
||||
void AddNewStateEntry(uint64_t senderId, const string& state)
|
||||
void CountStates(fair::mq::State lastState, fair::mq::State currentState)
|
||||
{
|
||||
{
|
||||
unique_lock<mutex> lock(fMtx);
|
||||
fTargetStates[senderId] = state;
|
||||
if (fTargetStatePair.first == fair::mq::State::Ok) {
|
||||
if (fTargetStatePair.second == currentState) {
|
||||
fTransitionedCount++;
|
||||
// cout << "fTransitionedCount = " << fTransitionedCount << " for single value" << endl;
|
||||
}
|
||||
} else {
|
||||
if (fTargetStatePair.first == lastState && fTargetStatePair.second == currentState) {
|
||||
fTransitionedCount++;
|
||||
// cout << "fTransitionedCount = " << fTransitionedCount << " for double value" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
fCV.notify_one();
|
||||
}
|
||||
|
||||
mutex fMtx;
|
||||
condition_variable fCV;
|
||||
unordered_map<uint64_t, string> fTargetStates;
|
||||
string fTargetState;
|
||||
pair<fair::mq::State, fair::mq::State> fTargetStatePair;
|
||||
unsigned int fTransitionedCount;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
@@ -216,7 +222,7 @@ int main(int argc, char* argv[])
|
||||
string topologyPath;
|
||||
string targetState;
|
||||
unsigned int timeout;
|
||||
unsigned int numberDevices(0);
|
||||
unsigned int numDevices(0);
|
||||
|
||||
bpo::options_description options("Common options");
|
||||
|
||||
@@ -232,7 +238,7 @@ int main(int argc, char* argv[])
|
||||
("path,p", bpo::value<string> (&topologyPath)->default_value(""), "DDS Topology path to send command to (empty - send to all tasks)")
|
||||
("wait-for-state,w", bpo::value<string> (&targetState)->default_value(""), "Wait until targeted FairMQ devices reach the given state")
|
||||
("timeout,t", bpo::value<unsigned int> (&timeout)->default_value(0), "Timeout in milliseconds when waiting for a device state (0 - wait infinitely)")
|
||||
("number-devices,n", bpo::value<unsigned int> (&numberDevices)->default_value(0), "Number of devices (will be removed in the future)")
|
||||
("number-devices,n", bpo::value<unsigned int> (&numDevices)->default_value(0), "Number of devices (will be removed in the future)")
|
||||
("help,h", "Produce help message");
|
||||
|
||||
bpo::variables_map vm;
|
||||
@@ -257,40 +263,58 @@ int main(int argc, char* argv[])
|
||||
|
||||
// subscribe to receive messages from DDS
|
||||
ddsCustomCmd.subscribe([&](const string& msg, const string& /*condition*/, uint64_t senderId) {
|
||||
// cerr << "Received: " << msg << endl;
|
||||
vector<string> parts;
|
||||
boost::algorithm::split(parts, msg, boost::algorithm::is_any_of(":,"));
|
||||
if (parts[0] == "state-change") {
|
||||
// cerr << "Received: " << msg << endl;
|
||||
boost::trim(parts[2]);
|
||||
waitMode.AddNewStateEntry(senderId, parts[3]);
|
||||
if(parts[3] == "IDLE->EXITING") {
|
||||
ddsCustomCmd.send("state-change-exiting-received", std::to_string(senderId));
|
||||
Cmds cmds;
|
||||
cmds.Deserialize(msg);
|
||||
// cout << "Received " << cmds.Size() << " command(s) with total size of " << msg.length() << " bytes: " << endl;
|
||||
for (const auto& cmd : cmds) {
|
||||
// cout << " > " << cmd->GetType() << endl;
|
||||
switch (cmd->GetType()) {
|
||||
case Type::state_change: {
|
||||
cout << "Received state_change from " << static_cast<StateChange&>(*cmd).GetDeviceId() << ": " << static_cast<StateChange&>(*cmd).GetLastState() << "->" << static_cast<StateChange&>(*cmd).GetCurrentState() << endl;
|
||||
if (static_cast<StateChange&>(*cmd).GetCurrentState() == fair::mq::State::Exiting) {
|
||||
ddsCustomCmd.send(Cmds(make<StateChangeExitingReceived>()).Serialize(), to_string(senderId));
|
||||
}
|
||||
waitMode.CountStates(static_cast<StateChange&>(*cmd).GetLastState(), static_cast<StateChange&>(*cmd).GetCurrentState());
|
||||
}
|
||||
break;
|
||||
case Type::state_change_subscription:
|
||||
if (static_cast<StateChangeSubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
cout << "State change subscription failed for " << static_cast<StateChangeSubscription&>(*cmd).GetDeviceId() << endl;
|
||||
}
|
||||
break;
|
||||
case Type::state_change_unsubscription:
|
||||
if (static_cast<StateChangeUnsubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
cout << "State change unsubscription failed for " << static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId() << endl;
|
||||
}
|
||||
break;
|
||||
case Type::transition_status: {
|
||||
// if (static_cast<TransitionStatus&>(*cmd).GetResult() == Result::Ok) {
|
||||
// cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " started to transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
||||
// } else {
|
||||
// cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " cannot transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
||||
// }
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cout << "Unexpected/unknown command received: " << cmd->GetType() << endl;
|
||||
cout << "Origin: " << senderId << endl;
|
||||
break;
|
||||
}
|
||||
} else if (parts[0] == "state-changes-subscription") {
|
||||
if (parts[2] != "OK") {
|
||||
cerr << "state-changes-subscription failed with return code: " << parts[2];
|
||||
}
|
||||
} else if (parts[0] == "state-changes-unsubscription") {
|
||||
if (parts[2] != "OK") {
|
||||
cerr << "state-changes-unsubscription failed with return code: " << parts[2];
|
||||
}
|
||||
} else {
|
||||
cout << "Received: " << msg << endl;
|
||||
}
|
||||
});
|
||||
|
||||
service.start(sessionID);
|
||||
|
||||
if (targetState == "") {
|
||||
commandMode(command, topologyPath, ddsCustomCmd);
|
||||
sendCommand(command, topologyPath, ddsCustomCmd);
|
||||
} else {
|
||||
waitMode.Run(chrono::milliseconds(timeout), topologyPath, ddsCustomCmd, numberDevices, command);
|
||||
waitMode.Run(chrono::milliseconds(timeout), topologyPath, ddsCustomCmd, numDevices, command);
|
||||
}
|
||||
|
||||
ddsCustomCmd.unsubscribe();
|
||||
} catch (exception& e) {
|
||||
cerr << "Error: " << e.what() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include <vector>
|
||||
#include <FairMQLogger.h>
|
||||
|
||||
// C++ PMIx v2.1 API
|
||||
// C++ PMIx v2.2 API
|
||||
namespace pmix
|
||||
{
|
||||
|
||||
@@ -90,12 +90,6 @@ struct value : pmix_value_t
|
||||
}
|
||||
}
|
||||
|
||||
// template<typename T>
|
||||
// value(const T* val, data_type dt)
|
||||
// {
|
||||
// PMIX_VALUE_LOAD(static_cast<pmix_value_t*>(this), const_cast<void*>(val), dt);
|
||||
// }
|
||||
|
||||
template<typename T>
|
||||
explicit value(T)
|
||||
{
|
||||
@@ -112,6 +106,11 @@ struct value : pmix_value_t
|
||||
PMIX_VALUE_LOAD(
|
||||
static_cast<pmix_value_t*>(this), const_cast<char*>(val.c_str()), PMIX_STRING);
|
||||
}
|
||||
|
||||
explicit value(int val)
|
||||
{
|
||||
PMIX_VALUE_LOAD(static_cast<pmix_value_t*>(this), &val, PMIX_INT);
|
||||
}
|
||||
};
|
||||
|
||||
struct info : pmix_info_t
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* 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, *
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "PMIxPlugin.h"
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -27,14 +26,28 @@ PMIxPlugin::PMIxPlugin(const std::string& name,
|
||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||
, fPid(getpid())
|
||||
{
|
||||
Init();
|
||||
SetProperty<std::string>("id", std::string(fProc.nspace) + "_" + std::to_string(fProc.rank));
|
||||
Fence();
|
||||
|
||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
||||
switch (newState) {
|
||||
case DeviceState::Connecting:
|
||||
Init();
|
||||
Publish();
|
||||
Fence();
|
||||
Lookup();
|
||||
break;
|
||||
case DeviceState::Idle:
|
||||
Fence();
|
||||
break;
|
||||
case DeviceState::Bound:
|
||||
Publish();
|
||||
Fence();
|
||||
break;
|
||||
case DeviceState::Connecting:
|
||||
Lookup();
|
||||
break;
|
||||
case DeviceState::DeviceReady:
|
||||
Fence();
|
||||
break;
|
||||
case DeviceState::Ready:
|
||||
Fence();
|
||||
break;
|
||||
case DeviceState::Exiting:
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
break;
|
||||
@@ -49,9 +62,9 @@ PMIxPlugin::~PMIxPlugin()
|
||||
while (pmix::initialized()) {
|
||||
try {
|
||||
pmix::finalize();
|
||||
LOG(debug) << PMIxClient() << " pmix::finalize() OK";
|
||||
LOG(debug) << PMIxClient() << "pmix::finalize() OK";
|
||||
} catch (const pmix::runtime_error& e) {
|
||||
LOG(debug) << PMIxClient() << " pmix::finalize() failed: " << e.what();
|
||||
LOG(debug) << PMIxClient() << "pmix::finalize() failed: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +72,7 @@ PMIxPlugin::~PMIxPlugin()
|
||||
auto PMIxPlugin::PMIxClient() const -> std::string
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "PMIx client(pid=" << fPid << ")";
|
||||
ss << "PMIx client(pid=" << fPid << ") ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@@ -67,7 +80,7 @@ auto PMIxPlugin::Init() -> void
|
||||
{
|
||||
if (!pmix::initialized()) {
|
||||
fProc = pmix::init();
|
||||
LOG(debug) << PMIxClient() << " pmix::init() OK: " << fProc
|
||||
LOG(debug) << PMIxClient() << "pmix::init() OK: " << fProc
|
||||
<< ",version=" << pmix::get_version();
|
||||
}
|
||||
}
|
||||
@@ -90,7 +103,7 @@ auto PMIxPlugin::Publish() -> void
|
||||
|
||||
if (info.size() > 0) {
|
||||
pmix::publish(info);
|
||||
LOG(debug) << PMIxClient() << " pmix::publish() OK: published "
|
||||
LOG(debug) << PMIxClient() << "pmix::publish() OK: published "
|
||||
<< info.size() << " binding channels.";
|
||||
}
|
||||
}
|
||||
@@ -101,44 +114,43 @@ auto PMIxPlugin::Fence() -> void
|
||||
all.rank = pmix::rank::wildcard;
|
||||
|
||||
pmix::fence({all});
|
||||
LOG(debug) << PMIxClient() << "pmix::fence() OK";
|
||||
}
|
||||
|
||||
auto PMIxPlugin::Lookup() -> void
|
||||
{
|
||||
auto channels(GetChannelInfo());
|
||||
std::vector<pmix::pdata> pdata;
|
||||
|
||||
for (const auto& c : channels) {
|
||||
std::string methodKey{"chans." + c.first + "." + std::to_string(c.second - 1) + ".method"};
|
||||
if (GetProperty<std::string>(methodKey) == "connect") {
|
||||
for (int i = 0; i < c.second; ++i) {
|
||||
std::vector<pmix::pdata> pdata;
|
||||
std::string addressKey{"chans." + c.first + "." + std::to_string(i) + ".address"};
|
||||
pdata.emplace_back();
|
||||
pdata.back().set_key(addressKey);
|
||||
std::vector<pmix::info> info;
|
||||
info.emplace_back(PMIX_WAIT, static_cast<int>(pdata.size()));
|
||||
|
||||
if (pdata.size() > 0) {
|
||||
pmix::lookup(pdata, info);
|
||||
LOG(debug) << PMIxClient() << "pmix::lookup() OK";
|
||||
}
|
||||
|
||||
for (const auto& p : pdata) {
|
||||
if (p.value.type == PMIX_UNDEF) {
|
||||
LOG(debug) << PMIxClient() << "pmix::lookup() not found: key=" << p.key;
|
||||
} else if (p.value.type == PMIX_STRING) {
|
||||
LOG(debug) << PMIxClient() << "pmix::lookup() found:"
|
||||
<< " key=" << p.key << ",value=" << p.value.data.string;
|
||||
SetProperty<std::string>(p.key, p.value.data.string);
|
||||
} else {
|
||||
LOG(debug) << PMIxClient() << "pmix::lookup() wrong type returned: "
|
||||
<< "key=" << p.key << ",type=" << p.value.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata.size() > 0) {
|
||||
pmix::lookup(pdata);
|
||||
LOG(debug) << PMIxClient() << " pmix::lookup() OK";
|
||||
}
|
||||
|
||||
LOG(info) << pdata.size();
|
||||
|
||||
for (const auto& p : pdata) {
|
||||
if (p.value.type == PMIX_UNDEF) {
|
||||
LOG(debug) << PMIxClient() << " pmix::lookup() not found: key=" << p.key;
|
||||
} else if (p.value.type == PMIX_STRING) {
|
||||
LOG(debug) << PMIxClient() << " pmix::lookup() found: key=" << p.key << ",value=" << p.value.data.string;
|
||||
SetProperty<std::string>(p.key, p.value.data.string);
|
||||
LOG(info) << GetProperty<std::string>(p.key);
|
||||
} else {
|
||||
LOG(debug) << PMIxClient() << " pmix::lookup() wrong type returned: key=" << p.key << ",type=" << p.value.type;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(info) << pdata.size();
|
||||
}
|
||||
|
||||
} /* namespace plugins */
|
||||
|
@@ -18,6 +18,7 @@ set(SDK_PUBLIC_HEADER_FILES
|
||||
AsioAsyncOp.h
|
||||
AsioBase.h
|
||||
DDSAgent.h
|
||||
DDSCollection.h
|
||||
DDSEnvironment.h
|
||||
DDSSession.h
|
||||
DDSTask.h
|
||||
@@ -60,6 +61,7 @@ target_link_libraries(${target}
|
||||
Threads::Threads
|
||||
Tools
|
||||
StateMachine
|
||||
Commands
|
||||
|
||||
PRIVATE
|
||||
DDS::dds_intercom_lib
|
||||
|
49
fairmq/sdk/DDSCollection.h
Normal file
49
fairmq/sdk/DDSCollection.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/********************************************************************************
|
||||
* 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" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSCOLLECTION_H
|
||||
#define FAIR_MQ_SDK_DDSCOLLECTION_H
|
||||
|
||||
// #include <fairmq/sdk/DDSAgent.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
namespace sdk {
|
||||
|
||||
/**
|
||||
* @class DDSCollection <fairmq/sdk/DDSCollection.h>
|
||||
* @brief Represents a DDS collection
|
||||
*/
|
||||
class DDSCollection
|
||||
{
|
||||
public:
|
||||
using Id = std::uint64_t;
|
||||
|
||||
explicit DDSCollection(Id id)
|
||||
: fId(id)
|
||||
{}
|
||||
|
||||
Id GetId() const { return fId; }
|
||||
|
||||
friend auto operator<<(std::ostream& os, const DDSCollection& collection) -> std::ostream&
|
||||
{
|
||||
return os << "DDSCollection id: " << collection.fId;
|
||||
}
|
||||
|
||||
private:
|
||||
Id fId;
|
||||
};
|
||||
|
||||
} // namespace sdk
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSCOLLECTION_H */
|
@@ -254,7 +254,7 @@ auto DDSSession::RequestTaskInfo() -> std::vector<DDSTask>
|
||||
std::vector<DDSTask> taskInfo;
|
||||
taskInfo.reserve(res.size());
|
||||
for (auto& a : res) {
|
||||
taskInfo.emplace_back(a.m_taskID);
|
||||
taskInfo.emplace_back(a.m_taskID, 0);
|
||||
}
|
||||
|
||||
return taskInfo;
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#ifndef FAIR_MQ_SDK_DDSTASK_H
|
||||
#define FAIR_MQ_SDK_DDSTASK_H
|
||||
|
||||
// #include <fairmq/sdk/DDSAgent.h>
|
||||
#include <fairmq/sdk/DDSCollection.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
@@ -27,19 +27,22 @@ class DDSTask
|
||||
public:
|
||||
using Id = std::uint64_t;
|
||||
|
||||
explicit DDSTask(Id id)
|
||||
explicit DDSTask(Id id, Id collectionId)
|
||||
: fId(id)
|
||||
, fCollectionId(collectionId)
|
||||
{}
|
||||
|
||||
Id GetId() const { return fId; }
|
||||
DDSCollection::Id GetCollectionId() const { return fCollectionId; }
|
||||
|
||||
friend auto operator<<(std::ostream& os, const DDSTask& task) -> std::ostream&
|
||||
{
|
||||
return os << "DDSTask id: " << task.fId;
|
||||
return os << "DDSTask id: " << task.fId << ", collection id: " << task.fCollectionId;
|
||||
}
|
||||
|
||||
private:
|
||||
Id fId;
|
||||
DDSCollection::Id fCollectionId;
|
||||
};
|
||||
|
||||
} // namespace sdk
|
||||
|
@@ -80,10 +80,31 @@ auto DDSTopology::GetTasks() const -> std::vector<DDSTask>
|
||||
auto tasks = boost::make_iterator_range(itPair.first, itPair.second);
|
||||
|
||||
for (const auto& task : tasks) {
|
||||
LOG(debug) << "Found task " << task.first << ": "
|
||||
LOG(debug) << "Found task with id: " << task.first << ", "
|
||||
<< "Path: " << task.second.m_taskPath << ", "
|
||||
<< "Collection id: " << task.second.m_taskCollectionId << ", "
|
||||
<< "Name: " << task.second.m_task->getName() << "_" << task.second.m_taskIndex;
|
||||
list.emplace_back(task.first);
|
||||
list.emplace_back(task.first, task.second.m_taskCollectionId);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
auto DDSTopology::GetCollections() const -> std::vector<DDSCollection>
|
||||
{
|
||||
std::vector<DDSCollection> list;
|
||||
|
||||
auto itPair = fImpl->fTopo.getRuntimeCollectionIterator(
|
||||
[](const dds::topology_api::STopoRuntimeCollection::FilterIterator_t::value_type&) -> bool {
|
||||
return true;
|
||||
});
|
||||
auto collections = boost::make_iterator_range(itPair.first, itPair.second);
|
||||
|
||||
for (const auto& c : collections) {
|
||||
LOG(debug) << "Found collection with id: " << c.first << ", "
|
||||
<< "Index: " << c.second.m_collectionIndex << ", "
|
||||
<< "Path: " << c.second.m_collectionPath;
|
||||
list.emplace_back(c.first);
|
||||
}
|
||||
|
||||
return list;
|
||||
|
@@ -10,11 +10,13 @@
|
||||
#define FAIR_MQ_SDK_DDSTOPOLOGY_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <fairmq/sdk/DDSCollection.h>
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <fairmq/sdk/DDSInfo.h>
|
||||
#include <fairmq/sdk/DDSTask.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
@@ -54,6 +56,9 @@ class DDSTopology
|
||||
/// @brief Get list of tasks in this topology
|
||||
auto GetTasks() const -> std::vector<DDSTask>;
|
||||
|
||||
/// @brief Get list of tasks in this topology
|
||||
auto GetCollections() const -> std::vector<DDSCollection>;
|
||||
|
||||
/// @brief Get the name of the topology
|
||||
auto GetName() const -> std::string;
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
#ifndef FAIR_MQ_SDK_ERROR_H
|
||||
#define FAIR_MQ_SDK_ERROR_H
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <stdexcept>
|
||||
#include <system_error>
|
||||
|
||||
|
@@ -9,22 +9,27 @@
|
||||
#ifndef FAIR_MQ_SDK_TOPOLOGY_H
|
||||
#define FAIR_MQ_SDK_TOPOLOGY_H
|
||||
|
||||
#include <asio/async_result.hpp>
|
||||
#include <asio/associated_executor.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <asio/system_executor.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <chrono>
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fairmq/States.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/sdk/AsioAsyncOp.h>
|
||||
#include <fairmq/sdk/AsioBase.h>
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
#include <fairmq/sdk/DDSCollection.h>
|
||||
#include <fairmq/sdk/DDSInfo.h>
|
||||
#include <fairmq/sdk/DDSSession.h>
|
||||
#include <fairmq/sdk/DDSTask.h>
|
||||
#include <fairmq/sdk/DDSTopology.h>
|
||||
#include <fairmq/sdk/Error.h>
|
||||
#include <fairmq/States.h>
|
||||
#include <fairmq/tools/Semaphore.h>
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
|
||||
#include <asio/associated_executor.hpp>
|
||||
#include <asio/async_result.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
#include <asio/system_executor.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -61,23 +66,27 @@ struct DeviceStatus
|
||||
{
|
||||
bool initialized;
|
||||
DeviceState state;
|
||||
DDSTask::Id taskId;
|
||||
DDSCollection::Id collectionId;
|
||||
};
|
||||
|
||||
using TopologyState = std::unordered_map<DDSTask::Id, DeviceStatus>;
|
||||
using TopologyState = std::vector<DeviceStatus>;
|
||||
using TopologyStateIndex = std::unordered_map<DDSTask::Id, int>; // task id -> index in the data vector
|
||||
using TopologyStateByTask = std::unordered_map<DDSTask::Id, DeviceStatus>;
|
||||
using TopologyStateByCollection = std::unordered_map<DDSCollection::Id, std::vector<DeviceStatus>>;
|
||||
using TopologyTransition = fair::mq::Transition;
|
||||
|
||||
inline DeviceState AggregateState(const TopologyState& topologyState)
|
||||
{
|
||||
DeviceState first = topologyState.begin()->second.state;
|
||||
DeviceState first = topologyState.begin()->state;
|
||||
|
||||
if (std::all_of(topologyState.cbegin(), topologyState.cend(), [&](TopologyState::value_type i) {
|
||||
return i.second.state == first;
|
||||
return i.state == first;
|
||||
})) {
|
||||
return first;
|
||||
}
|
||||
|
||||
throw MixedStateError("State is not uniform");
|
||||
|
||||
}
|
||||
|
||||
inline bool StateEqualsTo(const TopologyState& topologyState, DeviceState state)
|
||||
@@ -85,6 +94,28 @@ inline bool StateEqualsTo(const TopologyState& topologyState, DeviceState state)
|
||||
return AggregateState(topologyState) == state;
|
||||
}
|
||||
|
||||
inline TopologyStateByCollection GroupByCollectionId(const TopologyState& topologyState)
|
||||
{
|
||||
TopologyStateByCollection state;
|
||||
for (const auto& ds : topologyState) {
|
||||
if (ds.collectionId != 0) {
|
||||
state[ds.collectionId].push_back(ds);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
inline TopologyStateByTask GroupByTaskId(const TopologyState& topologyState)
|
||||
{
|
||||
TopologyStateByTask state;
|
||||
for (const auto& ds : topologyState) {
|
||||
state[ds.taskId] = ds;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class BasicTopology Topology.h <fairmq/sdk/Topology.h>
|
||||
* @tparam Executor Associated I/O executor
|
||||
@@ -103,9 +134,7 @@ class BasicTopology : public AsioBase<Executor, Allocator>
|
||||
/// @param topo DDSTopology
|
||||
/// @param session DDSSession
|
||||
BasicTopology(DDSTopology topo, DDSSession session)
|
||||
: BasicTopology<Executor, Allocator>(asio::system_executor(),
|
||||
std::move(topo),
|
||||
std::move(session))
|
||||
: BasicTopology<Executor, Allocator>(asio::system_executor(), std::move(topo), std::move(session))
|
||||
{}
|
||||
|
||||
/// @brief (Re)Construct a FairMQ topology from an existing DDS topology
|
||||
@@ -120,60 +149,72 @@ class BasicTopology : public AsioBase<Executor, Allocator>
|
||||
: AsioBase<Executor, Allocator>(ex, std::move(alloc))
|
||||
, fDDSSession(std::move(session))
|
||||
, fDDSTopo(std::move(topo))
|
||||
, fState(makeTopologyState(fDDSTopo))
|
||||
, fStateData()
|
||||
, fStateIndex()
|
||||
, fChangeStateOp()
|
||||
, fChangeStateOpTimer(ex)
|
||||
, fChangeStateTarget(DeviceState::Idle)
|
||||
{
|
||||
makeTopologyState();
|
||||
|
||||
std::string activeTopo(fDDSSession.RequestCommanderInfo().activeTopologyName);
|
||||
std::string givenTopo(fDDSTopo.GetName());
|
||||
if (activeTopo != givenTopo) {
|
||||
throw RuntimeError("Given topology ", givenTopo,
|
||||
" is not activated (active: ", activeTopo, ")");
|
||||
throw RuntimeError("Given topology ", givenTopo, " is not activated (active: ", activeTopo, ")");
|
||||
}
|
||||
|
||||
fDDSSession.SubscribeToCommands([&](const std::string& msg,
|
||||
const std::string& /* condition */,
|
||||
DDSChannel::Id senderId) {
|
||||
// LOG(debug) << "Received from " << senderId << ": " << msg;
|
||||
std::vector<std::string> parts;
|
||||
boost::algorithm::split(parts, msg, boost::algorithm::is_any_of(":,"));
|
||||
|
||||
for (unsigned int i = 0; i < parts.size(); ++i) {
|
||||
boost::trim(parts.at(i));
|
||||
}
|
||||
|
||||
if (parts[0] == "state-change") {
|
||||
DDSTask::Id taskId(std::stoull(parts[2]));
|
||||
fDDSSession.UpdateChannelToTaskAssociation(senderId, taskId);
|
||||
if(parts[3] == "IDLE->EXITING") {
|
||||
fDDSSession.SendCommand("state-change-exiting-received", senderId);
|
||||
}
|
||||
UpdateStateEntry(taskId, parts[3]);
|
||||
} else if (parts[0] == "state-changes-subscription") {
|
||||
LOG(debug) << "Received from " << senderId << ": " << msg;
|
||||
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];
|
||||
}
|
||||
} else if (parts[1] == "could not queue") {
|
||||
std::lock_guard<std::mutex> lk(fMtx);
|
||||
if (!fChangeStateOp.IsCompleted()
|
||||
&& fState.at(fDDSSession.GetTaskId(senderId)).state != fChangeStateTarget) {
|
||||
fChangeStateOpTimer.cancel();
|
||||
fChangeStateOp.Complete(MakeErrorCode(ErrorCode::DeviceChangeStateFailed),
|
||||
fState);
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
fDDSSession.SubscribeToCommands([&](const std::string& msg, const std::string& /* condition */, DDSChannel::Id senderId) {
|
||||
Cmds inCmds;
|
||||
inCmds.Deserialize(msg);
|
||||
// LOG(debug) << "Received " << inCmds.Size() << " command(s) with total size of " << msg.length() << " bytes: ";
|
||||
for (const auto& cmd : inCmds) {
|
||||
// LOG(debug) << " > " << cmd->GetType();
|
||||
switch (cmd->GetType()) {
|
||||
case Type::state_change: {
|
||||
DDSTask::Id taskId(static_cast<StateChange&>(*cmd).GetTaskId());
|
||||
fDDSSession.UpdateChannelToTaskAssociation(senderId, taskId);
|
||||
if (static_cast<StateChange&>(*cmd).GetCurrentState() == DeviceState::Exiting) {
|
||||
Cmds outCmds;
|
||||
outCmds.Add<StateChangeExitingReceived>();
|
||||
fDDSSession.SendCommand(outCmds.Serialize(), senderId);
|
||||
}
|
||||
UpdateStateEntry(taskId, static_cast<StateChange&>(*cmd).GetCurrentState());
|
||||
}
|
||||
break;
|
||||
case Type::state_change_subscription:
|
||||
if (static_cast<StateChangeSubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
LOG(error) << "State change subscription failed for " << static_cast<StateChangeSubscription&>(*cmd).GetDeviceId();
|
||||
}
|
||||
break;
|
||||
case Type::state_change_unsubscription:
|
||||
if (static_cast<StateChangeUnsubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
LOG(error) << "State change unsubscription failed for " << static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId();
|
||||
}
|
||||
break;
|
||||
case Type::transition_status: {
|
||||
if (static_cast<TransitionStatus&>(*cmd).GetResult() != Result::Ok) {
|
||||
LOG(error) << "Transition failed for " << static_cast<TransitionStatus&>(*cmd).GetDeviceId();
|
||||
std::lock_guard<std::mutex> lk(fMtx);
|
||||
if (!fChangeStateOp.IsCompleted() && fStateData.at(fStateIndex.at(fDDSSession.GetTaskId(senderId))).state != fChangeStateTarget) {
|
||||
fChangeStateOpTimer.cancel();
|
||||
fChangeStateOp.Complete(MakeErrorCode(ErrorCode::DeviceChangeStateFailed), fStateData);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(warn) << "Unexpected/unknown command received: " << cmd->GetType();
|
||||
LOG(warn) << "Origin: " << senderId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fDDSSession.StartDDSService();
|
||||
LOG(debug) << "subscribe-to-state-changes";
|
||||
fDDSSession.SendCommand("subscribe-to-state-changes");
|
||||
LOG(debug) << "Subscribing to state change";
|
||||
Cmds cmds(make<SubscribeToStateChange>());
|
||||
fDDSSession.SendCommand(cmds.Serialize());
|
||||
}
|
||||
|
||||
/// not copyable
|
||||
@@ -189,7 +230,7 @@ class BasicTopology : public AsioBase<Executor, Allocator>
|
||||
std::lock_guard<std::mutex> lk(fMtx);
|
||||
fDDSSession.UnsubscribeFromCommands();
|
||||
try {
|
||||
fChangeStateOp.Cancel(fState);
|
||||
fChangeStateOp.Cancel(fStateData);
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
@@ -292,22 +333,22 @@ class BasicTopology : public AsioBase<Executor, Allocator>
|
||||
AsioBase<Executor, Allocator>::GetAllocator(),
|
||||
std::move(handler));
|
||||
fChangeStateTarget = expectedState.at(transition);
|
||||
fDDSSession.SendCommand(GetTransitionName(transition));
|
||||
ResetTransitionedCount(fChangeStateTarget);
|
||||
cmd::Cmds cmds(cmd::make<cmd::ChangeState>(transition));
|
||||
fDDSSession.SendCommand(cmds.Serialize());
|
||||
if (timeout > std::chrono::milliseconds(0)) {
|
||||
fChangeStateOpTimer.expires_after(timeout);
|
||||
fChangeStateOpTimer.async_wait([&](std::error_code ec) {
|
||||
if (!ec) {
|
||||
std::lock_guard<std::mutex> lk2(fMtx);
|
||||
fChangeStateOp.Timeout(fState);
|
||||
fChangeStateOp.Timeout(fStateData);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// TODO refactor to hide boiler plate
|
||||
auto ex2(asio::get_associated_executor(
|
||||
handler, AsioBase<Executor, Allocator>::GetExecutor()));
|
||||
auto alloc2(asio::get_associated_allocator(
|
||||
handler, AsioBase<Executor, Allocator>::GetAllocator()));
|
||||
auto ex2(asio::get_associated_executor(handler, AsioBase<Executor, Allocator>::GetExecutor()));
|
||||
auto alloc2(asio::get_associated_allocator(handler, AsioBase<Executor, Allocator>::GetAllocator()));
|
||||
auto state(GetCurrentStateUnsafe());
|
||||
|
||||
ex2.post(
|
||||
@@ -315,8 +356,7 @@ class BasicTopology : public AsioBase<Executor, Allocator>
|
||||
try {
|
||||
h(MakeErrorCode(ErrorCode::OperationInProgress), s);
|
||||
} catch (const std::exception& e) {
|
||||
LOG(error)
|
||||
<< "Uncaught exception in completion handler: " << e.what();
|
||||
LOG(error) << "Uncaught exception in completion handler: " << e.what();
|
||||
} catch (...) {
|
||||
LOG(error) << "Unknown uncaught exception in completion handler.";
|
||||
}
|
||||
@@ -359,7 +399,7 @@ class BasicTopology : public AsioBase<Executor, Allocator>
|
||||
auto GetCurrentState() const -> TopologyState
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(fMtx);
|
||||
return fState;
|
||||
return fStateData;
|
||||
}
|
||||
|
||||
auto AggregateState() const -> DeviceState { return sdk::AggregateState(GetCurrentState()); }
|
||||
@@ -367,59 +407,72 @@ class BasicTopology : public AsioBase<Executor, Allocator>
|
||||
auto StateEqualsTo(DeviceState state) const -> bool { return sdk::StateEqualsTo(GetCurrentState(), state); }
|
||||
|
||||
private:
|
||||
using TransitionedCount = unsigned int;
|
||||
|
||||
DDSSession fDDSSession;
|
||||
DDSTopology fDDSTopo;
|
||||
TopologyState fState;
|
||||
TopologyState fStateData;
|
||||
TopologyStateIndex fStateIndex;
|
||||
mutable std::mutex fMtx;
|
||||
|
||||
using ChangeStateOp = AsioAsyncOp<Executor, Allocator, ChangeStateCompletionSignature>;
|
||||
ChangeStateOp fChangeStateOp;
|
||||
asio::steady_timer fChangeStateOpTimer;
|
||||
DeviceState fChangeStateTarget;
|
||||
TransitionedCount fTransitionedCount;
|
||||
|
||||
static auto makeTopologyState(const DDSTopo& topo) -> TopologyState
|
||||
auto makeTopologyState() -> void
|
||||
{
|
||||
TopologyState state;
|
||||
for (const auto& task : topo.GetTasks()) {
|
||||
state.emplace(task.GetId(), DeviceStatus{false, DeviceState::Ok});
|
||||
fStateData.reserve(fDDSTopo.GetTasks().size());
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (const auto& task : fDDSTopo.GetTasks()) {
|
||||
fStateData.push_back(DeviceStatus{false, DeviceState::Ok, task.GetId(), task.GetCollectionId()});
|
||||
fStateIndex.emplace(task.GetId(), index);
|
||||
index++;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
auto UpdateStateEntry(DDSTask::Id taskId, const std::string& state) -> void
|
||||
auto UpdateStateEntry(const DDSTask::Id taskId, const DeviceState state) -> void
|
||||
{
|
||||
std::size_t pos = state.find("->");
|
||||
std::string endState = state.substr(pos + 2);
|
||||
try {
|
||||
std::lock_guard<std::mutex> lk(fMtx);
|
||||
fState[taskId] = DeviceStatus{true, fair::mq::GetState(endState)};
|
||||
LOG(debug) << "Updated state entry: taskId=" << taskId << ",state=" << state;
|
||||
DeviceStatus& task = fStateData.at(fStateIndex.at(taskId));
|
||||
task.initialized = true;
|
||||
task.state = state;
|
||||
if (task.state == fChangeStateTarget) {
|
||||
++fTransitionedCount;
|
||||
}
|
||||
// LOG(debug) << "Updated state entry: taskId=" << taskId << ", state=" << state;
|
||||
TryChangeStateCompletion();
|
||||
} catch (const std::exception& e) {
|
||||
LOG(error) << "Exception in UpdateStateEntry: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
/// call only under locked fMtx!
|
||||
/// precodition: fMtx is locked.
|
||||
auto TryChangeStateCompletion() -> void
|
||||
{
|
||||
bool targetStateReached(
|
||||
std::all_of(fState.cbegin(), fState.cend(), [&](TopologyState::value_type i) {
|
||||
return (i.second.state == fChangeStateTarget) && i.second.initialized;
|
||||
}));
|
||||
|
||||
if (!fChangeStateOp.IsCompleted() && targetStateReached) {
|
||||
if (!fChangeStateOp.IsCompleted() && fTransitionedCount == fStateData.size()) {
|
||||
fChangeStateOpTimer.cancel();
|
||||
fChangeStateOp.Complete(fState);
|
||||
fChangeStateOp.Complete(fStateData);
|
||||
}
|
||||
}
|
||||
|
||||
/// call only under locked fMtx!
|
||||
auto GetCurrentStateUnsafe() const -> TopologyState
|
||||
/// precodition: fMtx is locked.
|
||||
auto ResetTransitionedCount(DeviceState targetState) -> void
|
||||
{
|
||||
return fState;
|
||||
fTransitionedCount = std::count_if(fStateIndex.cbegin(), fStateIndex.cend(), [=](const auto& s) {
|
||||
return fStateData.at(s.second).state == targetState;
|
||||
});
|
||||
}
|
||||
|
||||
/// precodition: fMtx is locked.
|
||||
auto GetCurrentStateUnsafe() const -> TopologyState
|
||||
{
|
||||
return fStateData;
|
||||
}
|
||||
};
|
||||
|
||||
using Topology = BasicTopology<DefaultExecutor, DefaultAllocator>;
|
||||
|
55
fairmq/sdk/commands/CMakeLists.txt
Normal file
55
fairmq/sdk/commands/CMakeLists.txt
Normal file
@@ -0,0 +1,55 @@
|
||||
################################################################################
|
||||
# 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" #
|
||||
################################################################################
|
||||
|
||||
set(target Commands)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h
|
||||
COMMAND $<TARGET_FILE:flatbuffers::flatc> -c -o ${CMAKE_CURRENT_BINARY_DIR} CommandsFormat.fbs
|
||||
COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat_generated.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
# JSON serialization needs to see the .fbs file at run time, save it as constexpr string instead of locating/opening it every time
|
||||
file(STRINGS CommandsFormat.fbs tmp)
|
||||
list(JOIN tmp "\n" commands_format_def_fbs)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CommandsFormatDef.h.in ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
|
||||
|
||||
add_library(${target} Commands.cxx Commands.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
|
||||
add_library(FairMQ::${target} ALIAS ${target})
|
||||
|
||||
# Some distros may not package the static library (e.g. Fedora), so we pick up the dynamic library instead
|
||||
set(_flatbuffers flatbuffers::flatbuffers)
|
||||
if(NOT TARGET flatbuffers::flatbuffers AND TARGET flatbuffers::flatbuffers_shared)
|
||||
set(_flatbuffers flatbuffers::flatbuffers_shared)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
StateMachine
|
||||
Tools
|
||||
|
||||
PRIVATE
|
||||
${_flatbuffers}
|
||||
)
|
||||
|
||||
target_include_directories(${target}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${target}
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
install(FILES Commands.h
|
||||
DESTINATION ${PROJECT_INSTALL_INCDIR}/sdk/commands
|
||||
)
|
431
fairmq/sdk/commands/Commands.cxx
Normal file
431
fairmq/sdk/commands/Commands.cxx
Normal file
@@ -0,0 +1,431 @@
|
||||
/********************************************************************************
|
||||
* 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 "Commands.h"
|
||||
|
||||
#include <fairmq/sdk/commands/CommandsFormatDef.h>
|
||||
#include <fairmq/sdk/commands/CommandsFormat.h>
|
||||
|
||||
#include <flatbuffers/idl.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
namespace sdk {
|
||||
namespace cmd {
|
||||
|
||||
array<Result, 2> fbResultToResult =
|
||||
{
|
||||
{
|
||||
Result::Ok,
|
||||
Result::Failure
|
||||
}
|
||||
};
|
||||
|
||||
array<FBResult, 2> resultToFBResult =
|
||||
{
|
||||
{
|
||||
FBResult::FBResult_Ok,
|
||||
FBResult::FBResult_Failure
|
||||
}
|
||||
};
|
||||
|
||||
array<string, 2> resultNames =
|
||||
{
|
||||
{
|
||||
"Ok",
|
||||
"Failure"
|
||||
}
|
||||
};
|
||||
|
||||
array<string, 17> typeNames =
|
||||
{
|
||||
{
|
||||
"CheckState",
|
||||
"ChangeState",
|
||||
"DumpConfig",
|
||||
"SubscribeToHeartbeats",
|
||||
"UnsubscribeFromHeartbeats",
|
||||
"SubscribeToStateChange",
|
||||
"UnsubscribeFromStateChange",
|
||||
"StateChangeExitingReceived",
|
||||
|
||||
"CurrentState",
|
||||
"TransitionStatus",
|
||||
"Config",
|
||||
"HeartbeatSubscription",
|
||||
"HeartbeatUnsubscription",
|
||||
"Heartbeat",
|
||||
"StateChangeSubscription",
|
||||
"StateChangeUnsubscription",
|
||||
"StateChange"
|
||||
}
|
||||
};
|
||||
|
||||
array<fair::mq::State, 15> fbStateToMQState =
|
||||
{
|
||||
{
|
||||
fair::mq::State::Ok,
|
||||
fair::mq::State::Error,
|
||||
fair::mq::State::Idle,
|
||||
fair::mq::State::InitializingDevice,
|
||||
fair::mq::State::Initialized,
|
||||
fair::mq::State::Binding,
|
||||
fair::mq::State::Bound,
|
||||
fair::mq::State::Connecting,
|
||||
fair::mq::State::DeviceReady,
|
||||
fair::mq::State::InitializingTask,
|
||||
fair::mq::State::Ready,
|
||||
fair::mq::State::Running,
|
||||
fair::mq::State::ResettingTask,
|
||||
fair::mq::State::ResettingDevice,
|
||||
fair::mq::State::Exiting
|
||||
}
|
||||
};
|
||||
|
||||
array<sdk::cmd::FBState, 15> mqStateToFBState =
|
||||
{
|
||||
{
|
||||
sdk::cmd::FBState_Ok,
|
||||
sdk::cmd::FBState_Error,
|
||||
sdk::cmd::FBState_Idle,
|
||||
sdk::cmd::FBState_InitializingDevice,
|
||||
sdk::cmd::FBState_Initialized,
|
||||
sdk::cmd::FBState_Binding,
|
||||
sdk::cmd::FBState_Bound,
|
||||
sdk::cmd::FBState_Connecting,
|
||||
sdk::cmd::FBState_DeviceReady,
|
||||
sdk::cmd::FBState_InitializingTask,
|
||||
sdk::cmd::FBState_Ready,
|
||||
sdk::cmd::FBState_Running,
|
||||
sdk::cmd::FBState_ResettingTask,
|
||||
sdk::cmd::FBState_ResettingDevice,
|
||||
sdk::cmd::FBState_Exiting
|
||||
}
|
||||
};
|
||||
|
||||
array<fair::mq::Transition, 12> fbTransitionToMQTransition =
|
||||
{
|
||||
{
|
||||
fair::mq::Transition::Auto,
|
||||
fair::mq::Transition::InitDevice,
|
||||
fair::mq::Transition::CompleteInit,
|
||||
fair::mq::Transition::Bind,
|
||||
fair::mq::Transition::Connect,
|
||||
fair::mq::Transition::InitTask,
|
||||
fair::mq::Transition::Run,
|
||||
fair::mq::Transition::Stop,
|
||||
fair::mq::Transition::ResetTask,
|
||||
fair::mq::Transition::ResetDevice,
|
||||
fair::mq::Transition::End,
|
||||
fair::mq::Transition::ErrorFound
|
||||
}
|
||||
};
|
||||
|
||||
array<sdk::cmd::FBTransition, 12> mqTransitionToFBTransition =
|
||||
{
|
||||
{
|
||||
sdk::cmd::FBTransition_Auto,
|
||||
sdk::cmd::FBTransition_InitDevice,
|
||||
sdk::cmd::FBTransition_CompleteInit,
|
||||
sdk::cmd::FBTransition_Bind,
|
||||
sdk::cmd::FBTransition_Connect,
|
||||
sdk::cmd::FBTransition_InitTask,
|
||||
sdk::cmd::FBTransition_Run,
|
||||
sdk::cmd::FBTransition_Stop,
|
||||
sdk::cmd::FBTransition_ResetTask,
|
||||
sdk::cmd::FBTransition_ResetDevice,
|
||||
sdk::cmd::FBTransition_End,
|
||||
sdk::cmd::FBTransition_ErrorFound
|
||||
}
|
||||
};
|
||||
|
||||
array<FBCmd, 17> typeToFBCmd =
|
||||
{
|
||||
{
|
||||
FBCmd::FBCmd_check_state,
|
||||
FBCmd::FBCmd_change_state,
|
||||
FBCmd::FBCmd_dump_config,
|
||||
FBCmd::FBCmd_subscribe_to_heartbeats,
|
||||
FBCmd::FBCmd_unsubscribe_from_heartbeats,
|
||||
FBCmd::FBCmd_subscribe_to_state_change,
|
||||
FBCmd::FBCmd_unsubscribe_from_state_change,
|
||||
FBCmd::FBCmd_state_change_exiting_received,
|
||||
FBCmd::FBCmd_current_state,
|
||||
FBCmd::FBCmd_transition_status,
|
||||
FBCmd::FBCmd_config,
|
||||
FBCmd::FBCmd_heartbeat_subscription,
|
||||
FBCmd::FBCmd_heartbeat_unsubscription,
|
||||
FBCmd::FBCmd_heartbeat,
|
||||
FBCmd::FBCmd_state_change_subscription,
|
||||
FBCmd::FBCmd_state_change_unsubscription,
|
||||
FBCmd::FBCmd_state_change
|
||||
}
|
||||
};
|
||||
|
||||
array<Type, 17> fbCmdToType =
|
||||
{
|
||||
{
|
||||
Type::check_state,
|
||||
Type::change_state,
|
||||
Type::dump_config,
|
||||
Type::subscribe_to_heartbeats,
|
||||
Type::unsubscribe_from_heartbeats,
|
||||
Type::subscribe_to_state_change,
|
||||
Type::unsubscribe_from_state_change,
|
||||
Type::state_change_exiting_received,
|
||||
Type::current_state,
|
||||
Type::transition_status,
|
||||
Type::config,
|
||||
Type::heartbeat_subscription,
|
||||
Type::heartbeat_unsubscription,
|
||||
Type::heartbeat,
|
||||
Type::state_change_subscription,
|
||||
Type::state_change_unsubscription,
|
||||
Type::state_change
|
||||
}
|
||||
};
|
||||
|
||||
fair::mq::State GetMQState(const FBState state) { return fbStateToMQState.at(state); }
|
||||
FBState GetFBState(const fair::mq::State state) { return mqStateToFBState.at(static_cast<int>(state)); }
|
||||
fair::mq::Transition GetMQTransition(const FBTransition transition) { return fbTransitionToMQTransition.at(transition); }
|
||||
FBTransition GetFBTransition(const fair::mq::Transition transition) { return mqTransitionToFBTransition.at(static_cast<int>(transition)); }
|
||||
|
||||
Result GetResult(const FBResult result) { return fbResultToResult.at(result); }
|
||||
FBResult GetFBResult(const Result result) { return resultToFBResult.at(static_cast<int>(result)); }
|
||||
string GetResultName(const Result result) { return resultNames.at(static_cast<int>(result)); }
|
||||
string GetTypeName(const Type type) { return typeNames.at(static_cast<int>(type)); }
|
||||
|
||||
FBCmd GetFBCmd(const Type type) { return typeToFBCmd.at(static_cast<int>(type)); }
|
||||
|
||||
string Cmds::Serialize(const Format type) const
|
||||
{
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
vector<flatbuffers::Offset<FBCommand>> commandOffsets;
|
||||
|
||||
for (auto& cmd : fCmds) {
|
||||
flatbuffers::Offset<FBCommand> cmdOffset;
|
||||
unique_ptr<FBCommandBuilder> cmdBuilder; // delay the creation of the builder, because child strings need to be constructed first (which are conditional)
|
||||
|
||||
switch (cmd->GetType()) {
|
||||
case Type::check_state: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::change_state: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_transition(GetFBTransition(static_cast<ChangeState&>(*cmd).GetTransition()));
|
||||
}
|
||||
break;
|
||||
case Type::dump_config: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::subscribe_to_heartbeats: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_heartbeats: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::subscribe_to_state_change: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_state_change: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::state_change_exiting_received: {
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::current_state: {
|
||||
auto deviceId = fbb.CreateString(static_cast<CurrentState&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_current_state(GetFBState(static_cast<CurrentState&>(*cmd).GetCurrentState()));
|
||||
}
|
||||
break;
|
||||
case Type::transition_status: {
|
||||
auto deviceId = fbb.CreateString(static_cast<TransitionStatus&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_result(GetFBResult(static_cast<TransitionStatus&>(*cmd).GetResult()));
|
||||
cmdBuilder->add_transition(GetFBTransition(static_cast<TransitionStatus&>(*cmd).GetTransition()));
|
||||
}
|
||||
break;
|
||||
case Type::config: {
|
||||
auto deviceId = fbb.CreateString(static_cast<Config&>(*cmd).GetDeviceId());
|
||||
auto config = fbb.CreateString(static_cast<Config&>(*cmd).GetConfig());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_config_string(config);
|
||||
}
|
||||
break;
|
||||
case Type::heartbeat_subscription: {
|
||||
auto deviceId = fbb.CreateString(static_cast<HeartbeatSubscription&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_result(GetFBResult(static_cast<HeartbeatSubscription&>(*cmd).GetResult()));
|
||||
}
|
||||
break;
|
||||
case Type::heartbeat_unsubscription: {
|
||||
auto deviceId = fbb.CreateString(static_cast<HeartbeatUnsubscription&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_result(GetFBResult(static_cast<HeartbeatUnsubscription&>(*cmd).GetResult()));
|
||||
}
|
||||
break;
|
||||
case Type::heartbeat: {
|
||||
auto deviceId = fbb.CreateString(static_cast<Heartbeat&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
}
|
||||
break;
|
||||
case Type::state_change_subscription: {
|
||||
auto deviceId = fbb.CreateString(static_cast<StateChangeSubscription&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_result(GetFBResult(static_cast<StateChangeSubscription&>(*cmd).GetResult()));
|
||||
}
|
||||
break;
|
||||
case Type::state_change_unsubscription: {
|
||||
auto deviceId = fbb.CreateString(static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_result(GetFBResult(static_cast<StateChangeUnsubscription&>(*cmd).GetResult()));
|
||||
}
|
||||
break;
|
||||
case Type::state_change: {
|
||||
auto deviceId = fbb.CreateString(static_cast<StateChange&>(*cmd).GetDeviceId());
|
||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_task_id(static_cast<StateChange&>(*cmd).GetTaskId());
|
||||
cmdBuilder->add_last_state(GetFBState(static_cast<StateChange&>(*cmd).GetLastState()));
|
||||
cmdBuilder->add_current_state(GetFBState(static_cast<StateChange&>(*cmd).GetCurrentState()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Serialize()");
|
||||
break;
|
||||
}
|
||||
|
||||
cmdBuilder->add_command_id(typeToFBCmd.at(static_cast<int>(cmd->GetType())));
|
||||
|
||||
cmdOffset = cmdBuilder->Finish();
|
||||
commandOffsets.push_back(cmdOffset);
|
||||
}
|
||||
|
||||
auto commands = fbb.CreateVector(commandOffsets);
|
||||
auto cmds = CreateFBCommands(fbb, commands);
|
||||
fbb.Finish(cmds);
|
||||
|
||||
if (type == Format::Binary) {
|
||||
return string(reinterpret_cast<char*>(fbb.GetBufferPointer()), fbb.GetSize());
|
||||
} else { // Type == Format::JSON
|
||||
flatbuffers::Parser parser;
|
||||
if (!parser.Parse(commandsFormatDefFbs)) {
|
||||
throw CommandFormatError("Serialize couldn't parse commands format");
|
||||
}
|
||||
std::string json;
|
||||
if (!flatbuffers::GenerateText(parser, fbb.GetBufferPointer(), &json)) {
|
||||
throw CommandFormatError("Serialize couldn't serialize parsed data to JSON!");
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
void Cmds::Deserialize(const string& str, const Format type)
|
||||
{
|
||||
fCmds.clear();
|
||||
|
||||
const flatbuffers::Vector<flatbuffers::Offset<FBCommand>>* cmds;
|
||||
|
||||
if (type == Format::Binary) {
|
||||
cmds = cmd::GetFBCommands(const_cast<char*>(str.c_str()))->commands();
|
||||
} else { // Type == Format::JSON
|
||||
flatbuffers::Parser parser;
|
||||
if (!parser.Parse(commandsFormatDefFbs)) {
|
||||
throw CommandFormatError("Deserialize couldn't parse commands format");
|
||||
}
|
||||
if (!parser.Parse(str.c_str())) {
|
||||
throw CommandFormatError("Deserialize couldn't parse incoming JSON string");
|
||||
}
|
||||
cmds = cmd::GetFBCommands(parser.builder_.GetBufferPointer())->commands();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < cmds->size(); ++i) {
|
||||
const fair::mq::sdk::cmd::FBCommand& cmdPtr = *(cmds->Get(i));
|
||||
switch (cmdPtr.command_id()) {
|
||||
case FBCmd_check_state:
|
||||
fCmds.emplace_back(make<CheckState>());
|
||||
break;
|
||||
case FBCmd_change_state:
|
||||
fCmds.emplace_back(make<ChangeState>(GetMQTransition(cmdPtr.transition())));
|
||||
break;
|
||||
case FBCmd_dump_config:
|
||||
fCmds.emplace_back(make<DumpConfig>());
|
||||
break;
|
||||
case FBCmd_subscribe_to_heartbeats:
|
||||
fCmds.emplace_back(make<SubscribeToHeartbeats>());
|
||||
break;
|
||||
case FBCmd_unsubscribe_from_heartbeats:
|
||||
fCmds.emplace_back(make<UnsubscribeFromHeartbeats>());
|
||||
break;
|
||||
case FBCmd_subscribe_to_state_change:
|
||||
fCmds.emplace_back(make<SubscribeToStateChange>());
|
||||
break;
|
||||
case FBCmd_unsubscribe_from_state_change:
|
||||
fCmds.emplace_back(make<UnsubscribeFromStateChange>());
|
||||
break;
|
||||
case FBCmd_state_change_exiting_received:
|
||||
fCmds.emplace_back(make<StateChangeExitingReceived>());
|
||||
break;
|
||||
case FBCmd_current_state:
|
||||
fCmds.emplace_back(make<CurrentState>(cmdPtr.device_id()->str(), GetMQState(cmdPtr.current_state())));
|
||||
break;
|
||||
case FBCmd_transition_status:
|
||||
fCmds.emplace_back(make<TransitionStatus>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result()), GetMQTransition(cmdPtr.transition())));
|
||||
break;
|
||||
case FBCmd_config:
|
||||
fCmds.emplace_back(make<Config>(cmdPtr.device_id()->str(), cmdPtr.config_string()->str()));
|
||||
break;
|
||||
case FBCmd_heartbeat_subscription:
|
||||
fCmds.emplace_back(make<HeartbeatSubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
||||
break;
|
||||
case FBCmd_heartbeat_unsubscription:
|
||||
fCmds.emplace_back(make<HeartbeatUnsubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
||||
break;
|
||||
case FBCmd_heartbeat:
|
||||
fCmds.emplace_back(make<Heartbeat>(cmdPtr.device_id()->str()));
|
||||
break;
|
||||
case FBCmd_state_change_subscription:
|
||||
fCmds.emplace_back(make<StateChangeSubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
||||
break;
|
||||
case FBCmd_state_change_unsubscription:
|
||||
fCmds.emplace_back(make<StateChangeUnsubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
||||
break;
|
||||
case FBCmd_state_change:
|
||||
fCmds.emplace_back(make<StateChange>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetMQState(cmdPtr.last_state()), GetMQState(cmdPtr.current_state())));
|
||||
break;
|
||||
default:
|
||||
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Deserialize()");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace sdk
|
||||
} // namespace mq
|
||||
} // namespace fair
|
361
fairmq/sdk/commands/Commands.h
Normal file
361
fairmq/sdk/commands/Commands.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 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" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_COMMANDFACTORY
|
||||
#define FAIR_MQ_SDK_COMMANDFACTORY
|
||||
|
||||
#include <fairmq/States.h>
|
||||
#include <fairmq/tools/CppSTL.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
namespace sdk
|
||||
{
|
||||
namespace cmd
|
||||
{
|
||||
|
||||
enum class Format : int {
|
||||
Binary,
|
||||
JSON
|
||||
};
|
||||
|
||||
enum class Result : int {
|
||||
Ok,
|
||||
Failure
|
||||
};
|
||||
|
||||
enum class Type : int
|
||||
{
|
||||
check_state, // args: { }
|
||||
change_state, // args: { transition }
|
||||
dump_config, // args: { }
|
||||
subscribe_to_heartbeats, // args: { }
|
||||
unsubscribe_from_heartbeats, // args: { }
|
||||
subscribe_to_state_change, // args: { }
|
||||
unsubscribe_from_state_change, // args: { }
|
||||
state_change_exiting_received, // args: { }
|
||||
|
||||
current_state, // args: { device_id, current_state }
|
||||
transition_status, // args: { device_id, Result, transition }
|
||||
config, // args: { device_id, config_string }
|
||||
heartbeat_subscription, // args: { device_id, Result }
|
||||
heartbeat_unsubscription, // args: { device_id, Result }
|
||||
heartbeat, // args: { device_id }
|
||||
state_change_subscription, // args: { device_id, Result }
|
||||
state_change_unsubscription, // args: { device_id, Result }
|
||||
state_change // args: { device_id, task_id, last_state, current_state }
|
||||
};
|
||||
|
||||
struct Cmd
|
||||
{
|
||||
explicit Cmd(const Type type) : fType(type) {}
|
||||
|
||||
Type GetType() const { return fType; }
|
||||
|
||||
private:
|
||||
Type fType;
|
||||
};
|
||||
|
||||
struct CheckState : Cmd
|
||||
{
|
||||
explicit CheckState() : Cmd(Type::check_state) {}
|
||||
};
|
||||
|
||||
struct ChangeState : Cmd
|
||||
{
|
||||
explicit ChangeState(Transition transition)
|
||||
: Cmd(Type::change_state)
|
||||
, fTransition(transition)
|
||||
{}
|
||||
|
||||
Transition GetTransition() const { return fTransition; }
|
||||
void SetTransition(Transition transition) { fTransition = transition; }
|
||||
|
||||
private:
|
||||
Transition fTransition;
|
||||
};
|
||||
|
||||
struct DumpConfig : Cmd
|
||||
{
|
||||
explicit DumpConfig() : Cmd(Type::dump_config) {}
|
||||
};
|
||||
|
||||
struct SubscribeToHeartbeats : Cmd
|
||||
{
|
||||
explicit SubscribeToHeartbeats() : Cmd(Type::subscribe_to_heartbeats) {}
|
||||
};
|
||||
|
||||
struct UnsubscribeFromHeartbeats : Cmd
|
||||
{
|
||||
explicit UnsubscribeFromHeartbeats() : Cmd(Type::unsubscribe_from_heartbeats) {}
|
||||
};
|
||||
|
||||
struct SubscribeToStateChange : Cmd
|
||||
{
|
||||
explicit SubscribeToStateChange() : Cmd(Type::subscribe_to_state_change) {}
|
||||
};
|
||||
|
||||
struct UnsubscribeFromStateChange : Cmd
|
||||
{
|
||||
explicit UnsubscribeFromStateChange() : Cmd(Type::unsubscribe_from_state_change) {}
|
||||
};
|
||||
|
||||
struct StateChangeExitingReceived : Cmd
|
||||
{
|
||||
explicit StateChangeExitingReceived() : Cmd(Type::state_change_exiting_received) {}
|
||||
};
|
||||
|
||||
struct CurrentState : Cmd
|
||||
{
|
||||
explicit CurrentState(const std::string& id, State currentState)
|
||||
: Cmd(Type::current_state)
|
||||
, fDeviceId(id)
|
||||
, fCurrentState(currentState)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
||||
void SetCurrentState(fair::mq::State state) { fCurrentState = state; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
fair::mq::State fCurrentState;
|
||||
};
|
||||
|
||||
struct TransitionStatus : Cmd
|
||||
{
|
||||
explicit TransitionStatus(const std::string& id, const Result result, const Transition transition)
|
||||
: Cmd(Type::transition_status)
|
||||
, fDeviceId(id)
|
||||
, fResult(result)
|
||||
, fTransition(transition)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
Transition GetTransition() const { return fTransition; }
|
||||
void SetTransition(const Transition transition) { fTransition = transition; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
Result fResult;
|
||||
Transition fTransition;
|
||||
};
|
||||
|
||||
struct Config : Cmd
|
||||
{
|
||||
explicit Config(const std::string& id, const std::string& config)
|
||||
: Cmd(Type::config)
|
||||
, fDeviceId(id)
|
||||
, fConfig(config)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
std::string GetConfig() const { return fConfig; }
|
||||
void SetConfig(const std::string& config) { fConfig = config; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
std::string fConfig;
|
||||
};
|
||||
|
||||
struct HeartbeatSubscription : Cmd
|
||||
{
|
||||
explicit HeartbeatSubscription(const std::string& id, const Result result)
|
||||
: Cmd(Type::heartbeat_subscription)
|
||||
, fDeviceId(id)
|
||||
, fResult(result)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
Result fResult;
|
||||
};
|
||||
|
||||
struct HeartbeatUnsubscription : Cmd
|
||||
{
|
||||
explicit HeartbeatUnsubscription(const std::string& id, const Result result)
|
||||
: Cmd(Type::heartbeat_unsubscription)
|
||||
, fDeviceId(id)
|
||||
, fResult(result)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
Result fResult;
|
||||
};
|
||||
|
||||
struct Heartbeat : Cmd
|
||||
{
|
||||
explicit Heartbeat(const std::string& id)
|
||||
: Cmd(Type::heartbeat)
|
||||
, fDeviceId(id)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
};
|
||||
|
||||
struct StateChangeSubscription : Cmd
|
||||
{
|
||||
explicit StateChangeSubscription(const std::string& id, const Result result)
|
||||
: Cmd(Type::state_change_subscription)
|
||||
, fDeviceId(id)
|
||||
, fResult(result)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
Result fResult;
|
||||
};
|
||||
|
||||
struct StateChangeUnsubscription : Cmd
|
||||
{
|
||||
explicit StateChangeUnsubscription(const std::string& id, const Result result)
|
||||
: Cmd(Type::state_change_unsubscription)
|
||||
, fDeviceId(id)
|
||||
, fResult(result)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
Result fResult;
|
||||
};
|
||||
|
||||
struct StateChange : Cmd
|
||||
{
|
||||
explicit StateChange(const std::string& deviceId, const uint64_t taskId, const State lastState, const State currentState)
|
||||
: Cmd(Type::state_change)
|
||||
, fDeviceId(deviceId)
|
||||
, fTaskId(taskId)
|
||||
, fLastState(lastState)
|
||||
, fCurrentState(currentState)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
uint64_t GetTaskId() const { return fTaskId; }
|
||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
||||
fair::mq::State GetLastState() const { return fLastState; }
|
||||
void SetLastState(const fair::mq::State state) { fLastState = state; }
|
||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
||||
void SetCurrentState(const fair::mq::State state) { fCurrentState = state; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
uint64_t fTaskId;
|
||||
fair::mq::State fLastState;
|
||||
fair::mq::State fCurrentState;
|
||||
};
|
||||
|
||||
template<typename C, typename... Args>
|
||||
std::unique_ptr<Cmd> make(Args&&... args)
|
||||
{
|
||||
return fair::mq::tools::make_unique<C>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
struct Cmds
|
||||
{
|
||||
using container = std::vector<std::unique_ptr<Cmd>>;
|
||||
struct CommandFormatError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
explicit Cmds() {}
|
||||
|
||||
template<typename... Rest>
|
||||
explicit Cmds(std::unique_ptr<Cmd>&& first, Rest&&... rest)
|
||||
{
|
||||
Unpack(std::forward<std::unique_ptr<Cmd>&&>(first), std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
|
||||
void Add(std::unique_ptr<Cmd>&& cmd) { fCmds.emplace_back(std::move(cmd)); }
|
||||
|
||||
template<typename C, typename... Args>
|
||||
void Add(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<Cmd, C>::value, "Only types derived from fair::mq::cmd::Cmd are allowed");
|
||||
Add(make<C>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
Cmd& At(size_t i) { return *(fCmds.at(i)); }
|
||||
|
||||
size_t Size() const { return fCmds.size(); }
|
||||
void Reset() { fCmds.clear(); }
|
||||
|
||||
std::string Serialize(const Format type = Format::Binary) const;
|
||||
void Deserialize(const std::string&, const Format type = Format::Binary);
|
||||
|
||||
private:
|
||||
container fCmds;
|
||||
|
||||
void Unpack() {}
|
||||
|
||||
template <class... Rest>
|
||||
void Unpack(std::unique_ptr<Cmd>&& first, Rest&&... rest)
|
||||
{
|
||||
fCmds.emplace_back(std::move(first));
|
||||
Unpack(std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
public:
|
||||
using iterator = container::iterator;
|
||||
using const_iterator = container::const_iterator;
|
||||
|
||||
auto begin() -> decltype(fCmds.begin()) { return fCmds.begin(); }
|
||||
auto end() -> decltype(fCmds.end()) { return fCmds.end(); }
|
||||
auto cbegin() -> decltype(fCmds.cbegin()) { return fCmds.cbegin(); }
|
||||
auto cend() -> decltype(fCmds.cend()) { return fCmds.cend(); }
|
||||
};
|
||||
|
||||
std::string GetResultName(const Result result);
|
||||
std::string GetTypeName(const Type type);
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Result& result) { return os << GetResultName(result); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const Type& type) { return os << GetTypeName(type); }
|
||||
|
||||
} /* namespace cmd */
|
||||
} /* namespace sdk */
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
||||
#endif /* FAIR_MQ_SDK_COMMANDFACTORY */
|
79
fairmq/sdk/commands/CommandsFormat.fbs
Normal file
79
fairmq/sdk/commands/CommandsFormat.fbs
Normal file
@@ -0,0 +1,79 @@
|
||||
namespace fair.mq.sdk.cmd;
|
||||
|
||||
enum FBResult:byte {
|
||||
Ok,
|
||||
Failure
|
||||
}
|
||||
|
||||
enum FBState:byte {
|
||||
Ok,
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
Initialized,
|
||||
Binding,
|
||||
Bound,
|
||||
Connecting,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
}
|
||||
|
||||
enum FBTransition:byte {
|
||||
Auto,
|
||||
InitDevice,
|
||||
CompleteInit,
|
||||
Bind,
|
||||
Connect,
|
||||
InitTask,
|
||||
Run,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
End,
|
||||
ErrorFound
|
||||
}
|
||||
|
||||
enum FBCmd:byte {
|
||||
check_state, // args: { }
|
||||
change_state, // args: { transition }
|
||||
dump_config, // args: { }
|
||||
subscribe_to_heartbeats, // args: { }
|
||||
unsubscribe_from_heartbeats, // args: { }
|
||||
subscribe_to_state_change, // args: { }
|
||||
unsubscribe_from_state_change, // args: { }
|
||||
state_change_exiting_received, // args: { }
|
||||
|
||||
current_state, // args: { device_id, current_state }
|
||||
transition_status, // args: { device_id, Result, transition }
|
||||
config, // args: { device_id, config_string }
|
||||
heartbeat_subscription, // args: { device_id, Result }
|
||||
heartbeat_unsubscription, // args: { device_id, Result }
|
||||
heartbeat, // args: { device_id }
|
||||
state_change_subscription, // args: { device_id, Result }
|
||||
state_change_unsubscription, // args: { device_id, Result }
|
||||
state_change // args: { device_id, task_id, last_state, current_state }
|
||||
}
|
||||
|
||||
table FBCommand {
|
||||
command_id:FBCmd;
|
||||
device_id:string;
|
||||
task_id:uint64;
|
||||
state:FBState;
|
||||
transition:FBTransition;
|
||||
result:FBResult;
|
||||
config_string:string;
|
||||
last_state:FBState;
|
||||
current_state:FBState;
|
||||
debug:string;
|
||||
}
|
||||
|
||||
table FBCommands {
|
||||
commands:[FBCommand];
|
||||
}
|
||||
|
||||
root_type FBCommands;
|
21
fairmq/sdk/commands/CommandsFormatDef.h.in
Normal file
21
fairmq/sdk/commands/CommandsFormatDef.h.in
Normal file
@@ -0,0 +1,21 @@
|
||||
/********************************************************************************
|
||||
* 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 <string>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
namespace sdk {
|
||||
namespace cmd {
|
||||
|
||||
constexpr auto commandsFormatDefFbs = R"(@commands_format_def_fbs@)";
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace sdk
|
||||
} // namespace mq
|
||||
} // namespace fair
|
@@ -73,15 +73,6 @@ struct RegionCounter
|
||||
std::atomic<uint64_t> fCount;
|
||||
};
|
||||
|
||||
struct MonitorStatus
|
||||
{
|
||||
MonitorStatus()
|
||||
: fActive(true)
|
||||
{}
|
||||
|
||||
bool fActive;
|
||||
};
|
||||
|
||||
struct MetaHeader
|
||||
{
|
||||
size_t fSize;
|
||||
|
@@ -5,8 +5,8 @@
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
#include <fairmq/shmem/Common.h>
|
||||
#include <fairmq/shmem/Region.h>
|
||||
#include "Common.h"
|
||||
#include "Region.h"
|
||||
|
||||
#include "FairMQMessageSHM.h"
|
||||
#include "FairMQUnmanagedRegionSHM.h"
|
||||
@@ -38,8 +38,7 @@ FairMQMessageSHM::FairMQMessageSHM(Manager& manager, FairMQTransportFactory* fac
|
||||
, fHint(0)
|
||||
, fLocalPtr(nullptr)
|
||||
{
|
||||
if (zmq_msg_init(&fMessage) != 0)
|
||||
{
|
||||
if (zmq_msg_init(&fMessage) != 0) {
|
||||
LOG(error) << "failed initializing message, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
fMetaCreated = true;
|
||||
@@ -74,15 +73,11 @@ FairMQMessageSHM::FairMQMessageSHM(Manager& manager, void* data, const size_t si
|
||||
, fHint(0)
|
||||
, fLocalPtr(nullptr)
|
||||
{
|
||||
if (InitializeChunk(size))
|
||||
{
|
||||
if (InitializeChunk(size)) {
|
||||
memcpy(fLocalPtr, data, size);
|
||||
if (ffn)
|
||||
{
|
||||
if (ffn) {
|
||||
ffn(data, hint);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
@@ -102,16 +97,12 @@ FairMQMessageSHM::FairMQMessageSHM(Manager& manager, FairMQUnmanagedRegionPtr& r
|
||||
, fLocalPtr(static_cast<char*>(data))
|
||||
{
|
||||
if (reinterpret_cast<const char*>(data) >= reinterpret_cast<const char*>(region->GetData()) ||
|
||||
reinterpret_cast<const char*>(data) <= reinterpret_cast<const char*>(region->GetData()) + region->GetSize())
|
||||
{
|
||||
reinterpret_cast<const char*>(data) <= reinterpret_cast<const char*>(region->GetData()) + region->GetSize()) {
|
||||
fHandle = (bipc::managed_shared_memory::handle_t)(reinterpret_cast<const char*>(data) - reinterpret_cast<const char*>(region->GetData()));
|
||||
|
||||
if (zmq_msg_init_size(&fMessage, sizeof(MetaHeader)) != 0)
|
||||
{
|
||||
if (zmq_msg_init_size(&fMessage, sizeof(MetaHeader)) != 0) {
|
||||
LOG(error) << "failed initializing meta message, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
MetaHeader header;
|
||||
header.fSize = size;
|
||||
header.fHandle = fHandle;
|
||||
@@ -121,9 +112,7 @@ FairMQMessageSHM::FairMQMessageSHM(Manager& manager, FairMQUnmanagedRegionPtr& r
|
||||
|
||||
fMetaCreated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG(error) << "trying to create region message with data from outside the region";
|
||||
throw runtime_error("trying to create region message with data from outside the region");
|
||||
}
|
||||
@@ -131,24 +120,17 @@ FairMQMessageSHM::FairMQMessageSHM(Manager& manager, FairMQUnmanagedRegionPtr& r
|
||||
|
||||
bool FairMQMessageSHM::InitializeChunk(const size_t size)
|
||||
{
|
||||
while (fHandle < 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (fHandle < 0) {
|
||||
try {
|
||||
bipc::managed_shared_memory::size_type actualSize = size;
|
||||
char* hint = 0; // unused for bipc::allocate_new
|
||||
fLocalPtr = fManager.Segment().allocation_command<char>(bipc::allocate_new, size, actualSize, hint);
|
||||
}
|
||||
catch (bipc::bad_alloc& ba)
|
||||
{
|
||||
} catch (bipc::bad_alloc& ba) {
|
||||
// LOG(warn) << "Shared memory full...";
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
if (fInterrupted)
|
||||
{
|
||||
if (fInterrupted) {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -157,8 +139,7 @@ bool FairMQMessageSHM::InitializeChunk(const size_t size)
|
||||
|
||||
fSize = size;
|
||||
|
||||
if (zmq_msg_init_size(&fMessage, sizeof(MetaHeader)) != 0)
|
||||
{
|
||||
if (zmq_msg_init_size(&fMessage, sizeof(MetaHeader)) != 0) {
|
||||
LOG(error) << "failed initializing meta message, reason: " << zmq_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
@@ -180,8 +161,7 @@ void FairMQMessageSHM::Rebuild()
|
||||
|
||||
fQueued = false;
|
||||
|
||||
if (zmq_msg_init(&fMessage) != 0)
|
||||
{
|
||||
if (zmq_msg_init(&fMessage) != 0) {
|
||||
LOG(error) << "failed initializing message, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
fMetaCreated = true;
|
||||
@@ -190,9 +170,7 @@ void FairMQMessageSHM::Rebuild()
|
||||
void FairMQMessageSHM::Rebuild(const size_t size)
|
||||
{
|
||||
CloseMessage();
|
||||
|
||||
fQueued = false;
|
||||
|
||||
InitializeChunk(size);
|
||||
}
|
||||
|
||||
@@ -202,32 +180,25 @@ void FairMQMessageSHM::Rebuild(void* data, const size_t size, fairmq_free_fn* ff
|
||||
|
||||
fQueued = false;
|
||||
|
||||
if (InitializeChunk(size))
|
||||
{
|
||||
if (InitializeChunk(size)) {
|
||||
memcpy(fLocalPtr, data, size);
|
||||
if (ffn)
|
||||
{
|
||||
if (ffn) {
|
||||
ffn(data, hint);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zmq_msg_t* FairMQMessageSHM::GetMessage()
|
||||
{
|
||||
return &fMessage;
|
||||
}
|
||||
|
||||
void* FairMQMessageSHM::GetData() const
|
||||
{
|
||||
if (fLocalPtr) {
|
||||
return fLocalPtr;
|
||||
} else {
|
||||
if (!fLocalPtr) {
|
||||
if (fRegionId == 0) {
|
||||
return fManager.Segment().get_address_from_handle(fHandle);
|
||||
if (fSize > 0) {
|
||||
fLocalPtr = reinterpret_cast<char*>(fManager.Segment().get_address_from_handle(fHandle));
|
||||
} else {
|
||||
fLocalPtr = nullptr;
|
||||
}
|
||||
} else {
|
||||
fRegionPtr = fManager.GetRemoteRegion(fRegionId);
|
||||
if (fRegionPtr) {
|
||||
@@ -236,14 +207,10 @@ void* FairMQMessageSHM::GetData() const
|
||||
// LOG(warn) << "could not get pointer from a region message";
|
||||
fLocalPtr = nullptr;
|
||||
}
|
||||
return fLocalPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t FairMQMessageSHM::GetSize() const
|
||||
{
|
||||
return fSize;
|
||||
return fLocalPtr;
|
||||
}
|
||||
|
||||
bool FairMQMessageSHM::SetUsedSize(const size_t size)
|
||||
@@ -270,72 +237,45 @@ bool FairMQMessageSHM::SetUsedSize(const size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
fair::mq::Transport FairMQMessageSHM::GetType() const
|
||||
{
|
||||
return fTransportType;
|
||||
}
|
||||
|
||||
void FairMQMessageSHM::Copy(const FairMQMessage& msg)
|
||||
{
|
||||
if (fHandle < 0)
|
||||
{
|
||||
if (fHandle < 0) {
|
||||
bipc::managed_shared_memory::handle_t otherHandle = static_cast<const FairMQMessageSHM&>(msg).fHandle;
|
||||
if (otherHandle)
|
||||
{
|
||||
if (InitializeChunk(msg.GetSize()))
|
||||
{
|
||||
if (otherHandle) {
|
||||
if (InitializeChunk(msg.GetSize())) {
|
||||
memcpy(GetData(), msg.GetData(), msg.GetSize());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG(error) << "copy fail: source message not initialized!";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG(error) << "copy fail: target message already initialized!";
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQMessageSHM::CloseMessage()
|
||||
{
|
||||
if (fHandle >= 0 && !fQueued)
|
||||
{
|
||||
if (fRegionId == 0)
|
||||
{
|
||||
if (fHandle >= 0 && !fQueued) {
|
||||
if (fRegionId == 0) {
|
||||
fManager.Segment().deallocate(fManager.Segment().get_address_from_handle(fHandle));
|
||||
fHandle = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fRegionPtr)
|
||||
{
|
||||
} else {
|
||||
if (!fRegionPtr) {
|
||||
fRegionPtr = fManager.GetRemoteRegion(fRegionId);
|
||||
}
|
||||
|
||||
if (fRegionPtr)
|
||||
{
|
||||
if (fRegionPtr) {
|
||||
fRegionPtr->ReleaseBlock({fHandle, fSize, fHint});
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG(warn) << "region ack queue for id " << fRegionId << " no longer exist. Not sending ack";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fMetaCreated)
|
||||
{
|
||||
if (zmq_msg_close(&fMessage) != 0)
|
||||
{
|
||||
if (fMetaCreated) {
|
||||
if (zmq_msg_close(&fMessage) != 0) {
|
||||
LOG(error) << "failed closing message, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
fMetaCreated = false;
|
||||
}
|
||||
}
|
||||
|
||||
FairMQMessageSHM::~FairMQMessageSHM()
|
||||
{
|
||||
CloseMessage();
|
||||
}
|
||||
|
@@ -40,15 +40,15 @@ class FairMQMessageSHM final : public FairMQMessage
|
||||
void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) override;
|
||||
|
||||
void* GetData() const override;
|
||||
size_t GetSize() const override;
|
||||
size_t GetSize() const override { return fSize; }
|
||||
|
||||
bool SetUsedSize(const size_t size) override;
|
||||
|
||||
fair::mq::Transport GetType() const override;
|
||||
fair::mq::Transport GetType() const override { return fTransportType; }
|
||||
|
||||
void Copy(const FairMQMessage& msg) override;
|
||||
|
||||
~FairMQMessageSHM() override;
|
||||
~FairMQMessageSHM() override { CloseMessage(); }
|
||||
|
||||
private:
|
||||
fair::mq::shmem::Manager& fManager;
|
||||
@@ -65,7 +65,7 @@ class FairMQMessageSHM final : public FairMQMessage
|
||||
mutable char* fLocalPtr;
|
||||
|
||||
bool InitializeChunk(const size_t size);
|
||||
zmq_msg_t* GetMessage();
|
||||
zmq_msg_t* GetMessage() { return &fMessage; }
|
||||
void CloseMessage();
|
||||
};
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
#include <fairmq/shmem/Common.h>
|
||||
#include "Common.h"
|
||||
|
||||
#include "FairMQSocketSHM.h"
|
||||
#include "FairMQMessageSHM.h"
|
||||
@@ -38,32 +38,27 @@ FairMQSocketSHM::FairMQSocketSHM(Manager& manager, const string& type, const str
|
||||
assert(context);
|
||||
fSocket = zmq_socket(context, GetConstant(type));
|
||||
|
||||
if (fSocket == nullptr)
|
||||
{
|
||||
if (fSocket == nullptr) {
|
||||
LOG(error) << "Failed creating socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (zmq_setsockopt(fSocket, ZMQ_IDENTITY, fId.c_str(), fId.length()) != 0)
|
||||
{
|
||||
if (zmq_setsockopt(fSocket, ZMQ_IDENTITY, fId.c_str(), fId.length()) != 0) {
|
||||
LOG(error) << "Failed setting ZMQ_IDENTITY socket option, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
// Tell socket to try and send/receive outstanding messages for <linger> milliseconds before terminating.
|
||||
// Default value for ZeroMQ is -1, which is to wait forever.
|
||||
int linger = 1000;
|
||||
if (zmq_setsockopt(fSocket, ZMQ_LINGER, &linger, sizeof(linger)) != 0)
|
||||
{
|
||||
if (zmq_setsockopt(fSocket, ZMQ_LINGER, &linger, sizeof(linger)) != 0) {
|
||||
LOG(error) << "Failed setting ZMQ_LINGER socket option, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
if (zmq_setsockopt(fSocket, ZMQ_SNDTIMEO, &fSndTimeout, sizeof(fSndTimeout)) != 0)
|
||||
{
|
||||
if (zmq_setsockopt(fSocket, ZMQ_SNDTIMEO, &fSndTimeout, sizeof(fSndTimeout)) != 0) {
|
||||
LOG(error) << "Failed setting ZMQ_SNDTIMEO socket option, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
if (zmq_setsockopt(fSocket, ZMQ_RCVTIMEO, &fRcvTimeout, sizeof(fRcvTimeout)) != 0)
|
||||
{
|
||||
if (zmq_setsockopt(fSocket, ZMQ_RCVTIMEO, &fRcvTimeout, sizeof(fRcvTimeout)) != 0) {
|
||||
LOG(error) << "Failed setting ZMQ_RCVTIMEO socket option, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
@@ -75,8 +70,7 @@ FairMQSocketSHM::FairMQSocketSHM(Manager& manager, const string& type, const str
|
||||
// }
|
||||
// }
|
||||
|
||||
if (type == "sub" || type == "pub")
|
||||
{
|
||||
if (type == "sub" || type == "pub") {
|
||||
LOG(error) << "PUB/SUB socket type is not supported for shared memory transport";
|
||||
throw fair::mq::SocketError("PUB/SUB socket type is not supported for shared memory transport");
|
||||
}
|
||||
@@ -86,10 +80,9 @@ FairMQSocketSHM::FairMQSocketSHM(Manager& manager, const string& type, const str
|
||||
|
||||
bool FairMQSocketSHM::Bind(const string& address)
|
||||
{
|
||||
// LOG(info) << "bind socket " << fId << " on " << address;
|
||||
// LOG(info) << "binding socket " << fId << " on " << address;
|
||||
|
||||
if (zmq_bind(fSocket, address.c_str()) != 0)
|
||||
{
|
||||
if (zmq_bind(fSocket, address.c_str()) != 0) {
|
||||
if (errno == EADDRINUSE) {
|
||||
// do not print error in this case, this is handled by FairMQDevice in case no connection could be established after trying a number of random ports from a range.
|
||||
return false;
|
||||
@@ -102,10 +95,9 @@ bool FairMQSocketSHM::Bind(const string& address)
|
||||
|
||||
bool FairMQSocketSHM::Connect(const string& address)
|
||||
{
|
||||
// LOG(info) << "connect socket " << fId << " on " << address;
|
||||
// LOG(info) << "connecting socket " << fId << " on " << address;
|
||||
|
||||
if (zmq_connect(fSocket, address.c_str()) != 0)
|
||||
{
|
||||
if (zmq_connect(fSocket, address.c_str()) != 0) {
|
||||
LOG(error) << "Failed connecting socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
@@ -116,55 +108,38 @@ bool FairMQSocketSHM::Connect(const string& address)
|
||||
int FairMQSocketSHM::Send(FairMQMessagePtr& msg, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
if (timeout == 0) {
|
||||
flags = ZMQ_DONTWAIT;
|
||||
}
|
||||
int elapsed = 0;
|
||||
|
||||
while (true && !fInterrupted)
|
||||
{
|
||||
while (true && !fInterrupted) {
|
||||
int nbytes = zmq_msg_send(static_cast<FairMQMessageSHM*>(msg.get())->GetMessage(), fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
if (nbytes == 0) {
|
||||
++fMessagesTx;
|
||||
return nbytes;
|
||||
}
|
||||
else if (nbytes > 0)
|
||||
{
|
||||
} else if (nbytes > 0) {
|
||||
static_cast<FairMQMessageSHM*>(msg.get())->fQueued = true;
|
||||
|
||||
size_t size = msg->GetSize();
|
||||
fBytesTx += size;
|
||||
++fMessagesTx;
|
||||
|
||||
return size;
|
||||
}
|
||||
else if (zmq_errno() == EAGAIN)
|
||||
{
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
} else if (zmq_errno() == EAGAIN) {
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0)) {
|
||||
if (timeout > 0) {
|
||||
elapsed += fSndTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
if (elapsed >= timeout) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (zmq_errno() == ETERM)
|
||||
{
|
||||
} else if (zmq_errno() == ETERM) {
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG(error) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
@@ -176,72 +151,53 @@ int FairMQSocketSHM::Send(FairMQMessagePtr& msg, const int timeout)
|
||||
int FairMQSocketSHM::Receive(FairMQMessagePtr& msg, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
if (timeout == 0) {
|
||||
flags = ZMQ_DONTWAIT;
|
||||
}
|
||||
int elapsed = 0;
|
||||
|
||||
zmq_msg_t* msgPtr = static_cast<FairMQMessageSHM*>(msg.get())->GetMessage();
|
||||
while (true)
|
||||
{
|
||||
int nbytes = zmq_msg_recv(msgPtr, fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
while (true) {
|
||||
FairMQMessageSHM* shmMsg = static_cast<FairMQMessageSHM*>(msg.get());
|
||||
zmq_msg_t* zmqMsg = shmMsg->GetMessage();
|
||||
int nbytes = zmq_msg_recv(zmqMsg, fSocket, flags);
|
||||
if (nbytes == 0) {
|
||||
++fMessagesRx;
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
else if (nbytes > 0)
|
||||
{
|
||||
// check for number of receiving messages. must be 1
|
||||
} else if (nbytes > 0) {
|
||||
// check for number of received messages. must be 1
|
||||
const auto numMsgs = nbytes / sizeof(MetaHeader);
|
||||
if (numMsgs > 1)
|
||||
{
|
||||
if (numMsgs > 1) {
|
||||
LOG(error) << "Receiving SHM multipart with a single message receive call";
|
||||
}
|
||||
|
||||
assert (numMsgs == 1);
|
||||
assert(numMsgs == 1);
|
||||
|
||||
MetaHeader* hdr = static_cast<MetaHeader*>(zmq_msg_data(msgPtr));
|
||||
size_t size = 0;
|
||||
static_cast<FairMQMessageSHM*>(msg.get())->fHandle = hdr->fHandle;
|
||||
static_cast<FairMQMessageSHM*>(msg.get())->fSize = hdr->fSize;
|
||||
static_cast<FairMQMessageSHM*>(msg.get())->fRegionId = hdr->fRegionId;
|
||||
static_cast<FairMQMessageSHM*>(msg.get())->fHint = hdr->fHint;
|
||||
size = msg->GetSize();
|
||||
MetaHeader* hdr = static_cast<MetaHeader*>(zmq_msg_data(zmqMsg));
|
||||
size_t size = hdr->fSize;
|
||||
shmMsg->fHandle = hdr->fHandle;
|
||||
shmMsg->fSize = size;
|
||||
shmMsg->fRegionId = hdr->fRegionId;
|
||||
shmMsg->fHint = hdr->fHint;
|
||||
|
||||
fBytesRx += size;
|
||||
++fMessagesRx;
|
||||
|
||||
return size;
|
||||
}
|
||||
else if (zmq_errno() == EAGAIN)
|
||||
{
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
} else if (zmq_errno() == EAGAIN) {
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0)) {
|
||||
if (timeout > 0) {
|
||||
elapsed += fRcvTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
if (elapsed >= timeout) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (zmq_errno() == ETERM)
|
||||
{
|
||||
} else if (zmq_errno() == ETERM) {
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG(error) << "Failed receiving on socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
@@ -251,8 +207,7 @@ int FairMQSocketSHM::Receive(FairMQMessagePtr& msg, const int timeout)
|
||||
int64_t FairMQSocketSHM::Send(vector<FairMQMessagePtr>& msgVec, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
if (timeout == 0) {
|
||||
flags = ZMQ_DONTWAIT;
|
||||
}
|
||||
const unsigned int vecSize = msgVec.size();
|
||||
@@ -269,27 +224,32 @@ int64_t FairMQSocketSHM::Send(vector<FairMQMessagePtr>& msgVec, const int timeou
|
||||
// prepare the message with shm metas
|
||||
MetaHeader* metas = static_cast<MetaHeader*>(zmq_msg_data(&zmqMsg));
|
||||
|
||||
for (auto& msg : msgVec)
|
||||
{
|
||||
for (auto& msg : msgVec) {
|
||||
zmq_msg_t* metaMsg = static_cast<FairMQMessageSHM*>(msg.get())->GetMessage();
|
||||
memcpy(metas++, zmq_msg_data(metaMsg), sizeof(MetaHeader));
|
||||
if (zmq_msg_size(metaMsg) > 0) {
|
||||
memcpy(metas++, zmq_msg_data(metaMsg), sizeof(MetaHeader));
|
||||
} else {
|
||||
// if the message is empty, create meta data to reflect this
|
||||
// (always creating meta data for empty messages would add an unnecessary allocation for the receive case, so we do it lazily here)
|
||||
MetaHeader hdr;
|
||||
hdr.fSize = 0;
|
||||
hdr.fHandle = -1;
|
||||
hdr.fRegionId = 0;
|
||||
hdr.fHint = 0;
|
||||
memcpy(metas++, &hdr, sizeof(MetaHeader));
|
||||
}
|
||||
}
|
||||
|
||||
while (!fInterrupted)
|
||||
{
|
||||
while (!fInterrupted) {
|
||||
int64_t totalSize = 0;
|
||||
int nbytes = zmq_msg_send(&zmqMsg, fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
if (nbytes == 0) {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return nbytes;
|
||||
}
|
||||
else if (nbytes > 0)
|
||||
{
|
||||
} else if (nbytes > 0) {
|
||||
assert(static_cast<unsigned int>(nbytes) == (vecSize * sizeof(MetaHeader))); // all or nothing
|
||||
|
||||
for (auto& msg : msgVec)
|
||||
{
|
||||
for (auto& msg : msgVec) {
|
||||
FairMQMessageSHM* shmMsg = static_cast<FairMQMessageSHM*>(msg.get());
|
||||
shmMsg->fQueued = true;
|
||||
totalSize += shmMsg->fSize;
|
||||
@@ -301,36 +261,25 @@ int64_t FairMQSocketSHM::Send(vector<FairMQMessagePtr>& msgVec, const int timeou
|
||||
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return totalSize;
|
||||
}
|
||||
else if (zmq_errno() == EAGAIN)
|
||||
{
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
} else if (zmq_errno() == EAGAIN) {
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0)) {
|
||||
if (timeout > 0) {
|
||||
elapsed += fSndTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
if (elapsed >= timeout) {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (zmq_errno() == ETERM)
|
||||
{
|
||||
} else if (zmq_errno() == ETERM) {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
LOG(error) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
return nbytes;
|
||||
@@ -344,8 +293,7 @@ int64_t FairMQSocketSHM::Send(vector<FairMQMessagePtr>& msgVec, const int timeou
|
||||
int64_t FairMQSocketSHM::Receive(vector<FairMQMessagePtr>& msgVec, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
if (timeout == 0) {
|
||||
flags = ZMQ_DONTWAIT;
|
||||
}
|
||||
int elapsed = 0;
|
||||
@@ -353,17 +301,13 @@ int64_t FairMQSocketSHM::Receive(vector<FairMQMessagePtr>& msgVec, const int tim
|
||||
zmq_msg_t zmqMsg;
|
||||
zmq_msg_init(&zmqMsg);
|
||||
|
||||
while (!fInterrupted)
|
||||
{
|
||||
while (!fInterrupted) {
|
||||
int64_t totalSize = 0;
|
||||
int nbytes = zmq_msg_recv(&zmqMsg, fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
if (nbytes == 0) {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return 0;
|
||||
}
|
||||
else if (nbytes > 0)
|
||||
{
|
||||
} else if (nbytes > 0) {
|
||||
MetaHeader* hdrVec = static_cast<MetaHeader*>(zmq_msg_data(&zmqMsg));
|
||||
const auto hdrVecSize = zmq_msg_size(&zmqMsg);
|
||||
assert(hdrVecSize > 0);
|
||||
@@ -373,24 +317,22 @@ int64_t FairMQSocketSHM::Receive(vector<FairMQMessagePtr>& msgVec, const int tim
|
||||
|
||||
msgVec.reserve(numMessages);
|
||||
|
||||
for (size_t m = 0; m < numMessages; m++)
|
||||
{
|
||||
MetaHeader hdr;
|
||||
memcpy(&hdr, &hdrVec[m], sizeof(MetaHeader));
|
||||
for (size_t m = 0; m < numMessages; m++) {
|
||||
// get the meta data pointer
|
||||
MetaHeader* hdr = &hdrVec[m];
|
||||
|
||||
msgVec.emplace_back(fair::mq::tools::make_unique<FairMQMessageSHM>(fManager, GetTransport()));
|
||||
// create new message (part)
|
||||
msgVec.emplace_back(tools::make_unique<FairMQMessageSHM>(fManager, GetTransport()));
|
||||
FairMQMessageSHM* shmMsg = static_cast<FairMQMessageSHM*>(msgVec.back().get());
|
||||
// fill the zmq buffer with the delivered meta data
|
||||
memcpy(zmq_msg_data(shmMsg->GetMessage()), hdr, sizeof(MetaHeader));
|
||||
// set the message members with the meta data
|
||||
shmMsg->fHandle = hdr->fHandle;
|
||||
shmMsg->fSize = hdr->fSize;
|
||||
shmMsg->fRegionId = hdr->fRegionId;
|
||||
shmMsg->fHint = hdr->fHint;
|
||||
|
||||
FairMQMessageSHM* msg = static_cast<FairMQMessageSHM*>(msgVec.back().get());
|
||||
MetaHeader* msgHdr = static_cast<MetaHeader*>(zmq_msg_data(msg->GetMessage()));
|
||||
|
||||
memcpy(msgHdr, &hdr, sizeof(MetaHeader));
|
||||
|
||||
msg->fHandle = hdr.fHandle;
|
||||
msg->fSize = hdr.fSize;
|
||||
msg->fRegionId = hdr.fRegionId;
|
||||
msg->fHint = hdr.fHint;
|
||||
|
||||
totalSize += msg->GetSize();
|
||||
totalSize += shmMsg->GetSize();
|
||||
}
|
||||
|
||||
// store statistics on how many messages have been received (handle all parts as a single message)
|
||||
@@ -399,30 +341,21 @@ int64_t FairMQSocketSHM::Receive(vector<FairMQMessagePtr>& msgVec, const int tim
|
||||
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return totalSize;
|
||||
}
|
||||
else if (zmq_errno() == EAGAIN)
|
||||
{
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
} else if (zmq_errno() == EAGAIN) {
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0)) {
|
||||
if (timeout > 0) {
|
||||
elapsed += fRcvTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
if (elapsed >= timeout) {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
zmq_msg_close(&zmqMsg);
|
||||
LOG(error) << "Failed receiving on socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
return nbytes;
|
||||
@@ -437,13 +370,11 @@ void FairMQSocketSHM::Close()
|
||||
{
|
||||
// LOG(debug) << "Closing socket " << fId;
|
||||
|
||||
if (fSocket == nullptr)
|
||||
{
|
||||
if (fSocket == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (zmq_close(fSocket) != 0)
|
||||
{
|
||||
if (zmq_close(fSocket) != 0) {
|
||||
LOG(error) << "Failed closing socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
@@ -464,23 +395,16 @@ void FairMQSocketSHM::Resume()
|
||||
fInterrupted = false;
|
||||
}
|
||||
|
||||
void* FairMQSocketSHM::GetSocket() const
|
||||
{
|
||||
return fSocket;
|
||||
}
|
||||
|
||||
void FairMQSocketSHM::SetOption(const string& option, const void* value, size_t valueSize)
|
||||
{
|
||||
if (zmq_setsockopt(fSocket, GetConstant(option), value, valueSize) < 0)
|
||||
{
|
||||
if (zmq_setsockopt(fSocket, GetConstant(option), value, valueSize) < 0) {
|
||||
LOG(error) << "Failed setting socket option, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQSocketSHM::GetOption(const string& option, void* value, size_t* valueSize)
|
||||
{
|
||||
if (zmq_getsockopt(fSocket, GetConstant(option), value, valueSize) < 0)
|
||||
{
|
||||
if (zmq_getsockopt(fSocket, GetConstant(option), value, valueSize) < 0) {
|
||||
LOG(error) << "Failed getting socket option, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
}
|
||||
@@ -570,26 +494,6 @@ int FairMQSocketSHM::GetRcvKernelSize() const
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned long FairMQSocketSHM::GetBytesTx() const
|
||||
{
|
||||
return fBytesTx;
|
||||
}
|
||||
|
||||
unsigned long FairMQSocketSHM::GetBytesRx() const
|
||||
{
|
||||
return fBytesRx;
|
||||
}
|
||||
|
||||
unsigned long FairMQSocketSHM::GetMessagesTx() const
|
||||
{
|
||||
return fMessagesTx;
|
||||
}
|
||||
|
||||
unsigned long FairMQSocketSHM::GetMessagesRx() const
|
||||
{
|
||||
return fMessagesRx;
|
||||
}
|
||||
|
||||
int FairMQSocketSHM::GetConstant(const string& constant)
|
||||
{
|
||||
if (constant == "") return 0;
|
||||
@@ -618,8 +522,3 @@ int FairMQSocketSHM::GetConstant(const string& constant)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
FairMQSocketSHM::~FairMQSocketSHM()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ class FairMQSocketSHM final : public FairMQSocket
|
||||
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = -1) override;
|
||||
int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = -1) override;
|
||||
|
||||
void* GetSocket() const;
|
||||
void* GetSocket() const { return fSocket; }
|
||||
|
||||
void Close() override;
|
||||
|
||||
@@ -55,14 +55,14 @@ class FairMQSocketSHM final : public FairMQSocket
|
||||
void SetRcvKernelSize(const int value) override;
|
||||
int GetRcvKernelSize() const override;
|
||||
|
||||
unsigned long GetBytesTx() const override;
|
||||
unsigned long GetBytesRx() const override;
|
||||
unsigned long GetMessagesTx() const override;
|
||||
unsigned long GetMessagesRx() const override;
|
||||
unsigned long GetBytesTx() const override { return fBytesTx; }
|
||||
unsigned long GetBytesRx() const override { return fBytesRx; }
|
||||
unsigned long GetMessagesTx() const override { return fMessagesTx; }
|
||||
unsigned long GetMessagesRx() const override { return fMessagesRx; }
|
||||
|
||||
static int GetConstant(const std::string& constant);
|
||||
|
||||
~FairMQSocketSHM() override;
|
||||
~FairMQSocketSHM() override { Close(); }
|
||||
|
||||
private:
|
||||
void* fSocket;
|
||||
|
@@ -77,11 +77,12 @@ FairMQTransportFactorySHM::FairMQTransportFactorySHM(const string& id, const fai
|
||||
LOG(error) << "failed configuring context, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
if (autolaunchMonitor) {
|
||||
Manager::StartMonitor(fShmId);
|
||||
}
|
||||
|
||||
fManager = fair::mq::tools::make_unique<Manager>(fShmId, segmentSize);
|
||||
|
||||
if (autolaunchMonitor) {
|
||||
fManager->StartMonitor();
|
||||
}
|
||||
} catch (bipc::interprocess_exception& e) {
|
||||
LOG(error) << "Could not initialize shared memory transport: " << e.what();
|
||||
throw runtime_error(fair::mq::tools::ToString("Could not initialize shared memory transport: ", e.what()));
|
||||
|
@@ -6,7 +6,7 @@
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <fairmq/shmem/Common.h>
|
||||
#include "Common.h"
|
||||
|
||||
#include "FairMQUnmanagedRegionSHM.h"
|
||||
|
||||
@@ -41,18 +41,3 @@ FairMQUnmanagedRegionSHM::FairMQUnmanagedRegionSHM(Manager& manager, const size_
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void* FairMQUnmanagedRegionSHM::GetData() const
|
||||
{
|
||||
return fRegion->get_address();
|
||||
}
|
||||
|
||||
size_t FairMQUnmanagedRegionSHM::GetSize() const
|
||||
{
|
||||
return fRegion->get_size();
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionSHM::~FairMQUnmanagedRegionSHM()
|
||||
{
|
||||
fManager.RemoveRegion(fRegionId);
|
||||
}
|
||||
|
@@ -28,10 +28,10 @@ class FairMQUnmanagedRegionSHM final : public FairMQUnmanagedRegion
|
||||
public:
|
||||
FairMQUnmanagedRegionSHM(fair::mq::shmem::Manager& manager, const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0);
|
||||
|
||||
void* GetData() const override;
|
||||
size_t GetSize() const override;
|
||||
void* GetData() const override { return fRegion->get_address(); }
|
||||
size_t GetSize() const override { return fRegion->get_size(); }
|
||||
|
||||
~FairMQUnmanagedRegionSHM() override;
|
||||
~FairMQUnmanagedRegionSHM() override { fManager.RemoveRegion(fRegionId); }
|
||||
|
||||
private:
|
||||
fair::mq::shmem::Manager& fManager;
|
||||
|
@@ -8,11 +8,14 @@
|
||||
|
||||
#include <fairmq/shmem/Manager.h>
|
||||
#include <fairmq/shmem/Common.h>
|
||||
#include <fairmq/tools/CppSTL.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
using namespace std;
|
||||
using bie = ::boost::interprocess::interprocess_exception;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
namespace bfs = ::boost::filesystem;
|
||||
|
||||
@@ -51,57 +54,42 @@ Manager::Manager(const std::string& id, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
bipc::managed_shared_memory& Manager::Segment()
|
||||
{
|
||||
return fSegment;
|
||||
}
|
||||
|
||||
bipc::managed_shared_memory& Manager::ManagementSegment()
|
||||
{
|
||||
return fManagementSegment;
|
||||
}
|
||||
|
||||
void Manager::StartMonitor()
|
||||
void Manager::StartMonitor(const std::string& id)
|
||||
{
|
||||
try {
|
||||
MonitorStatus* monitorStatus = fManagementSegment.find<MonitorStatus>(bipc::unique_instance).first;
|
||||
if (monitorStatus == nullptr) {
|
||||
LOG(debug) << "no fairmq-shmmonitor found, starting...";
|
||||
auto env = boost::this_process::environment();
|
||||
bipc::named_mutex monitorStatus(bipc::open_only, string("fmq_" + id + "_ms").c_str());
|
||||
LOG(debug) << "Found fairmq-shmmonitor for shared memory id " << id;
|
||||
} catch (bie&) {
|
||||
LOG(debug) << "no fairmq-shmmonitor found for shared memory id " << id << ", starting...";
|
||||
auto env = boost::this_process::environment();
|
||||
|
||||
vector<bfs::path> ownPath = boost::this_process::path();
|
||||
vector<bfs::path> ownPath = boost::this_process::path();
|
||||
|
||||
if (const char* fmqp = getenv("FAIRMQ_PATH")) {
|
||||
ownPath.insert(ownPath.begin(), bfs::path(fmqp));
|
||||
}
|
||||
|
||||
bfs::path p = boost::process::search_path("fairmq-shmmonitor", ownPath);
|
||||
|
||||
if (!p.empty()) {
|
||||
boost::process::spawn(p, "-x", "--shmid", fShmId, "-d", "-t", "2000", env);
|
||||
int numTries = 0;
|
||||
do {
|
||||
monitorStatus = fManagementSegment.find<MonitorStatus>(bipc::unique_instance).first;
|
||||
if (monitorStatus) {
|
||||
LOG(debug) << "fairmq-shmmonitor started";
|
||||
break;
|
||||
} else {
|
||||
this_thread::sleep_for(chrono::milliseconds(10));
|
||||
if (++numTries > 1000) {
|
||||
LOG(error) << "Did not get response from fairmq-shmmonitor after " << 10 * 1000 << " milliseconds. Exiting.";
|
||||
throw runtime_error(fair::mq::tools::ToString("Did not get response from fairmq-shmmonitor after ", 10 * 1000, " milliseconds. Exiting."));
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
} else {
|
||||
LOG(warn) << "could not find fairmq-shmmonitor in the path";
|
||||
}
|
||||
} else {
|
||||
LOG(debug) << "found fairmq-shmmonitor.";
|
||||
if (const char* fmqp = getenv("FAIRMQ_PATH")) {
|
||||
ownPath.insert(ownPath.begin(), bfs::path(fmqp));
|
||||
}
|
||||
|
||||
bfs::path p = boost::process::search_path("fairmq-shmmonitor", ownPath);
|
||||
|
||||
if (!p.empty()) {
|
||||
boost::process::spawn(p, "-x", "--shmid", id, "-d", "-t", "2000", env);
|
||||
int numTries = 0;
|
||||
do {
|
||||
try {
|
||||
bipc::named_mutex monitorStatus(bipc::open_only, string("fmq_" + id + "_ms").c_str());
|
||||
LOG(debug) << "Started fairmq-shmmonitor for shared memory id " << id;
|
||||
break;
|
||||
} catch (bie&) {
|
||||
this_thread::sleep_for(chrono::milliseconds(10));
|
||||
if (++numTries > 1000) {
|
||||
LOG(error) << "Did not get response from fairmq-shmmonitor after " << 10 * 1000 << " milliseconds. Exiting.";
|
||||
throw runtime_error(fair::mq::tools::ToString("Did not get response from fairmq-shmmonitor after ", 10 * 1000, " milliseconds. Exiting."));
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
} else {
|
||||
LOG(warn) << "could not find fairmq-shmmonitor in the path";
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
LOG(error) << "Exception during fairmq-shmmonitor initialization: " << e.what() << ", application will now exit";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,9 +120,10 @@ bipc::mapped_region* Manager::CreateRegion(const size_t size, const uint64_t id,
|
||||
{
|
||||
bipc::scoped_lock<bipc::named_mutex> lock(fShmMtx);
|
||||
VoidAlloc voidAlloc(fManagementSegment.get_segment_manager());
|
||||
Uint64RegionInfoMap* m = fManagementSegment.find_or_construct<Uint64RegionInfoMap>(bipc::unique_instance)(voidAlloc);
|
||||
m->emplace(id, RegionInfo(path.c_str(), flags, voidAlloc));
|
||||
Uint64RegionInfoMap* infoMap = fManagementSegment.find_or_construct<Uint64RegionInfoMap>(bipc::unique_instance)(voidAlloc);
|
||||
infoMap->emplace(id, RegionInfo(path.c_str(), flags, voidAlloc));
|
||||
}
|
||||
// LOG(debug) << "Created region with id '" << id << "', path: '" << path << "', flags: '" << flags << "'";
|
||||
|
||||
auto r = fRegions.emplace(id, fair::mq::tools::make_unique<Region>(*this, id, size, false, callback, path, flags));
|
||||
|
||||
@@ -158,17 +147,20 @@ Region* Manager::GetRemoteRegion(const uint64_t id)
|
||||
// get region info
|
||||
{
|
||||
bipc::scoped_lock<bipc::named_mutex> lock(fShmMtx);
|
||||
VoidAlloc voidAlloc(fSegment.get_segment_manager());
|
||||
Uint64RegionInfoMap* m = fManagementSegment.find<Uint64RegionInfoMap>(bipc::unique_instance).first;
|
||||
RegionInfo ri = m->at(id);
|
||||
path = ri.fPath.c_str();
|
||||
flags = ri.fFlags;
|
||||
// LOG(debug) << "path: " << path << ", flags: " << flags;
|
||||
Uint64RegionInfoMap* infoMap = fManagementSegment.find<Uint64RegionInfoMap>(bipc::unique_instance).first;
|
||||
if (infoMap == nullptr) {
|
||||
LOG(error) << "Unable to locate the region info";
|
||||
throw SharedMemoryError("Unable to locate remote region info");
|
||||
}
|
||||
RegionInfo regionInfo = infoMap->at(id);
|
||||
path = regionInfo.fPath.c_str();
|
||||
flags = regionInfo.fFlags;
|
||||
}
|
||||
// LOG(debug) << "Located remote region with id '" << id << "', path: '" << path << "', flags: '" << flags << "'";
|
||||
|
||||
auto r = fRegions.emplace(id, fair::mq::tools::make_unique<Region>(*this, id, 0, true, nullptr, path, flags));
|
||||
return r.first->second.get();
|
||||
} catch (bipc::interprocess_exception& e) {
|
||||
} catch (bie& e) {
|
||||
LOG(warn) << "Could not get remote region for id: " << id;
|
||||
return nullptr;
|
||||
}
|
||||
|
@@ -15,7 +15,6 @@
|
||||
#ifndef FAIR_MQ_SHMEM_MANAGER_H_
|
||||
#define FAIR_MQ_SHMEM_MANAGER_H_
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/shmem/Region.h>
|
||||
#include <fairmq/shmem/Common.h>
|
||||
|
||||
@@ -28,6 +27,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -36,6 +36,8 @@ namespace mq
|
||||
namespace shmem
|
||||
{
|
||||
|
||||
struct SharedMemoryError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
class Manager
|
||||
{
|
||||
friend struct Region;
|
||||
@@ -50,10 +52,10 @@ class Manager
|
||||
|
||||
~Manager();
|
||||
|
||||
boost::interprocess::managed_shared_memory& Segment();
|
||||
boost::interprocess::managed_shared_memory& ManagementSegment();
|
||||
boost::interprocess::managed_shared_memory& Segment() { return fSegment; }
|
||||
boost::interprocess::managed_shared_memory& ManagementSegment() { return fManagementSegment; }
|
||||
|
||||
void StartMonitor();
|
||||
static void StartMonitor(const std::string&);
|
||||
|
||||
static void Interrupt();
|
||||
static void Resume();
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <poll.h>
|
||||
|
||||
using namespace std;
|
||||
using bie = ::boost::interprocess::interprocess_exception;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
namespace bpt = ::boost::posix_time;
|
||||
|
||||
@@ -45,11 +46,12 @@ void signalHandler(int signal)
|
||||
gSignalStatus = signal;
|
||||
}
|
||||
|
||||
Monitor::Monitor(const string& shmId, bool selfDestruct, bool interactive, unsigned int timeoutInMS, bool runAsDaemon, bool cleanOnExit)
|
||||
Monitor::Monitor(const string& shmId, bool selfDestruct, bool interactive, bool viewOnly, unsigned int timeoutInMS, bool runAsDaemon, bool cleanOnExit)
|
||||
: fSelfDestruct(selfDestruct)
|
||||
, fInteractive(interactive)
|
||||
, fSeenOnce(false)
|
||||
, fViewOnly(viewOnly)
|
||||
, fIsDaemon(runAsDaemon)
|
||||
, fSeenOnce(false)
|
||||
, fCleanOnExit(cleanOnExit)
|
||||
, fTimeoutInMS(timeoutInMS)
|
||||
, fShmId(shmId)
|
||||
@@ -63,14 +65,14 @@ Monitor::Monitor(const string& shmId, bool selfDestruct, bool interactive, unsig
|
||||
, fManagementSegment(bipc::open_or_create, fManagementSegmentName.c_str(), 65536)
|
||||
, fDeviceHeartbeats()
|
||||
{
|
||||
MonitorStatus* monitorStatus = fManagementSegment.find<MonitorStatus>(bipc::unique_instance).first;
|
||||
if (monitorStatus != nullptr) {
|
||||
cout << "fairmq-shmmonitor already started or not properly exited. Try `fairmq-shmmonitor --cleanup`" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
if (!fViewOnly) {
|
||||
try {
|
||||
bipc::named_mutex monitorStatus(bipc::create_only, string("fmq_" + fShmId + "_ms").c_str());
|
||||
} catch (bie&) {
|
||||
cout << "fairmq-shmmonitor for shared memory id " << fShmId << " already started or not properly exited. Try `fairmq-shmmonitor --cleanup --shmid " << fShmId << "`" << endl;
|
||||
throw DaemonPresent(tools::ToString("fairmq-shmmonitor for shared memory id ", fShmId, " already started or not properly exited."));
|
||||
}
|
||||
}
|
||||
fManagementSegment.construct<MonitorStatus>(bipc::unique_instance)();
|
||||
|
||||
RemoveQueue(fControlQueueName);
|
||||
}
|
||||
|
||||
void Monitor::CatchSignals()
|
||||
@@ -97,7 +99,11 @@ void Monitor::SignalMonitor()
|
||||
|
||||
void Monitor::Run()
|
||||
{
|
||||
thread heartbeatThread(&Monitor::MonitorHeartbeats, this);
|
||||
thread heartbeatThread;
|
||||
if (!fViewOnly) {
|
||||
RemoveQueue(fControlQueueName);
|
||||
heartbeatThread = thread(&Monitor::MonitorHeartbeats, this);
|
||||
}
|
||||
|
||||
if (fInteractive) {
|
||||
Interactive();
|
||||
@@ -108,7 +114,9 @@ void Monitor::Run()
|
||||
}
|
||||
}
|
||||
|
||||
heartbeatThread.join();
|
||||
if (!fViewOnly) {
|
||||
heartbeatThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::MonitorHeartbeats()
|
||||
@@ -131,13 +139,34 @@ void Monitor::MonitorHeartbeats()
|
||||
// cout << "control queue timeout" << endl;
|
||||
}
|
||||
}
|
||||
} catch (bipc::interprocess_exception& ie) {
|
||||
} catch (bie& ie) {
|
||||
cout << ie.what() << endl;
|
||||
}
|
||||
|
||||
RemoveQueue(fControlQueueName);
|
||||
}
|
||||
|
||||
struct TerminalConfig
|
||||
{
|
||||
TerminalConfig()
|
||||
{
|
||||
termios t;
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag &= ~ICANON; // disable canonical input
|
||||
t.c_lflag &= ~ECHO; // do not echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
}
|
||||
|
||||
~TerminalConfig()
|
||||
{
|
||||
termios t;
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag |= ICANON; // re-enable canonical input
|
||||
t.c_lflag |= ECHO; // echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
}
|
||||
};
|
||||
|
||||
void Monitor::Interactive()
|
||||
{
|
||||
char c;
|
||||
@@ -145,11 +174,7 @@ void Monitor::Interactive()
|
||||
cinfd[0].fd = fileno(stdin);
|
||||
cinfd[0].events = POLLIN;
|
||||
|
||||
struct termios t;
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag &= ~ICANON; // disable canonical input
|
||||
t.c_lflag &= ~ECHO; // do not echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
TerminalConfig tcfg;
|
||||
|
||||
cout << endl;
|
||||
PrintHelp();
|
||||
@@ -175,7 +200,11 @@ void Monitor::Interactive()
|
||||
break;
|
||||
case 'x':
|
||||
cout << "\n[x] --> closing shared memory:" << endl;
|
||||
Cleanup(fShmId);
|
||||
if (!fViewOnly) {
|
||||
Cleanup(fShmId);
|
||||
} else {
|
||||
cout << "cannot close because in view only mode" << endl;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
cout << "\n[h] --> help:" << endl << endl;
|
||||
@@ -207,11 +236,6 @@ void Monitor::Interactive()
|
||||
cout << "\r";
|
||||
}
|
||||
}
|
||||
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag |= ICANON; // re-enable canonical input
|
||||
t.c_lflag |= ECHO; // echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
}
|
||||
|
||||
void Monitor::CheckSegment()
|
||||
@@ -250,9 +274,11 @@ void Monitor::CheckSegment()
|
||||
|
||||
unsigned int numDevices = 0;
|
||||
|
||||
fair::mq::shmem::DeviceCounter* dc = managementSegment.find<fair::mq::shmem::DeviceCounter>(bipc::unique_instance).first;
|
||||
if (dc) {
|
||||
numDevices = dc->fCount;
|
||||
if (fInteractive) {
|
||||
fair::mq::shmem::DeviceCounter* dc = managementSegment.find<fair::mq::shmem::DeviceCounter>(bipc::unique_instance).first;
|
||||
if (dc) {
|
||||
numDevices = dc->fCount;
|
||||
}
|
||||
}
|
||||
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
@@ -270,31 +296,23 @@ void Monitor::CheckSegment()
|
||||
|
||||
if (fInteractive) {
|
||||
cout << "| "
|
||||
<< setw(18) << fSegmentName << " | "
|
||||
<< setw(10) << segment.get_size() << " | "
|
||||
<< setw(10) << segment.get_free_memory() << " | "
|
||||
// << setw(15) << segment.all_memory_deallocated() << " | "
|
||||
<< setw(2) << segment.check_sanity() << " | "
|
||||
// << setw(10) << segment.get_num_named_objects() << " | "
|
||||
<< setw(10) << numDevices << " | "
|
||||
// << setw(10) << segment.get_num_unique_objects() << " |"
|
||||
<< setw(10) << duration << " |"
|
||||
<< c
|
||||
<< flush;
|
||||
<< setw(18) << fSegmentName << " | "
|
||||
<< setw(10) << segment.get_size() << " | "
|
||||
<< setw(10) << segment.get_free_memory() << " | "
|
||||
<< setw(8) << numDevices << " | "
|
||||
<< setw(10) << (fViewOnly ? "view only" : to_string(duration)) << " |"
|
||||
<< c << flush;
|
||||
}
|
||||
} catch (bipc::interprocess_exception& ie) {
|
||||
} catch (bie&) {
|
||||
fHeartbeatTriggered = false;
|
||||
if (fInteractive) {
|
||||
cout << "| "
|
||||
<< setw(18) << "-" << " | "
|
||||
<< setw(10) << "-" << " | "
|
||||
<< setw(10) << "-" << " | "
|
||||
// << setw(15) << "-" << " | "
|
||||
<< setw(2) << "-" << " | "
|
||||
<< setw(10) << "-" << " | "
|
||||
<< setw(10) << "-" << " |"
|
||||
<< c
|
||||
<< flush;
|
||||
<< setw(18) << "-" << " | "
|
||||
<< setw(10) << "-" << " | "
|
||||
<< setw(10) << "-" << " | "
|
||||
<< setw(8) << "-" << " | "
|
||||
<< setw(10) << "-" << " |"
|
||||
<< c << flush;
|
||||
}
|
||||
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
@@ -318,50 +336,60 @@ void Monitor::CheckSegment()
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::Cleanup(const string& shmId)
|
||||
void Monitor::PrintQueues()
|
||||
{
|
||||
string managementSegmentName("fmq_" + shmId + "_mng");
|
||||
cout << '\n';
|
||||
|
||||
try {
|
||||
bipc::managed_shared_memory managementSegment(bipc::open_only, managementSegmentName.c_str());
|
||||
RegionCounter* rc = managementSegment.find<RegionCounter>(bipc::unique_instance).first;
|
||||
if (rc) {
|
||||
cout << "Region counter found: " << rc->fCount << endl;
|
||||
uint64_t regionCount = rc->fCount;
|
||||
bipc::managed_shared_memory segment(bipc::open_only, fSegmentName.c_str());
|
||||
StrVector* queues = segment.find<StrVector>(string("fmq_" + fShmId + "_qs").c_str()).first;
|
||||
if (queues) {
|
||||
cout << "found " << queues->size() << " queue(s):" << endl;
|
||||
|
||||
Uint64RegionInfoMap* m = managementSegment.find<Uint64RegionInfoMap>(bipc::unique_instance).first;
|
||||
|
||||
for (uint64_t i = 1; i <= regionCount; ++i) {
|
||||
if (m != nullptr) {
|
||||
RegionInfo ri = m->at(i);
|
||||
string path = ri.fPath.c_str();
|
||||
int flags = ri.fFlags;
|
||||
cout << "Found RegionInfo with path: '" << path << "', flags: " << flags << "'." << endl;
|
||||
if (path != "") {
|
||||
RemoveFileMapping(tools::ToString(path, "fmq_" + shmId + "_rg_" + to_string(i)));
|
||||
} else {
|
||||
RemoveObject("fmq_" + shmId + "_rg_" + to_string(i));
|
||||
}
|
||||
for (const auto& queue : *queues) {
|
||||
string name(queue.c_str());
|
||||
cout << '\t' << name << " : ";
|
||||
atomic<int>* queueSize = segment.find<atomic<int>>(name.c_str()).first;
|
||||
if (queueSize) {
|
||||
cout << *queueSize << " messages" << endl;
|
||||
} else {
|
||||
RemoveObject("fmq_" + shmId + "_rg_" + to_string(i));
|
||||
cout << "\tqueue does not have a queue size entry." << endl;
|
||||
}
|
||||
|
||||
RemoveQueue(string("fmq_" + shmId + "_rgq_" + to_string(i)));
|
||||
}
|
||||
} else {
|
||||
cout << "No region counter found. no regions to cleanup." << endl;
|
||||
cout << "\tno queues found" << endl;
|
||||
}
|
||||
|
||||
RemoveObject(managementSegmentName.c_str());
|
||||
} catch (bipc::interprocess_exception& ie) {
|
||||
cout << "Did not find '" << managementSegmentName << "' shared memory segment. No regions to cleanup." << endl;
|
||||
} catch (bie&) {
|
||||
cout << "\tno queues found" << endl;
|
||||
} catch (out_of_range&) {
|
||||
cout << "\tno queues found" << endl;
|
||||
}
|
||||
|
||||
RemoveObject("fmq_" + shmId + "_main");
|
||||
RemoveMutex("fmq_" + shmId + "_mtx");
|
||||
cout << "\n --> last heartbeats: " << endl << endl;
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
for (const auto& h : fDeviceHeartbeats) {
|
||||
cout << "\t" << h.first << " : " << chrono::duration<double, milli>(now - h.second).count() << "ms ago." << endl;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void Monitor::PrintHeader()
|
||||
{
|
||||
cout << "| "
|
||||
<< setw(18) << "name" << " | "
|
||||
<< setw(10) << "size" << " | "
|
||||
<< setw(10) << "free" << " | "
|
||||
<< setw(8) << "devices" << " | "
|
||||
<< setw(10) << "last hb" << " |"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
void Monitor::PrintHelp()
|
||||
{
|
||||
cout << "controls: [x] close memory, [p] print queues, [h] help, [q] quit." << endl;
|
||||
}
|
||||
|
||||
void Monitor::RemoveObject(const string& name)
|
||||
{
|
||||
if (bipc::shared_memory_object::remove(name.c_str())) {
|
||||
@@ -398,73 +426,61 @@ void Monitor::RemoveMutex(const string& name)
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::PrintQueues()
|
||||
void Monitor::Cleanup(const string& shmId)
|
||||
{
|
||||
cout << '\n';
|
||||
|
||||
string managementSegmentName("fmq_" + shmId + "_mng");
|
||||
try {
|
||||
bipc::managed_shared_memory segment(bipc::open_only, fSegmentName.c_str());
|
||||
StrVector* queues = segment.find<StrVector>(string("fmq_" + fShmId + "_qs").c_str()).first;
|
||||
if (queues) {
|
||||
cout << "found " << queues->size() << " queue(s):" << endl;
|
||||
bipc::managed_shared_memory managementSegment(bipc::open_only, managementSegmentName.c_str());
|
||||
RegionCounter* rc = managementSegment.find<RegionCounter>(bipc::unique_instance).first;
|
||||
if (rc) {
|
||||
cout << "Region counter found: " << rc->fCount << endl;
|
||||
uint64_t regionCount = rc->fCount;
|
||||
|
||||
for (const auto& queue : *queues) {
|
||||
string name(queue.c_str());
|
||||
cout << '\t' << name << " : ";
|
||||
atomic<int>* queueSize = segment.find<atomic<int>>(name.c_str()).first;
|
||||
if (queueSize) {
|
||||
cout << *queueSize << " messages" << endl;
|
||||
Uint64RegionInfoMap* m = managementSegment.find<Uint64RegionInfoMap>(bipc::unique_instance).first;
|
||||
|
||||
for (uint64_t i = 1; i <= regionCount; ++i) {
|
||||
if (m != nullptr) {
|
||||
RegionInfo ri = m->at(i);
|
||||
string path = ri.fPath.c_str();
|
||||
int flags = ri.fFlags;
|
||||
cout << "Found RegionInfo with path: '" << path << "', flags: " << flags << "'." << endl;
|
||||
if (path != "") {
|
||||
RemoveFileMapping(tools::ToString(path, "fmq_" + shmId + "_rg_" + to_string(i)));
|
||||
} else {
|
||||
RemoveObject("fmq_" + shmId + "_rg_" + to_string(i));
|
||||
}
|
||||
} else {
|
||||
cout << "\tqueue does not have a queue size entry." << endl;
|
||||
RemoveObject("fmq_" + shmId + "_rg_" + to_string(i));
|
||||
}
|
||||
|
||||
RemoveQueue(string("fmq_" + shmId + "_rgq_" + to_string(i)));
|
||||
}
|
||||
} else {
|
||||
cout << "\tno queues found" << endl;
|
||||
cout << "No region counter found. no regions to cleanup." << endl;
|
||||
}
|
||||
} catch (bipc::interprocess_exception& ie) {
|
||||
cout << "\tno queues found" << endl;
|
||||
} catch (out_of_range& ie) {
|
||||
cout << "\tno queues found" << endl;
|
||||
|
||||
RemoveObject(managementSegmentName.c_str());
|
||||
} catch (bie&) {
|
||||
cout << "Did not find '" << managementSegmentName << "' shared memory segment. No regions to cleanup." << endl;
|
||||
}
|
||||
|
||||
cout << "\n --> last heartbeats: " << endl << endl;
|
||||
auto now = chrono::high_resolution_clock::now();
|
||||
for (const auto& h : fDeviceHeartbeats) {
|
||||
cout << "\t" << h.first << " : " << chrono::duration<double, milli>(now - h.second).count() << "ms ago." << endl;
|
||||
}
|
||||
RemoveObject("fmq_" + shmId + "_main");
|
||||
RemoveMutex("fmq_" + shmId + "_mtx");
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void Monitor::PrintHeader()
|
||||
{
|
||||
cout << "| "
|
||||
<< "\033[01;32m" << setw(18) << "name" << "\033[0m" << " | "
|
||||
<< "\033[01;32m" << setw(10) << "size" << "\033[0m" << " | "
|
||||
<< "\033[01;32m" << setw(10) << "free" << "\033[0m" << " | "
|
||||
// << "\033[01;32m" << setw(15) << "all deallocated" << "\033[0m" << " | "
|
||||
<< "\033[01;32m" << setw(2) << "ok" << "\033[0m" << " | "
|
||||
// << "\033[01;32m" << setw(10) << "# named" << "\033[0m" << " | "
|
||||
<< "\033[01;32m" << setw(10) << "# devices" << "\033[0m" << " | "
|
||||
// << "\033[01;32m" << setw(10) << "# unique" << "\033[0m" << " |"
|
||||
<< "\033[01;32m" << setw(10) << "ms since" << "\033[0m" << " |"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
void Monitor::PrintHelp()
|
||||
{
|
||||
cout << "controls: [x] close memory, [p] print queues, [h] help, [q] quit." << endl;
|
||||
}
|
||||
|
||||
Monitor::~Monitor()
|
||||
{
|
||||
fManagementSegment.destroy<MonitorStatus>(bipc::unique_instance);
|
||||
if (fSignalThread.joinable()) {
|
||||
fSignalThread.join();
|
||||
}
|
||||
if (fCleanOnExit) {
|
||||
Cleanup(fShmId);
|
||||
}
|
||||
if (!fViewOnly) {
|
||||
RemoveMutex("fmq_" + fShmId + "_ms");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace shmem
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace fair
|
||||
@@ -26,22 +27,24 @@ namespace shmem
|
||||
class Monitor
|
||||
{
|
||||
public:
|
||||
Monitor(const std::string& shmId, bool selfDestruct, bool interactive, unsigned int timeoutInMS, bool runAsDaemon, bool cleanOnExit);
|
||||
Monitor(const std::string& shmId, bool selfDestruct, bool interactive, bool viewOnly, unsigned int timeoutInMS, bool runAsDaemon, bool cleanOnExit);
|
||||
|
||||
Monitor(const Monitor&) = delete;
|
||||
Monitor operator=(const Monitor&) = delete;
|
||||
|
||||
virtual ~Monitor();
|
||||
|
||||
void CatchSignals();
|
||||
void Run();
|
||||
|
||||
virtual ~Monitor();
|
||||
|
||||
static void Cleanup(const std::string& shmId);
|
||||
static void RemoveObject(const std::string&);
|
||||
static void RemoveFileMapping(const std::string&);
|
||||
static void RemoveQueue(const std::string&);
|
||||
static void RemoveMutex(const std::string&);
|
||||
|
||||
struct DaemonPresent : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
private:
|
||||
void PrintHeader();
|
||||
void PrintHelp();
|
||||
@@ -53,8 +56,9 @@ class Monitor
|
||||
|
||||
bool fSelfDestruct; // will self-destruct after the memory has been closed
|
||||
bool fInteractive; // running in interactive mode
|
||||
bool fSeenOnce; // true is segment has been opened successfully at least once
|
||||
bool fViewOnly; // view only mode
|
||||
bool fIsDaemon;
|
||||
bool fSeenOnce; // true is segment has been opened successfully at least once
|
||||
bool fCleanOnExit;
|
||||
unsigned int fTimeoutInMS;
|
||||
std::string fShmId;
|
||||
|
@@ -32,5 +32,6 @@ FairMQ Shared Memory currently uses following names to register shared memory on
|
||||
`fmq_<shmId>_mng` - management segment name, used for storing management data.
|
||||
`fmq_<shmId>_cq` - message queue for communicating between shm transport and shm monitor (exists independent of above segments).
|
||||
`fmq_<shmId>_mtx` - boost::interprocess::named_mutex for management purposes (exists independent of above segments).
|
||||
`fmq_<shmId>_ms` - shmmonitor status used to signal if it is active or not (exists independent of above segments).
|
||||
`fmq_<shmId>_rg_<index>` - names of unmanaged regions.
|
||||
`fmq_<shmId>_rgq_<index>` - names of queues for the unmanaged regions.
|
||||
|
@@ -9,6 +9,8 @@
|
||||
#include <fairmq/shmem/Region.h>
|
||||
#include <fairmq/shmem/Common.h>
|
||||
#include <fairmq/shmem/Manager.h>
|
||||
#include <fairmq/tools/CppSTL.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/process.hpp>
|
||||
|
@@ -18,7 +18,6 @@
|
||||
#include "FairMQLogger.h"
|
||||
#include "FairMQUnmanagedRegion.h"
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/shmem/Common.h>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
|
@@ -26,19 +26,25 @@ using namespace fair::mq::shmem;
|
||||
static void daemonize()
|
||||
{
|
||||
// already a daemon?
|
||||
// if (getppid() == 1) return;
|
||||
if (getppid() == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fork off the parent process
|
||||
// pid_t pid = fork();
|
||||
// if (pid < 0) exit(1);
|
||||
// Fork
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// If we got a good PID, then we can exit the parent process.
|
||||
// if (pid > 0) exit(0);
|
||||
if (pid > 0) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Change the file mode mask
|
||||
umask(0);
|
||||
|
||||
// Create a new SID for the child process
|
||||
// Create a new session with the calling process as its leader.
|
||||
if (setsid() < 0) {
|
||||
exit(1);
|
||||
}
|
||||
@@ -68,20 +74,22 @@ int main(int argc, char** argv)
|
||||
bool cleanup = false;
|
||||
bool selfDestruct = false;
|
||||
bool interactive = false;
|
||||
bool viewOnly = false;
|
||||
unsigned int timeoutInMS = 5000;
|
||||
bool runAsDaemon = false;
|
||||
bool cleanOnExit = false;
|
||||
|
||||
options_description desc("Options");
|
||||
desc.add_options()
|
||||
("session,s", value<string>(&sessionName)->default_value("default"), "session id which to monitor")
|
||||
("shmid", value<string>(&shmId)->default_value(""), "Shmem Id to monitor (if not provided, it is generated out of session id and user id)")
|
||||
("cleanup,c", value<bool>(&cleanup)->implicit_value(true), "Perform cleanup and quit")
|
||||
("self-destruct,x", value<bool>(&selfDestruct)->implicit_value(true), "Quit after first closing of the memory")
|
||||
("interactive,i", value<bool>(&interactive)->implicit_value(true), "Interactive run")
|
||||
("timeout,t", value<unsigned int>(&timeoutInMS)->default_value(5000), "Heartbeat timeout in milliseconds")
|
||||
("daemonize,d", value<bool>(&runAsDaemon)->implicit_value(true), "Daemonize the monitor")
|
||||
("clean-on-exit,e", value<bool>(&cleanOnExit)->implicit_value(true), "Perform cleanup on exit")
|
||||
("session,s" , value<string>(&sessionName)->default_value("default"), "Session id")
|
||||
("shmid" , value<string>(&shmId)->default_value(""), "Shmem id (if not provided, it is generated out of session id and user id)")
|
||||
("cleanup,c" , value<bool>(&cleanup)->implicit_value(true), "Perform cleanup and quit")
|
||||
("self-destruct,x", value<bool>(&selfDestruct)->implicit_value(true), "Quit after first closing of the memory")
|
||||
("interactive,i" , value<bool>(&interactive)->implicit_value(true), "Interactive run")
|
||||
("view,v" , value<bool>(&viewOnly)->implicit_value(true), "Run in view only mode")
|
||||
("timeout,t" , value<unsigned int>(&timeoutInMS)->default_value(5000), "Heartbeat timeout in milliseconds")
|
||||
("daemonize,d" , value<bool>(&runAsDaemon)->implicit_value(true), "Daemonize the monitor")
|
||||
("clean-on-exit,e", value<bool>(&cleanOnExit)->implicit_value(true), "Perform cleanup on exit")
|
||||
("help,h", "Print help");
|
||||
|
||||
variables_map vm;
|
||||
@@ -111,10 +119,12 @@ int main(int argc, char** argv)
|
||||
|
||||
cout << "Starting shared memory monitor for session: \"" << sessionName << "\" (shmId: " << shmId << ")..." << endl;
|
||||
|
||||
Monitor monitor{shmId, selfDestruct, interactive, timeoutInMS, runAsDaemon, cleanOnExit};
|
||||
Monitor monitor(shmId, selfDestruct, interactive, viewOnly, timeoutInMS, runAsDaemon, cleanOnExit);
|
||||
|
||||
monitor.CatchSignals();
|
||||
monitor.Run();
|
||||
} catch (Monitor::DaemonPresent& dp) {
|
||||
return 0;
|
||||
} catch (exception& e) {
|
||||
cerr << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << endl;
|
||||
return 2;
|
||||
|
@@ -10,7 +10,6 @@
|
||||
#define FAIR_MQ_TOOLS_STRINGS_H
|
||||
|
||||
#include <array>
|
||||
#include <boost/beast/core/span.hpp>
|
||||
#include <initializer_list>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -37,16 +36,11 @@ auto ToString(T&&... t) -> std::string
|
||||
/// @brief convert command line arguments from main function to vector of strings
|
||||
inline auto ToStrVector(const int argc, char*const* argv, const bool dropProgramName = true) -> std::vector<std::string>
|
||||
{
|
||||
auto res = std::vector<std::string>{};
|
||||
boost::beast::span<char*const> argvView(argv, argc);
|
||||
if (dropProgramName)
|
||||
{
|
||||
res.assign(argvView.begin() + 1, argvView.end());
|
||||
} else
|
||||
{
|
||||
res.assign(argvView.begin(), argvView.end());
|
||||
if (dropProgramName) {
|
||||
return std::vector<std::string>(argv + 1, argv + argc);
|
||||
} else {
|
||||
return std::vector<std::string>(argv, argv + argc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} /* namespace tools */
|
||||
|
@@ -17,7 +17,6 @@
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <initializer_list>
|
||||
|
||||
#include <zmq.h>
|
||||
|
||||
|
@@ -316,3 +316,20 @@ if(BUILD_SDK)
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
add_testsuite(Commands
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
commands/_commands.cxx
|
||||
|
||||
LINKS
|
||||
Commands
|
||||
StateMachine
|
||||
Tools
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 30
|
||||
${definitions}
|
||||
)
|
||||
endif()
|
||||
|
212
test/commands/_commands.cxx
Normal file
212
test/commands/_commands.cxx
Normal file
@@ -0,0 +1,212 @@
|
||||
/********************************************************************************
|
||||
* 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 <gtest/gtest.h>
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace fair::mq;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
|
||||
TEST(Format, Construction)
|
||||
{
|
||||
Cmds checkStateCmds(make<CheckState>());
|
||||
Cmds changeStateCmds(make<ChangeState>(Transition::Stop));
|
||||
Cmds dumpConfigCmds(make<DumpConfig>());
|
||||
Cmds subscribeToHeartbeatsCmds(make<SubscribeToHeartbeats>());
|
||||
Cmds unsubscribeFromHeartbeatsCmds(make<UnsubscribeFromHeartbeats>());
|
||||
Cmds subscribeToStateChangeCmds(make<SubscribeToStateChange>());
|
||||
Cmds unsubscribeFromStateChangeCmds(make<UnsubscribeFromStateChange>());
|
||||
Cmds stateChangeExitingReceivedCmds(make<StateChangeExitingReceived>());
|
||||
Cmds currentStateCmds(make<CurrentState>("somedeviceid", State::Running));
|
||||
Cmds transitionStatusCmds(make<TransitionStatus>("somedeviceid", Result::Ok, Transition::Stop));
|
||||
Cmds configCmds(make<Config>("somedeviceid", "someconfig"));
|
||||
Cmds heartbeatSubscriptionCmds(make<HeartbeatSubscription>("somedeviceid", Result::Ok));
|
||||
Cmds heartbeatUnsubscriptionCmds(make<HeartbeatUnsubscription>("somedeviceid", Result::Ok));
|
||||
Cmds heartbeatCmds(make<Heartbeat>("somedeviceid"));
|
||||
Cmds stateChangeSubscriptionCmds(make<StateChangeSubscription>("somedeviceid", Result::Ok));
|
||||
Cmds stateChangeUnsubscriptionCmds(make<StateChangeUnsubscription>("somedeviceid", Result::Ok));
|
||||
Cmds stateChangeCmds(make<StateChange>("somedeviceid", 123456, State::Running, State::Ready));
|
||||
|
||||
ASSERT_EQ(checkStateCmds.At(0).GetType(), Type::check_state);
|
||||
ASSERT_EQ(changeStateCmds.At(0).GetType(), Type::change_state);
|
||||
ASSERT_EQ(static_cast<ChangeState&>(changeStateCmds.At(0)).GetTransition(), Transition::Stop);
|
||||
ASSERT_EQ(dumpConfigCmds.At(0).GetType(), Type::dump_config);
|
||||
ASSERT_EQ(subscribeToHeartbeatsCmds.At(0).GetType(), Type::subscribe_to_heartbeats);
|
||||
ASSERT_EQ(unsubscribeFromHeartbeatsCmds.At(0).GetType(), Type::unsubscribe_from_heartbeats);
|
||||
ASSERT_EQ(subscribeToStateChangeCmds.At(0).GetType(), Type::subscribe_to_state_change);
|
||||
ASSERT_EQ(unsubscribeFromStateChangeCmds.At(0).GetType(), Type::unsubscribe_from_state_change);
|
||||
ASSERT_EQ(stateChangeExitingReceivedCmds.At(0).GetType(), Type::state_change_exiting_received);
|
||||
ASSERT_EQ(currentStateCmds.At(0).GetType(), Type::current_state);
|
||||
ASSERT_EQ(static_cast<CurrentState&>(currentStateCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<CurrentState&>(currentStateCmds.At(0)).GetCurrentState(), State::Running);
|
||||
ASSERT_EQ(transitionStatusCmds.At(0).GetType(), Type::transition_status);
|
||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetResult(), Result::Ok);
|
||||
ASSERT_EQ(static_cast<TransitionStatus&>(transitionStatusCmds.At(0)).GetTransition(), Transition::Stop);
|
||||
ASSERT_EQ(configCmds.At(0).GetType(), Type::config);
|
||||
ASSERT_EQ(static_cast<Config&>(configCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<Config&>(configCmds.At(0)).GetConfig(), "someconfig");
|
||||
ASSERT_EQ(heartbeatSubscriptionCmds.At(0).GetType(), Type::heartbeat_subscription);
|
||||
ASSERT_EQ(static_cast<HeartbeatSubscription&>(heartbeatSubscriptionCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<HeartbeatSubscription&>(heartbeatSubscriptionCmds.At(0)).GetResult(), Result::Ok);
|
||||
ASSERT_EQ(heartbeatUnsubscriptionCmds.At(0).GetType(), Type::heartbeat_unsubscription);
|
||||
ASSERT_EQ(static_cast<HeartbeatUnsubscription&>(heartbeatUnsubscriptionCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<HeartbeatUnsubscription&>(heartbeatUnsubscriptionCmds.At(0)).GetResult(), Result::Ok);
|
||||
ASSERT_EQ(heartbeatCmds.At(0).GetType(), Type::heartbeat);
|
||||
ASSERT_EQ(static_cast<Heartbeat&>(heartbeatCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(stateChangeSubscriptionCmds.At(0).GetType(), Type::state_change_subscription);
|
||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(stateChangeSubscriptionCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(stateChangeSubscriptionCmds.At(0)).GetResult(), Result::Ok);
|
||||
ASSERT_EQ(stateChangeUnsubscriptionCmds.At(0).GetType(), Type::state_change_unsubscription);
|
||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(stateChangeUnsubscriptionCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(stateChangeUnsubscriptionCmds.At(0)).GetResult(), Result::Ok);
|
||||
ASSERT_EQ(stateChangeCmds.At(0).GetType(), Type::state_change);
|
||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetTaskId(), 123456);
|
||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetLastState(), State::Running);
|
||||
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetCurrentState(), State::Ready);
|
||||
}
|
||||
|
||||
void fillCommands(Cmds& cmds)
|
||||
{
|
||||
cmds.Add<CheckState>();
|
||||
cmds.Add<ChangeState>(Transition::Stop);
|
||||
cmds.Add<DumpConfig>();
|
||||
cmds.Add<SubscribeToHeartbeats>();
|
||||
cmds.Add<UnsubscribeFromHeartbeats>();
|
||||
cmds.Add<SubscribeToStateChange>();
|
||||
cmds.Add<UnsubscribeFromStateChange>();
|
||||
cmds.Add<StateChangeExitingReceived>();
|
||||
cmds.Add<CurrentState>("somedeviceid", State::Running);
|
||||
cmds.Add<TransitionStatus>("somedeviceid", Result::Ok, Transition::Stop);
|
||||
cmds.Add<Config>("somedeviceid", "someconfig");
|
||||
cmds.Add<HeartbeatSubscription>("somedeviceid", Result::Ok);
|
||||
cmds.Add<HeartbeatUnsubscription>("somedeviceid", Result::Ok);
|
||||
cmds.Add<Heartbeat>("somedeviceid");
|
||||
cmds.Add<StateChangeSubscription>("somedeviceid", Result::Ok);
|
||||
cmds.Add<StateChangeUnsubscription>("somedeviceid", Result::Ok);
|
||||
cmds.Add<StateChange>("somedeviceid", 123456, State::Running, State::Ready);
|
||||
}
|
||||
|
||||
void checkCommands(Cmds& cmds)
|
||||
{
|
||||
ASSERT_EQ(cmds.Size(), 17);
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (const auto& cmd : cmds) {
|
||||
switch (cmd->GetType()) {
|
||||
case Type::check_state:
|
||||
++count;
|
||||
break;
|
||||
case Type::change_state:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<ChangeState&>(*cmd).GetTransition(), Transition::Stop);
|
||||
break;
|
||||
case Type::dump_config:
|
||||
++count;
|
||||
break;
|
||||
case Type::subscribe_to_heartbeats:
|
||||
++count;
|
||||
break;
|
||||
case Type::unsubscribe_from_heartbeats:
|
||||
++count;
|
||||
break;
|
||||
case Type::subscribe_to_state_change:
|
||||
++count;
|
||||
break;
|
||||
case Type::unsubscribe_from_state_change:
|
||||
++count;
|
||||
break;
|
||||
case Type::state_change_exiting_received:
|
||||
++count;
|
||||
break;
|
||||
case Type::current_state:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<CurrentState&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<CurrentState&>(*cmd).GetCurrentState(), State::Running);
|
||||
break;
|
||||
case Type::transition_status:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetResult(), Result::Ok);
|
||||
ASSERT_EQ(static_cast<TransitionStatus&>(*cmd).GetTransition(), Transition::Stop);
|
||||
break;
|
||||
case Type::config:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<Config&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<Config&>(*cmd).GetConfig(), "someconfig");
|
||||
break;
|
||||
case Type::heartbeat_subscription:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<HeartbeatSubscription&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<HeartbeatSubscription&>(*cmd).GetResult(), Result::Ok);
|
||||
break;
|
||||
case Type::heartbeat_unsubscription:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<HeartbeatUnsubscription&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<HeartbeatUnsubscription&>(*cmd).GetResult(), Result::Ok);
|
||||
break;
|
||||
case Type::heartbeat:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<Heartbeat&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
break;
|
||||
case Type::state_change_subscription:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<StateChangeSubscription&>(*cmd).GetResult(), Result::Ok);
|
||||
break;
|
||||
case Type::state_change_unsubscription:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<StateChangeUnsubscription&>(*cmd).GetResult(), Result::Ok);
|
||||
break;
|
||||
case Type::state_change:
|
||||
++count;
|
||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetDeviceId(), "somedeviceid");
|
||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetTaskId(), 123456);
|
||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetLastState(), State::Running);
|
||||
ASSERT_EQ(static_cast<StateChange&>(*cmd).GetCurrentState(), State::Ready);
|
||||
break;
|
||||
default:
|
||||
ASSERT_TRUE(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_EQ(count, 17);
|
||||
}
|
||||
|
||||
TEST(Format, SerializationBinary)
|
||||
{
|
||||
Cmds outCmds;
|
||||
fillCommands(outCmds);
|
||||
std::string buffer(outCmds.Serialize());
|
||||
|
||||
Cmds inCmds;
|
||||
inCmds.Deserialize(buffer);
|
||||
checkCommands(inCmds);
|
||||
}
|
||||
|
||||
TEST(Format, SerializationJSON)
|
||||
{
|
||||
Cmds outCmds;
|
||||
fillCommands(outCmds);
|
||||
std::string buffer(outCmds.Serialize(Format::JSON));
|
||||
|
||||
Cmds inCmds;
|
||||
inCmds.Deserialize(buffer, Format::JSON);
|
||||
checkCommands(inCmds);
|
||||
}
|
||||
|
||||
} // namespace
|
@@ -16,7 +16,7 @@
|
||||
#include <cstdlib>
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fairmq/SDK.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <thread>
|
||||
|
||||
@@ -59,14 +59,27 @@ struct TopologyFixture : ::testing::Test
|
||||
auto n(mDDSTopo.GetNumRequiredAgents());
|
||||
mDDSSession.SubmitAgents(n);
|
||||
mDDSSession.ActivateTopology(mDDSTopo);
|
||||
|
||||
std::vector<sdk::DDSAgent> agents = mDDSSession.RequestAgentInfo();
|
||||
LOG(debug) << "##### AgentInfo:";
|
||||
LOG(debug) << "size: " << agents.size();
|
||||
for (const auto& a : agents) {
|
||||
LOG(debug) << a;
|
||||
}
|
||||
|
||||
std::vector<sdk::DDSTask> tasks = mDDSSession.RequestTaskInfo();
|
||||
LOG(debug) << "##### TaskInfo:";
|
||||
LOG(debug) << "size: " << tasks.size();
|
||||
for (const auto& t : tasks) {
|
||||
LOG(debug) << t;
|
||||
}
|
||||
|
||||
std::vector<sdk::DDSCollection> collections = mDDSTopo.GetCollections();
|
||||
LOG(debug) << "##### CollectionInfo:";
|
||||
LOG(debug) << "size: " << collections.size();
|
||||
for (const auto& c : collections) {
|
||||
LOG(debug) << c;
|
||||
}
|
||||
}
|
||||
|
||||
auto TearDown() -> void override {
|
||||
|
@@ -171,6 +171,35 @@ TEST_F(Topology, AsyncChangeStateTimeout)
|
||||
mIoContext.run();
|
||||
}
|
||||
|
||||
TEST_F(Topology, AsyncChangeStateCollectionView)
|
||||
{
|
||||
using namespace fair::mq;
|
||||
|
||||
tools::SharedSemaphore blocker;
|
||||
sdk::Topology topo(mDDSTopo, mDDSSession);
|
||||
topo.AsyncChangeState(
|
||||
sdk::TopologyTransition::InitDevice,
|
||||
[=](std::error_code ec, sdk::TopologyState state) mutable {
|
||||
LOG(info) << ec;
|
||||
sdk::TopologyStateByCollection cstate(sdk::GroupByCollectionId(state));
|
||||
LOG(debug) << "num collections: " << cstate.size();
|
||||
ASSERT_EQ(cstate.size(), 5);
|
||||
for (const auto& c : cstate) {
|
||||
LOG(debug) << "\t" << c.first;
|
||||
State s;
|
||||
ASSERT_NO_THROW(s = sdk::AggregateState(c.second));
|
||||
ASSERT_EQ(s, State::InitializingDevice);
|
||||
LOG(debug) << "\tAggregated state: " << s;
|
||||
for (const auto& ds : c.second) {
|
||||
LOG(debug) << "\t\t" << ds.state;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(ec, std::error_code());
|
||||
blocker.Signal();
|
||||
});
|
||||
blocker.Wait();
|
||||
}
|
||||
|
||||
TEST_F(Topology, ChangeStateFullDeviceLifecycle)
|
||||
{
|
||||
using namespace fair::mq;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<topology name="ExampleDDS">
|
||||
|
||||
<property name="data" />
|
||||
<property name="fmqchan_data" />
|
||||
|
||||
<declrequirement name="SamplerWorker" type="wnname" value="sampler"/>
|
||||
<declrequirement name="SinkWorker" type="wnname" value="sink"/>
|
||||
@@ -11,7 +11,7 @@
|
||||
<name>SamplerWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="write">data</name>
|
||||
<name access="write">fmqchan_data</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
@@ -21,14 +21,20 @@
|
||||
<name>SinkWorker</name>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="read">data</name>
|
||||
<name access="read">fmqchan_data</name>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<declcollection name="Sinks">
|
||||
<tasks>
|
||||
<name>Sink</name>
|
||||
</tasks>
|
||||
</declcollection>
|
||||
|
||||
<main name="main">
|
||||
<task>Sampler</task>
|
||||
<group name="SinkGroup" n="5">
|
||||
<task>Sink</task>
|
||||
<collection>Sinks</collection>
|
||||
</group>
|
||||
</main>
|
||||
|
||||
|
Reference in New Issue
Block a user