Compare commits

...

149 Commits

Author SHA1 Message Date
Dennis Klein
93eb599df7 Example.DDS: Install new example topology 2019-07-26 14:55:32 +02:00
Dennis Klein
98aeb16dc7 SDK: Adapt to new DDS plugin external mode 2019-07-26 14:55:32 +02:00
Dennis Klein
6c07920fc6 DDS plugin: Adapt command ui to changes in DDS plugin
* Add COMPLETE INIT support
* Add -n option, shall be replaced with inspecting DDS topo spec in the
future
* Update DDS example to work again
2019-07-26 14:55:32 +02:00
Dennis Klein
b54df715ea DDS plugin: Do not auto-transition after Initializing 2019-07-26 14:55:32 +02:00
Dennis Klein
ce1f507a24 Example.DDS: Add topology that runs infinitely 2019-07-26 14:55:32 +02:00
Dennis Klein
f7cdf5ee23 DDS plugin: Implement --control external 2019-07-26 14:55:32 +02:00
Dennis Klein
6208cbb508 SDK: Initialize members 2019-07-25 14:43:39 +02:00
Dennis Klein
377eaf2bb8 SDK: Implement error handling for RequestCommanderInfo 2019-07-25 14:42:57 +02:00
Dennis Klein
363576496d SDK: Pass CSession as shared ptr
Even though it is copyable the copy does not work.
2019-07-25 14:42:44 +02:00
Dennis Klein
5ab328b01f SDK: Add ctors to adopt existing DDS API objects 2019-07-25 10:40:31 +02:00
Alexey Rybalchenko
ac8cd19915 SDK: wait for devices to be in running 2019-07-24 16:42:36 +02:00
Alexey Rybalchenko
5d535163f1 SDK: Add test for timeout, concurrent call. Implement TODOs 2019-07-24 15:47:20 +02:00
Dennis Klein
dc55272317 SDK: Implement WaitForExecutingAgents
* Require DDS 2.5.22
* Apply in meaningful places
* Adapt test fixture
2019-07-24 14:54:21 +02:00
Dennis Klein
388b1be056 SDK: Make GetDeviceList implementation more readable 2019-07-24 10:48:19 +02:00
Dennis Klein
d70a203449 SDK: Add sync ChangeState and add msg to its result 2019-07-24 10:41:08 +02:00
Dennis Klein
a93840b240 SDK: Implement WaitForIdleAgents and CommanderInfoRequest 2019-07-24 10:37:58 +02:00
Dennis Klein
bc98ab1eed SDK: Fix CTopology member init and remove separate init step again 2019-07-24 10:34:10 +02:00
Dennis Klein
de4fca177e SDK: Require DDS 2.5.20
* Use the new interface: CTopology::getName
* Enhance Example.DDS
2019-07-24 10:28:32 +02:00
Alexey Rybalchenko
7d1ee82c6b Add timeout test, disable for now 2019-07-23 16:08:15 +02:00
Alexey Rybalchenko
be022cfab8 Fix SDK topology shutdown to include unsubscribe 2019-07-23 16:08:15 +02:00
Alexey Rybalchenko
8789664cfd First working version of SDK ChangeState 2019-07-23 16:08:15 +02:00
Alexey Rybalchenko
cf26dd6aa7 Testing the double subscription 2019-07-23 16:08:15 +02:00
Dennis Klein
18dc536f3d (WIP) SDK: Implement Topology::ChangeState 2019-07-23 16:08:15 +02:00
Dennis Klein
499ffcd300 Fix various clang-tidy warnings 2019-07-23 16:08:15 +02:00
Dennis Klein
a65f0e6777 Tests.Message: Fix race condition 2019-07-23 16:08:15 +02:00
Dennis Klein
b58f6ede74 Ctest: Disable multiple runs of the tests
We tried for a while but it did not help to reduce the unstable coverage
number calculated by codecov.
2019-07-23 16:08:15 +02:00
Dennis Klein
8aad6c062b Tests.SDK: Run serial for now
DDS currently has a race condition which causes session creation to
either hang or not complete properly.
2019-07-23 16:08:15 +02:00
Dennis Klein
152c8431c6 SDK: Let DDSEnvironment manage $LD_LIBRARY_PATH
* Remove configurable install prefix
* Add singleton
2019-07-23 16:08:15 +02:00
Dennis Klein
5a7bf68c8c SDK: Do not always stop the session on destruction 2019-07-23 16:08:15 +02:00
Dennis Klein
7aa95fcd93 SDK: Have DDSSession manage $DDS_SESSION_ID 2019-07-23 16:08:15 +02:00
Dennis Klein
a9b4788756 SDK: Forward declare types where possible 2019-07-23 16:08:15 +02:00
Dennis Klein
eb9dcdd1f9 SDK: Fix installation of <fairmq/sdk/DDSInfo.h> 2019-07-23 16:08:15 +02:00
Dennis Klein
3f655e330b SDK: Add convenience header <fairmq/SDK.h> 2019-07-23 16:08:15 +02:00
Dennis Klein
e6149b7c38 SDK: Require DDS 2.5.7 2019-07-23 16:08:15 +02:00
Dennis Klein
b5da31498d Tools: Add InstanceLimiter utility 2019-07-23 16:08:15 +02:00
Dennis Klein
44da054e78 SDK: Implement Topology ctor 2019-07-23 16:08:15 +02:00
Dennis Klein
53be96d93c Tests.SDK: Implement Topology test fixture 2019-07-23 16:08:15 +02:00
Dennis Klein
cfcdd666bf SDK: Implement DDS helpers 2019-07-23 16:08:15 +02:00
Dennis Klein
90496c89fe Test: Add new testsuite SDK 2019-07-23 16:08:15 +02:00
Dennis Klein
1a93da5be0 SDK: Remove Session stub 2019-07-23 16:08:15 +02:00
Dennis Klein
99ed61a58b Tools: Introduce semaphore 2019-07-23 16:08:15 +02:00
Dennis Klein
a98965031f clang-tidy: Skip llvm-header-guard check 2019-07-23 16:08:15 +02:00
Dennis Klein
fd682c3392 CMake: Mark sdk component EXPERIMENTAL 2019-07-23 16:08:15 +02:00
Dennis Klein
2c4a6674d2 Example.DDS: Add option to switch DDS RMS plugin 2019-07-19 14:45:27 +02:00
Dennis Klein
7002dcbca3 Example.DDS: Fix support for ssh rms plugin 2019-07-19 14:45:27 +02:00
Dennis Klein
790de84bbc Example.DDS: reachable attribute is true by default 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
e3d39f39f2 Don't use absolute paths in dds example 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
6e353d78b1 Remove -S from dds example topology file 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
f515eb1100 Extract state queue into own class. Use in device, plugins 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
4487b81de8 Extract States & Transitions to own header, use in plugins 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
8bb6a9518a Use TransitionTo in Plugins 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
857ef0c9d3 Formatting 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
63c02657c1 Fix SHUTDOWN & STARTUP listed as a transition in plugin 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
5256e7c580 Add support and test for concurrent TransitionTo 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
74d301a16f Implement Device::TransitionTo() and test it 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
1c7da53386 Refactor multiple devices test for better readability 2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
07f7142ae2 Rebased, cleaned up 2019-07-19 14:45:27 +02:00
Dennis Klein
ff581985f3 Example.DDS: Remove sleep to speed up testing 2019-07-19 14:45:27 +02:00
Dennis Klein
5e8a442342 Example.DDS: Fix typo 2019-07-19 14:45:27 +02:00
Dennis Klein
0b43bec9a7 CMake: Simplify summary of DDS dependency 2019-07-19 14:45:27 +02:00
Dennis Klein
afadb2a078 Make find_package2 a bit smarter
The VERSION arguments now supports multiple values and picks the highest
version from the given. The COMPONENTS argument now automatically
removes duplicates.
2019-07-19 14:45:27 +02:00
Dennis Klein
7c185ac4a5 Search plugins in system directories and LD_LIBRARY_PATH
Fixes #133
2019-07-19 14:45:27 +02:00
Dennis Klein
a60edc43dc Fix -Winconsistent-missing-override 2019-07-19 14:45:27 +02:00
Dennis Klein
d4f96db69c Example.DDS: Add start script 2019-07-19 14:45:27 +02:00
Dennis Klein
b53691c8ad Add -i option as exit condition
After -i# iterations sampler and sink will exit RUNNING state.
2019-07-19 14:45:27 +02:00
Dennis Klein
14980d7486 Implement old_state->new_state notifications 2019-07-19 14:45:27 +02:00
Dennis Klein
d966a0a991 Handle some edge cases 2019-07-19 14:45:27 +02:00
Dennis Klein
66c01f2cda Introduce wait mode
Allows for fairmq-dds-command-ui to block until a certain device state
(-w) or a timeout (-t) is reached. If multiple devices are addressed (-p),
the command blocks until all of them reached the given state.
2019-07-19 14:45:27 +02:00
Alexey Rybalchenko
2150257c1d Extend configuration docs 2019-07-11 18:58:46 +02:00
Alexey Rybalchenko
8be2fd33f4 Refactor some device code for better readability 2019-07-11 18:58:46 +02:00
Alexey Rybalchenko
26fe5e2bd8 Move PropertyNotFound handling to ProgOptions 2019-07-11 18:58:46 +02:00
Alexey Rybalchenko
48e04b636b Initialize initialization timeout in InitWrapper() 2019-07-11 18:58:46 +02:00
Alexey Rybalchenko
937c9e8921 Clear channels & transports containers in Reset() 2019-07-11 18:58:46 +02:00
Alexey Rybalchenko
5c943bbedb Add debug output 2019-07-11 18:58:46 +02:00
Alexey Rybalchenko
418d42b060 Fix WaitForState(string stateName) 2019-07-11 11:07:16 +02:00
Dennis Klein
4af0393c11 Test.Properties: Refine 2019-07-10 19:35:18 +02:00
Dennis Klein
12f05355d3 ProgOptions: Fix minor things 2019-07-10 19:35:18 +02:00
Dennis Klein
69268eecfb Tools: Fix various clang-tidy warnings 2019-07-10 19:35:18 +02:00
Dennis Klein
4351b98d85 clang-tidy: Configure via file 2019-07-10 19:35:18 +02:00
Dennis Klein
051f064c60 Test.PluginServices: Fix -Wdeprecated-copy 2019-07-10 19:35:18 +02:00
Dennis Klein
caffbf2ebf Copyright: Update year 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
daed714146 Fix CMake after rebase 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
4cefb9fb5b Add tests for property conversions and subscriptions 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
7486249c1e Declare operator<< for boost::any in boost namespace 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
7c13503e22 Include definitions of constexpr members in cxx 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
3db32b03d4 only allow a-z A-Z 0-9 - _ [ ] # as channel name characters 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
7bea2bc0e6 Add PluginServices::DeleteProperty, test for property accessors 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
5271d4236e Add additional test for running device with plugins without DeviceRunner 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
4281d7b27e Subscribe DeviceRunner for config properties 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
7c9744760e Add UpdateProperty/ies() 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
b905f517cc Fix PropertyHelper::AddType() to include event emitter creation 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
c515cbb3bf Update config documentation 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
cba6d19781 Add config plugin class. 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
bf8ec968e7 Remove FairMQChannel from parser, implement bulk operations 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
fbb003b50f FairMQChannel: defaults values, copy-ability 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
4ce378b6b8 Add DeleteProperty 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
29313bbec3 Add SetProperties() 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
fe241fe9ee Add *Property methods to replace *Value methods, simplify options helper 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
5646d531f3 Add GetProperties() 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
f46803a8b6 Remove unused methods from FairMQProgOptions 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
3538d9f410 Deprecate Channel::GetChannelX() in favor of Channel::GetX() 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
73ccefa4cb Remove deprecated *Async() methods 2019-07-10 19:35:18 +02:00
Alexey Rybalchenko
0e35f1cb22 Shmem region: support huge pages via path to hugetlbfs mount 2019-07-05 15:58:28 +02:00
Dennis Klein
a8c76accdc Split StateMachine and Tools into separate targets
This change is needed to share the functionality between
the core library and the SDK library. We want to support building/installing
just the SDK without having a dependency on the core library which adds
additional dependencies.
2019-07-02 21:30:37 +02:00
Dennis Klein
3da5f4d5db SDK: Add CMake skeleton
* New build flag BUILD_SDK
* New component "sdk"
2019-07-02 21:30:37 +02:00
Dennis Klein
b1c8264123 find_package2: Fix list sub-command REMOVE_DUPLICATES requires list to be present
Fixes #175
2019-06-27 14:02:15 +02:00
Dennis Klein
4d53b7c024 CMake: Support FairLogger v1.5.0 2019-06-27 14:02:15 +02:00
Dennis Klein
09853e3031 CMake: Support Boost 1.70 config mode
Below CMake 3.15 we disable config mode by default, this can
be overridden via -DBoost_NO_BOOST_CMAKE=OFF

Resolves #174
2019-06-27 14:02:15 +02:00
Dennis Klein
a866c6d936 CMake: Add Boost version requirement of DDS
* Fix dependency summary table entry for DDS
2019-06-26 20:42:20 +02:00
Dennis Klein
a30a6955ef CMake: Apply new ADD_REQUIREMENTS_OF option 2019-06-26 20:42:20 +02:00
Dennis Klein
187a821f36 CMake: Revert VERSION option to single value arg
This fixes a regression introduced in 0ff8eaf that caused other options
to be ineffective in certain cases.

Resolves #164
2019-06-26 20:42:20 +02:00
Dennis Klein
465d90924b CMake: Implement ADD_REQUIREMENTS_OF option for find_package2
Resolves #142
2019-06-26 20:42:20 +02:00
Dennis Klein
3358a2ba12 Require DDS 2.4
* Remove obsolete FindDDS.cmake
* Adapt to new DDS version
2019-06-26 18:39:12 +02:00
Dennis Klein
479c16a8fa CMake: Export build type and cxx flags
Resolve #158
2019-06-24 19:06:38 +02:00
Dennis Klein
374eb84039 Docs: Add section about plugins
Resolve #3
2019-06-24 18:18:29 +02:00
Dennis Klein
56dc91ab87 Update year 2019-06-13 18:04:44 +02:00
Dennis Klein
99c8d33191 DDS plugin: Remove unused dependency 2019-06-13 17:47:47 +02:00
Dennis Klein
660420e4f3 CMake: Support running static analysis
OFF by default (Imposes significant additional build time). Controlled
with CMake variable RUN_STATIC_ANALYSIS.

Supported analysers:
* clang-tidy
* iwyu
* cpplint
2019-06-04 12:17:37 +02:00
Dennis Klein
f8f997abe6 CMake: Set policies by version
This is the recommended way of dealing with policies. Also, this patch
fixes a problem with the policies being set at the wrong depth in the
policy stack.
2019-06-04 12:17:37 +02:00
Gvozden Neskovic
40f6db430a Print channel name in error log 2019-06-01 06:20:39 +02:00
Gvozden Neskovic
2ed2177555 Batch Region ack messages
Reduce CPU utilization by batching release ack messages on the IPC queue.
2019-05-14 14:56:08 +02:00
Gvozden Neskovic
9b326c7a71 add array variant of fair::mq::tools::make_unique() 2019-05-14 14:56:08 +02:00
Alexey Rybalchenko
9b4c5deb0b Handle invalid transition to init in the control plugin 2019-05-07 16:28:55 +02:00
Alexey Rybalchenko
7b16c33ccd Allow PluginServices::SetProperty in Ready state 2019-05-07 15:51:59 +02:00
Alexey Rybalchenko
7e6eb382d5 Extend Readout example 2019-04-29 20:32:38 +02:00
Alexey Rybalchenko
35399ee039 Update state machine picture 2019-04-29 20:32:37 +02:00
Alexey Rybalchenko
2cc1117637 Notify all listeners on state changes 2019-04-29 20:32:37 +02:00
Dennis Klein
3582091b1c Add experimental static size mode for ofi transport
Whenever --ofi-size-hint > 0, the ofi transport does not use the control
band. Multipart is not supported.
2019-04-29 20:28:40 +02:00
Dennis Klein
2457094b6c Require correct asiofi version v0.3.1 2019-03-21 18:03:32 +01:00
Dennis Klein
54b7742d85 Drop obsolete dependency to AZMQ 2019-03-21 18:03:32 +01:00
Dennis Klein
195644f132 Add some debug output 2019-03-21 18:03:32 +01:00
Dennis Klein
f17dade8f8 Fix example after rebase 2019-03-21 18:03:32 +01:00
Dennis Klein
cc8fd73025 Fix recv logic 2019-03-21 18:03:32 +01:00
Dennis Klein
90fdcc26bb Run multipart example with ofi 2019-03-21 18:03:32 +01:00
Dennis Klein
b45e4da2a9 Implement linger for ofi
This reduces test runtime significantly for most transports
2019-03-21 18:03:32 +01:00
Dennis Klein
a1b7efa2f4 Unify implementation of multi part and single part message interfaces 2019-03-21 18:03:32 +01:00
Dennis Klein
6ee7e5fbf0 Improve error handling 2019-03-21 18:03:32 +01:00
Alexey Rybalchenko
99ffb732f4 Use process tools for WaitFor test 2019-03-19 18:09:01 +01:00
Alexey Rybalchenko
6809d60fad Fix mismatch of docs/API, wrong return value 2019-03-19 18:09:01 +01:00
Alexey Rybalchenko
ef4d6a3310 Process tools: add print helper, support signals 2019-03-19 18:09:01 +01:00
Matthias Richter
696257fd4f Extending FairMQParts by a constructor taking list of FairMQMessagePtr
This introduces a little helper to create a FairMQParts object in place from a
variable list of arguments. As a side effect also AddParts is extended to support
more than one FairMQMessagePtr.
2019-03-19 12:48:02 +01:00
Alexey Rybalchenko
cdc1ba084c Fix broken pipe errors in tools::execute 2019-03-15 15:51:50 +01:00
Alexey Rybalchenko
922f7e9a92 Use Asio to launch processes in fair::mq::tools::execute 2019-03-14 18:15:17 +01:00
Dennis Klein
a8f1a4dfdb Try to reconnect on refused connection 2019-03-13 18:04:49 +01:00
Dennis Klein
fb42b1e2f0 Adapt to new asiofi release 2019-03-13 18:04:49 +01:00
Alexey Rybalchenko
1a00f3edbd Remove controller input for several tests
The affected tests have independent shutdown
  conditions that race with the controller inputs.
2019-03-12 17:51:33 +01:00
Alexey Rybalchenko
74881d27e3 Remove obsolete state machine code 2019-03-12 12:10:47 +01:00
Alexey Rybalchenko
dd02c01c36 Extend tests of error cases
- test raising SIGINT in every state
 - test going to Error state from every state
 - add new states (bind/connect) to exception tests
2019-03-12 12:10:47 +01:00
Alexey Rybalchenko
44a9946ea6 Allow creating region with a callback with default transport 2019-03-11 20:20:22 +01:00
229 changed files with 8768 additions and 5230 deletions

3
.clang-tidy Normal file
View File

@@ -0,0 +1,3 @@
---
Checks: '*,-google-*,-fuchsia-*,-cert-*,-llvm-header-guard,-readability-named-parameter,-misc-non-private-member-variables-in-classes,-*-magic-numbers,-llvm-include-order,-hicpp-no-array-decay,-performance-unnecessary-value-param,-cppcoreguidelines-pro-bounds-array-to-pointer-decay'
HeaderFilterRegex: '/(fairmq/|FairMQ)'

View File

@@ -7,13 +7,12 @@
################################################################################
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
cmake_policy(VERSION 3.10...3.14)
# Project ######################################################################
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
include(FairMQLib)
set_fairmq_cmake_policies()
get_git_version()
project(FairMQ VERSION ${PROJECT_VERSION} LANGUAGES CXX)
@@ -40,6 +39,7 @@ cmake_dependent_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport." O
cmake_dependent_option(BUILD_DDS_PLUGIN "Build DDS plugin." OFF "BUILD_FAIRMQ" OFF)
cmake_dependent_option(BUILD_PMIX_PLUGIN "Build PMIx plugin." OFF "BUILD_FAIRMQ" OFF)
cmake_dependent_option(BUILD_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF)
option(BUILD_SDK "Build the FairMQ controller SDK." OFF)
option(BUILD_DOCS "Build FairMQ documentation." OFF)
option(FAST_BUILD "Fast production build. Not recommended for development." OFF)
################################################################################
@@ -61,14 +61,11 @@ endif()
if(BUILD_OFI_TRANSPORT)
find_package2(PRIVATE asiofi REQUIRED
VERSION 0.2.0
VERSION 0.3.1
)
find_package2(PRIVATE OFI REQUIRED
VERSION ${asiofi_OFI_VERSION}
COMPONENTS ${asiofi_OFI_COMPONENTS}
ADD_REQUIREMENTS_OF asiofi
)
find_package2(PRIVATE AZMQ REQUIRED)
set(PROJECT_AZMQ_VERSION 1.0.2)
endif()
if(BUILD_NANOMSG_TRANSPORT)
@@ -77,9 +74,38 @@ if(BUILD_NANOMSG_TRANSPORT)
)
endif()
if(BUILD_FAIRMQ)
if(BUILD_SDK)
set(required_dds_version 2.5.22)
else()
set(required_dds_version 2.4)
endif()
if(BUILD_DDS_PLUGIN OR BUILD_SDK)
find_package2(PRIVATE DDS REQUIRED
VERSION ${required_dds_version}
)
set(DDS_Boost_COMPONENTS system log log_setup)
set(DDS_Boost_VERSION 1.67)
endif()
if(BUILD_PMIX_PLUGIN)
find_package2(PRIVATE PMIx REQUIRED
VERSION 2.1.4
)
endif()
if(BUILD_FAIRMQ OR BUILD_SDK)
find_package2(PUBLIC FairLogger REQUIRED
VERSION 1.2.0
)
if(NOT DEFINED Boost_NO_BOOST_CMAKE AND CMAKE_VERSION VERSION_LESS 3.15)
# Since Boost 1.70 a CMake package is shipped by default. Unfortunately, it has a number
# of problems that are only fixed in Boost 1.71 or CMake 3.15. By default we skip the
# BoostConfig lookup. This can be overridden on the command line via -DBoost_NO_BOOST_CMAKE=OFF
set(Boost_NO_BOOST_CMAKE ON)
endif()
find_package2(PUBLIC Boost REQUIRED
VERSION 1.64 ${asiofi_Boost_VERSION}
VERSION 1.64
COMPONENTS
container
@@ -87,24 +113,20 @@ if(BUILD_FAIRMQ)
filesystem
date_time
regex
${asiofi_Boost_COMPONENTS}
)
find_package2(PUBLIC FairLogger REQUIRED
VERSION 1.2.0
ADD_REQUIREMENTS_OF
asiofi
DDS
FairLogger
)
endif()
if(BUILD_FAIRMQ)
find_package2(PRIVATE ZeroMQ REQUIRED
VERSION 4.1.5
)
endif()
if(BUILD_DDS_PLUGIN)
find_package2(PRIVATE DDS VERSION 2.2 REQUIRED)
endif()
if(BUILD_PMIX_PLUGIN)
find_package2(PRIVATE PMIx VERSION 2.1.4 REQUIRED)
endif()
if(BUILD_TESTING)
find_package2(PRIVATE GTest REQUIRED
VERSION 1.7.0
@@ -122,12 +144,7 @@ endif()
# Targets ######################################################################
if(BUILD_FAIRMQ)
configure_file(${PROJECT_NAME_LOWER}/Version.h.in
${CMAKE_BINARY_DIR}/${PROJECT_NAME_LOWER}/Version.h
@ONLY
)
if(BUILD_FAIRMQ OR BUILD_SDK)
add_subdirectory(fairmq)
endif()
@@ -176,29 +193,18 @@ endif()
if(BUILD_DOCS)
list(APPEND PROJECT_PACKAGE_COMPONENTS docs)
endif()
if(BUILD_SDK)
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk)
endif()
################################################################################
# Installation #################################################################
if(BUILD_FAIRMQ)
install(FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME_LOWER}/Version.h
DESTINATION ${PROJECT_INSTALL_INCDIR}
)
install(FILES cmake/FindZeroMQ.cmake
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
)
endif()
if(BUILD_DDS_PLUGIN)
install(FILES cmake/FindDDS.cmake
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
)
endif()
if(BUILD_OFI_TRANSPORT)
install(FILES cmake/FindAZMQ.cmake
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
)
endif()
if(BUILD_DOCS)
install(DIRECTORY ${CMAKE_BINARY_DIR}/doxygen/html
DESTINATION ${PROJECT_INSTALL_DATADIR}/docs
@@ -241,7 +247,11 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
foreach(dep IN LISTS PROJECT_PACKAGE_DEPENDENCIES)
if(${dep}_VERSION)
if(${dep} STREQUAL Boost)
set(version_str "${BGreen}${${dep}_MAJOR_VERSION}.${${dep}_MINOR_VERSION}${CR}")
if(Boost_VERSION_MAJOR)
set(version_str "${BGreen}${${dep}_VERSION_MAJOR}.${${dep}_VERSION_MINOR}${CR}")
else()
set(version_str "${BGreen}${${dep}_MAJOR_VERSION}.${${dep}_MINOR_VERSION}${CR}")
endif()
else()
set(version_str "${BGreen}${${dep}_VERSION}${CR}")
endif()
@@ -258,7 +268,11 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
pad("${version_str}${version_req_str}" 25 " " version_padded COLOR 1)
endif()
if(${dep} STREQUAL FairLogger)
set(prefix ${FairLogger_ROOT})
if(FairLogger_PREFIX)
set(prefix ${FairLogger_PREFIX})
else()
set(prefix ${FairLogger_ROOT})
endif()
elseif(${dep} STREQUAL GTest)
get_filename_component(prefix ${GTEST_INCLUDE_DIRS}/.. ABSOLUTE)
elseif(${dep} STREQUAL msgpack)
@@ -271,6 +285,15 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
elseif(${dep} STREQUAL nanomsg)
get_target_property(nn_include nanomsg INTERFACE_INCLUDE_DIRECTORIES)
get_filename_component(prefix ${nn_include}/.. ABSOLUTE)
elseif(${dep} STREQUAL DDS)
set(prefix "${DDS_INSTALL_PREFIX}")
elseif(${dep} STREQUAL Boost)
if(TARGET Boost::headers)
get_target_property(boost_include Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
else()
get_target_property(boost_include Boost::boost INTERFACE_INCLUDE_DIRECTORIES)
endif()
get_filename_component(prefix ${boost_include}/.. ABSOLUTE)
elseif(${dep} STREQUAL Doxygen)
get_target_property(doxygen_bin Doxygen::doxygen INTERFACE_LOCATION)
get_filename_component(prefix ${doxygen_bin} DIRECTORY)
@@ -334,5 +357,33 @@ else()
set(docs_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_DOCS=ON${CR})")
endif()
message(STATUS " ${BWhite}docs${CR} ${docs_summary}")
if(BUILD_SDK)
set(sdk_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_SDK=OFF${CR})")
else()
set(sdk_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_SDK=ON${CR})")
endif()
message(STATUS " ${BWhite}sdk${CR} ${sdk_summary}")
message(STATUS " ")
if(RUN_STATIC_ANALYSIS)
list(LENGTH PROJECT_STATIC_ANALYSERS size)
unset(analyser_list)
set(count 0)
foreach(analyser IN LISTS PROJECT_STATIC_ANALYSERS)
if(${analyser}_FOUND)
set(${analyser}_status "${analyser} ${BGreen}YES${CR}")
else()
set(${analyser}_status "${analyser} ${BRed}NO${CR}")
endif()
math(EXPR count "${count} + 1")
string(APPEND analyser_list "${${analyser}_status}")
if(count LESS size)
string(APPEND analyser_list "${BWhite},${CR} ")
endif()
endforeach()
set(static_ana_summary "${BWhite}(${CR}${analyser_list}${BWhite})${CR} (disable with ${BMagenta}-DRUN_STATIC_ANALYSIS=OFF${CR})")
else()
set(static_ana_summary "${BRed}OFF${CR} (default, enable with ${BMagenta}-DRUN_STATIC_ANALYSIS=ON${CR})")
endif()
message(STATUS " ${Cyan}RUN STATIC ANALYSIS ${static_ana_summary}")
message(STATUS " ")
################################################################################

View File

@@ -4,9 +4,9 @@ Upstream-Contact: Mohammad Al-Turany <m.al-turany@gsi.de>
Source: https://github.com/FairRootGroup/FairMQ
Files: *
Copyright: 2012-2018, GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
Copyright: 2012-2018, [see AUTHORS file]
Copyright: 2012-2018, [see CONTRIBUTORS file]
Copyright: 2012-2019, GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
Copyright: 2012-2019, [see AUTHORS file]
Copyright: 2012-2019, [see CONTRIBUTORS file]
Comment: The copyright of individual contributors is documented in the
Git history.
License: LGPL-3.0-only

View File

@@ -29,6 +29,7 @@ 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=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}")
@@ -59,17 +60,9 @@ Ctest_Build(BUILD "${CTEST_BINARY_DIRECTORY}")
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
# PARALLEL_LEVEL $ENV{number_of_processors}
PARALLEL_LEVEL 1
PARALLEL_LEVEL $ENV{number_of_processors}
RETURN_VALUE _ctest_test_ret_val
)
If("$ENV{do_codecov_upload}")
ForEach(i RANGE 4)
# Gather statistics to catch time sensitive branches
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL $ENV{number_of_processors}
)
EndForEach()
EndIf()
If(GCOV_COMMAND)
Ctest_Coverage(BUILD "${CTEST_BINARY_DIRECTORY}" LABELS coverage)

View File

@@ -38,7 +38,7 @@ a simulation, reconstruction and analysis framework.
* PUBLIC: [**Boost**](https://www.boost.org/), [**FairLogger**](https://github.com/FairRootGroup/FairLogger)
* BUILD: [CMake](https://cmake.org/), [GTest](https://github.com/google/googletest), [Doxygen](http://www.doxygen.org/)
* PRIVATE: [ZeroMQ](http://zeromq.org/), [Msgpack](https://msgpack.org/index.html), [nanomsg](http://nanomsg.org/),
[asiofi](https://github.com/FairRootGroup/asiofi), [DDS](http://dds.gsi.de), [PMIx](https://pmix.org/), [AZMQ](https://github.com/zeromq/azmq), [asiofi](https://github.com/FairRootGroup/asiofi)
[asiofi](https://github.com/FairRootGroup/asiofi), [DDS](http://dds.gsi.de), [PMIx](https://pmix.org/)
Supported platforms: Linux and MacOS.
@@ -51,7 +51,7 @@ cmake -DCMAKE_INSTALL_PREFIX=./fairmq_install ../fairmq
cmake --build . --target install
```
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `MSGPACK`, `NANOMSG`, `OFI`, `PMIX`, `ASIOFI`, `AZMQ` or `DDS` (`*_ROOT` variables can also be environment variables).
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `MSGPACK`, `NANOMSG`, `OFI`, `PMIX`, `ASIOFI` or `DDS` (`*_ROOT` variables can also be environment variables).
## Usage
@@ -126,9 +126,11 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
| `${FairMQ_LIBDIR}` | the installation lib directory |
| `${FairMQ_DATADIR}` | the installation data directory (`../share/fairmq`) |
| `${FairMQ_CMAKEMODDIR}` | the installation directory of shipped CMake find modules |
| `${FairMQ_CXX_STANDARD_REQUIRED}` | the value of `CMAKE_CXX_STANDARD_REQUIRED` at built-time |
| `${FairMQ_CXX_STANDARD}` | the value of `CMAKE_CXX_STANDARD` at built-time |
| `${FairMQ_CXX_EXTENSIONS}` | the values of `CMAKE_CXX_EXTENSIONS` at built-time |
| `${FairMQ_CXX_STANDARD_REQUIRED}` | the value of `CMAKE_CXX_STANDARD_REQUIRED` at build-time |
| `${FairMQ_CXX_STANDARD}` | the value of `CMAKE_CXX_STANDARD` at build-time |
| `${FairMQ_CXX_EXTENSIONS}` | the values of `CMAKE_CXX_EXTENSIONS` at build-time |
| `${FairMQ_BUILD_TYPE}` | the value of `CMAKE_BUILD_TYPE` at build-time |
| `${FairMQ_CXX_FLAGS}` | the values of `CMAKE_CXX_FLAGS` and `CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}` at build-time |
## Documentation
@@ -157,3 +159,10 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
4. [File output](docs/Logging.md#54-file-output)
5. [Custom sinks](docs/Logging.md#55-custom-sinks)
6. [Examples](docs/Examples.md#6-examples)
7. [Plugins](docs/Plugins.md#7-plugins)
1. [Usage](docs/Plugins.md#71-usage)
2. [Development](docs/Plugins.md#72-development)
3. [Provided Plugins](docs/Plugins.md#73-provided-plugins)
1. [DDS](docs/Plugins.md#731-dds)
2. [PMIx](docs/Plugins.md#732-pmix)

View File

@@ -13,17 +13,20 @@ set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
set(@PROJECT_NAME@_GIT_VERSION @PROJECT_GIT_VERSION@)
set(@PROJECT_NAME@_GIT_DATE @PROJECT_GIT_DATE@)
set_and_check(@PROJECT_NAME@_PREFIX @PACKAGE_CMAKE_INSTALL_PREFIX@)
set_and_check(@PROJECT_NAME@_BINDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_BINDIR@)
set_and_check(@PROJECT_NAME@_INCDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@)
set_and_check(@PROJECT_NAME@_LIBDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_LIBDIR@)
set_and_check(@PROJECT_NAME@_DATADIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_DATADIR@)
set_and_check(@PROJECT_NAME@_CMAKEMODDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_CMAKEMODDIR@)
set(@PROJECT_NAME@_PREFIX @PACKAGE_CMAKE_INSTALL_PREFIX@)
set(@PROJECT_NAME@_BINDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_BINDIR@)
set(@PROJECT_NAME@_INCDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@)
set(@PROJECT_NAME@_LIBDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_LIBDIR@)
set(@PROJECT_NAME@_DATADIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_DATADIR@)
set(@PROJECT_NAME@_CMAKEMODDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_CMAKEMODDIR@)
set(@PROJECT_NAME@_CXX_STANDARD_REQUIRED @CMAKE_CXX_STANDARD_REQUIRED@)
set(@PROJECT_NAME@_CXX_STANDARD @CMAKE_CXX_STANDARD@)
set(@PROJECT_NAME@_CXX_EXTENSIONS @CMAKE_CXX_EXTENSIONS@)
set(@PROJECT_NAME@_VERSION_HOTFIX @PROJECT_VERSION_HOTFIX@)
set(@PROJECT_NAME@_BUILD_TYPE @CMAKE_BUILD_TYPE@)
set(@PROJECT_NAME@_BUILD_TYPE_UPPER @PROJECT_BUILD_TYPE_UPPER@)
set(@PROJECT_NAME@_CXX_FLAGS @PROJECT_CXX_FLAGS@)
### Import cmake modules
set(CMAKE_MODULE_PATH ${@PROJECT_NAME@_CMAKEMODDIR} ${CMAKE_MODULE_PATH})

View File

@@ -29,26 +29,6 @@ if(NOT WIN32 AND NOT DISABLE_COLOR)
set(BWhite "${Esc}[1;37m")
endif()
# set_fairmq_cmake_policies()
#
# Sets CMake policies.
macro(set_fairmq_cmake_policies)
# Find more details to each policy with cmake --help-policy CMPXXXX
foreach(policy
CMP0025 # Compiler id for Apple Clang is now AppleClang.
CMP0028 # Double colon in target name means ALIAS or IMPORTED target.
CMP0042 # MACOSX_RPATH is enabled by default.
CMP0048 # The ``project()`` command manages VERSION variables.
CMP0054 # Only interpret ``if()`` arguments as variables or keywords when unquoted.
CMP0074 # ``find_package()`` uses ``<PackageName>_ROOT`` variables.
)
if(POLICY ${policy})
cmake_policy(SET ${policy} NEW)
endif()
endforeach()
endmacro()
find_package(Git)
# get_git_version([DEFAULT_VERSION version] [DEFAULT_DATE date] [OUTVAR_PREFIX prefix])
#
@@ -186,6 +166,34 @@ macro(set_fairmq_defaults)
else()
set(PROJECT_VERSION_HOTFIX ${PROJECT_VERSION_TWEAK})
endif()
if(NOT DEFINED RUN_STATIC_ANALYSIS)
set(RUN_STATIC_ANALYSIS OFF)
endif()
unset(PROJECT_STATIC_ANALYSERS)
if(RUN_STATIC_ANALYSIS)
set(analyser "clang-tidy")
find_program(${analyser}_FOUND "${analyser}")
if(${analyser}_FOUND)
set(CMAKE_CXX_CLANG_TIDY "${${analyser}_FOUND}")
endif()
list(APPEND PROJECT_STATIC_ANALYSERS "${analyser}")
set(analyser "iwyu")
find_program(${analyser}_FOUND "${analyser}")
if(${analyser}_FOUND)
set(CMAKE_CXX_IWYU "${${analyser}_FOUND}")
endif()
list(APPEND PROJECT_STATIC_ANALYSERS "${analyser}")
set(analyser "cpplint")
find_program(${analyser}_FOUND "${analyser}")
if(${analyser}_FOUND)
set(CMAKE_CXX_CPPLINT "${${analyser}_FOUND}")
endif()
list(APPEND PROJECT_STATIC_ANALYSERS "${analyser}")
endif()
endmacro()
function(join VALUES GLUE OUTPUT)
@@ -280,6 +288,8 @@ macro(install_cmake_package)
)
generate_package_dependencies() # fills ${PACKAGE_DEPENDENCIES}
generate_package_components() # fills ${PACKAGE_COMPONENTS}
string(TOUPPER ${CMAKE_BUILD_TYPE} PROJECT_BUILD_TYPE_UPPER)
set(PROJECT_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${PROJECT_BUILD_TYPE_UPPER}})
configure_package_config_file(
${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
@@ -293,49 +303,97 @@ macro(install_cmake_package)
)
endmacro()
#
# find_package2(PRIVATE|PUBLIC|INTERFACE <pkgname>
# [VERSION <version>]
# [COMPONENTS <list of components>]
# [ADD_REQUIREMENTS_OF <list of dep_pgkname>]
# [any other option the native find_package supports]...)
#
# Wrapper around CMake's native find_package command to add some features and bookkeeping.
#
# The qualifier (PRIVATE|PUBLIC|INTERFACE) to the package to populate
# the variables PROJECT_[INTERFACE]_<pkgname>_([VERSION]|[COMPONENTS]|PACKAGE_DEPENDENCIES)
# accordingly. This bookkeeping information is used to print our dependency found summary
# table and to generate a part of our CMake package.
#
# When a dependending package is listed with ADD_REQUIREMENTS_OF the variables
# <dep_pkgname>_<pkgname>_VERSION|COMPONENTS are looked up to and added to the native
# VERSION (selected highest version) and COMPONENTS (deduplicated) args.
#
# COMPONENTS and VERSION args are then just passed to the native find_package.
#
macro(find_package2 qualifier pkgname)
cmake_parse_arguments(ARGS "" "" "VERSION;COMPONENTS" ${ARGN})
cmake_parse_arguments(ARGS "" "VERSION" "COMPONENTS;ADD_REQUIREMENTS_OF" ${ARGN})
string(TOUPPER ${pkgname} pkgname_upper)
set(old_CPP ${CMAKE_PREFIX_PATH})
set(__old_cpp__ ${CMAKE_PREFIX_PATH})
set(CMAKE_PREFIX_PATH ${${pkgname_upper}_ROOT} $ENV{${pkgname_upper}_ROOT} ${CMAKE_PREFIX_PATH})
unset(__version__)
# build lists of required versions and components
unset(__required_versions__)
unset(__components__)
if(ARGS_VERSION)
list(GET ARGS_VERSION 0 __version__)
list(LENGTH ARGS_VERSION __length__)
foreach(v IN LISTS ARGS_VERSION)
list(APPEND __required_versions__ ${ARGS_VERSION})
endif()
if(ARGS_COMPONENTS)
list(APPEND __components__ ${ARGS_COMPONENTS})
endif()
if(ARGS_ADD_REQUIREMENTS_OF)
foreach(dep_pkgname IN LISTS ARGS_ADD_REQUIREMENTS_OF)
if(${dep_pkgname}_${pkgname}_VERSION)
list(APPEND __required_versions__ ${${dep_pkgname}_${pkgname}_VERSION})
endif()
if(${dep_pkgname}_${pkgname}_COMPONENTS)
list(APPEND __components__ ${${dep_pkgname}_${pkgname}_COMPONENTS})
endif()
endforeach()
endif()
# select highest required version
unset(__version__)
if(__required_versions__)
list(GET __required_versions__ 0 __version__)
foreach(v IN LISTS __required_versions__)
if(${v} VERSION_GREATER ${__version__})
set(__version__ ${v})
endif()
endforeach()
endif()
if(ARGS_COMPONENTS)
list(REMOVE_DUPLICATES ARGS_COMPONENTS)
find_package(${pkgname} ${__version__} QUIET COMPONENTS ${ARGS_COMPONENTS} ${ARGS_UNPARSED_ARGUMENTS})
# deduplicate required component list
if(__components__)
list(REMOVE_DUPLICATES __components__)
endif()
# call native find_package
if(__components__)
find_package(${pkgname} ${__version__} QUIET COMPONENTS ${__components__} ${ARGS_UNPARSED_ARGUMENTS})
else()
find_package(${pkgname} ${__version__} QUIET ${ARGS_UNPARSED_ARGUMENTS})
endif()
set(CMAKE_PREFIX_PATH ${old_CPP})
unset(old_CPP)
if(${pkgname}_FOUND)
if(${qualifier} STREQUAL PRIVATE)
set(PROJECT_${pkgname}_VERSION ${__version__})
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
set(PROJECT_${pkgname}_COMPONENTS ${__components__})
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
elseif(${qualifier} STREQUAL PUBLIC)
set(PROJECT_${pkgname}_VERSION ${__version__})
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
set(PROJECT_${pkgname}_COMPONENTS ${__components__})
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
set(PROJECT_INTERFACE_${pkgname}_VERSION ${__version__})
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${__components__})
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
elseif(${qualifier} STREQUAL INTERFACE)
set(PROJECT_INTERFACE_${pkgname}_VERSION ${__version__})
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${__components__})
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
endif()
endif()
unset(__version__)
unset(__components__)
unset(__required_versions__)
set(CMAKE_PREFIX_PATH ${__old_cpp__})
unset(__old_cpp__)
endmacro()

View File

@@ -1,57 +0,0 @@
################################################################################
# Copyright (C) 2018 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" #
################################################################################
#
# ###########################
# # Locate the AZMQ library #
# ###########################
#
#
# Usage:
#
# find_package(AZMQ [version] [QUIET] [REQUIRED])
#
#
# Defines the following variables:
#
# AZMQ_FOUND - Found the ZeroMQ library
# AZMQ_INCLUDE_DIR (CMake cache) - Include directory
#
#
# Accepts the following variables as hints for installation directories:
#
# AZMQ_ROOT (CMake var, ENV var)
#
#
# If the above variables are not defined, or if ZeroMQ could not be found there,
# it will look for it in the system directories. Custom ZeroMQ installations
# will always have priority over system ones.
#
if(NOT AZMQ_ROOT)
set(AZMQ_ROOT $ENV{AZMQ_ROOT})
endif()
find_path(AZMQ_INCLUDE_DIR
NAMES azmq/socket.hpp
HINTS ${AZMQ_ROOT} $ENV{AZMQ_ROOT}
PATH_SUFFIXES include
DOC "AZMQ include directory"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AZMQ
REQUIRED_VARS AZMQ_INCLUDE_DIR
)
if(AZMQ_FOUND AND NOT TARGET AZMQ::AZMQ)
add_library(AZMQ::AZMQ INTERFACE IMPORTED)
set_target_properties(AZMQ::AZMQ PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${AZMQ_INCLUDE_DIR}
INTERFACE_LINK_LIBRARIES "libzmq;Boost::boost;Boost::container;Boost::system"
)
endif()

View File

@@ -1,88 +0,0 @@
################################################################################
# Copyright (C) 2014-2018 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" #
################################################################################
find_path(DDS_INCLUDE_DIR
NAMES dds_intercom.h
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
PATH_SUFFIXES include
)
find_path(DDS_LIBRARY_DIR
NAMES libdds_intercom_lib.dylib libdds_intercom_lib.so
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
PATH_SUFFIXES lib
)
find_library(DDS_INTERCOM_LIBRARY_SHARED
NAMES libdds_intercom_lib.dylib libdds_intercom_lib.so
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
PATH_SUFFIXES lib
DOC "Path to libdds_intercom_lib.dylib libdds_intercom_lib.so."
)
find_library(DDS_PROTOCOL_LIBRARY_SHARED
NAMES libdds_protocol_lib.dylib libdds_protocol_lib.so
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
PATH_SUFFIXES lib
DOC "Path to libdds_protocol_lib.dylib libdds_protocol_lib.so."
)
find_library(DDS_USER_DEFAULTS_LIBRARY_SHARED
NAMES libdds-user-defaults.dylib libdds-user-defaults.so
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
PATH_SUFFIXES lib
DOC "Path to libdds-user-defaults.dylib libdds-user-defaults.so."
)
find_file(DDS_VERSION_FILE
NAMES version
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
PATH_SUFFIXES etc
)
if(DDS_VERSION_FILE AND NOT DDS_VERSION)
file(READ ${DDS_VERSION_FILE} DDS_VERSION)
string(STRIP "${DDS_VERSION}" DDS_VERSION)
set(DDS_VERSION ${DDS_VERSION} CACHE string "DDS version.")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DDS
REQUIRED_VARS
DDS_INCLUDE_DIR
DDS_LIBRARY_DIR
DDS_INTERCOM_LIBRARY_SHARED
DDS_PROTOCOL_LIBRARY_SHARED
DDS_USER_DEFAULTS_LIBRARY_SHARED
VERSION_VAR DDS_VERSION
)
if(NOT TARGET DDS::dds_intercom_lib AND DDS_FOUND)
add_library(DDS::dds_intercom_lib SHARED IMPORTED)
set_target_properties(DDS::dds_intercom_lib PROPERTIES
IMPORTED_LOCATION ${DDS_INTERCOM_LIBRARY_SHARED}
INTERFACE_INCLUDE_DIRECTORIES ${DDS_INCLUDE_DIR}
)
endif()
if(NOT TARGET DDS::dds_protocol_lib AND DDS_FOUND)
add_library(DDS::dds_protocol_lib SHARED IMPORTED)
set_target_properties(DDS::dds_protocol_lib PROPERTIES
IMPORTED_LOCATION ${DDS_PROTOCOL_LIBRARY_SHARED}
INTERFACE_INCLUDE_DIRECTORIES ${DDS_INCLUDE_DIR}
)
endif()
if(NOT TARGET DDS::dds-user-defaults AND DDS_FOUND)
add_library(DDS::dds-user-defaults SHARED IMPORTED)
set_target_properties(DDS::dds-user-defaults PROPERTIES
IMPORTED_LOCATION ${DDS_USER_DEFAULTS_LIBRARY_SHARED}
INTERFACE_INCLUDE_DIRECTORIES ${DDS_INCLUDE_DIR}
)
endif()

View File

@@ -4,7 +4,37 @@
## 3.1 Device Configuration
Devices receive configuration primarily via provided command line options (that can be extended per device).
Device Configuration is stored in configuration object - `fair::mq::ProgOptions`. It is accessible by the device, plugins or from DeviceRunner/main:
Plugins <---read/write---> ProgOptions <---read/write---> Device
Whenever a configuration property is set, it is set in ProgOptions. Device/Channels/User code read this value and apply it as necessary at different stages:
- apply it immidiately
- apply it in device/channels during InitializingDevice/Binding/Connecting states
Here is an overview of the device/channel options and when they are applied:
| Property | Applied in |
| --- | --- |
| `severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `file-severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `verbosity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `color` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `log-to-file` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `id` | at the end of `fair::mq::State::InitializingDevice` |
| `io-threads` | at the end of `fair::mq::State::InitializingDevice` |
| `transport` | at the end of `fair::mq::State::InitializingDevice` |
| `network-interface` | at the end of `fair::mq::State::InitializingDevice` |
| `init-timeout` | at the end of `fair::mq::State::InitializingDevice` |
| `max-run-time` | at the end of `fair::mq::State::InitializingDevice` |
| `shm-segment-size` | at the end of `fair::mq::State::InitializingDevice` |
| `shm-monitor` | at the end of `fair::mq::State::InitializingDevice` |
| `ofi-size-hint` | at the end of `fair::mq::State::InitializingDevice` |
| `rate` | at the end of `fair::mq::State::InitializingDevice` |
| `session` | at the end of `fair::mq::State::InitializingDevice` |
| `chan.*` | at the end of `fair::mq::State::InitializingDevice` (channel addresses can be also applied during `fair::mq::State::Binding`/`fair::mq::State::Connecting`) |
## 3.2 Configuration options
## 3.2 Communication Channels Configuration
@@ -32,6 +62,14 @@ This parser reads channel configuration from a JSON file. Example:
"address": "tcp://*:5555",
"sndBufSize": 1000,
"rcvBufSize": 1000,
"sndKernelSize" : 0,
"rcvKernelSize" : 0,
"transport": "shmem",
"linger": "500",
"portRangeMin": "22000",
"portRangeMax": "23000",
"autoBind": false,
"numSockets": 0,
"rateLogging": 1
}
]
@@ -48,9 +86,7 @@ This parser reads channel configuration from a JSON file. Example:
"type": "pull",
"method": "connect",
"address": "tcp://localhost:5555",
"sndBufSize": 1000,
"rcvBufSize": 1000,
"rateLogging": 1
"transport": "shmem"
}
]
}

View File

@@ -24,7 +24,7 @@ FairMQ devices communicate via the communication patterns offered by ZeroMQ (or
Each FairMQ device has an internal state machine:
![FairMQ state machine](images/device_states.png?raw=true "FairMQ state machine")
![FairMQ state machine](images/device_states.svg "FairMQ state machine")
The state machine can be querried and controlled via `GetCurrentStateName()` and `ChangeState("<state name>")` methods. Only legal state transitions are allowed (see image above). Illegal transitions will fail with an error.
@@ -48,6 +48,6 @@ Without the interactive mode, for example for a run in background, two other con
## 1.4 Multiple devices in the same process
Technically one can create two or more devices within the same process without any conflicts. However the configuration (FairMQProgOptions) currently assumes the supplied configuration values are for one device/process.
Technically one can create two or more devices within the same process without any conflicts. However the configuration (fair::mq::ProgOptions) currently assumes the supplied configuration values are for one device/process.
← [Back](../README.md)

93
docs/Plugins.md Normal file
View File

@@ -0,0 +1,93 @@
← [Back](../README.md)
# 7. Plugins
FairMQ devices can be integrated with external configuration and control systems through its plugin system. FairMQ plugins are special dynamic libraries that can be loaded at runtime. Plugins have access to the Plugin API which includes the capability to control/monitor the device [state machine](Device.md#13-state-machine) and change/monitor configuration properties.
A simple plugin may add the feature to read configuration from a certain desired file format once at the start of a device. A more complex plugin may create a long-running thread that integrates a network client to an external API of a central experiment control system.
Because plugins are loaded dynamically, they can be developed in separate repositories/projects and also have their own set of runtime dependency that are not needed to be known at compile-time of the FairMQ device.
## 7.1 Usage
To load a plugin pass the `-P <name>[,<name>]` (or long `--plugin`) command line option. Multiple plugins can be loaded at the same time. The load order is as specified at the command line. This determines the order in which the plugins are instantiated (ctor call order) and in which order they are notified, should they subscribe to any notifications.
When passing `-h/--help` on the command line one can find more detailed information:
```
Plugin Manager:
-S [ --plugin-search-path ] arg List of plugin search paths.
* Override default search path, e.g.
-S /home/user/lib /lib
* Append(>) or prepend(<) to default
search path, e.g.
-S >/lib </home/user/lib
* If you mix the overriding and
appending/prepending syntaxes, the
overriding paths act as default search
path, e.g.
-S /usr/lib >/lib </home/user/lib
/usr/local/lib results in
/home/user/lib,/usr/local/lib,/usr/lib/
,/lib
If nothing is found, the default
dynamic library lookup is performed,
see man ld.so(8) for details.
-P [ --plugin ] arg List of plugin names to load in
order,e.g. if the file is called
'libFairMQPlugin_example.so', just list
'example' or 'd:example' here.To load a
prelinked plugin, list 'p:example'
here.
```
## 7.2 Development
To develop a custom FairMQ plugin, one simply needs to inherit from the `fair::mq::Plugin` base class (`#include <fairmq/Plugin.h>`) and call the `REGISTER_FAIRMQ_PLUGIN` macro. It is possible to introduce new command line option together with a plugin.
The Plugin API includes:
* `Take/Steal/ReleaseDeviceControl()`/`GetCurrent/ChangeDeviceState()`/`SubscribeTo/UnsubscribeFromDeviceStateChange()` APIs enable controlling the device state machine. Only one plugin is authorized to control at the same time. Which one is determined by which plugin calls `TakeDeviceControl()` first.
* `Set/GetProperty()`/`GetPropertyKeys()`/`SubscribeTo/UnsubscribeFromPropertyChange()` APIs enable configuration of device properties.
See [`<fairmq/Plugin.h>`](/fairmq/Plugin.h) for the full API.
A more complete example which may serve as a start including example CMake code can be found here: [FairRootGroup/FairMQPlugin_example](https://github.com/FairRootGroup/FairMQPlugin_example).
## 7.3 Provided Plugins
### 7.3.1 DDS
When launching a FairMQ topology via [DDS](http://dds.gsi.de/) the DDS plugin enables FairMQ devices to interact with DDS' custom command and property subsystems - enable the plugin by passing `-P dds` on the command line.
Via the property subsystem a FairMQ topology may exchange channel connection data (essentially to do service discovery) needed to connect/bind all FairMQ channels appropriately. DDS is highly optimized for this use case. See [examples/dds](examples/dds/README.md) for more details.
Via the custom command subsystem a FairMQ device can receive a number of commands. FairMQ provides a convenient command line tool `fairmq-dds-command-ui` that allows interactive or scripted control of a running FairMQ topology managed via DDS. If one develops directly against the custom command DDS API, the following table lists all the commands the DDS plugin currently understands:
| Custom Command | Response | Error | Description |
| --- | --- | --- | --- |
| `check-state` | `<ID>: <STATE> (pid: <PID>)` | n/a | Query current device state, see state machine for possible states |
| `dump-config` | `(<ID>: <PKEY> -> <PVALUE>\n)+` | n/a | Query current device config (list property key/value pairs) |
| `INIT DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `BIND` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `CONNECT` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `INIT TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `RUN` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `STOP` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `RESET TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `RESET DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `END` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `subscribe-to-heartbeats` | `heartbeat-subscription: <ID>,OK` | n/a | Subscribe to heartbeats |
| on heartbeat subscription | `heartbeat: <ID>,<PID>` | n/a | Heartbeat every 100ms |
| `unsubscribe-from-heartbeats` | `heartbeat-unsubscription: <ID>,OK` | n/a | Unsubscribe from heartbeats |
| `subscribe-to-state-changes` | `state-changes-subscription: <ID>,OK` | n/a | Subscribe to state changes |
| on state changes subscription | `state-change: <ID>,<STATE>` | n/a | State change notification |
| `unsubscribe-from-state-changes` | `state-changes-unsubscription: <ID>,OK` | n/a | Unsubscribe from state changes |
If unknown commands are received the plugin will print a warning.
### 7.3.2 PMIx
The [PMIx](https://pmix.org/) plugin enables launching a FairMQ topology with any PMIx capable launcher, e.g. the [Open Run-Time Environment (ORTE) of OpenMPI](https://www.open-mpi.org/doc/v4.0/man1/mpirun.1.php) or the [Slurm workload manager](https://slurm.schedmd.com/srun.html). This plugin is not (yet) very mature and serves as a proof of concept at the moment.
TODO example usage
← [Back](../README.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -26,8 +26,8 @@ Sampler::Sampler()
void Sampler::InitTask()
{
// Get the fText and fMaxIterations values from the command line options (via fConfig)
fText = fConfig->GetValue<string>("text");
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fText = fConfig->GetProperty<string>("text");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Sampler::ConditionalRun()

View File

@@ -30,7 +30,7 @@ Sink::Sink()
void Sink::InitTask()
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)

View File

@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_1_1::Sampler();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_1_1::Sink();
}

View File

@@ -32,8 +32,8 @@ Sampler::Sampler()
void Sampler::InitTask()
{
// Get the fText and fMaxIterations values from the command line options (via fConfig)
fText = fConfig->GetValue<string>("text");
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fText = fConfig->GetProperty<string>("text");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Sampler::ConditionalRun()

View File

@@ -30,7 +30,7 @@ Sink::Sink()
void Sink::InitTask()
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
// handler is called whenever a message arrives on "data2", with a reference to the message and a sub-channel index (here 0)

View File

@@ -15,7 +15,7 @@ void addCustomOptions(bpo::options_description& /*options*/)
{
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_1_n_1::Processor();
}

View File

@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_1_n_1::Sampler();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_1_n_1::Sink();
}

View File

@@ -33,12 +33,11 @@ Sampler::Sampler()
void Sampler::InitTask()
{
fNumDataChannels = fChannels.at("data").size();
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Sampler::ConditionalRun()
{
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
FairMQMessagePtr msg(NewSimpleMessage(fCounter++));

View File

@@ -27,7 +27,7 @@ Sink::Sink()
void Sink::InitTask()
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Sink::HandleData(FairMQMessagePtr& msg, int /*index*/)

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_copypush::Sampler();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_copypush::Sink();
}

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@@ -28,12 +28,13 @@ target_link_libraries(fairmq-ex-dds-sink PRIVATE ExampleDDSLib)
add_custom_target(ExampleDDS DEPENDS fairmq-ex-dds-sampler fairmq-ex-dds-processor fairmq-ex-dds-sink)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(DDS_PLUGIN_LIB_DIR ${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-topology-infinite.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology-infinite.xml @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-hosts.cfg ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-hosts.cfg COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-dds-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-dds-env.sh @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh @ONLY)
# test
@@ -50,10 +51,12 @@ install(
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(DDS_PLUGIN_LIB_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_LIBDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
set(BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(DATA_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_DATADIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml_install @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-topology-infinite.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology-infinite.xml_install @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-dds-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-dds-env.sh_install @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install @ONLY)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml_install
@@ -61,7 +64,25 @@ install(
RENAME ex-dds-topology.xml
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology-infinite.xml_install
DESTINATION ${PROJECT_INSTALL_DATADIR}
RENAME ex-dds-topology-infinite.xml
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-hosts.cfg
DESTINATION ${PROJECT_INSTALL_DATADIR}
)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-dds-env.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-ex-dds-env.sh
)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-dds.sh
)

View File

@@ -40,9 +40,9 @@ The configuration of the channel connection addresses is done by the DDS plugin
**If you chose step 2b earlier**, then modify the provided `ex-dds-topology.xml` in the top that the following lines read as following:
```xml
<declrequirement id="SamplerWorker" type="wnname" value=".*"/>
<declrequirement id="ProcessorWorker" type="wnname" value=".*"/>
<declrequirement id="SinkWorker" type="wnname" value=".*"/>
<declrequirement name="SamplerWorker" type="wnname" value=".*"/>
<declrequirement name="ProcessorWorker" type="wnname" value=".*"/>
<declrequirement name="SinkWorker" type="wnname" value=".*"/>
```
Note that the attributes `value` contain a different value.

View File

@@ -26,10 +26,14 @@ Sampler::Sampler()
{
}
void Sampler::InitTask()
{
fIterations = fConfig->GetValue<uint64_t>("iterations");
fCounter = 0;
}
bool Sampler::ConditionalRun()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
FairMQMessagePtr msg(NewSimpleMessage("Data"));
@@ -38,11 +42,18 @@ bool Sampler::ConditionalRun()
// in case of error or transfer interruption, return false to go to IDLE state
// successfull transfer will return number of bytes transfered (can be 0 if sending an empty message).
if (Send(msg, "data1") < 0)
{
if (Send(msg, "data1") < 0) {
return false;
}
if (fIterations > 0) {
++fCounter;
if (fCounter >= fIterations) {
LOG(info) << "Sent " << fCounter << " messages. Finished.";
return false;
}
}
return true;
}

View File

@@ -25,9 +25,14 @@ class Sampler : public FairMQDevice
public:
Sampler();
virtual ~Sampler();
void InitTask() override;
protected:
virtual bool ConditionalRun();
bool ConditionalRun() override;
private:
uint64_t fIterations;
uint64_t fCounter;
};
} // namespace example_dds

View File

@@ -25,11 +25,24 @@ Sink::Sink()
OnData("data2", &Sink::HandleData);
}
void Sink::InitTask()
{
fIterations = fConfig->GetValue<uint64_t>("iterations");
fCounter = 0;
}
// handler is called whenever a message arrives on "data2", with a reference to the message and a sub-channel index (here 0)
bool Sink::HandleData(FairMQMessagePtr& msg, int /*index*/)
{
LOG(info) << "Received: \"" << string(static_cast<char*>(msg->GetData()), msg->GetSize()) << "\"";
if (fIterations > 0) {
++fCounter;
if (fCounter >= fIterations) {
LOG(info) << "Received " << fCounter << " messages. Finished.";
return false;
}
}
// return true if want to be called again (otherwise go to IDLE state)
return true;
}

View File

@@ -25,9 +25,14 @@ class Sink : public FairMQDevice
public:
Sink();
virtual ~Sink();
void InitTask() override;
protected:
bool HandleData(FairMQMessagePtr&, int);
private:
uint64_t fIterations;
uint64_t fCounter;
};
} // namespace example_dds

View File

@@ -1,7 +1,3 @@
@bash_begin@
# source setup.sh
@bash_end@
sampler, username@localhost, , /path/to/dds-work/, 1
processor, username@localhost, , /path/to/dds-work/, 10
sink, username@localhost, , /path/to/dds-work/, 1
sampler, 127.0.0.1, , /tmp/fairmq-ex-dds, 1
processor, 127.0.0.1, , /tmp/fairmq-ex-dds, 10
sink, 127.0.0.1, , /tmp/fairmq-ex-dds, 1

View File

@@ -0,0 +1,52 @@
<topology name="ExampleDDS">
<property name="data1" />
<property name="data2" />
<declrequirement name="SamplerWorker" type="wnname" value="sampler"/>
<declrequirement name="ProcessorWorker" type="wnname" value="processor"/>
<declrequirement name="SinkWorker" type="wnname" value="sink"/>
<decltask name="Sampler">
<env reachable="false">fairmq-ex-dds-env.sh</env>
<exe>fairmq-ex-dds-sampler --id sampler --color false --channel-config name=data1,type=push,method=bind --rate 100 -P dds</exe>
<requirements>
<name>SamplerWorker</name>
</requirements>
<properties>
<name access="write">data1</name>
</properties>
</decltask>
<decltask name="Processor">
<env reachable="false">fairmq-ex-dds-env.sh</env>
<exe>fairmq-ex-dds-processor --id processor_%taskIndex% --color false --channel-config name=data1,type=pull,method=connect name=data2,type=push,method=connect -P dds</exe>
<requirements>
<id>ProcessorWorker</id>
</requirements>
<properties>
<name access="read">data1</name>
<name access="read">data2</name>
</properties>
</decltask>
<decltask name="Sink">
<env reachable="false">fairmq-ex-dds-env.sh</env>
<exe>fairmq-ex-dds-sink --id sink --color false --channel-config name=data2,type=pull,method=bind -P dds</exe>
<requirements>
<name>SinkWorker</name>
</requirements>
<properties>
<name access="write">data2</name>
</properties>
</decltask>
<main name="main">
<task>Sampler</task>
<task>Sink</task>
<group name="ProcessorGroup" n="10">
<task>Processor</task>
</group>
</main>
</topology>

View File

@@ -1,47 +1,50 @@
<topology id="ExampleDDS">
<topology name="ExampleDDS">
<property id="data1" />
<property id="data2" />
<property name="data1" />
<property name="data2" />
<declrequirement id="SamplerWorker" type="wnname" value="sampler"/>
<declrequirement id="ProcessorWorker" type="wnname" value="processor"/>
<declrequirement id="SinkWorker" type="wnname" value="sink"/>
<declrequirement name="SamplerWorker" type="wnname" value="sampler"/>
<declrequirement name="ProcessorWorker" type="wnname" value="processor"/>
<declrequirement name="SinkWorker" type="wnname" value="sink"/>
<decltask id="Sampler">
<exe reachable="true">@EX_BIN_DIR@/fairmq-ex-dds-sampler --id sampler --color false --channel-config name=data1,type=push,method=bind -S "&lt;@DDS_PLUGIN_LIB_DIR@/" -P dds</exe>
<decltask name="Sampler">
<env reachable="false">fairmq-ex-dds-env.sh</env>
<exe>fairmq-ex-dds-sampler --id sampler --color false --channel-config name=data1,type=push,method=bind -P dds --iterations 10</exe>
<requirements>
<id>SamplerWorker</id>
<name>SamplerWorker</name>
</requirements>
<properties>
<id access="write">data1</id>
<name access="write">data1</name>
</properties>
</decltask>
<decltask id="Processor">
<exe reachable="true">@EX_BIN_DIR@/fairmq-ex-dds-processor --id processor_%taskIndex% --config-key processor --color false --channel-config name=data1,type=pull,method=connect name=data2,type=push,method=connect -S "&lt;@DDS_PLUGIN_LIB_DIR@/" -P dds</exe>
<decltask name="Processor">
<env reachable="false">fairmq-ex-dds-env.sh</env>
<exe>fairmq-ex-dds-processor --id processor_%taskIndex% --color false --channel-config name=data1,type=pull,method=connect name=data2,type=push,method=connect -P dds</exe>
<requirements>
<id>ProcessorWorker</id>
</requirements>
<properties>
<id access="read">data1</id>
<id access="read">data2</id>
<name access="read">data1</name>
<name access="read">data2</name>
</properties>
</decltask>
<decltask id="Sink">
<exe reachable="true">@EX_BIN_DIR@/fairmq-ex-dds-sink --id sink --color false --channel-config name=data2,type=pull,method=bind -S "&lt;@DDS_PLUGIN_LIB_DIR@/" -P dds</exe>
<decltask name="Sink">
<env reachable="false">fairmq-ex-dds-env.sh</env>
<exe>fairmq-ex-dds-sink --id sink --color false --channel-config name=data2,type=pull,method=bind -P dds --iterations 10</exe>
<requirements>
<id>SinkWorker</id>
<name>SinkWorker</name>
</requirements>
<properties>
<id access="write">data2</id>
<name access="write">data2</name>
</properties>
</decltask>
<main id="main">
<main name="main">
<task>Sampler</task>
<task>Sink</task>
<group id="ProcessorGroup" n="10">
<group name="ProcessorGroup" n="10">
<task>Processor</task>
</group>
</main>

View File

@@ -0,0 +1,11 @@
#!/bin/bash
################################################################################
# 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" #
################################################################################
export PATH=@BIN_DIR@:$PATH

View File

@@ -0,0 +1,85 @@
#!/bin/bash
################################################################################
# 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" #
################################################################################
# fairmq-start-ex-dds.sh [localhost] -> submit agents with localhost plugin
# fairmq-start-ex-dds.sh ssh -> submit agents with ssh plugin
set -e
cleanup() {
dds-session stop $1
echo "CLEANUP PERFORMED"
}
source @DDS_INSTALL_PREFIX@/DDS_env.sh
export PATH=@BIN_DIR@:$PATH
plugin=${1:-localhost}
exec 5>&1
output=$(dds-session start | tee >(cat - >&5))
export DDS_SESSION_ID=$(echo ${output} | grep "DDS session ID: " | cut -d' ' -f4)
echo "SESSION ID: ${DDS_SESSION_ID}"
trap "cleanup ${DDS_SESSION_ID}" EXIT
requiredNofAgents=12
if [[ "$plugin" == "ssh" ]]; then
dds-submit -r ${plugin} -c @DATA_DIR@/ex-dds-hosts.cfg
else
dds-submit -r ${plugin} -n ${requiredNofAgents}
fi
echo "...waiting for ${requiredNofAgents} idle agents..."
dds-info --wait-for-idle-agents ${requiredNofAgents}
topologyFile=@DATA_DIR@/ex-dds-topology.xml
echo "TOPOLOGY FILE: ${topologyFile}"
# TODO Uncomment once DDS 2.6 is released
# echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${topologyFile})"
# TODO Uncomment once DDS 2.6 is released
# dds-info --active-topology
dds-topology --disable-validation --activate ${topologyFile}
# dds-info --active-topology
# dds-info --wait-for-executing-agents ${requiredNofAgents}
sleep 1
echo "------------------------"
echo "...waiting for Topology to finish..."
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
fairmq-dds-command-ui -w "IDLE" -n ${requiredNofAgents}
fairmq-dds-command-ui -c i -w "INITIALIZING DEVICE" -n ${requiredNofAgents}
fairmq-dds-command-ui -c k -w "INITIALIZED" -n ${requiredNofAgents}
fairmq-dds-command-ui -c b -w "BOUND" -n ${requiredNofAgents}
fairmq-dds-command-ui -c x -w "DEVICE READY" -n ${requiredNofAgents}
fairmq-dds-command-ui -c j -w "READY" -n ${requiredNofAgents}
fairmq-dds-command-ui -c r
sampler_and_sink="main/(Sampler|Sink)"
fairmq-dds-command-ui -p $sampler_and_sink -w "RUNNING->READY" -n 2
echo "...$sampler_and_sink are READY, sending shutdown..."
fairmq-dds-command-ui -c s -w "RUNNING->READY" -n ${requiredNofAgents}
fairmq-dds-command-ui -c t -w "DEVICE READY" -n ${requiredNofAgents}
fairmq-dds-command-ui -c d -w "IDLE" -n ${requiredNofAgents}
fairmq-dds-command-ui -c q
echo "...waiting for ${requiredNofAgents} idle agents..."
dds-info --wait-for-idle-agents ${requiredNofAgents}
echo "------------------------"
# TODO Uncomment once DDS 2.6 is released
# dds-info --active-topology
dds-topology --stop
# dds-info --active-topology
dds-agent-cmd getlog -a
logDir="${wrkDir}/logs"
for file in $(find "${logDir}" -name "*.tar.gz"); do tar -xf ${file} -C "${logDir}" ; done
echo "AGENT LOG FILES IN: ${logDir}"
# Cleanup function is called by EXIT trap

View File

@@ -15,7 +15,7 @@ void addCustomOptions(bpo::options_description& /*options*/)
{
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_dds::Processor();
}

View File

@@ -11,11 +11,15 @@
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& /*options*/)
void addCustomOptions(bpo::options_description& options)
{
options.add_options()(
"iterations,i",
bpo::value<uint64_t>()->default_value(1000),
"Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_dds::Sampler();
}

View File

@@ -11,11 +11,15 @@
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& /*options*/)
void addCustomOptions(bpo::options_description& options)
{
options.add_options()(
"iterations,i",
bpo::value<uint64_t>()->default_value(1000),
"Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_dds::Sink();
}

View File

@@ -32,15 +32,20 @@ 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 2 parts")
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 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 2 parts")
set_tests_properties(Example.Multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 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 2 parts")
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 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")
endif()
# install

View File

@@ -31,7 +31,7 @@ Sampler::Sampler()
void Sampler::InitTask()
{
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Sampler::ConditionalRun()
@@ -53,6 +53,13 @@ bool Sampler::ConditionalRun()
parts.AddPart(NewSimpleMessage(header));
parts.AddPart(NewMessage(1000));
// create more data parts, testing the FairMQParts in-place constructor
FairMQParts auxData{ NewMessage(500), NewMessage(600), NewMessage(700) };
assert(auxData.Size() == 3);
parts.AddPart(std::move(auxData));
assert(auxData.Size() == 0);
assert(parts.Size() == 5);
LOG(info) << "Sending body of size: " << parts.At(1)->GetSize();
Send(parts, "data");
@@ -74,4 +81,4 @@ Sampler::~Sampler()
{
}
} // namespace example_multipart
} // namespace example_multipart

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(5), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multipart::Sampler();
}

View File

@@ -15,7 +15,7 @@ void addCustomOptions(bpo::options_description& /*options*/)
{
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multipart::Sink();
}

View File

@@ -20,7 +20,7 @@ SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $SESSION"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --control static --color false"
SAMPLER+=" --channel-config name=data,type=push,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555"
SAMPLER+=" --channel-config name=data,type=pair,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
SAMPLER_PID=$!
@@ -30,7 +30,7 @@ SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh"
SINK+=" --session $SESSION"
SINK+=" --control static --color false"
SINK+=" --channel-config name=data,type=pull,method=bind,rateLogging=0,address=tcp://127.0.0.1:5555"
SINK+=" --channel-config name=data,type=pair,method=bind,rateLogging=0,address=tcp://127.0.0.1:5555"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
SINK_PID=$!

View File

@@ -33,8 +33,8 @@ Sampler::Sampler()
void Sampler::InitTask()
{
fText = fConfig->GetValue<string>("text");
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fText = fConfig->GetProperty<string>("text");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
void Sampler::Run()

View File

@@ -31,7 +31,7 @@ Sink::Sink()
void Sink::InitTask()
{
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Sink::HandleBroadcast(FairMQMessagePtr& msg, int /*index*/)

View File

@@ -15,7 +15,7 @@ void addCustomOptions(bpo::options_description& /*options*/)
{
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multiple_channels::Broadcaster();
}

View File

@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multiple_channels::Sampler();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multiple_channels::Sink();
}

View File

@@ -22,7 +22,7 @@ Sampler1::Sampler1()
void Sampler1::InitTask()
{
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
void Sampler1::PreRun()

View File

@@ -21,7 +21,7 @@ Sampler2::Sampler2()
void Sampler2::InitTask()
{
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Sampler2::ConditionalRun()

View File

@@ -31,7 +31,7 @@ Sink::Sink()
void Sink::InitTask()
{
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multiple_transports::Sampler1();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multiple_transports::Sampler2();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_multiple_transports::Sink();
}

View File

@@ -5,36 +5,42 @@
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIRMQEXAMPLEREGIONBUILDER_H
#define FAIRMQEXAMPLEREGIONBUILDER_H
#include <atomic>
#include "FairMQDevice.h"
namespace example_region
#include <string>
namespace example_readout
{
class Builder : public FairMQDevice
{
public:
Builder() {
OnData("data1", &Builder::HandleData);
}
virtual ~Builder() {}
Builder()
: fOutputChannelName()
{}
void Init() override
{
fOutputChannelName = fConfig->GetProperty<std::string>("output-name");
OnData("rb", &Builder::HandleData);
}
protected:
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
{
if (Send(msg, "data2") < 0) {
if (Send(msg, fOutputChannelName) < 0) {
return false;
}
return true;
}
private:
std::string fOutputChannelName;
};
} // namespace example_region
} // namespace example_readout
#endif /* FAIRMQEXAMPLEREGIONBUILDER_H */

View File

@@ -6,37 +6,35 @@
# copied verbatim in the file "LICENSE" #
################################################################################
add_library(ExampleReadoutLib STATIC
"Sampler.cxx"
"Sampler.h"
"Builder.h"
"Sink.cxx"
"Sink.h"
)
target_link_libraries(ExampleReadoutLib PUBLIC FairMQ)
add_executable(fairmq-ex-readout-sampler runSampler.cxx)
target_link_libraries(fairmq-ex-readout-sampler PRIVATE ExampleReadoutLib)
add_executable(fairmq-ex-readout-readout runReadout.cxx)
target_link_libraries(fairmq-ex-readout-readout PRIVATE FairMQ)
add_executable(fairmq-ex-readout-builder runBuilder.cxx)
target_link_libraries(fairmq-ex-readout-builder PRIVATE ExampleReadoutLib)
target_link_libraries(fairmq-ex-readout-builder PRIVATE FairMQ)
add_executable(fairmq-ex-readout-sink runSink.cxx)
target_link_libraries(fairmq-ex-readout-sink PRIVATE ExampleReadoutLib)
add_executable(fairmq-ex-readout-processor runProcessor.cxx)
target_link_libraries(fairmq-ex-readout-processor PRIVATE FairMQ)
add_custom_target(Examplereadout DEPENDS fairmq-ex-readout-sampler fairmq-ex-readout-sink)
add_executable(fairmq-ex-readout-sender runSender.cxx)
target_link_libraries(fairmq-ex-readout-sender PRIVATE FairMQ)
add_executable(fairmq-ex-readout-receiver runReceiver.cxx)
target_link_libraries(fairmq-ex-readout-receiver PRIVATE FairMQ)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh)
# install
install(
TARGETS
fairmq-ex-readout-sampler
fairmq-ex-readout-sink
fairmq-ex-readout-readout
fairmq-ex-readout-builder
fairmq-ex-readout-processor
fairmq-ex-readout-sender
fairmq-ex-readout-receiver
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
@@ -46,9 +44,16 @@ install(
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-readout.sh
)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-readout-processing.sh
)

View File

@@ -5,38 +5,33 @@
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
* Sink.h
*
* @since 2014-10-10
* @author A. Rybalchenko
*/
#ifndef FAIRMQEXAMPLEREGIONSINK_H
#define FAIRMQEXAMPLEREGIONSINK_H
#include <string>
#ifndef FAIRMQEXAMPLEREGIONPROCESSOR_H
#define FAIRMQEXAMPLEREGIONPROCESSOR_H
#include "FairMQDevice.h"
namespace example_region
namespace example_readout
{
class Sink : public FairMQDevice
class Processor : public FairMQDevice
{
public:
Sink();
virtual ~Sink();
Processor() {
OnData("bp", &Processor::HandleData);
}
protected:
virtual void Run();
virtual void InitTask();
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
{
FairMQMessagePtr msg2(NewMessageFor("ps", 0, msg->GetSize()));
if (Send(msg2, "ps") < 0) {
return false;
}
private:
uint64_t fMaxIterations;
uint64_t fNumIterations;
return true;
}
};
} // namespace example_region
} // namespace example_readout
#endif /* FAIRMQEXAMPLEREGIONSINK_H */
#endif /* FAIRMQEXAMPLEREGIONPROCESSOR_H */

View File

@@ -1,5 +1,27 @@
Region example
==============
# Readout example
This example demonstrates the use of a more advanced feature - UnmanagedRegion, that can be used to create a buffer through one of FairMQ transports. The contents of this buffer are managed by the user, who can also create messages out of sub-buffers of the created buffer. Such feature can be interesting in environments that have special requirements by the hardware that writes the data, to keep the transfer efficient (e.g. shared memory).
This examples shows two possible topologies (out of many) for a node connected to a detector readout (followed by a processing node).
## Setup without new data generation
```
|------------------------------- Readout Node ---------------------------| |- Processing Node -|
| Readout --> Builder --> Sender | --> | Receiver |
| [# shared memory segment (unused in this topology) ##################] | ofi | |
| [# shmem unmanaged region (readout writes here, others read) ########] | | |
|------------------------------------------------------------------------| |-------------------|
```
The devices one the Readout Node communicate via shared memory transport. Readout device writes into shared memory unmanaged region. The data is then forwarded through Builder to Sender process, which sends it out via OFI transport.
## Setup with generating new data on the Readout node
```
|------------------------------- Readout Node ---------------------------| |- Processing Node -|
| Readout --> Builder --> Processor --> Sender | --> | Receiver |
| [# shared memory segment (used between Proccessor and Sender) #######] | ofi | |
| [# shmem unmanaged region (readout writes here, builder & proc read) ] | | |
|------------------------------------------------------------------------| |-------------------|
```
In this topology one more device is added - Processor. It examines the arriving data and creates new data in shared memory. This data is not part of the unmanaged region, but lives in the general shared memory segment (unused in the previous setup). This new data is then forwarded to Sender and the Readout device is notified that the corresponding data piece in the unmanaged region is no longer used.

View File

@@ -0,0 +1,91 @@
/********************************************************************************
* Copyright (C) 2014 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 FAIRMQEXAMPLEREADOUTREADOUT_H
#define FAIRMQEXAMPLEREADOUTREADOUT_H
#include <atomic>
#include <thread>
#include <chrono>
#include "FairMQDevice.h"
namespace example_readout
{
class Readout : public FairMQDevice
{
public:
Readout()
: fMsgSize(10000)
, fMaxIterations(0)
, fNumIterations(0)
, fRegion(nullptr)
, fNumUnackedMsgs(0)
{}
protected:
void InitTask() override
{
fMsgSize = fConfig->GetProperty<int>("msg-size");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("rb",
0,
10000000,
[this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
--fNumUnackedMsgs;
if (fMaxIterations > 0) {
LOG(debug) << "Received ack";
}
}
));
}
bool ConditionalRun() override
{
FairMQMessagePtr msg(NewMessageFor("rb", // channel
0, // sub-channel
fRegion, // region
fRegion->GetData(), // ptr within region
fMsgSize, // offset from ptr
nullptr // hint
));
if (Send(msg, "rb", 0) > 0) {
++fNumUnackedMsgs;
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
return false;
}
}
return true;
}
void ResetTask() override
{
// if not all messages acknowledged, wait for a bit. But only once, since receiver could be already dead.
if (fNumUnackedMsgs != 0) {
LOG(debug) << "waiting for all acknowledgements... (" << fNumUnackedMsgs << ")";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;
}
fRegion.reset();
}
private:
int fMsgSize;
uint64_t fMaxIterations;
uint64_t fNumIterations;
FairMQUnmanagedRegionPtr fRegion;
std::atomic<uint64_t> fNumUnackedMsgs;
};
} // namespace example_readout
#endif /* FAIRMQEXAMPLEREADOUTREADOUT_H */

View File

@@ -0,0 +1,54 @@
/********************************************************************************
* Copyright (C) 2014 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 FAIRMQEXAMPLEREGIONRECEIVER_H
#define FAIRMQEXAMPLEREGIONRECEIVER_H
#include "FairMQDevice.h"
namespace example_readout
{
class Receiver : public FairMQDevice
{
public:
Receiver()
: fMaxIterations(0)
, fNumIterations(0)
{}
protected:
void InitTask() override
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
void Run() override
{
FairMQChannel& dataInChannel = fChannels.at("sr").at(0);
while (!NewStatePending()) {
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
dataInChannel.Receive(msg);
// void* ptr = msg->GetData();
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
break;
}
}
}
private:
uint64_t fMaxIterations;
uint64_t fNumIterations;
};
} // namespace example_readout
#endif /* FAIRMQEXAMPLEREGIONRECEIVER_H */

View File

@@ -1,91 +0,0 @@
/********************************************************************************
* Copyright (C) 2014 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" *
********************************************************************************/
/**
* Sampler.cpp
*
* @since 2014-10-10
* @author A. Rybalchenko
*/
#include "Sampler.h"
#include <thread>
using namespace std;
namespace example_region
{
Sampler::Sampler()
: fMsgSize(10000)
, fMaxIterations(0)
, fNumIterations(0)
, fRegion(nullptr)
, fNumUnackedMsgs(0)
{
}
void Sampler::InitTask()
{
fMsgSize = fConfig->GetValue<int>("msg-size");
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data1",
0,
10000000,
[this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
--fNumUnackedMsgs;
if (fMaxIterations > 0)
{
LOG(debug) << "Received ack";
}
}
));
}
bool Sampler::ConditionalRun()
{
FairMQMessagePtr msg(NewMessageFor("data1", // channel
0, // sub-channel
fRegion, // region
fRegion->GetData(), // ptr within region
fMsgSize, // offset from ptr
nullptr // hint
));
if (Send(msg, "data1", 0) > 0)
{
++fNumUnackedMsgs;
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations)
{
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
return false;
}
}
return true;
}
void Sampler::ResetTask()
{
// if not all messages acknowledged, wait for a bit. But only once, since receiver could be already dead.
if (fNumUnackedMsgs != 0)
{
LOG(debug) << "waiting for all acknowledgements... (" << fNumUnackedMsgs << ")";
this_thread::sleep_for(chrono::milliseconds(500));
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;
}
fRegion.reset();
}
Sampler::~Sampler()
{
}
} // namespace example_region

View File

@@ -1,46 +0,0 @@
/********************************************************************************
* Copyright (C) 2014 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" *
********************************************************************************/
/**
* Sampler.h
*
* @since 2014-10-10
* @author A. Rybalchenko
*/
#ifndef FAIRMQEXAMPLEREGIONSAMPLER_H
#define FAIRMQEXAMPLEREGIONSAMPLER_H
#include <atomic>
#include "FairMQDevice.h"
namespace example_region
{
class Sampler : public FairMQDevice
{
public:
Sampler();
virtual ~Sampler();
protected:
virtual void InitTask();
virtual bool ConditionalRun();
virtual void ResetTask();
private:
int fMsgSize;
uint64_t fMaxIterations;
uint64_t fNumIterations;
FairMQUnmanagedRegionPtr fRegion;
std::atomic<uint64_t> fNumUnackedMsgs;
};
} // namespace example_region
#endif /* FAIRMQEXAMPLEREGIONSAMPLER_H */

46
examples/readout/Sender.h Normal file
View File

@@ -0,0 +1,46 @@
/********************************************************************************
* Copyright (C) 2014 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 FAIRMQEXAMPLEREGIONSENDER_H
#define FAIRMQEXAMPLEREGIONSENDER_H
#include "FairMQDevice.h"
#include <string>
namespace example_readout
{
class Sender : public FairMQDevice
{
public:
Sender()
: fInputChannelName()
{}
void Init() override
{
fInputChannelName = fConfig->GetProperty<std::string>("input-name");
OnData(fInputChannelName, &Sender::HandleData);
}
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
{
if (Send(msg, "sr") < 0) {
return false;
}
return true;
}
private:
std::string fInputChannelName;
};
} // namespace example_readout
#endif /* FAIRMQEXAMPLEREGIONSENDER_H */

View File

@@ -1,56 +0,0 @@
/********************************************************************************
* Copyright (C) 2014 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" *
********************************************************************************/
/**
* Sink.cxx
*
* @since 2014-10-10
* @author A. Rybalchenko
*/
#include "Sink.h"
using namespace std;
namespace example_region
{
Sink::Sink()
: fMaxIterations(0)
, fNumIterations(0)
{
}
void Sink::InitTask()
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
}
void Sink::Run()
{
FairMQChannel& dataInChannel = fChannels.at("data").at(0);
while (!NewStatePending())
{
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
dataInChannel.Receive(msg);
// void* ptr = msg->GetData();
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations)
{
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
break;
}
}
}
Sink::~Sink()
{
}
} // namespace example_region

View File

@@ -0,0 +1,40 @@
#!/bin/bash
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
msgSize="1000000"
if [[ $1 =~ ^[0-9]+$ ]]; then
msgSize=$1
fi
READOUT="fairmq-ex-readout-readout"
READOUT+=" --id readout1"
READOUT+=" --msg-size $msgSize"
READOUT+=" --channel-config name=rb,type=pair,method=bind,address=tcp://localhost:7777,transport=shmem"
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$READOUT &
BUILDER="fairmq-ex-readout-builder"
BUILDER+=" --id builder1"
BUILDER+=" --output-name bp"
BUILDER+=" --channel-config name=rb,type=pair,method=connect,address=tcp://localhost:7777,transport=shmem"
BUILDER+=" name=bp,type=pair,method=connect,address=tcp://localhost:7778,transport=shmem"
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$BUILDER &
PROCESSOR="fairmq-ex-readout-processor"
PROCESSOR+=" --id processor1"
PROCESSOR+=" --channel-config name=bp,type=pair,method=bind,address=tcp://localhost:7778,transport=shmem"
PROCESSOR+=" name=ps,type=pair,method=connect,address=tcp://localhost:7779,transport=shmem"
xterm -geometry 80x23+750+500 -hold -e @EX_BIN_DIR@/$PROCESSOR &
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"
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"
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &

View File

@@ -8,23 +8,27 @@ if [[ $1 =~ ^[0-9]+$ ]]; then
msgSize=$1
fi
SAMPLER="fairmq-ex-readout-sampler"
SAMPLER+=" --id sampler1"
SAMPLER+=" --severity debug"
SAMPLER+=" --msg-size $msgSize"
# SAMPLER+=" --rate 10"
SAMPLER+=" --channel-config name=data1,type=pair,method=bind,address=tcp://127.0.0.1:7777,transport=shmem"
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
READOUT="fairmq-ex-readout-readout"
READOUT+=" --id readout1"
READOUT+=" --msg-size $msgSize"
READOUT+=" --channel-config name=rb,type=pair,method=bind,address=tcp://localhost:7777,transport=shmem"
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$READOUT &
BUILDER="fairmq-ex-readout-builder"
BUILDER+=" --id builder1"
BUILDER+=" --severity debug"
BUILDER+=" --channel-config name=data1,type=pair,method=connect,address=tcp://127.0.0.1:7777,transport=shmem"
BUILDER+=" name=data2,type=pair,method=connect,address=tcp://127.0.0.1:7778,transport=ofi"
BUILDER+=" --output-name bs"
BUILDER+=" --channel-config name=rb,type=pair,method=connect,address=tcp://localhost:7777,transport=shmem"
BUILDER+=" name=bs,type=pair,method=connect,address=tcp://localhost:7778,transport=shmem"
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$BUILDER &
SINK="fairmq-ex-readout-sink"
SINK+=" --id sink1"
SINK+=" --severity debug"
SINK+=" --channel-config name=data,type=pair,method=bind,address=tcp://127.0.0.1:7778,transport=ofi"
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SINK &
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"
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"
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &

View File

@@ -11,10 +11,13 @@
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& /* options */)
{}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
void addCustomOptions(bpo::options_description& options)
{
return new example_region::Builder();
options.add_options()
("output-name", bpo::value<std::string>()->default_value("bs"), "Output channel name");
}
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_readout::Builder();
}

View File

@@ -0,0 +1,20 @@
/********************************************************************************
* Copyright (C) 2014 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 "runFairMQDevice.h"
#include "Processor.h"
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& /* options */)
{}
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_readout::Processor();
}

View File

@@ -7,7 +7,7 @@
********************************************************************************/
#include "runFairMQDevice.h"
#include "Sampler.h"
#include "Readout.h"
namespace bpo = boost::program_options;
@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_region::Sampler();
return new example_readout::Readout();
}

View File

@@ -7,7 +7,7 @@
********************************************************************************/
#include "runFairMQDevice.h"
#include "Sink.h"
#include "Receiver.h"
namespace bpo = boost::program_options;
@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_region::Sink();
return new example_readout::Receiver();
}

View File

@@ -0,0 +1,23 @@
/********************************************************************************
* Copyright (C) 2014 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 "runFairMQDevice.h"
#include "Sender.h"
namespace bpo = boost::program_options;
void addCustomOptions(bpo::options_description& options)
{
options.add_options()
("input-name", bpo::value<std::string>()->default_value("bs"), "Input channel name");
}
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_readout::Sender();
}

View File

@@ -32,16 +32,15 @@ Sampler::Sampler()
void Sampler::InitTask()
{
fMsgSize = fConfig->GetValue<int>("msg-size");
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMsgSize = fConfig->GetProperty<int>("msg-size");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data",
0,
10000000,
[this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
--fNumUnackedMsgs;
if (fMaxIterations > 0)
{
if (fMaxIterations > 0) {
LOG(debug) << "Received ack";
}
}
@@ -58,12 +57,14 @@ bool Sampler::ConditionalRun()
nullptr // hint
));
if (Send(msg, "data", 0) > 0)
{
// static_cast<char*>(fRegion->GetData())[3] = 97;
// LOG(info) << "check: " << static_cast<char*>(fRegion->GetData())[3];
// std::this_thread::sleep_for(std::chrono::seconds(1));
if (Send(msg, "data", 0) > 0) {
++fNumUnackedMsgs;
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations)
{
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
return false;
}
@@ -75,8 +76,7 @@ bool Sampler::ConditionalRun()
void Sampler::ResetTask()
{
// if not all messages acknowledged, wait for a bit. But only once, since receiver could be already dead.
if (fNumUnackedMsgs != 0)
{
if (fNumUnackedMsgs != 0) {
LOG(debug) << "waiting for all acknowledgements... (" << fNumUnackedMsgs << ")";
this_thread::sleep_for(chrono::milliseconds(500));
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;

View File

@@ -28,21 +28,22 @@ Sink::Sink()
void Sink::InitTask()
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
void Sink::Run()
{
FairMQChannel& dataInChannel = fChannels.at("data").at(0);
while (!NewStatePending())
{
while (!NewStatePending()) {
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
dataInChannel.Receive(msg);
// void* ptr = msg->GetData();
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations)
{
// void* ptr = msg->GetData();
// char* cptr = static_cast<char*>(ptr);
// LOG(info) << "check: " << cptr[3];
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
break;
}

View File

@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_region::Sampler();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_region::Sink();
}

View File

@@ -31,8 +31,8 @@ Client::Client()
void Client::InitTask()
{
fText = fConfig->GetValue<string>("text");
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fText = fConfig->GetProperty<string>("text");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Client::ConditionalRun()

View File

@@ -29,7 +29,7 @@ Server::Server()
void Server::InitTask()
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool Server::HandleData(FairMQMessagePtr& req, int /*index*/)

View File

@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_req_rep::Client();
}

View File

@@ -17,7 +17,7 @@ void addCustomOptions(bpo::options_description& options)
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/)
{
return new example_req_rep::Server();
}

View File

@@ -16,328 +16,450 @@ if(BUILD_PMIX_PLUGIN)
add_subdirectory(plugins/PMIx)
endif()
##########################
# libFairMQ header files #
##########################
set(FAIRMQ_PUBLIC_HEADER_FILES
DeviceRunner.h
EventManager.h
FairMQChannel.h
FairMQDevice.h
FairMQLogger.h
FairMQMessage.h
FairMQParts.h
FairMQPoller.h
FairMQUnmanagedRegion.h
FairMQSocket.h
StateMachine.h
FairMQTransportFactory.h
MemoryResources.h
MemoryResourceTools.h
Tools.h
Transports.h
options/FairMQProgOptions.h
options/FairProgOptions.h
Plugin.h
PluginManager.h
PluginServices.h
runFairMQDevice.h
tools/CppSTL.h
tools/Network.h
tools/Process.h
tools/RateLimit.h
tools/Strings.h
tools/Unique.h
tools/Version.h
)
set(FAIRMQ_PRIVATE_HEADER_FILES
devices/FairMQBenchmarkSampler.h
devices/FairMQMerger.h
devices/FairMQMultiplier.h
devices/FairMQProxy.h
devices/FairMQSink.h
devices/FairMQSplitter.h
options/FairMQParser.h
options/FairMQSuboptParser.h
options/FairProgOptionsHelper.h
plugins/Builtin.h
plugins/Control.h
shmem/FairMQMessageSHM.h
shmem/FairMQPollerSHM.h
shmem/FairMQUnmanagedRegionSHM.h
shmem/FairMQSocketSHM.h
shmem/FairMQTransportFactorySHM.h
shmem/Common.h
shmem/Manager.h
shmem/Region.h
zeromq/FairMQMessageZMQ.h
zeromq/FairMQPollerZMQ.h
zeromq/FairMQUnmanagedRegionZMQ.h
zeromq/FairMQSocketZMQ.h
zeromq/FairMQTransportFactoryZMQ.h
)
if(BUILD_NANOMSG_TRANSPORT)
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
nanomsg/FairMQMessageNN.h
nanomsg/FairMQPollerNN.h
nanomsg/FairMQUnmanagedRegionNN.h
nanomsg/FairMQSocketNN.h
nanomsg/FairMQTransportFactoryNN.h
if(BUILD_FAIRMQ OR BUILD_SDK)
###########
# Version #
###########
configure_file(Version.h.in
${CMAKE_BINARY_DIR}/${PROJECT_NAME_LOWER}/Version.h
@ONLY
)
endif()
if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
ofi/Context.h
ofi/Message.h
ofi/Poller.h
ofi/Socket.h
ofi/TransportFactory.h
install(FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME_LOWER}/Version.h
DESTINATION ${PROJECT_INSTALL_INCDIR}
)
endif()
##########################
# libFairMQ source files #
##########################
set(FAIRMQ_SOURCE_FILES
DeviceRunner.cxx
FairMQChannel.cxx
FairMQDevice.cxx
FairMQLogger.cxx
FairMQMessage.cxx
FairMQPoller.cxx
FairMQSocket.cxx
StateMachine.cxx
FairMQTransportFactory.cxx
devices/FairMQBenchmarkSampler.cxx
devices/FairMQMerger.cxx
devices/FairMQMultiplier.cxx
devices/FairMQProxy.cxx
devices/FairMQSplitter.cxx
options/FairMQParser.cxx
options/FairMQProgOptions.cxx
options/FairMQSuboptParser.cxx
Plugin.cxx
PluginManager.cxx
PluginServices.cxx
plugins/Control.cxx
shmem/FairMQMessageSHM.cxx
shmem/FairMQPollerSHM.cxx
shmem/FairMQUnmanagedRegionSHM.cxx
shmem/FairMQSocketSHM.cxx
shmem/FairMQTransportFactorySHM.cxx
shmem/Manager.cxx
shmem/Region.cxx
tools/Network.cxx
tools/Process.cxx
tools/Unique.cxx
zeromq/FairMQMessageZMQ.cxx
zeromq/FairMQPollerZMQ.cxx
zeromq/FairMQUnmanagedRegionZMQ.cxx
zeromq/FairMQSocketZMQ.cxx
zeromq/FairMQTransportFactoryZMQ.cxx
MemoryResources.cxx
)
#########
# Tools #
#########
set(target Tools)
if(BUILD_NANOMSG_TRANSPORT)
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
nanomsg/FairMQMessageNN.cxx
nanomsg/FairMQPollerNN.cxx
nanomsg/FairMQUnmanagedRegionNN.cxx
nanomsg/FairMQSocketNN.cxx
nanomsg/FairMQTransportFactoryNN.cxx
set(TOOLS_PUBLIC_HEADER_FILES
tools/CppSTL.h
tools/InstanceLimit.h
tools/Network.h
tools/Process.h
tools/RateLimit.h
tools/Semaphore.h
tools/Strings.h
tools/Unique.h
tools/Version.h
Tools.h
)
endif()
if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
ofi/Context.cxx
ofi/Message.cxx
ofi/Poller.cxx
ofi/Socket.cxx
ofi/TransportFactory.cxx
set(TOOLS_SOURCE_FILES
tools/Network.cxx
tools/Process.cxx
tools/Semaphore.cxx
tools/Unique.cxx
)
add_library(${target}
${TOOLS_SOURCE_FILES}
${TOOLS_PUBLIC_HEADER_FILES}
)
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
target_include_directories(${target}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(${target}
PRIVATE
FairLogger::FairLogger
PUBLIC
Boost::boost
)
set_target_properties(${target} PROPERTIES
VERSION ${PROJECT_GIT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
OUTPUT_NAME FairMQ${target}
)
install(
TARGETS ${target}
EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
)
foreach(HEADER ${TOOLS_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER}
DESTINATION ${_destination}
)
endforeach()
#################
# State Machine #
#################
set(target StateMachine)
set(FSM_PUBLIC_HEADER_FILES
StateMachine.h
States.h
StateQueue.h
)
set(FSM_SOURCE_FILES
StateMachine.cxx
States.cxx
)
add_library(${target}
${FSM_SOURCE_FILES}
${FSM_PUBLIC_HEADER_FILES}
)
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
target_include_directories(${target}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(${target}
PUBLIC
FairLogger::FairLogger
PRIVATE
Boost::boost
Tools
)
set_target_properties(${target} PROPERTIES
VERSION ${PROJECT_GIT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
OUTPUT_NAME FairMQ${target}
)
install(
TARGETS ${target}
EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
)
foreach(HEADER ${FSM_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER}
DESTINATION ${_destination}
)
endforeach()
endif()
if(BUILD_FAIRMQ)
##########################
# libFairMQ header files #
##########################
set(FAIRMQ_PUBLIC_HEADER_FILES
DeviceRunner.h
EventManager.h
FairMQChannel.h
FairMQDevice.h
FairMQLogger.h
FairMQMessage.h
FairMQParts.h
FairMQPoller.h
FairMQUnmanagedRegion.h
FairMQSocket.h
FairMQTransportFactory.h
MemoryResources.h
MemoryResourceTools.h
Transports.h
options/FairMQProgOptions.h
JSONParser.h
ProgOptionsFwd.h
ProgOptions.h
Properties.h
PropertyOutput.h
SuboptParser.h
Plugin.h
PluginManager.h
PluginServices.h
runFairMQDevice.h
)
###################
# configure files #
###################
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run/startMQBenchmark.sh.in ${CMAKE_CURRENT_BINARY_DIR}/startMQBenchmark.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/options/startConfigExample.sh.in ${CMAKE_CURRENT_BINARY_DIR}/startConfigExample.sh)
set(FAIRMQ_PRIVATE_HEADER_FILES
devices/FairMQBenchmarkSampler.h
devices/FairMQMerger.h
devices/FairMQMultiplier.h
devices/FairMQProxy.h
devices/FairMQSink.h
devices/FairMQSplitter.h
plugins/Builtin.h
plugins/config/Config.h
plugins/Control.h
shmem/FairMQMessageSHM.h
shmem/FairMQPollerSHM.h
shmem/FairMQUnmanagedRegionSHM.h
shmem/FairMQSocketSHM.h
shmem/FairMQTransportFactorySHM.h
shmem/Common.h
shmem/Manager.h
shmem/Region.h
zeromq/FairMQMessageZMQ.h
zeromq/FairMQPollerZMQ.h
zeromq/FairMQUnmanagedRegionZMQ.h
zeromq/FairMQSocketZMQ.h
zeromq/FairMQTransportFactoryZMQ.h
)
if(BUILD_NANOMSG_TRANSPORT)
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
nanomsg/FairMQMessageNN.h
nanomsg/FairMQPollerNN.h
nanomsg/FairMQUnmanagedRegionNN.h
nanomsg/FairMQSocketNN.h
nanomsg/FairMQTransportFactoryNN.h
)
endif()
if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
ofi/Context.h
ofi/Message.h
ofi/Poller.h
ofi/Socket.h
ofi/TransportFactory.h
)
endif()
##########################
# libFairMQ source files #
##########################
set(FAIRMQ_SOURCE_FILES
DeviceRunner.cxx
FairMQChannel.cxx
FairMQDevice.cxx
FairMQLogger.cxx
FairMQMessage.cxx
FairMQPoller.cxx
FairMQSocket.cxx
FairMQTransportFactory.cxx
devices/FairMQBenchmarkSampler.cxx
devices/FairMQMerger.cxx
devices/FairMQMultiplier.cxx
devices/FairMQProxy.cxx
devices/FairMQSplitter.cxx
Plugin.cxx
PluginManager.cxx
PluginServices.cxx
ProgOptions.cxx
JSONParser.cxx
Properties.cxx
SuboptParser.cxx
plugins/config/Config.cxx
plugins/Control.cxx
shmem/FairMQMessageSHM.cxx
shmem/FairMQPollerSHM.cxx
shmem/FairMQUnmanagedRegionSHM.cxx
shmem/FairMQSocketSHM.cxx
shmem/FairMQTransportFactorySHM.cxx
shmem/Manager.cxx
shmem/Region.cxx
zeromq/FairMQMessageZMQ.cxx
zeromq/FairMQPollerZMQ.cxx
zeromq/FairMQUnmanagedRegionZMQ.cxx
zeromq/FairMQSocketZMQ.cxx
zeromq/FairMQTransportFactoryZMQ.cxx
MemoryResources.cxx
)
if(BUILD_NANOMSG_TRANSPORT)
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
nanomsg/FairMQMessageNN.cxx
nanomsg/FairMQPollerNN.cxx
nanomsg/FairMQUnmanagedRegionNN.cxx
nanomsg/FairMQSocketNN.cxx
nanomsg/FairMQTransportFactoryNN.cxx
)
endif()
if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
ofi/Context.cxx
ofi/Message.cxx
ofi/Poller.cxx
ofi/Socket.cxx
ofi/TransportFactory.cxx
)
endif()
#################################
# define libFairMQ build target #
#################################
if(FAST_BUILD)
set(_target FairMQ_)
else()
set(_target FairMQ)
endif()
add_library(${_target}
${FAIRMQ_SOURCE_FILES}
${FAIRMQ_PUBLIC_HEADER_FILES} # for IDE integration
${FAIRMQ_PRIVATE_HEADER_FILES} # for IDE integration
)
set_target_properties(${_target} PROPERTIES LABELS coverage)
if(FAST_BUILD)
set_target_properties(${_target} PROPERTIES OUTPUT_NAME FairMQ)
endif()
###################
# configure files #
###################
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run/startMQBenchmark.sh.in ${CMAKE_CURRENT_BINARY_DIR}/startMQBenchmark.sh)
#################################
# define libFairMQ build target #
#################################
if(FAST_BUILD)
set(_target FairMQ_)
else()
set(_target FairMQ)
endif()
add_library(${_target}
${FAIRMQ_SOURCE_FILES}
${FAIRMQ_PUBLIC_HEADER_FILES} # for IDE integration
${FAIRMQ_PRIVATE_HEADER_FILES} # for IDE integration
)
set_target_properties(${_target} PROPERTIES LABELS coverage)
if(FAST_BUILD)
set_target_properties(${_target} PROPERTIES OUTPUT_NAME FairMQ)
endif()
############################
# preprocessor definitions #
############################
target_compile_definitions(${_target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
if(BUILD_NANOMSG_TRANSPORT)
target_compile_definitions(${_target} PRIVATE BUILD_NANOMSG_TRANSPORT)
endif()
if(BUILD_OFI_TRANSPORT)
target_compile_definitions(${_target} PRIVATE BUILD_OFI_TRANSPORT)
endif()
############################
# preprocessor definitions #
############################
target_compile_definitions(${_target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
if(BUILD_NANOMSG_TRANSPORT)
target_compile_definitions(${_target} PRIVATE BUILD_NANOMSG_TRANSPORT)
endif()
if(BUILD_OFI_TRANSPORT)
target_compile_definitions(${_target} PRIVATE BUILD_OFI_TRANSPORT)
endif()
#######################
# include directories #
#######################
target_include_directories(${_target}
PUBLIC # consumers inherit public include directories
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
$<INSTALL_INTERFACE:include/fairmq>
$<INSTALL_INTERFACE:include>
)
#######################
# include directories #
#######################
target_include_directories(${_target}
PUBLIC # consumers inherit public include directories
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
$<INSTALL_INTERFACE:include/fairmq>
$<INSTALL_INTERFACE:include>
)
##################
# link libraries #
##################
if(BUILD_NANOMSG_TRANSPORT)
set(NANOMSG_DEPS nanomsg msgpackc-cxx)
endif()
if(BUILD_OFI_TRANSPORT)
set(OFI_DEPS
asiofi::asiofi
##################
# link libraries #
##################
if(BUILD_NANOMSG_TRANSPORT)
set(NANOMSG_DEPS nanomsg msgpackc-cxx)
endif()
if(BUILD_OFI_TRANSPORT)
set(OFI_DEPS
asiofi::asiofi
Boost::container
)
endif()
set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS})
if(optional_deps)
list(REMOVE_DUPLICATES optional_deps)
endif()
target_link_libraries(${_target}
INTERFACE # only consumers link against interface dependencies
Boost::container
AZMQ::AZMQ
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
Threads::Threads
dl
$<$<PLATFORM_ID:Linux>:rt>
Boost::boost
Boost::program_options
Boost::filesystem
Boost::regex
FairLogger::FairLogger
Tools
StateMachine
PRIVATE # only libFairMQ links against private dependencies
libzmq
${NANOMSG_DEPS}
${OFI_DEPS}
)
endif()
set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS})
if(optional_deps)
list(REMOVE_DUPLICATES optional_deps)
endif()
target_link_libraries(${_target}
INTERFACE # only consumers link against interface dependencies
Boost::container
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
Threads::Threads
dl
$<$<PLATFORM_ID:Linux>:rt>
Boost::boost
Boost::program_options
Boost::filesystem
Boost::regex
FairLogger::FairLogger
PRIVATE # only libFairMQ links against private dependencies
libzmq
${NANOMSG_DEPS}
${OFI_DEPS}
)
set_target_properties(${_target} PROPERTIES
VERSION ${PROJECT_GIT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)
##############
# fast build #
##############
if(FAST_BUILD)
set_target_properties(${_target} PROPERTIES
COTIRE_UNITY_TARGET_NAME "FairMQ"
# COTIRE_ENABLE_PRECOMPILED_HEADER FALSE
EXCLUDE_FROM_ALL TRUE
VERSION ${PROJECT_GIT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)
cotire(${_target})
set_target_properties(FairMQ PROPERTIES EXCLUDE_FROM_ALL FALSE)
set_target_properties(FairMQ PROPERTIES LABELS coverage)
##############
# fast build #
##############
if(FAST_BUILD)
set_target_properties(${_target} PROPERTIES
COTIRE_UNITY_TARGET_NAME "FairMQ"
# COTIRE_ENABLE_PRECOMPILED_HEADER FALSE
EXCLUDE_FROM_ALL TRUE
)
cotire(${_target})
set_target_properties(FairMQ PROPERTIES EXCLUDE_FROM_ALL FALSE)
set_target_properties(FairMQ PROPERTIES LABELS coverage)
endif()
###############
# executables #
###############
add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx)
target_link_libraries(fairmq-bsampler FairMQ)
add_executable(fairmq-merger run/runMerger.cxx)
target_link_libraries(fairmq-merger FairMQ)
add_executable(fairmq-multiplier run/runMultiplier.cxx)
target_link_libraries(fairmq-multiplier FairMQ)
add_executable(fairmq-proxy run/runProxy.cxx)
target_link_libraries(fairmq-proxy FairMQ)
add_executable(fairmq-sink run/runSink.cxx)
target_link_libraries(fairmq-sink FairMQ)
add_executable(fairmq-splitter run/runSplitter.cxx)
target_link_libraries(fairmq-splitter FairMQ)
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
target_compile_definitions(fairmq-shmmonitor PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
target_link_libraries(fairmq-shmmonitor PUBLIC
Threads::Threads
$<$<PLATFORM_ID:Linux>:rt>
Boost::boost
Boost::date_time
Boost::program_options
)
target_include_directories(fairmq-shmmonitor PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
)
add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx)
target_link_libraries(fairmq-uuid-gen FairMQ)
###########
# install #
###########
install(
TARGETS
FairMQ
fairmq-bsampler
fairmq-merger
fairmq-multiplier
fairmq-proxy
fairmq-sink
fairmq-splitter
fairmq-shmmonitor
fairmq-uuid-gen
EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
)
# preserve relative path and prepend fairmq
foreach(HEADER ${FAIRMQ_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER}
DESTINATION ${_destination}
)
endforeach()
endif()
###############
# executables #
###############
add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx)
target_link_libraries(fairmq-bsampler FairMQ)
add_executable(fairmq-merger run/runMerger.cxx)
target_link_libraries(fairmq-merger FairMQ)
add_executable(fairmq-multiplier run/runMultiplier.cxx)
target_link_libraries(fairmq-multiplier FairMQ)
add_executable(fairmq-proxy run/runProxy.cxx)
target_link_libraries(fairmq-proxy FairMQ)
add_executable(fairmq-sink run/runSink.cxx)
target_link_libraries(fairmq-sink FairMQ)
add_executable(fairmq-splitter run/runSplitter.cxx)
target_link_libraries(fairmq-splitter FairMQ)
add_executable(runConfigExample options/runConfigEx.cxx)
target_link_libraries(runConfigExample FairMQ)
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
target_link_libraries(fairmq-shmmonitor PUBLIC
Threads::Threads
$<$<PLATFORM_ID:Linux>:rt>
Boost::boost
Boost::date_time
Boost::program_options
)
target_include_directories(fairmq-shmmonitor PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
)
add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx)
target_link_libraries(fairmq-uuid-gen FairMQ)
###########
# install #
###########
install(
TARGETS
FairMQ
fairmq-bsampler
fairmq-merger
fairmq-multiplier
fairmq-proxy
fairmq-sink
fairmq-splitter
fairmq-shmmonitor
fairmq-uuid-gen
EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
)
# preserve relative path and prepend fairmq
foreach(HEADER ${FAIRMQ_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER}
DESTINATION ${_destination}
)
endforeach()
if(BUILD_SDK)
add_subdirectory(sdk)
endif()

View File

@@ -12,9 +12,10 @@
#include <fairmq/Tools.h>
#include <fairmq/Version.h>
using namespace std;
using namespace fair::mq;
DeviceRunner::DeviceRunner(int argc, char* const argv[], bool printLogo)
DeviceRunner::DeviceRunner(int argc, char*const* argv, bool printLogo)
: fRawCmdLineArgs(tools::ToStrVector(argc, argv, false))
, fConfig()
, fDevice(nullptr)
@@ -23,8 +24,82 @@ DeviceRunner::DeviceRunner(int argc, char* const argv[], bool printLogo)
, fEvents()
{}
bool DeviceRunner::HandleGeneralOptions(const fair::mq::ProgOptions& config, bool printLogo)
{
if (config.Count("help")) {
config.PrintHelp();
return false;
}
if (config.Count("print-options")) {
config.PrintOptionsRaw();
return false;
}
if (config.Count("print-channels") || config.Count("version")) {
fair::Logger::SetConsoleSeverity("nolog");
} else {
string severity = config.GetProperty<string>("severity");
string logFile = config.GetProperty<string>("log-to-file");
string logFileSeverity = config.GetProperty<string>("file-severity");
bool color = config.GetProperty<bool>("color");
string verbosity = config.GetProperty<string>("verbosity");
fair::Logger::SetVerbosity(verbosity);
if (logFile != "") {
fair::Logger::InitFileSink(logFileSeverity, logFile);
fair::Logger::SetConsoleSeverity("nolog");
} else {
fair::Logger::SetConsoleColor(color);
fair::Logger::SetConsoleSeverity(severity);
}
if (printLogo) {
LOG(info) << endl
<< " ______ _ _______ _________ " << endl
<< " / ____/___ _(_)_______ |/ /_ __ \\ version " << FAIRMQ_GIT_VERSION << endl
<< " / /_ / __ `/ / ___/__ /|_/ /_ / / / build " << FAIRMQ_BUILD_TYPE << endl
<< " / __/ / /_/ / / / _ / / / / /_/ / " << FAIRMQ_REPO_URL << endl
<< " /_/ \\__,_/_/_/ /_/ /_/ \\___\\_\\ " << FAIRMQ_LICENSE << " © " << FAIRMQ_COPYRIGHT << endl;
}
config.PrintOptions();
}
return true;
}
void DeviceRunner::SubscribeForConfigChange()
{
fConfig.Subscribe<bool>("device-runner", [](const std::string& key, const bool val) {
if (key == "color") {
fair::Logger::SetConsoleColor(val);
}
});
fConfig.Subscribe<string>("device-runner", [&](const std::string& key, const std::string val) {
if (key == "severity") {
fair::Logger::SetConsoleSeverity(val);
} else if (key == "file-severity") {
fair::Logger::SetFileSeverity(val);
} else if (key == "verbosity") {
fair::Logger::SetVerbosity(val);
} else if (key == "log-to-file") {
string fileSeverity = fConfig.GetProperty<string>("file-severity");
fair::Logger::InitFileSink(fileSeverity, val);
}
});
}
void DeviceRunner::UnsubscribeFromConfigChange()
{
fConfig.Unsubscribe<bool>("device-runner");
fConfig.Unsubscribe<string>("device-runner");
}
auto DeviceRunner::Run() -> int
{
fPluginManager.LoadPlugin("s:config");
////// CALL HOOK ///////
fEvents.Emit<hooks::LoadPlugins>(*this);
////////////////////////
@@ -36,28 +111,25 @@ auto DeviceRunner::Run() -> int
fEvents.Emit<hooks::SetCustomCmdLineOptions>(*this);
////////////////////////
fPluginManager.ForEachPluginProgOptions(
[&](boost::program_options::options_description options) {
fConfig.AddToCmdLineOptions(options);
});
fPluginManager.ForEachPluginProgOptions([&](boost::program_options::options_description options) {
fConfig.AddToCmdLineOptions(options);
});
fConfig.AddToCmdLineOptions(fPluginManager.ProgramOptions());
////// CALL HOOK ///////
fEvents.Emit<hooks::ModifyRawCmdLineArgs>(*this);
////////////////////////
if (fConfig.ParseAll(fRawCmdLineArgs, true)) {
fConfig.ParseAll(fRawCmdLineArgs, true);
if (!HandleGeneralOptions(fConfig)) {
return 0;
}
if (fPrintLogo) {
LOG(info) << std::endl
<< " ______ _ _______ _________ " << std::endl
<< " / ____/___ _(_)_______ |/ /_ __ \\ version " << FAIRMQ_GIT_VERSION << std::endl
<< " / /_ / __ `/ / ___/__ /|_/ /_ / / / build " << FAIRMQ_BUILD_TYPE << std::endl
<< " / __/ / /_/ / / / _ / / / / /_/ / " << FAIRMQ_REPO_URL << std::endl
<< " /_/ \\__,_/_/_/ /_/ /_/ \\___\\_\\ " << FAIRMQ_LICENSE << " © " << FAIRMQ_COPYRIGHT << std::endl;
}
fConfig.Notify();
// handle configuration updates (for general options)
SubscribeForConfigChange();
////// CALL HOOK ///////
fEvents.Emit<hooks::InstantiateDevice>(*this);
@@ -80,7 +152,8 @@ auto DeviceRunner::Run() -> int
// Handle --version
if (fConfig.Count("version")) {
std::cout << "User device version: " << fDevice->GetVersion() << std::endl;
cout << "FairMQ version: " << FAIRMQ_GIT_VERSION << endl;
cout << "User device version: " << fDevice->GetVersion() << endl;
fDevice->ChangeState(fair::mq::Transition::End);
return 0;
}
@@ -102,6 +175,9 @@ auto DeviceRunner::Run() -> int
// Wait for control plugin to release device control
fPluginManager.WaitForPluginsToReleaseDeviceControl();
// stop handling configuration updates (for general options)
UnsubscribeFromConfigChange();
return 0;
}
@@ -109,7 +185,7 @@ auto DeviceRunner::RunWithExceptionHandlers() -> int
{
try {
return Run();
} catch (std::exception& e) {
} catch (exception& e) {
LOG(error) << "Uncaught exception reached the top of DeviceRunner: " << e.what();
return 1;
} catch (...) {

View File

@@ -11,9 +11,9 @@
#include <fairmq/EventManager.h>
#include <fairmq/PluginManager.h>
#include <fairmq/ProgOptions.h>
#include <FairMQDevice.h>
#include <FairMQLogger.h>
#include <options/FairMQProgOptions.h>
#include <functional>
#include <memory>
@@ -51,11 +51,16 @@ namespace mq {
class DeviceRunner
{
public:
DeviceRunner(int argc, char* const argv[], bool printLogo = true);
DeviceRunner(int argc, char*const* argv, bool printLogo = true);
auto Run() -> int;
auto RunWithExceptionHandlers() -> int;
static bool HandleGeneralOptions(const fair::mq::ProgOptions& config, bool printLogo = true);
void SubscribeForConfigChange();
void UnsubscribeFromConfigChange();
template<typename H>
auto AddHook(std::function<void(DeviceRunner&)> hook) -> void
{
@@ -68,7 +73,7 @@ class DeviceRunner
}
std::vector<std::string> fRawCmdLineArgs;
FairMQProgOptions fConfig;
fair::mq::ProgOptions fConfig;
std::unique_ptr<FairMQDevice> fDevice;
PluginManager fPluginManager;
const bool fPrintLogo;

View File

@@ -5,64 +5,113 @@
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
* FairMQChannel.cxx
*
* @since 2015-06-02
* @author A. Rybalchenko
*/
#include "FairMQChannel.h"
#include <fairmq/Tools.h>
#include <boost/algorithm/string.hpp> // join/split
#include <regex>
#include <set>
#include <random>
using namespace std;
using namespace fair::mq;
mutex FairMQChannel::fChannelMutex;
template<typename T>
T GetPropertyOrDefault(const fair::mq::Properties& m, const string& k, const T& ifNotFound) noexcept
{
if (m.count(k)) {
return boost::any_cast<T>(m.at(k));
}
return ifNotFound;
}
constexpr fair::mq::Transport FairMQChannel::DefaultTransportType;
constexpr const char* FairMQChannel::DefaultTransportName;
constexpr const char* FairMQChannel::DefaultName;
constexpr const char* FairMQChannel::DefaultType;
constexpr const char* FairMQChannel::DefaultMethod;
constexpr const char* FairMQChannel::DefaultAddress;
constexpr int FairMQChannel::DefaultSndBufSize;
constexpr int FairMQChannel::DefaultRcvBufSize;
constexpr int FairMQChannel::DefaultSndKernelSize;
constexpr int FairMQChannel::DefaultRcvKernelSize;
constexpr int FairMQChannel::DefaultLinger;
constexpr int FairMQChannel::DefaultRateLogging;
constexpr int FairMQChannel::DefaultPortRangeMin;
constexpr int FairMQChannel::DefaultPortRangeMax;
constexpr bool FairMQChannel::DefaultAutoBind;
FairMQChannel::FairMQChannel()
: FairMQChannel("", "unspecified", "unspecified", "unspecified", nullptr)
: FairMQChannel(DefaultName, DefaultType, DefaultMethod, DefaultAddress, nullptr)
{}
FairMQChannel::FairMQChannel(const string& name)
: FairMQChannel(name, DefaultType, DefaultMethod, DefaultAddress, nullptr)
{}
FairMQChannel::FairMQChannel(const string& type, const string& method, const string& address)
: FairMQChannel("", type, method, address, nullptr)
: FairMQChannel(DefaultName, type, method, address, nullptr)
{}
FairMQChannel::FairMQChannel(const string& name, const string& type, shared_ptr<FairMQTransportFactory> factory)
: FairMQChannel(name, type, "unspecified", "unspecified", factory)
: FairMQChannel(name, type, DefaultMethod, DefaultAddress, factory)
{}
FairMQChannel::FairMQChannel(const string& name, const string& type, const string& method, const string& address, shared_ptr<FairMQTransportFactory> factory)
: fTransportFactory(factory)
, fTransportType(factory ? factory->GetType() : fair::mq::Transport::DEFAULT)
, fTransportType(factory ? factory->GetType() : DefaultTransportType)
, fSocket(factory ? factory->CreateSocket(type, name) : nullptr)
, fName(name)
, fType(type)
, fMethod(method)
, fAddress(address)
, fSndBufSize(1000)
, fRcvBufSize(1000)
, fSndKernelSize(0)
, fRcvKernelSize(0)
, fLinger(500)
, fRateLogging(1)
, fPortRangeMin(22000)
, fPortRangeMax(23000)
, fAutoBind(true)
, fName(name)
, fSndBufSize(DefaultSndBufSize)
, fRcvBufSize(DefaultRcvBufSize)
, fSndKernelSize(DefaultSndKernelSize)
, fRcvKernelSize(DefaultRcvKernelSize)
, fLinger(DefaultLinger)
, fRateLogging(DefaultRateLogging)
, fPortRangeMin(DefaultPortRangeMin)
, fPortRangeMax(DefaultPortRangeMax)
, fAutoBind(DefaultAutoBind)
, fIsValid(false)
, fMultipart(false)
, fModified(true)
, fReset(false)
, fMtx()
{}
FairMQChannel::FairMQChannel(const string& name, int index, const fair::mq::Properties& properties)
: FairMQChannel(tools::ToString(name, "[", index, "]"), "unspecified", "unspecified", "unspecified", nullptr)
{
string prefix(tools::ToString("chans.", name, ".", index, "."));
fType = GetPropertyOrDefault(properties, string(prefix + "type"), fType);
fMethod = GetPropertyOrDefault(properties, string(prefix + "method"), fMethod);
fAddress = GetPropertyOrDefault(properties, string(prefix + "address"), fAddress);
fTransportType = TransportTypes.at(GetPropertyOrDefault(properties, string(prefix + "transport"), TransportNames.at(fTransportType)));
fSndBufSize = GetPropertyOrDefault(properties, string(prefix + "sndBufSize"), fSndBufSize);
fRcvBufSize = GetPropertyOrDefault(properties, string(prefix + "rcvBufSize"), fRcvBufSize);
fSndKernelSize = GetPropertyOrDefault(properties, string(prefix + "sndKernelSize"), fSndKernelSize);
fRcvKernelSize = GetPropertyOrDefault(properties, string(prefix + "rcvKernelSize"), fRcvKernelSize);
fLinger = GetPropertyOrDefault(properties, string(prefix + "linger"), fLinger);
fRateLogging = GetPropertyOrDefault(properties, string(prefix + "rateLogging"), fRateLogging);
fPortRangeMin = GetPropertyOrDefault(properties, string(prefix + "portRangeMin"), fPortRangeMin);
fPortRangeMax = GetPropertyOrDefault(properties, string(prefix + "portRangeMax"), fPortRangeMax);
fAutoBind = GetPropertyOrDefault(properties, string(prefix + "autoBind"), fAutoBind);
}
FairMQChannel::FairMQChannel(const FairMQChannel& chan)
: FairMQChannel(chan, chan.fName)
{}
FairMQChannel::FairMQChannel(const FairMQChannel& chan, const string& newName)
: fTransportFactory(nullptr)
, fTransportType(chan.fTransportType)
, fSocket(nullptr)
, fName(newName)
, fType(chan.fType)
, fMethod(chan.fMethod)
, fAddress(chan.fAddress)
@@ -75,7 +124,6 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan)
, fPortRangeMin(chan.fPortRangeMin)
, fPortRangeMax(chan.fPortRangeMax)
, fAutoBind(chan.fAutoBind)
, fName(chan.fName)
, fIsValid(false)
, fMultipart(chan.fMultipart)
, fModified(chan.fModified)
@@ -87,6 +135,7 @@ FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
fTransportFactory = nullptr;
fTransportType = chan.fTransportType;
fSocket = nullptr;
fName = chan.fName;
fType = chan.fType;
fMethod = chan.fMethod;
fAddress = chan.fAddress;
@@ -99,7 +148,6 @@ FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
fPortRangeMin = chan.fPortRangeMin;
fPortRangeMax = chan.fPortRangeMax;
fAutoBind = chan.fAutoBind;
fName = chan.fName;
fIsValid = false;
fMultipart = chan.fMultipart;
fModified = chan.fModified;
@@ -116,13 +164,13 @@ FairMQSocket & FairMQChannel::GetSocket() const
string FairMQChannel::GetName() const
{
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fName;
}
string FairMQChannel::GetPrefix() const
{
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
string prefix = fName;
prefix = prefix.erase(fName.rfind('['));
return prefix;
@@ -130,7 +178,7 @@ string FairMQChannel::GetPrefix() const
string FairMQChannel::GetIndex() const
{
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
string indexStr = fName;
indexStr.erase(indexStr.rfind(']'));
indexStr.erase(0, indexStr.rfind('[') + 1);
@@ -139,296 +187,306 @@ string FairMQChannel::GetIndex() const
string FairMQChannel::GetType() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fType;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetType: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
string FairMQChannel::GetMethod() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fMethod;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetMethod: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
string FairMQChannel::GetAddress() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fAddress;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetAddress: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
string FairMQChannel::GetTransportName() const
try {
lock_guard<mutex> lock(fChannelMutex);
return fair::mq::TransportNames.at(fTransportType);
lock_guard<mutex> lock(fMtx);
return TransportNames.at(fTransportType);
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetTransportName: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
Transport FairMQChannel::GetTransportType() const
try {
lock_guard<mutex> lock(fMtx);
return fTransportType;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetTransportType: " << e.what();
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetSndBufSize() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fSndBufSize;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetSndBufSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetRcvBufSize() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fRcvBufSize;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetRcvBufSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetSndKernelSize() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fSndKernelSize;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetSndKernelSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetRcvKernelSize() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fRcvKernelSize;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetRcvKernelSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetLinger() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fLinger;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetLinger: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetRateLogging() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fRateLogging;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetRateLogging: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetPortRangeMin() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fPortRangeMin;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetPortRangeMin: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
int FairMQChannel::GetPortRangeMax() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fPortRangeMax;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetPortRangeMax: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
bool FairMQChannel::GetAutoBind() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fAutoBind;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::GetAutoBind: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateType(const string& type)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fType = type;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateType: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateMethod(const string& method)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fMethod = method;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateMethod: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateAddress(const string& address)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fAddress = address;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateAddress: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateTransport(const string& transport)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fTransportType = fair::mq::TransportTypes.at(transport);
fTransportType = TransportTypes.at(transport);
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateTransport: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateSndBufSize(const int sndBufSize)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fSndBufSize = sndBufSize;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateSndBufSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateRcvBufSize(const int rcvBufSize)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fRcvBufSize = rcvBufSize;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateRcvBufSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateSndKernelSize(const int sndKernelSize)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fSndKernelSize = sndKernelSize;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateSndKernelSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateRcvKernelSize(const int rcvKernelSize)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fRcvKernelSize = rcvKernelSize;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateRcvKernelSize: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateLinger(const int duration)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fLinger = duration;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateLinger: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateRateLogging(const int rateLogging)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fRateLogging = rateLogging;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateRateLogging: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdatePortRangeMin(const int minPort)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fPortRangeMin = minPort;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdatePortRangeMin: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdatePortRangeMax(const int maxPort)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fPortRangeMax = maxPort;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdatePortRangeMax: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateAutoBind(const bool autobind)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fAutoBind = autobind;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateAutoBind: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
auto FairMQChannel::SetModified(const bool modified) -> void
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fModified = modified;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::SetModified: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
void FairMQChannel::UpdateName(const string& name)
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
fName = name;
fModified = true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::UpdateName: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
bool FairMQChannel::IsValid() const
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fIsValid;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::IsValid: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString("failed to acquire lock: ", e.what()));
throw ChannelConfigurationError(tools::ToString("failed to acquire lock: ", e.what()));
}
bool FairMQChannel::Validate()
try {
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
stringstream ss;
ss << "Validating channel '" << fName << "'... ";
@@ -438,13 +496,22 @@ try {
return true;
}
// validate channel name
smatch m;
if (regex_search(fName, m, regex("[^a-zA-Z0-9\\-_\\[\\]#]"))) {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "channel name contains illegal character: '" << m.str(0) << "', allowed characters are: a-z, A-Z, 0-9, -, _, [, ], #";
return false;
}
// validate socket type
const set<string> socketTypes{ "sub", "pub", "pull", "push", "req", "rep", "xsub", "xpub", "dealer", "router", "pair" };
if (socketTypes.find(fType) == socketTypes.end()) {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "Invalid channel type: '" << fType << "'";
throw ChannelConfigurationError(fair::mq::tools::ToString("Invalid channel type: '", fType, "'"));
throw ChannelConfigurationError(tools::ToString("Invalid channel type: '", fType, "'"));
}
// validate socket address
@@ -467,7 +534,7 @@ try {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "Invalid endpoint connection method: '" << fMethod << "' for " << endpoint;
throw ChannelConfigurationError(fair::mq::tools::ToString("Invalid endpoint connection method: '", fMethod, "' for ", endpoint));
throw ChannelConfigurationError(tools::ToString("Invalid endpoint connection method: '", fMethod, "' for ", endpoint));
}
address = endpoint;
}
@@ -523,7 +590,7 @@ try {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "invalid channel send buffer size (cannot be negative): '" << fSndBufSize << "'";
throw ChannelConfigurationError(fair::mq::tools::ToString("invalid channel send buffer size (cannot be negative): '", fSndBufSize, "'"));
throw ChannelConfigurationError(tools::ToString("invalid channel send buffer size (cannot be negative): '", fSndBufSize, "'"));
}
// validate socket buffer size for receiving
@@ -531,7 +598,7 @@ try {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "invalid channel receive buffer size (cannot be negative): '" << fRcvBufSize << "'";
throw ChannelConfigurationError(fair::mq::tools::ToString("invalid channel receive buffer size (cannot be negative): '", fRcvBufSize, "'"));
throw ChannelConfigurationError(tools::ToString("invalid channel receive buffer size (cannot be negative): '", fRcvBufSize, "'"));
}
// validate socket kernel transmit size for sending
@@ -539,7 +606,7 @@ try {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "invalid channel send kernel transmit size (cannot be negative): '" << fSndKernelSize << "'";
throw ChannelConfigurationError(fair::mq::tools::ToString("invalid channel send kernel transmit size (cannot be negative): '", fSndKernelSize, "'"));
throw ChannelConfigurationError(tools::ToString("invalid channel send kernel transmit size (cannot be negative): '", fSndKernelSize, "'"));
}
// validate socket kernel transmit size for receiving
@@ -547,7 +614,7 @@ try {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "invalid channel receive kernel transmit size (cannot be negative): '" << fRcvKernelSize << "'";
throw ChannelConfigurationError(fair::mq::tools::ToString("invalid channel receive kernel transmit size (cannot be negative): '", fRcvKernelSize, "'"));
throw ChannelConfigurationError(tools::ToString("invalid channel receive kernel transmit size (cannot be negative): '", fRcvKernelSize, "'"));
}
// validate socket rate logging interval
@@ -555,7 +622,7 @@ try {
ss << "INVALID";
LOG(debug) << ss.str();
LOG(error) << "invalid socket rate logging interval (cannot be negative): '" << fRateLogging << "'";
throw ChannelConfigurationError(fair::mq::tools::ToString("invalid socket rate logging interval (cannot be negative): '", fRateLogging, "'"));
throw ChannelConfigurationError(tools::ToString("invalid socket rate logging interval (cannot be negative): '", fRateLogging, "'"));
}
fIsValid = true;
@@ -564,12 +631,12 @@ try {
return true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::ValidateChannel: " << e.what();
throw ChannelConfigurationError(fair::mq::tools::ToString(e.what()));
throw ChannelConfigurationError(tools::ToString(e.what()));
}
void FairMQChannel::Init()
{
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fSocket = fTransportFactory->CreateSocket(fType, fName);
@@ -591,14 +658,14 @@ void FairMQChannel::Init()
bool FairMQChannel::ConnectEndpoint(const string& endpoint)
{
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
return fSocket->Connect(endpoint);
}
bool FairMQChannel::BindEndpoint(string& endpoint)
{
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
// try to bind to the configured port. If it fails, try random one (if AutoBind is on).
if (fSocket->Bind(endpoint)) {
@@ -623,7 +690,7 @@ bool FairMQChannel::BindEndpoint(string& endpoint)
}
size_t pos = endpoint.rfind(':');
endpoint = endpoint.substr(0, pos + 1) + fair::mq::tools::ToString(static_cast<int>(randomPort(generator)));
endpoint = endpoint.substr(0, pos + 1) + tools::ToString(static_cast<int>(randomPort(generator)));
} while (!fSocket->Bind(endpoint));
return true;
@@ -636,7 +703,7 @@ bool FairMQChannel::BindEndpoint(string& endpoint)
void FairMQChannel::ResetChannel()
{
lock_guard<mutex> lock(fChannelMutex);
lock_guard<mutex> lock(fMtx);
fIsValid = false;
// TODO: implement channel resetting
}

View File

@@ -9,6 +9,16 @@
#ifndef FAIRMQCHANNEL_H_
#define FAIRMQCHANNEL_H_
#include <FairMQTransportFactory.h>
#include <FairMQSocket.h>
#include <fairmq/Transports.h>
#include <FairMQLogger.h>
#include <FairMQParts.h>
#include <fairmq/Properties.h>
#include <FairMQMessage.h>
#include <boost/any.hpp>
#include <string>
#include <memory> // unique_ptr, shared_ptr
#include <vector>
@@ -17,13 +27,6 @@
#include <stdexcept>
#include <utility> // std::move
#include <FairMQTransportFactory.h>
#include <FairMQSocket.h>
#include <fairmq/Transports.h>
#include <FairMQLogger.h>
#include <FairMQParts.h>
#include <FairMQMessage.h>
class FairMQChannel
{
friend class FairMQDevice;
@@ -32,6 +35,10 @@ class FairMQChannel
/// Default constructor
FairMQChannel();
/// Constructor
/// @param name Channel name
FairMQChannel(const std::string& name);
/// Constructor
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param method Socket method (bind/connect)
@@ -52,14 +59,28 @@ class FairMQChannel
/// @param factory TransportFactory
FairMQChannel(const std::string& name, const std::string& type, const std::string& method, const std::string& address, std::shared_ptr<FairMQTransportFactory> factory);
FairMQChannel(const std::string& name, int index, const fair::mq::Properties& properties);
/// Copy Constructor
FairMQChannel(const FairMQChannel&);
/// Copy Constructor (with new name)
FairMQChannel(const FairMQChannel&, const std::string& name);
/// Move constructor
FairMQChannel(FairMQChannel&&) = default;
/// Assignment operator
FairMQChannel& operator=(const FairMQChannel&);
/// Default destructor
virtual ~FairMQChannel() {}
/// Move assignment operator
FairMQChannel& operator=(FairMQChannel&&) = default;
/// Destructor
virtual ~FairMQChannel()
{
// LOG(debug) << "Destroying channel " << fName;
}
struct ChannelConfigurationError : std::runtime_error { using std::runtime_error::runtime_error; };
@@ -81,17 +102,17 @@ class FairMQChannel
/// Get channel name
/// @return Returns full channel name (e.g. "data[0]")
std::string GetChannelName() const { return GetName(); } // TODO: deprecate this in favor of following
std::string GetName() const;
std::string GetChannelName() const __attribute__((deprecated("Use GetName()"))) { return GetName(); }
std::string GetName() const ;
/// Get channel prefix
/// @return Returns channel prefix (e.g. "data" in "data[0]")
std::string GetChannelPrefix() const { return GetPrefix(); } // TODO: deprecate this in favor of following
std::string GetChannelPrefix() const __attribute__((deprecated("Use GetPrefix()"))) { return GetPrefix(); }
std::string GetPrefix() const;
/// Get channel index
/// @return Returns channel index (e.g. 0 in "data[0]")
std::string GetChannelIndex() const { return GetIndex(); } // TODO: deprecate this in favor of following
std::string GetChannelIndex() const __attribute__((deprecated("Use GetIndex()"))) { return GetIndex(); }
std::string GetIndex() const;
/// Get socket type
@@ -106,10 +127,14 @@ class FairMQChannel
/// @return Returns socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
std::string GetAddress() const;
/// Get channel transport ("default", "zeromq", "nanomsg" or "shmem")
/// @return Returns channel transport (e.g. "default", "zeromq", "nanomsg" or "shmem")
/// Get channel transport name ("default", "zeromq", "nanomsg" or "shmem")
/// @return Returns channel transport name (e.g. "default", "zeromq", "nanomsg" or "shmem")
std::string GetTransportName() const;
/// Get channel transport type
/// @return Returns channel transport type
fair::mq::Transport GetTransportType() const;
/// Get socket send buffer size (in number of messages)
/// @return Returns socket send buffer size (in number of messages)
int GetSndBufSize() const;
@@ -200,7 +225,7 @@ class FairMQChannel
/// Set channel name
/// @param name Arbitrary channel name
void UpdateChannelName(const std::string& name) { UpdateName(name); } // TODO: deprecate this in favor of following
void UpdateChannelName(const std::string& name) __attribute__((deprecated("Use UpdateName()"))) { UpdateName(name); }
void UpdateName(const std::string& name);
/// Checks if the configured channel settings are valid (checks the validity parameter, without running full validation (as oposed to ValidateChannel()))
@@ -209,10 +234,7 @@ class FairMQChannel
/// Validates channel configuration
/// @return true if channel settings are valid, false otherwise.
bool ValidateChannel() // TODO: deprecate this
{
return Validate();
}
bool ValidateChannel() __attribute__((deprecated("Use Validate()"))) { return Validate(); }
/// Validates channel configuration
/// @return true if channel settings are valid, false otherwise.
@@ -247,17 +269,6 @@ class FairMQChannel
return fSocket->Receive(msg, rcvTimeoutInMs);
}
int SendAsync(FairMQMessagePtr& msg) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msg, timeout);")))
{
CheckSendCompatibility(msg);
return fSocket->Send(msg, 0);
}
int ReceiveAsync(FairMQMessagePtr& msg) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msg, timeout);")))
{
CheckReceiveCompatibility(msg);
return fSocket->Receive(msg, 0);
}
/// Send a vector of messages
/// @param msgVec message vector reference
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
@@ -278,17 +289,6 @@ class FairMQChannel
return fSocket->Receive(msgVec, rcvTimeoutInMs);
}
int64_t SendAsync(std::vector<FairMQMessagePtr>& msgVec) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msgVec, timeout);")))
{
CheckSendCompatibility(msgVec);
return fSocket->Send(msgVec, 0);
}
int64_t ReceiveAsync(std::vector<FairMQMessagePtr>& msgVec) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msgVec, timeout);")))
{
CheckReceiveCompatibility(msgVec);
return fSocket->Receive(msgVec, 0);
}
/// Send FairMQParts
/// @param parts FairMQParts reference
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
@@ -307,16 +307,6 @@ class FairMQChannel
return Receive(parts.fParts, rcvTimeoutInMs);
}
int64_t SendAsync(FairMQParts& parts) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(parts, timeout);")))
{
return Send(parts.fParts, 0);
}
int64_t ReceiveAsync(FairMQParts& parts) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(parts, timeout);")))
{
return Receive(parts.fParts, 0);
}
unsigned long GetBytesTx() const { return fSocket->GetBytesTx(); }
unsigned long GetBytesRx() const { return fSocket->GetBytesRx(); }
unsigned long GetMessagesTx() const { return fSocket->GetMessagesTx(); }
@@ -345,11 +335,33 @@ class FairMQChannel
return Transport()->NewStaticMessage(data);
}
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0)
{
return Transport()->CreateUnmanagedRegion(size, callback, path, flags);
}
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::DEFAULT;
static constexpr const char* DefaultTransportName = "default";
static constexpr const char* DefaultName = "";
static constexpr const char* DefaultType = "unspecified";
static constexpr const char* DefaultMethod = "unspecified";
static constexpr const char* DefaultAddress = "unspecified";
static constexpr int DefaultSndBufSize = 1000;
static constexpr int DefaultRcvBufSize = 1000;
static constexpr int DefaultSndKernelSize = 0;
static constexpr int DefaultRcvKernelSize = 0;
static constexpr int DefaultLinger = 500;
static constexpr int DefaultRateLogging = 1;
static constexpr int DefaultPortRangeMin = 22000;
static constexpr int DefaultPortRangeMax = 23000;
static constexpr bool DefaultAutoBind = true;
private:
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
fair::mq::Transport fTransportType;
std::unique_ptr<FairMQSocket> fSocket;
std::string fName;
std::string fType;
std::string fMethod;
std::string fAddress;
@@ -363,23 +375,17 @@ class FairMQChannel
int fPortRangeMax;
bool fAutoBind;
std::string fName;
std::atomic<bool> fIsValid;
// use static mutex to make the class easily copyable
// implication: same mutex is used for all instances of the class
// this does not hurt much, because mutex is used only during initialization with very low contention
// possible TODO: improve this
static std::mutex fChannelMutex;
bool fIsValid;
bool fMultipart;
bool fModified;
bool fReset;
mutable std::mutex fMtx;
void CheckSendCompatibility(FairMQMessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
@@ -395,7 +401,7 @@ class FairMQChannel
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
@@ -411,7 +417,6 @@ class FairMQChannel
void CheckReceiveCompatibility(FairMQMessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
@@ -421,7 +426,7 @@ class FairMQChannel
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
@@ -433,6 +438,7 @@ class FairMQChannel
fTransportFactory = factory;
fTransportType = factory->GetType();
}
auto SetModified(const bool modified) -> void;
};

View File

@@ -26,63 +26,91 @@
#include <algorithm> // std::max
using namespace std;
using namespace fair::mq;
static map<fair::mq::Transition, fair::mq::State> backwardsCompatibilityWaitForEndOfStateHelper =
static map<Transition, State> backwardsCompatibilityWaitForEndOfStateHelper =
{
{ fair::mq::Transition::InitDevice, fair::mq::State::InitializingDevice },
{ fair::mq::Transition::CompleteInit, fair::mq::State::Initialized },
{ fair::mq::Transition::Bind, fair::mq::State::Bound },
{ fair::mq::Transition::Connect, fair::mq::State::DeviceReady },
{ fair::mq::Transition::InitTask, fair::mq::State::Ready },
{ fair::mq::Transition::Run, fair::mq::State::Ready },
{ fair::mq::Transition::Stop, fair::mq::State::Ready },
{ fair::mq::Transition::ResetTask, fair::mq::State::DeviceReady },
{ fair::mq::Transition::ResetDevice, fair::mq::State::Idle }
{ Transition::InitDevice, State::InitializingDevice },
{ Transition::CompleteInit, State::Initialized },
{ Transition::Bind, State::Bound },
{ Transition::Connect, State::DeviceReady },
{ Transition::InitTask, State::Ready },
{ Transition::Run, State::Ready },
{ Transition::Stop, State::Ready },
{ Transition::ResetTask, State::DeviceReady },
{ Transition::ResetDevice, State::Idle }
};
static map<int, fair::mq::Transition> backwardsCompatibilityChangeStateHelper =
static map<int, Transition> backwardsCompatibilityChangeStateHelper =
{
{ FairMQDevice::Event::INIT_DEVICE, fair::mq::Transition::InitDevice },
{ FairMQDevice::Event::internal_DEVICE_READY, fair::mq::Transition::Auto },
{ FairMQDevice::Event::INIT_TASK, fair::mq::Transition::InitTask },
{ FairMQDevice::Event::internal_READY, fair::mq::Transition::Auto },
{ FairMQDevice::Event::RUN, fair::mq::Transition::Run },
{ FairMQDevice::Event::STOP, fair::mq::Transition::Stop },
{ FairMQDevice::Event::RESET_TASK, fair::mq::Transition::ResetTask },
{ FairMQDevice::Event::RESET_DEVICE, fair::mq::Transition::ResetDevice },
{ FairMQDevice::Event::internal_IDLE, fair::mq::Transition::Auto },
{ FairMQDevice::Event::END, fair::mq::Transition::End },
{ FairMQDevice::Event::ERROR_FOUND, fair::mq::Transition::ErrorFound }
{ FairMQDevice::Event::INIT_DEVICE, Transition::InitDevice },
{ FairMQDevice::Event::internal_DEVICE_READY, Transition::Auto },
{ FairMQDevice::Event::INIT_TASK, Transition::InitTask },
{ FairMQDevice::Event::internal_READY, Transition::Auto },
{ FairMQDevice::Event::RUN, Transition::Run },
{ FairMQDevice::Event::STOP, Transition::Stop },
{ FairMQDevice::Event::RESET_TASK, Transition::ResetTask },
{ FairMQDevice::Event::RESET_DEVICE, Transition::ResetDevice },
{ FairMQDevice::Event::internal_IDLE, Transition::Auto },
{ FairMQDevice::Event::END, Transition::End },
{ FairMQDevice::Event::ERROR_FOUND, Transition::ErrorFound }
};
constexpr const char* FairMQDevice::DefaultId;
constexpr int FairMQDevice::DefaultIOThreads;
constexpr const char* FairMQDevice::DefaultTransportName;
constexpr fair::mq::Transport FairMQDevice::DefaultTransportType;
constexpr const char* FairMQDevice::DefaultNetworkInterface;
constexpr int FairMQDevice::DefaultInitTimeout;
constexpr uint64_t FairMQDevice::DefaultMaxRunTime;
constexpr float FairMQDevice::DefaultRate;
constexpr const char* FairMQDevice::DefaultSession;
struct StateSubscription
{
fair::mq::StateMachine& fStateMachine;
fair::mq::StateQueue& fStateQueue;
string fId;
explicit StateSubscription(const string& id, fair::mq::StateMachine& stateMachine, fair::mq::StateQueue& stateQueue)
: fStateMachine(stateMachine)
, fStateQueue(stateQueue)
, fId(id)
{
fStateMachine.SubscribeToStateChange(fId, [&](fair::mq::State state) {
fStateQueue.Push(state);
});
}
~StateSubscription() {
fStateMachine.UnsubscribeFromStateChange(fId);
}
};
FairMQDevice::FairMQDevice()
: FairMQDevice(nullptr, {0, 0, 0})
{
}
{}
FairMQDevice::FairMQDevice(FairMQProgOptions& config)
FairMQDevice::FairMQDevice(ProgOptions& config)
: FairMQDevice(&config, {0, 0, 0})
{
}
{}
FairMQDevice::FairMQDevice(const fair::mq::tools::Version version)
FairMQDevice::FairMQDevice(const tools::Version version)
: FairMQDevice(nullptr, version)
{
}
{}
FairMQDevice::FairMQDevice(FairMQProgOptions& config, const fair::mq::tools::Version version)
FairMQDevice::FairMQDevice(ProgOptions& config, const tools::Version version)
: FairMQDevice(&config, version)
{
}
{}
FairMQDevice::FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Version version)
FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
: fTransportFactory(nullptr)
, fTransports()
, fChannels()
, fInternalConfig(config ? nullptr : fair::mq::tools::make_unique<FairMQProgOptions>())
, fInternalConfig(config ? nullptr : tools::make_unique<ProgOptions>())
, fConfig(config ? config : fInternalConfig.get())
, fId()
, fDefaultTransportType(fair::mq::Transport::ZMQ)
, fId(DefaultId)
, fDefaultTransportType(DefaultTransportType)
, fStateMachine()
, fUninitializedBindingChannels()
, fUninitializedConnectingChannels()
@@ -95,15 +123,18 @@ FairMQDevice::FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Ver
, fMultitransportMutex()
, fMultitransportProceed(false)
, fVersion(version)
, fRate(0.)
, fMaxRunRuntimeInS(0)
, fRate(DefaultRate)
, fMaxRunRuntimeInS(DefaultMaxRunTime)
, fInitializationTimeoutInS(DefaultInitTimeout)
, fRawCmdLineArgs()
, fTransitionMtx()
, fTransitioning(false)
{
SubscribeToNewTransition("device", [&](fair::mq::Transition transition) {
SubscribeToNewTransition("device", [&](Transition transition) {
LOG(trace) << "device notified on new transition: " << transition;
switch (transition) {
case fair::mq::Transition::Stop:
case Transition::Stop:
UnblockTransports();
break;
default:
@@ -114,11 +145,7 @@ FairMQDevice::FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Ver
fStateMachine.HandleStates([&](fair::mq::State state) {
LOG(trace) << "device notified on new state: " << state;
{
lock_guard<mutex> lock(fStatesMtx);
fStates.push(state);
}
fStatesCV.notify_one();
fStateQueue.Push(state);
switch (state) {
case fair::mq::State::InitializingDevice:
@@ -154,27 +181,71 @@ FairMQDevice::FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Ver
fStateMachine.Start();
}
fair::mq::State FairMQDevice::WaitForNextState()
void FairMQDevice::TransitionTo(const fair::mq::State s)
{
unique_lock<mutex> lock(fStatesMtx);
while (fStates.empty()) {
fStatesCV.wait_for(lock, chrono::milliseconds(50));
{
lock_guard<mutex> lock(fTransitionMtx);
if (fTransitioning) {
LOG(debug) << "Attempting a transition with TransitionTo() while another one is already in progress";
throw OngoingTransition("Attempting a transition with TransitionTo() while another one is already in progress");
}
fTransitioning = true;
}
auto result = fStates.front();
using fair::mq::State;
if (result == fair::mq::State::Error) {
throw DeviceStateError("Device transitioned to error state.");
StateQueue sq;
StateSubscription ss(tools::ToString(fId, ".TransitionTo"), fStateMachine, sq);
State currentState = GetCurrentState();
while (s != currentState) {
switch (currentState) {
case State::Idle:
if (s == State::Exiting) { ChangeState(Transition::End); }
else { ChangeState(Transition::InitDevice); }
break;
case State::InitializingDevice:
ChangeState(Transition::CompleteInit);
break;
case State::Initialized:
if (s == State::Exiting || s == State::Idle) { ChangeState(Transition::ResetDevice); }
else { ChangeState(Transition::Bind); }
break;
case State::Bound:
if (s == State::DeviceReady || s == State::Ready || s == State::Running) { ChangeState(Transition::Connect); }
else { ChangeState(Transition::ResetDevice); }
break;
case State::DeviceReady:
if (s == State::Running || s == State::Ready) { ChangeState(Transition::InitTask); }
else { ChangeState(Transition::ResetDevice); }
break;
case State::Ready:
if (s == State::Running) { ChangeState(Transition::Run); }
else { ChangeState(Transition::ResetTask); }
break;
case State::Running:
ChangeState(Transition::Stop);
break;
case State::Binding:
case State::Connecting:
case State::InitializingTask:
case State::ResettingDevice:
case State::ResettingTask:
LOG(debug) << "TransitionTo ignoring state: " << currentState << " (expected, automatic transition).";
break;
default:
LOG(debug) << "TransitionTo ignoring state: " << currentState;
break;
}
currentState = sq.WaitForNext();
}
fStates.pop();
return result;
}
void FairMQDevice::WaitForState(fair::mq::State state)
{
while (WaitForNextState() != state) {}
{
lock_guard<mutex> lock(fTransitionMtx);
fTransitioning = false;
}
}
bool FairMQDevice::ChangeState(const int transition)
@@ -182,83 +253,79 @@ bool FairMQDevice::ChangeState(const int transition)
return ChangeState(backwardsCompatibilityChangeStateHelper.at(transition));
}
void FairMQDevice::WaitForEndOfState(fair::mq::Transition transition)
void FairMQDevice::WaitForEndOfState(Transition transition)
{
WaitForState(backwardsCompatibilityWaitForEndOfStateHelper.at(transition));
}
void FairMQDevice::InitWrapper()
{
// run initialization once CompleteInit transition is requested
fStateMachine.WaitForPendingState();
fId = fConfig->GetValue<string>("id");
fId = fConfig->GetProperty<string>("id", DefaultId);
Init();
fRate = fConfig->GetValue<float>("rate");
fMaxRunRuntimeInS = fConfig->GetValue<uint64_t>("max-run-time");
fRate = fConfig->GetProperty<float>("rate", DefaultRate);
fMaxRunRuntimeInS = fConfig->GetProperty<uint64_t>("max-run-time", DefaultMaxRunTime);
fInitializationTimeoutInS = fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout);
try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetProperty<string>("transport", DefaultTransportName));
} catch (const exception& e) {
LOG(error) << "exception: " << e.what();
LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
LOG(error) << "invalid transport type provided: " << fConfig->GetProperty<string>("transport", "not provided");
throw;
}
for (auto& c : fConfig->GetFairMQMap()) {
if (fChannels.find(c.first) == fChannels.end()) {
LOG(debug) << "Inserting new device channel from config: " << c.first;
fChannels.insert(c);
} else {
LOG(debug) << "Updating existing device channel from config: " << c.first;
fChannels[c.first] = c.second;
unordered_map<string, int> infos = fConfig->GetChannelInfo();
for (const auto& info : infos) {
for (int i = 0; i < info.second; ++i) {
fChannels[info.first].emplace_back(info.first, i, fConfig->GetPropertiesStartingWith(tools::ToString("chans.", info.first, ".", i, ".")));
}
}
LOG(debug) << "Setting '" << fair::mq::TransportNames.at(fDefaultTransportType) << "' as default transport for the device";
fTransportFactory = AddTransport(fDefaultTransportType);
string networkInterface = fConfig->GetValue<string>("network-interface");
string networkInterface = fConfig->GetProperty<string>("network-interface", DefaultNetworkInterface);
// Fill the uninitialized channel containers
for (auto& mi : fChannels) {
for (auto& channel : fChannels) {
int subChannelIndex = 0;
for (auto& vi : mi.second) {
// set channel name: name + vector index
vi.fName = fair::mq::tools::ToString(mi.first, "[", subChannelIndex, "]");
for (auto& subChannel : channel.second) {
// set channel transport
LOG(debug) << "Initializing transport for channel " << vi.fName << ": " << fair::mq::TransportNames.at(vi.fTransportType);
vi.InitTransport(AddTransport(vi.fTransportType));
LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << fair::mq::TransportNames.at(subChannel.fTransportType);
subChannel.InitTransport(AddTransport(subChannel.fTransportType));
if (vi.fMethod == "bind") {
if (subChannel.fMethod == "bind") {
// if binding address is not specified, try getting it from the configured network interface
if (vi.fAddress == "unspecified" || vi.fAddress == "") {
if (subChannel.fAddress == "unspecified" || subChannel.fAddress == "") {
// if the configured network interface is default, get its name from the default route
if (networkInterface == "default") {
networkInterface = fair::mq::tools::getDefaultRouteNetworkInterface();
networkInterface = tools::getDefaultRouteNetworkInterface();
}
vi.fAddress = "tcp://" + fair::mq::tools::getInterfaceIP(networkInterface) + ":1";
subChannel.fAddress = "tcp://" + tools::getInterfaceIP(networkInterface) + ":1";
}
// fill the uninitialized list
fUninitializedBindingChannels.push_back(&vi);
} else if (vi.fMethod == "connect") {
fUninitializedBindingChannels.push_back(&subChannel);
} else if (subChannel.fMethod == "connect") {
// fill the uninitialized list
fUninitializedConnectingChannels.push_back(&vi);
} else if (vi.fAddress.find_first_of("@+>") != string::npos) {
fUninitializedConnectingChannels.push_back(&subChannel);
} else if (subChannel.fAddress.find_first_of("@+>") != string::npos) {
// fill the uninitialized list
fUninitializedConnectingChannels.push_back(&vi);
fUninitializedConnectingChannels.push_back(&subChannel);
} else {
LOG(error) << "Cannot update configuration. Socket method (bind/connect) for channel '" << vi.fName << "' not specified.";
throw runtime_error(fair::mq::tools::ToString("Cannot update configuration. Socket method (bind/connect) for channel ", vi.fName, " not specified."));
LOG(error) << "Cannot update configuration. Socket method (bind/connect) for channel '" << subChannel.fName << "' not specified.";
throw runtime_error(tools::ToString("Cannot update configuration. Socket method (bind/connect) for channel ", subChannel.fName, " not specified."));
}
subChannelIndex++;
}
}
// ChangeState(fair::mq::Transition::Auto);
// ChangeState(Transition::Auto);
}
void FairMQDevice::BindWrapper()
@@ -269,22 +336,20 @@ void FairMQDevice::BindWrapper()
if (!fUninitializedBindingChannels.empty()) {
LOG(error) << fUninitializedBindingChannels.size() << " of the binding channels could not initialize. Initial configuration incomplete.";
throw runtime_error(fair::mq::tools::ToString(fUninitializedBindingChannels.size(), " of the binding channels could not initialize. Initial configuration incomplete."));
throw runtime_error(tools::ToString(fUninitializedBindingChannels.size(), " of the binding channels could not initialize. Initial configuration incomplete."));
}
Bind();
ChangeState(fair::mq::Transition::Auto);
ChangeState(Transition::Auto);
}
void FairMQDevice::ConnectWrapper()
{
int initializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
// go over the list of channels until all are initialized (and removed from the uninitialized list)
int numAttempts = 1;
auto sleepTimeInMS = 50;
auto maxAttempts = initializationTimeoutInS * 1000 / sleepTimeInMS;
auto maxAttempts = fInitializationTimeoutInS * 1000 / sleepTimeInMS;
// first attempt
AttachChannels(fUninitializedConnectingChannels);
// if not all channels could be connected, update their address values from config and retry
@@ -292,16 +357,16 @@ void FairMQDevice::ConnectWrapper()
this_thread::sleep_for(chrono::milliseconds(sleepTimeInMS));
for (auto& chan : fUninitializedConnectingChannels) {
string key{"chans." + chan->GetChannelPrefix() + "." + chan->GetChannelIndex() + ".address"};
string newAddress = fConfig->GetValue<string>(key);
string key{"chans." + chan->GetPrefix() + "." + chan->GetIndex() + ".address"};
string newAddress = fConfig->GetProperty<string>(key);
if (newAddress != chan->GetAddress()) {
chan->UpdateAddress(newAddress);
}
}
if (numAttempts++ > maxAttempts) {
LOG(error) << "could not connect all channels after " << initializationTimeoutInS << " attempts";
throw runtime_error(fair::mq::tools::ToString("could not connect all channels after ", initializationTimeoutInS, " attempts"));
LOG(error) << "could not connect all channels after " << fInitializationTimeoutInS << " attempts";
throw runtime_error(tools::ToString("could not connect all channels after ", fInitializationTimeoutInS, " attempts"));
}
AttachChannels(fUninitializedConnectingChannels);
@@ -313,7 +378,7 @@ void FairMQDevice::ConnectWrapper()
Connect();
ChangeState(fair::mq::Transition::Auto);
ChangeState(Transition::Auto);
}
void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans)
@@ -321,7 +386,7 @@ void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans)
auto itr = chans.begin();
while (itr != chans.end()) {
if ((*itr)->ValidateChannel()) {
if ((*itr)->Validate()) {
(*itr)->Init();
if (AttachChannel(**itr)) {
(*itr)->SetModified(false);
@@ -366,7 +431,7 @@ bool FairMQDevice::AttachChannel(FairMQChannel& chan)
string hostPart = addressString.substr(0, pos);
if (!(bind && hostPart == "*")) {
string portPart = addressString.substr(pos + 1);
string resolvedHost = fair::mq::tools::getIpFromHostname(hostPart);
string resolvedHost = tools::getIpFromHostname(hostPart);
if (resolvedHost == "") {
return false;
}
@@ -404,7 +469,7 @@ bool FairMQDevice::AttachChannel(FairMQChannel& chan)
chan.UpdateAddress(newAddress);
// update address in the config, it could have been modified during binding
fConfig->SetValue({"chans." + chan.GetPrefix() + "." + chan.GetIndex() + ".address"}, newAddress);
fConfig->SetProperty({"chans." + chan.GetPrefix() + "." + chan.GetIndex() + ".address"}, newAddress);
}
return true;
@@ -414,7 +479,7 @@ void FairMQDevice::InitTaskWrapper()
{
InitTask();
ChangeState(fair::mq::Transition::Auto);
ChangeState(Transition::Auto);
}
bool FairMQDevice::SortSocketsByAddress(const FairMQChannel &lhs, const FairMQChannel &rhs)
@@ -433,7 +498,7 @@ void FairMQDevice::SortChannel(const string& name, const bool reindex)
for (auto vi = fChannels.at(name).begin(); vi != fChannels.at(name).end(); ++vi)
{
// set channel name: name + vector index
vi->fName = fair::mq::tools::ToString(name, "[", vi - fChannels.at(name).begin(), "]");
vi->fName = tools::ToString(name, "[", vi - fChannels.at(name).begin(), "]");
}
}
}
@@ -467,7 +532,7 @@ void FairMQDevice::RunWrapper()
HandleMultipleChannelInput();
}
} else {
fair::mq::tools::RateLimiter rateLimiter(fRate);
tools::RateLimiter rateLimiter(fRate);
while (!NewStatePending() && ConditionalRun()) {
if (fRate > 0.001) {
@@ -481,7 +546,7 @@ void FairMQDevice::RunWrapper()
// if Run() exited and the state is still RUNNING, transition to READY.
if (!NewStatePending()) {
UnblockTransports();
ChangeState(fair::mq::Transition::Stop);
ChangeState(Transition::Stop);
}
PostRun();
@@ -489,10 +554,10 @@ void FairMQDevice::RunWrapper()
} catch (const out_of_range& oor) {
LOG(error) << "out of range: " << oor.what();
LOG(error) << "incorrect/incomplete channel configuration?";
ChangeState(fair::mq::Transition::ErrorFound);
ChangeState(Transition::ErrorFound);
throw;
} catch (...) {
ChangeState(fair::mq::Transition::ErrorFound);
ChangeState(Transition::ErrorFound);
throw;
}
@@ -664,7 +729,7 @@ void FairMQDevice::PollForTransport(const FairMQTransportFactory* factory, const
catch (exception& e)
{
LOG(error) << "FairMQDevice::PollForTransport() failed: " << e.what() << ", going to ERROR state.";
throw runtime_error(fair::mq::tools::ToString("FairMQDevice::PollForTransport() failed: ", e.what(), ", going to ERROR state."));
throw runtime_error(tools::ToString("FairMQDevice::PollForTransport() failed: ", e.what(), ", going to ERROR state."));
}
}
@@ -715,7 +780,7 @@ shared_ptr<FairMQTransportFactory> FairMQDevice::AddTransport(fair::mq::Transpor
}
}
void FairMQDevice::SetConfig(FairMQProgOptions& config)
void FairMQDevice::SetConfig(ProgOptions& config)
{
fInternalConfig.reset();
fConfig = &config;
@@ -723,7 +788,7 @@ void FairMQDevice::SetConfig(FairMQProgOptions& config)
void FairMQDevice::LogSocketRates()
{
vector<FairMQSocket*> filteredSockets;
vector<FairMQChannel*> filteredChannels;
vector<string> filteredChannelNames;
vector<int> logIntervals;
vector<int> intervalCounters;
@@ -731,40 +796,40 @@ void FairMQDevice::LogSocketRates()
size_t chanNameLen = 0;
// iterate over the channels map
for (const auto& mi : fChannels) {
for (auto& channel : fChannels) {
// iterate over the channels vector
for (auto vi = (mi.second).begin(); vi != (mi.second).end(); ++vi) {
if (vi->fRateLogging > 0) {
filteredSockets.push_back(vi->fSocket.get());
logIntervals.push_back(vi->fRateLogging);
for (auto& subChannel : channel.second) {
if (subChannel.fRateLogging > 0) {
filteredChannels.push_back(&subChannel);
logIntervals.push_back(subChannel.fRateLogging);
intervalCounters.push_back(0);
filteredChannelNames.push_back(fair::mq::tools::ToString(mi.first, "[", vi - (mi.second).begin(), "]"));
filteredChannelNames.push_back(subChannel.GetName());
chanNameLen = max(chanNameLen, filteredChannelNames.back().length());
}
}
}
vector<unsigned long> bytesIn(filteredSockets.size());
vector<unsigned long> msgIn(filteredSockets.size());
vector<unsigned long> bytesOut(filteredSockets.size());
vector<unsigned long> msgOut(filteredSockets.size());
vector<unsigned long> bytesIn(filteredChannels.size());
vector<unsigned long> msgIn(filteredChannels.size());
vector<unsigned long> bytesOut(filteredChannels.size());
vector<unsigned long> msgOut(filteredChannels.size());
vector<unsigned long> bytesInNew(filteredSockets.size());
vector<unsigned long> msgInNew(filteredSockets.size());
vector<unsigned long> bytesOutNew(filteredSockets.size());
vector<unsigned long> msgOutNew(filteredSockets.size());
vector<unsigned long> bytesInNew(filteredChannels.size());
vector<unsigned long> msgInNew(filteredChannels.size());
vector<unsigned long> bytesOutNew(filteredChannels.size());
vector<unsigned long> msgOutNew(filteredChannels.size());
vector<double> mbPerSecIn(filteredSockets.size());
vector<double> msgPerSecIn(filteredSockets.size());
vector<double> mbPerSecOut(filteredSockets.size());
vector<double> msgPerSecOut(filteredSockets.size());
vector<double> mbPerSecIn(filteredChannels.size());
vector<double> msgPerSecIn(filteredChannels.size());
vector<double> mbPerSecOut(filteredChannels.size());
vector<double> msgPerSecOut(filteredChannels.size());
int i = 0;
for (const auto& vi : filteredSockets) {
bytesIn.at(i) = vi->GetBytesRx();
bytesOut.at(i) = vi->GetBytesTx();
msgIn.at(i) = vi->GetMessagesRx();
msgOut.at(i) = vi->GetMessagesTx();
for (const auto& channel : filteredChannels) {
bytesIn.at(i) = channel->GetBytesRx();
bytesOut.at(i) = channel->GetBytesTx();
msgIn.at(i) = channel->GetMessagesRx();
msgOut.at(i) = channel->GetMessagesTx();
++i;
}
@@ -781,17 +846,17 @@ void FairMQDevice::LogSocketRates()
i = 0;
for (const auto& vi : filteredSockets) {
for (const auto& channel : filteredChannels) {
intervalCounters.at(i)++;
if (intervalCounters.at(i) == logIntervals.at(i)) {
intervalCounters.at(i) = 0;
if (msSinceLastLog > 0) {
bytesInNew.at(i) = vi->GetBytesRx();
msgInNew.at(i) = vi->GetMessagesRx();
bytesOutNew.at(i) = vi->GetBytesTx();
msgOutNew.at(i) = vi->GetMessagesTx();
bytesInNew.at(i) = channel->GetBytesRx();
msgInNew.at(i) = channel->GetMessagesRx();
bytesOutNew.at(i) = channel->GetBytesTx();
msgOutNew.at(i) = channel->GetMessagesTx();
mbPerSecIn.at(i) = (static_cast<double>(bytesInNew.at(i) - bytesIn.at(i)) / (1000. * 1000.)) / static_cast<double>(msSinceLastLog) * 1000.;
msgPerSecIn.at(i) = static_cast<double>(msgInNew.at(i) - msgIn.at(i)) / static_cast<double>(msSinceLastLog) * 1000.;
@@ -814,15 +879,15 @@ void FairMQDevice::LogSocketRates()
t0 = t1;
if (fMaxRunRuntimeInS > 0 && ++secondsElapsed >= fMaxRunRuntimeInS) {
ChangeState(fair::mq::Transition::Stop);
ChangeState(Transition::Stop);
}
}
}
void FairMQDevice::UnblockTransports()
{
for (auto& t : fTransports) {
t.second->Interrupt();
for (auto& transport : fTransports) {
transport.second->Interrupt();
}
}
@@ -830,27 +895,21 @@ void FairMQDevice::ResetTaskWrapper()
{
ResetTask();
ChangeState(fair::mq::Transition::Auto);
ChangeState(Transition::Auto);
}
void FairMQDevice::ResetWrapper()
{
for (auto& t : fTransports) {
t.second->Reset();
}
// iterate over the channels map
for (auto& mi : fChannels) {
// iterate over the channels vector
for (auto& vi : mi.second) {
// vi.fReset = true;
vi.fSocket.reset(); // destroy FairMQSocket
}
for (auto& transport : fTransports) {
transport.second->Reset();
}
Reset();
ChangeState(fair::mq::Transition::Auto);
fChannels.clear();
fTransports.clear();
fTransportFactory.reset();
ChangeState(Transition::Auto);
}
FairMQDevice::~FairMQDevice()

View File

@@ -12,6 +12,7 @@
#include <StateMachine.h>
#include <FairMQTransportFactory.h>
#include <fairmq/Transports.h>
#include <fairmq/StateQueue.h>
#include <FairMQSocket.h>
#include <FairMQChannel.h>
@@ -19,7 +20,7 @@
#include <FairMQParts.h>
#include <FairMQUnmanagedRegion.h>
#include <FairMQLogger.h>
#include <options/FairMQProgOptions.h>
#include <fairmq/ProgOptions.h>
#include <vector>
#include <memory> // unique_ptr
@@ -44,6 +45,14 @@ using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChann
using InputMsgCallback = std::function<bool(FairMQMessagePtr&, int)>;
using InputMultipartCallback = std::function<bool(FairMQParts&, int)>;
namespace fair
{
namespace mq
{
struct OngoingTransition : std::runtime_error { using std::runtime_error::runtime_error; };
}
}
class FairMQDevice
{
friend class FairMQChannel;
@@ -83,17 +92,17 @@ class FairMQDevice
/// Default constructor
FairMQDevice();
/// Constructor with external FairMQProgOptions
FairMQDevice(FairMQProgOptions& config);
/// Constructor with external fair::mq::ProgOptions
FairMQDevice(fair::mq::ProgOptions& config);
/// Constructor that sets the version
FairMQDevice(const fair::mq::tools::Version version);
/// Constructor that sets the version and external FairMQProgOptions
FairMQDevice(FairMQProgOptions& config, const fair::mq::tools::Version version);
/// Constructor that sets the version and external fair::mq::ProgOptions
FairMQDevice(fair::mq::ProgOptions& config, const fair::mq::tools::Version version);
private:
FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Version version);
FairMQDevice(fair::mq::ProgOptions* config, const fair::mq::tools::Version version);
public:
/// Copy constructor (disabled)
@@ -191,50 +200,58 @@ class FairMQDevice
return fTransportFactory.get();
}
// creates message with the default device transport
template<typename... Args>
FairMQMessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
// creates message with the transport of the specified channel
template<typename... Args>
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
}
// creates a message that will not be cleaned up after transfer, with the default device transport
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
// creates a message that will not be cleaned up after transfer, with the transport of the specified channel
template<typename T>
FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewStaticMessage(data);
}
// creates a message with a copy of the provided data, with the default device transport
template<typename T>
FairMQMessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
// creates a message with a copy of the provided data, with the transport of the specified channel
template<typename T>
FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewSimpleMessage(data);
}
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size)
// creates unamanaged region with the default device transport
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr)
{
return Transport()->CreateUnmanagedRegion(size);
return Transport()->CreateUnmanagedRegion(size, callback);
}
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, const size_t size, FairMQRegionCallback callback = nullptr)
// creates unmanaged region with the transport of the specified channel
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0)
{
return GetChannel(channel, index).Transport()->CreateUnmanagedRegion(size, callback);
return GetChannel(channel, index).NewUnmanagedRegion(size, callback, path, flags);
}
template<typename ...Ts>
@@ -288,9 +305,9 @@ class FairMQDevice
std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
/// Assigns config to the device
void SetConfig(FairMQProgOptions& config);
void SetConfig(fair::mq::ProgOptions& config);
/// Get pointer to the config
FairMQProgOptions* GetConfig() const
fair::mq::ProgOptions* GetConfig() const
{
return fConfig;
}
@@ -358,8 +375,9 @@ class FairMQDevice
try {
return fChannels.at(channelName).at(index);
} catch (const std::out_of_range& oor) {
LOG(error) << "out of range: " << oor.what();
LOG(error) << "requested channel has not been configured? check channel names/configuration.";
LOG(error) << "channel: " << channelName << ", index: " << index;
LOG(error) << "out of range: " << oor.what();
throw;
}
@@ -390,23 +408,23 @@ class FairMQDevice
const fair::mq::tools::Version GetVersion() const { return fVersion; }
void SetNumIoThreads(int numIoThreads) { fConfig->SetValue<int>("io-threads", numIoThreads);}
int GetNumIoThreads() const { return fConfig->GetValue<int>("io-threads"); }
void SetNumIoThreads(int numIoThreads) { fConfig->SetProperty("io-threads", numIoThreads);}
int GetNumIoThreads() const { return fConfig->GetProperty<int>("io-threads", DefaultIOThreads); }
void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetValue<std::string>("network-interface", networkInterface); }
std::string GetNetworkInterface() const { return fConfig->GetValue<std::string>("network-interface"); }
void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetProperty("network-interface", networkInterface); }
std::string GetNetworkInterface() const { return fConfig->GetProperty<std::string>("network-interface", DefaultNetworkInterface); }
void SetDefaultTransport(const std::string& name) { fConfig->SetValue<std::string>("transport", name); }
std::string GetDefaultTransport() const { return fConfig->GetValue<std::string>("transport"); }
void SetDefaultTransport(const std::string& name) { fConfig->SetProperty("transport", name); }
std::string GetDefaultTransport() const { return fConfig->GetProperty<std::string>("transport", DefaultTransportName); }
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fConfig->SetValue<int>("initialization-timeout", initializationTimeoutInS); }
int GetInitializationTimeoutInS() const { return fConfig->GetValue<int>("initialization-timeout"); }
void SetInitTimeoutInS(int initTimeoutInS) { fConfig->SetProperty("init-timeout", initTimeoutInS); }
int GetInitTimeoutInS() const { return fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout); }
/// Sets the default transport for the device
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
void SetTransport(const std::string& transport) { fConfig->SetValue<std::string>("transport", transport); }
void SetTransport(const std::string& transport) { fConfig->SetProperty("transport", transport); }
/// Gets the default transport name
std::string GetTransportName() const { return fConfig->GetValue<std::string>("transport"); }
std::string GetTransportName() const { return fConfig->GetProperty<std::string>("transport", DefaultTransportName); }
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
@@ -419,10 +437,10 @@ class FairMQDevice
/// Wait for the supplied amount of time or for interruption.
/// If interrupted, returns false, otherwise true.
/// @param duration wait duration
template<class Rep, class Period>
template<typename Rep, typename Period>
bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
{
return fStateMachine.WaitForPendingStateFor(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
return !fStateMachine.WaitForPendingStateFor(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
}
protected:
@@ -431,12 +449,12 @@ class FairMQDevice
public:
std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels; ///< Device channels
std::unique_ptr<FairMQProgOptions> fInternalConfig; ///< Internal program options configuration
FairMQProgOptions* fConfig; ///< Pointer to config (internal or external)
std::unique_ptr<fair::mq::ProgOptions> fInternalConfig; ///< Internal program options configuration
fair::mq::ProgOptions* fConfig; ///< Pointer to config (internal or external)
void AddChannel(const std::string& channelName, const FairMQChannel& channel)
void AddChannel(const std::string& name, FairMQChannel&& channel)
{
fConfig->AddChannel(channelName, channel);
fConfig->AddChannel(name, channel);
}
protected:
@@ -474,16 +492,18 @@ class FairMQDevice
public:
bool ChangeState(const fair::mq::Transition transition) { return fStateMachine.ChangeState(transition); }
bool ChangeState(const std::string& transition) { return fStateMachine.ChangeState(fair::mq::StateMachine::GetTransition(transition)); }
bool ChangeState(const std::string& transition) { return fStateMachine.ChangeState(fair::mq::GetTransition(transition)); }
bool ChangeState(const int transition) __attribute__((deprecated("Use ChangeState(const fair::mq::Transition transition).")));
void WaitForEndOfState(const fair::mq::Transition transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState).")));
void WaitForEndOfState(const std::string& transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState)."))) { WaitForState(transition); }
fair::mq::State WaitForNextState();
void WaitForState(fair::mq::State state);
void WaitForState(const std::string& state) { fair::mq::StateMachine::GetState(state); }
fair::mq::State WaitForNextState() { return fStateQueue.WaitForNext(); }
void WaitForState(fair::mq::State state) { fStateQueue.WaitForState(state); }
void WaitForState(const std::string& state) { WaitForState(fair::mq::GetState(state)); }
void TransitionTo(const fair::mq::State state);
void SubscribeToStateChange(const std::string& key, std::function<void(const fair::mq::State)> callback) { fStateMachine.SubscribeToStateChange(key, callback); }
void UnsubscribeFromStateChange(const std::string& key) { fStateMachine.UnsubscribeFromStateChange(key); }
@@ -500,10 +520,18 @@ class FairMQDevice
fair::mq::State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
static std::string GetStateName(const fair::mq::State state) { return fair::mq::StateMachine::GetStateName(state); }
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::StateMachine::GetTransitionName(transition); }
static std::string GetStateName(const fair::mq::State state) { return fair::mq::GetStateName(state); }
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::GetTransitionName(transition); }
struct DeviceStateError : std::runtime_error { using std::runtime_error::runtime_error; };
static constexpr const char* DefaultId = "";
static constexpr int DefaultIOThreads = 1;
static constexpr const char* DefaultTransportName = "zeromq";
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::ZMQ;
static constexpr const char* DefaultNetworkInterface = "default";
static constexpr int DefaultInitTimeout = 120;
static constexpr uint64_t DefaultMaxRunTime = 0;
static constexpr float DefaultRate = 0.;
static constexpr const char* DefaultSession = "default";
private:
fair::mq::Transport fDefaultTransportType; ///< Default transport for the device
@@ -557,11 +585,13 @@ class FairMQDevice
const fair::mq::tools::Version fVersion;
float fRate; ///< Rate limiting for ConditionalRun
uint64_t fMaxRunRuntimeInS; ///< Maximum runtime for the Running state handler, after which state will change to Ready (in seconds, 0 for no limit).
int fInitializationTimeoutInS;
std::vector<std::string> fRawCmdLineArgs;
std::queue<fair::mq::State> fStates;
std::mutex fStatesMtx;
std::condition_variable fStatesCV;
fair::mq::StateQueue fStateQueue;
std::mutex fTransitionMtx;
bool fTransitioning;
};
#endif /* FAIRMQDEVICE_H_ */

View File

@@ -31,6 +31,9 @@ class FairMQParts
FairMQParts(FairMQParts&& p) = default;
/// Assignment operator
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)...);}
/// Default destructor
~FairMQParts() {};
@@ -41,14 +44,6 @@ class FairMQParts
fParts.push_back(std::unique_ptr<FairMQMessage>(msg));
}
/// Adds part (std::unique_ptr<FairMQMessage>&) to the container (move)
/// @param msg unique pointer to FairMQMessage
/// lvalue ref (move not required when passing argument)
// inline void AddPart(std::unique_ptr<FairMQMessage>& msg)
// {
// fParts.push_back(std::move(msg));
// }
/// Adds part (std::unique_ptr<FairMQMessage>&) to the container (move)
/// @param msg unique pointer to FairMQMessage
/// rvalue ref (move required when passing argument)
@@ -57,6 +52,23 @@ class FairMQParts
fParts.push_back(std::move(msg));
}
/// Add variable list of parts to the container (move)
template <typename... Ts>
void AddPart(std::unique_ptr<FairMQMessage>&& first, Ts&&... remaining)
{
AddPart(std::move(first));
AddPart(std::forward<Ts>(remaining)...);
}
/// 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));
}
}
/// Get reference to part in the container at index (without bounds check)
/// @param index container index
FairMQMessage& operator[](const int index) { return *(fParts[index]); }

View File

@@ -27,7 +27,7 @@ FairMQTransportFactory::FairMQTransportFactory(const std::string& id)
{
}
auto FairMQTransportFactory::CreateTransportFactory(const std::string& type, const std::string& id, const FairMQProgOptions* config) -> std::shared_ptr<FairMQTransportFactory>
auto FairMQTransportFactory::CreateTransportFactory(const std::string& type, const std::string& id, const fair::mq::ProgOptions* config) -> std::shared_ptr<FairMQTransportFactory>
{
using namespace std;

View File

@@ -12,6 +12,7 @@
#include <FairMQLogger.h>
#include <FairMQMessage.h>
#include <FairMQPoller.h>
#include <fairmq/ProgOptionsFwd.h>
#include <FairMQSocket.h>
#include <FairMQUnmanagedRegion.h>
#include <fairmq/MemoryResources.h>
@@ -23,7 +24,6 @@
#include <unordered_map>
class FairMQChannel;
class FairMQProgOptions;
class FairMQTransportFactory
{
@@ -72,7 +72,7 @@ class FairMQTransportFactory
/// Create a poller for specific channels (all subchannels)
virtual FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const = 0;
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr) const = 0;
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const = 0;
/// Get transport type
virtual fair::mq::Transport GetType() const = 0;
@@ -83,7 +83,7 @@ class FairMQTransportFactory
virtual ~FairMQTransportFactory() {};
static auto CreateTransportFactory(const std::string& type, const std::string& id = "", const FairMQProgOptions* config = nullptr) -> std::shared_ptr<FairMQTransportFactory>;
static auto CreateTransportFactory(const std::string& type, const std::string& id = "", const fair::mq::ProgOptions* config = nullptr) -> std::shared_ptr<FairMQTransportFactory>;
static void FairMQNoCleanup(void* /*data*/, void* /*obj*/)
{

187
fairmq/JSONParser.cxx Normal file
View File

@@ -0,0 +1,187 @@
/********************************************************************************
* Copyright (C) 2014-2018 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" *
********************************************************************************/
/*
* File: JSONParser.cxx
* Author: winckler
*
* Created on May 14, 2015, 5:01 PM
*/
#include <fairmq/PropertyOutput.h>
#include "JSONParser.h"
#include "FairMQLogger.h"
#include <fairmq/Tools.h>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/any.hpp>
#include <ios>
using namespace std;
using namespace fair::mq;
using namespace fair::mq::tools;
using namespace boost::property_tree;
namespace fair
{
namespace mq
{
fair::mq::Properties PtreeParser(const ptree& pt, const string& id)
{
if (id == "") {
throw ParserError("no device ID provided. Provide with `--id` cmd option");
}
// json_parser::write_json(cout, pt);
return helper::DeviceParser(pt.get_child("fairMQOptions"), id);
}
fair::mq::Properties JSONParser(const string& filename, const string& deviceId)
{
ptree pt;
LOG(debug) << "Parsing JSON from " << filename << " ...";
read_json(filename, pt);
return PtreeParser(pt, deviceId);
}
namespace helper
{
fair::mq::Properties DeviceParser(const ptree& fairMQOptions, const string& deviceId)
{
fair::mq::Properties properties;
for (const auto& node : fairMQOptions) {
if (node.first == "devices") {
for (const auto& device : node.second) {
// check if key is provided, otherwise use id
string deviceIdKey = device.second.get<string>("key", device.second.get<string>("id", ""));
// if not correct device id, do not fill MQMap
if (deviceId != deviceIdKey) {
continue;
}
LOG(trace) << "Found following channels for device ID '" << deviceId << "' :";
ChannelParser(device.second, properties);
}
}
}
return properties;
}
void ChannelParser(const ptree& tree, fair::mq::Properties& properties)
{
for (const auto& node : tree) {
if (node.first == "channels") {
for (const auto& cn : node.second) {
fair::mq::Properties commonProperties;
commonProperties.emplace("type", cn.second.get<string>("type", FairMQChannel::DefaultType));
commonProperties.emplace("method", cn.second.get<string>("method", FairMQChannel::DefaultMethod));
commonProperties.emplace("address", cn.second.get<string>("address", FairMQChannel::DefaultAddress));
commonProperties.emplace("transport", cn.second.get<string>("transport", FairMQChannel::DefaultTransportName));
commonProperties.emplace("sndBufSize", cn.second.get<int>("sndBufSize", FairMQChannel::DefaultSndBufSize));
commonProperties.emplace("rcvBufSize", cn.second.get<int>("rcvBufSize", FairMQChannel::DefaultRcvBufSize));
commonProperties.emplace("sndKernelSize", cn.second.get<int>("sndKernelSize", FairMQChannel::DefaultSndKernelSize));
commonProperties.emplace("rcvKernelSize", cn.second.get<int>("rcvKernelSize", FairMQChannel::DefaultRcvKernelSize));
commonProperties.emplace("linger", cn.second.get<int>("linger", FairMQChannel::DefaultLinger));
commonProperties.emplace("rateLogging", cn.second.get<int>("rateLogging", FairMQChannel::DefaultRateLogging));
commonProperties.emplace("portRangeMin", cn.second.get<int>("portRangeMin", FairMQChannel::DefaultPortRangeMin));
commonProperties.emplace("portRangeMax", cn.second.get<int>("portRangeMax", FairMQChannel::DefaultPortRangeMax));
commonProperties.emplace("autoBind", cn.second.get<bool>("autoBind", FairMQChannel::DefaultAutoBind));
string name = cn.second.get<string>("name");
int numSockets = cn.second.get<int>("numSockets", 0);
if (numSockets > 0) {
LOG(trace) << name << ":";
LOG(trace) << "\tnumSockets of " << numSockets << " specified, applying common settings to each:";
for (auto& p : commonProperties) {
LOG(trace) << "\t" << setw(13) << left << p.first << " : " << p.second;
}
for (int i = 0; i < numSockets; ++i) {
for (const auto& p : commonProperties) {
properties.emplace(ToString("chans.", name, ".", i, ".", p.first), p.second);
}
}
} else {
SubChannelParser(cn.second.get_child(""), properties, name, commonProperties);
}
}
}
}
}
void SubChannelParser(const ptree& channelTree, fair::mq::Properties& properties, const string& channelName, const fair::mq::Properties& commonProperties)
{
// for each socket in channel
int i = 0;
for (const auto& node : channelTree) {
if (node.first == "sockets") {
for (const auto& sn : node.second) {
// a sub-channel inherits relevant properties from the common channel ...
fair::mq::Properties newProperties(commonProperties);
// ... and adds/overwrites its own properties
newProperties["type"] = sn.second.get<string>("type", boost::any_cast<string>(commonProperties.at("type")));
newProperties["method"] = sn.second.get<string>("method", boost::any_cast<string>(commonProperties.at("method")));
newProperties["address"] = sn.second.get<string>("address", boost::any_cast<string>(commonProperties.at("address")));
newProperties["transport"] = sn.second.get<string>("transport", boost::any_cast<string>(commonProperties.at("transport")));
newProperties["sndBufSize"] = sn.second.get<int>("sndBufSize", boost::any_cast<int>(commonProperties.at("sndBufSize")));
newProperties["rcvBufSize"] = sn.second.get<int>("rcvBufSize", boost::any_cast<int>(commonProperties.at("rcvBufSize")));
newProperties["sndKernelSize"] = sn.second.get<int>("sndKernelSize", boost::any_cast<int>(commonProperties.at("sndKernelSize")));
newProperties["rcvKernelSize"] = sn.second.get<int>("rcvKernelSize", boost::any_cast<int>(commonProperties.at("rcvKernelSize")));
newProperties["linger"] = sn.second.get<int>("linger", boost::any_cast<int>(commonProperties.at("linger")));
newProperties["rateLogging"] = sn.second.get<int>("rateLogging", boost::any_cast<int>(commonProperties.at("rateLogging")));
newProperties["portRangeMin"] = sn.second.get<int>("portRangeMin", boost::any_cast<int>(commonProperties.at("portRangeMin")));
newProperties["portRangeMax"] = sn.second.get<int>("portRangeMax", boost::any_cast<int>(commonProperties.at("portRangeMax")));
newProperties["autoBind"] = sn.second.get<bool>("autoBind", boost::any_cast<bool>(commonProperties.at("autoBind")));
LOG(trace) << "" << channelName << "[" << i << "]:";
for (auto& p : newProperties) {
LOG(trace) << "\t" << setw(13) << left << p.first << " : " << p.second;
}
for (const auto& p : newProperties) {
properties.emplace(ToString("chans.", channelName, ".", i, ".", p.first), p.second);
}
++i;
}
}
}
if (i > 0) {
LOG(trace) << "Found " << i << " socket(s) in channel.";
} else {
// if no sockets are specified, apply common channel properties
LOG(trace) << "" << channelName << ":";
LOG(trace) << "\tNo sockets specified,";
LOG(trace) << "\tapplying common settings to the channel:";
fair::mq::Properties newProperties(commonProperties);
for (auto& p : newProperties) {
LOG(trace) << "\t" << setw(13) << left << p.first << " : " << p.second;
}
for (const auto& p : newProperties) {
properties.emplace(ToString("chans.", channelName, ".0.", p.first), p.second);
}
}
}
} // helper namespace
} // namespace mq
} // namespace fair

51
fairmq/JSONParser.h Normal file
View File

@@ -0,0 +1,51 @@
/********************************************************************************
* Copyright (C) 2014-2018 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" *
********************************************************************************/
/*
* File: FairMQParser.h
* Author: winckler
*
* Created on May 14, 2015, 5:01 PM
*/
#ifndef FAIR_MQ_JSONPARSER_H
#define FAIR_MQ_JSONPARSER_H
#include <string>
#include <vector>
#include <unordered_map>
#include <exception>
#include <boost/property_tree/ptree_fwd.hpp>
#include "FairMQChannel.h"
#include <fairmq/Properties.h>
namespace fair
{
namespace mq
{
struct ParserError : std::runtime_error { using std::runtime_error::runtime_error; };
fair::mq::Properties PtreeParser(const boost::property_tree::ptree& pt, const std::string& deviceId);
fair::mq::Properties JSONParser(const std::string& filename, const std::string& deviceId);
namespace helper
{
fair::mq::Properties DeviceParser(const boost::property_tree::ptree& tree, const std::string& deviceId);
void ChannelParser(const boost::property_tree::ptree& tree, fair::mq::Properties& properties);
void SubChannelParser(const boost::property_tree::ptree& tree, fair::mq::Properties& properties, const std::string& channelName, const fair::mq::Properties& commonProperties);
} // helper namespace
} // namespace mq
} // namespace fair
#endif /* FAIR_MQ_JSONPARSER_H */

View File

@@ -79,19 +79,37 @@ class Plugin
auto StealDeviceControl() -> void { fPluginServices->StealDeviceControl(fkName); };
auto ReleaseDeviceControl() -> void { fPluginServices->ReleaseDeviceControl(fkName); };
auto ChangeDeviceState(const DeviceStateTransition next) -> bool { return fPluginServices->ChangeDeviceState(fkName, next); }
void TransitionDeviceStateTo(const DeviceState state) { return fPluginServices->TransitionDeviceStateTo(fkName, state); }
auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); }
auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); }
// device config API
// see <fairmq/PluginServices.h> for docs
auto PropertyExists(const std::string& key) -> int { return fPluginServices->PropertyExists(key); }
template<typename T>
auto SetProperty(const std::string& key, T val) -> void { fPluginServices->SetProperty(key, val); }
T GetProperty(const std::string& key) const { return fPluginServices->GetProperty<T>(key); }
template<typename T>
auto GetProperty(const std::string& key) const -> T { return fPluginServices->GetProperty<T>(key); }
auto GetPropertyAsString(const std::string& key) const -> std::string { return fPluginServices->GetPropertyAsString(key); }
T GetProperty(const std::string& key, const T& ifNotFound) const { return fPluginServices->GetProperty(key, ifNotFound); }
std::string GetPropertyAsString(const std::string& key) const { return fPluginServices->GetPropertyAsString(key); }
std::string GetPropertyAsString(const std::string& key, const std::string& ifNotFound) const { return fPluginServices->GetPropertyAsString(key, ifNotFound); }
fair::mq::Properties GetProperties(const std::string& q) const { return fPluginServices->GetProperties(q); }
fair::mq::Properties GetPropertiesStartingWith(const std::string& q) const { return fPluginServices->GetPropertiesStartingWith(q); };
std::map<std::string, std::string> GetPropertiesAsString(const std::string& q) const { return fPluginServices->GetPropertiesAsString(q); }
std::map<std::string, std::string> GetPropertiesAsStringStartingWith(const std::string& q) const { return fPluginServices->GetPropertiesAsStringStartingWith(q); };
auto GetChannelInfo() const -> std::unordered_map<std::string, int> { return fPluginServices->GetChannelInfo(); }
auto GetPropertyKeys() const -> std::vector<std::string> { return fPluginServices->GetPropertyKeys(); }
template<typename T>
auto SetProperty(const std::string& key, T val) -> void { fPluginServices->SetProperty(key, val); }
void SetProperties(const fair::mq::Properties& props) { fPluginServices->SetProperties(props); }
template<typename T>
bool UpdateProperty(const std::string& key, T val) { return fPluginServices->UpdateProperty(key, val); }
bool UpdateProperties(const fair::mq::Properties& input) { return fPluginServices->UpdateProperties(input); }
void DeleteProperty(const std::string& key) { fPluginServices->DeleteProperty(key); }
template<typename T>
auto SubscribeToPropertyChange(std::function<void(const std::string& key, T newValue)> callback) -> void { fPluginServices->SubscribeToPropertyChange<T>(fkName, callback); }
template<typename T>

View File

@@ -49,13 +49,11 @@ fair::mq::PluginManager::PluginManager(const vector<string> args)
// Parse command line options
auto options = ProgramOptions();
auto vm = po::variables_map{};
try
{
try {
auto parsed = po::command_line_parser(args).options(options).allow_unregistered().run();
po::store(parsed, vm);
po::notify(vm);
} catch (const po::error& e)
{
} catch (const po::error& e) {
throw ProgramOptionsParseError{ToString("Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
}
@@ -63,10 +61,8 @@ fair::mq::PluginManager::PluginManager(const vector<string> args)
auto append = vector<fs::path>{};
auto prepend = vector<fs::path>{};
auto searchPaths = vector<fs::path>{};
if (vm.count("plugin-search-path"))
{
for (const auto& path : vm["plugin-search-path"].as<vector<string>>())
{
if (vm.count("plugin-search-path")) {
for (const auto& path : vm["plugin-search-path"].as<vector<string>>()) {
if (path.substr(0, 1) == "<") { prepend.emplace_back(path.substr(1)); }
else if (path.substr(0, 1) == ">") { append.emplace_back(path.substr(1)); }
else { searchPaths.emplace_back(path); }
@@ -126,23 +122,16 @@ auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
{
if (pluginName.substr(0,2) == "p:")
{
if (pluginName.substr(0,2) == "p:") {
// Mechanism A: prelinked dynamic
LoadPluginPrelinkedDynamic(pluginName.substr(2));
}
else if (pluginName.substr(0,2) == "d:")
{
} else if (pluginName.substr(0,2) == "d:") {
// Mechanism B: dynamic
LoadPluginDynamic(pluginName.substr(2));
}
else if (pluginName.substr(0,2) == "s:")
{
} else if (pluginName.substr(0,2) == "s:") {
// Mechanism C: static (builtin)
LoadPluginStatic(pluginName.substr(2));
}
else
{
} else {
// Mechanism B: dynamic (default)
LoadPluginDynamic(pluginName);
}
@@ -151,15 +140,11 @@ auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
auto fair::mq::PluginManager::LoadPluginPrelinkedDynamic(const string& pluginName) -> void
{
// Load symbol
if (fPluginFactories.find(pluginName) == fPluginFactories.end())
{
try
{
if (fPluginFactories.find(pluginName) == fPluginFactories.end()) {
try {
LoadSymbols(pluginName, dll::program_location());
fPluginOrder.push_back(pluginName);
}
catch (boost::system::system_error& e)
{
} catch (boost::system::system_error& e) {
throw PluginLoadError(ToString("An error occurred while loading prelinked dynamic plugin ", pluginName, ": ", e.what()));
}
}
@@ -168,13 +153,11 @@ auto fair::mq::PluginManager::LoadPluginPrelinkedDynamic(const string& pluginNam
auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> void
{
// Search plugin and load, if found
if (fPluginFactories.find(pluginName) == fPluginFactories.end())
{
if (fPluginFactories.find(pluginName) == fPluginFactories.end()) {
auto success = false;
for (const auto& searchPath : SearchPaths()) {
try {
LoadSymbols(pluginName,
searchPath / ToString(LibPrefix(), pluginName),
LoadSymbols(pluginName, searchPath / ToString(LibPrefix(), pluginName),
dll::load_mode::append_decorations | dll::load_mode::rtld_global);
fPluginOrder.push_back(pluginName);
success = true;
@@ -213,15 +196,11 @@ auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> voi
auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
{
// Load symbol
if (fPluginFactories.find(pluginName) == fPluginFactories.end())
{
try
{
if (fPluginFactories.find(pluginName) == fPluginFactories.end()) {
try {
LoadSymbols(pluginName, dll::program_location());
fPluginOrder.push_back(pluginName);
}
catch (boost::system::system_error& e)
{
} catch (boost::system::system_error& e) {
throw PluginLoadError(ToString("An error occurred while loading static plugin ", pluginName, ": ", e.what()));
}
}
@@ -229,22 +208,17 @@ auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
auto fair::mq::PluginManager::InstantiatePlugin(const string& pluginName) -> void
{
if (fPlugins.find(pluginName) == fPlugins.end())
{
if (fPlugins.find(pluginName) == fPlugins.end()) {
fPlugins[pluginName] = fPluginFactories[pluginName](*fPluginServices);
}
}
auto fair::mq::PluginManager::InstantiatePlugins() -> void
{
for(const auto& pluginName : fPluginOrder)
{
try
{
for(const auto& pluginName : fPluginOrder) {
try {
InstantiatePlugin(pluginName);
}
catch (std::exception& e)
{
} catch (std::exception& e) {
throw PluginInstantiationError(ToString("An error occurred while instantiating plugin ", pluginName, ": ", e.what()));
}
}

View File

@@ -11,134 +11,47 @@
using namespace fair::mq;
using namespace std;
const std::unordered_map<std::string, PluginServices::DeviceState> PluginServices::fkDeviceStateStrMap = {
{"OK", DeviceState::Ok},
{"ERROR", DeviceState::Error},
{"IDLE", DeviceState::Idle},
{"INITIALIZING DEVICE", DeviceState::InitializingDevice},
{"INITIALIZED", DeviceState::Initialized},
{"BINDING", DeviceState::Binding},
{"BOUND", DeviceState::Bound},
{"CONNECTING", DeviceState::Connecting},
{"DEVICE READY", DeviceState::DeviceReady},
{"INITIALIZING TASK", DeviceState::InitializingTask},
{"READY", DeviceState::Ready},
{"RUNNING", DeviceState::Running},
{"RESETTING TASK", DeviceState::ResettingTask},
{"RESETTING DEVICE", DeviceState::ResettingDevice},
{"EXITING", DeviceState::Exiting}
};
const std::unordered_map<PluginServices::DeviceState, std::string, tools::HashEnum<PluginServices::DeviceState>> PluginServices::fkStrDeviceStateMap = {
{DeviceState::Ok, "OK"},
{DeviceState::Error, "ERROR"},
{DeviceState::Idle, "IDLE"},
{DeviceState::InitializingDevice, "INITIALIZING DEVICE"},
{DeviceState::Initialized, "INITIALIZED"},
{DeviceState::Binding, "BINDING"},
{DeviceState::Bound, "BOUND"},
{DeviceState::Connecting, "CONNECTING"},
{DeviceState::DeviceReady, "DEVICE READY"},
{DeviceState::InitializingTask, "INITIALIZING TASK"},
{DeviceState::Ready, "READY"},
{DeviceState::Running, "RUNNING"},
{DeviceState::ResettingTask, "RESETTING TASK"},
{DeviceState::ResettingDevice, "RESETTING DEVICE"},
{DeviceState::Exiting, "EXITING"}
};
const std::unordered_map<std::string, PluginServices::DeviceStateTransition> PluginServices::fkDeviceStateTransitionStrMap = {
{"AUTO", DeviceStateTransition::Auto},
{"INIT DEVICE", DeviceStateTransition::InitDevice},
{"COMPLETE INIT", DeviceStateTransition::CompleteInit},
{"BIND", DeviceStateTransition::Bind},
{"CONNECT", DeviceStateTransition::Connect},
{"INIT TASK", DeviceStateTransition::InitTask},
{"RUN", DeviceStateTransition::Run},
{"STOP", DeviceStateTransition::Stop},
{"RESET TASK", DeviceStateTransition::ResetTask},
{"RESET DEVICE", DeviceStateTransition::ResetDevice},
{"END", DeviceStateTransition::End},
{"ERROR FOUND", DeviceStateTransition::ErrorFound},
};
const std::unordered_map<PluginServices::DeviceStateTransition, std::string, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkStrDeviceStateTransitionMap = {
{DeviceStateTransition::Auto, "Auto"},
{DeviceStateTransition::InitDevice, "INIT DEVICE"},
{DeviceStateTransition::CompleteInit, "COMPLETE INIT"},
{DeviceStateTransition::Bind, "BIND"},
{DeviceStateTransition::Connect, "CONNECT"},
{DeviceStateTransition::InitTask, "INIT TASK"},
{DeviceStateTransition::Run, "RUN"},
{DeviceStateTransition::Stop, "STOP"},
{DeviceStateTransition::ResetTask, "RESET TASK"},
{DeviceStateTransition::ResetDevice, "RESET DEVICE"},
{DeviceStateTransition::End, "END"},
{DeviceStateTransition::ErrorFound, "ERROR FOUND"},
};
const std::unordered_map<fair::mq::State, PluginServices::DeviceState, fair::mq::tools::HashEnum<fair::mq::State>> PluginServices::fkDeviceStateMap = {
{fair::mq::State::Ok, DeviceState::Ok},
{fair::mq::State::Error, DeviceState::Error},
{fair::mq::State::Idle, DeviceState::Idle},
{fair::mq::State::InitializingDevice, DeviceState::InitializingDevice},
{fair::mq::State::Initialized, DeviceState::Initialized},
{fair::mq::State::Binding, DeviceState::Binding},
{fair::mq::State::Bound, DeviceState::Bound},
{fair::mq::State::Connecting, DeviceState::Connecting},
{fair::mq::State::DeviceReady, DeviceState::DeviceReady},
{fair::mq::State::InitializingTask, DeviceState::InitializingTask},
{fair::mq::State::Ready, DeviceState::Ready},
{fair::mq::State::Running, DeviceState::Running},
{fair::mq::State::ResettingTask, DeviceState::ResettingTask},
{fair::mq::State::ResettingDevice, DeviceState::ResettingDevice},
{fair::mq::State::Exiting, DeviceState::Exiting}
};
const std::unordered_map<PluginServices::DeviceStateTransition, fair::mq::Transition, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkDeviceStateTransitionMap = {
{DeviceStateTransition::Auto, fair::mq::Transition::Auto},
{DeviceStateTransition::InitDevice, fair::mq::Transition::InitDevice},
{DeviceStateTransition::CompleteInit, fair::mq::Transition::CompleteInit},
{DeviceStateTransition::Bind, fair::mq::Transition::Bind},
{DeviceStateTransition::Connect, fair::mq::Transition::Connect},
{DeviceStateTransition::InitTask, fair::mq::Transition::InitTask},
{DeviceStateTransition::Run, fair::mq::Transition::Run},
{DeviceStateTransition::Stop, fair::mq::Transition::Stop},
{DeviceStateTransition::ResetTask, fair::mq::Transition::ResetTask},
{DeviceStateTransition::ResetDevice, fair::mq::Transition::ResetDevice},
{DeviceStateTransition::End, fair::mq::Transition::End},
{DeviceStateTransition::ErrorFound, fair::mq::Transition::ErrorFound}
};
auto PluginServices::ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> bool
auto PluginServices::ChangeDeviceState(const string& controller, const DeviceStateTransition next) -> bool
{
lock_guard<mutex> lock{fDeviceControllerMutex};
if (!fDeviceController) fDeviceController = controller;
bool result = false;
if (fDeviceController == controller) {
result = fDevice.ChangeState(fkDeviceStateTransitionMap.at(next));
return fDevice.ChangeState(next);
} else {
throw DeviceControlError{tools::ToString(
"Plugin '", controller, "' is not allowed to change device states. ",
"Currently, plugin '", *fDeviceController, "' has taken control."
)};
}
return result;
}
auto PluginServices::TakeDeviceControl(const std::string& controller) -> void
void PluginServices::TransitionDeviceStateTo(const std::string& controller, DeviceState state)
{
lock_guard<mutex> lock{fDeviceControllerMutex};
if (!fDeviceController)
{
if (!fDeviceController) fDeviceController = controller;
if (fDeviceController == controller) {
fDevice.TransitionTo(state);
} else {
throw DeviceControlError{tools::ToString(
"Plugin '", controller, "' is not allowed to change device states. ",
"Currently, plugin '", *fDeviceController, "' has taken control."
)};
}
}
auto PluginServices::TakeDeviceControl(const string& controller) -> void
{
lock_guard<mutex> lock{fDeviceControllerMutex};
if (!fDeviceController) {
fDeviceController = controller;
}
else if (fDeviceController == controller)
{
} else if (fDeviceController == controller) {
// nothing to do
}
else
{
} else {
throw DeviceControlError{tools::ToString(
"Plugin '", controller, "' is not allowed to take over control. ",
"Currently, plugin '", *fDeviceController, "' has taken control."
@@ -146,24 +59,21 @@ auto PluginServices::TakeDeviceControl(const std::string& controller) -> void
}
}
auto PluginServices::StealDeviceControl(const std::string& controller) -> void
auto PluginServices::StealDeviceControl(const string& controller) -> void
{
lock_guard<mutex> lock{fDeviceControllerMutex};
fDeviceController = controller;
}
auto PluginServices::ReleaseDeviceControl(const std::string& controller) -> void
auto PluginServices::ReleaseDeviceControl(const string& controller) -> void
{
{
lock_guard<mutex> lock{fDeviceControllerMutex};
if (fDeviceController == controller)
{
if (fDeviceController == controller) {
fDeviceController = boost::none;
}
else
{
} else {
throw DeviceControlError{tools::ToString("Plugin '", controller, "' cannot release control because it has not taken over control.")};
}
}
@@ -171,7 +81,7 @@ auto PluginServices::ReleaseDeviceControl(const std::string& controller) -> void
fReleaseDeviceControlCondition.notify_one();
}
auto PluginServices::GetDeviceController() const -> boost::optional<std::string>
auto PluginServices::GetDeviceController() const -> boost::optional<string>
{
lock_guard<mutex> lock{fDeviceControllerMutex};
@@ -182,8 +92,7 @@ auto PluginServices::WaitForReleaseDeviceControl() -> void
{
unique_lock<mutex> lock{fDeviceControllerMutex};
while (fDeviceController)
{
while (fDeviceController) {
fReleaseDeviceControlCondition.wait(lock);
}
}

View File

@@ -10,8 +10,10 @@
#define FAIR_MQ_PLUGINSERVICES_H
#include <fairmq/Tools.h>
#include <fairmq/States.h>
#include <FairMQDevice.h>
#include <options/FairMQProgOptions.h>
#include <fairmq/ProgOptions.h>
#include <fairmq/Properties.h>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
@@ -20,6 +22,7 @@
#include <string>
#include <unordered_map>
#include <mutex>
#include <map>
#include <condition_variable>
#include <stdexcept>
@@ -39,7 +42,7 @@ class PluginServices
{
public:
PluginServices() = delete;
PluginServices(FairMQProgOptions& config, FairMQDevice& device)
PluginServices(ProgOptions& config, FairMQDevice& device)
: fConfig(config)
, fDevice(device)
, fDeviceController()
@@ -56,41 +59,8 @@ class PluginServices
PluginServices(const PluginServices&) = delete;
PluginServices operator=(const PluginServices&) = delete;
/// See https://github.com/FairRootGroup/FairRoot/blob/dev/fairmq/docs/Device.md#13-state-machine
enum class DeviceState : int
{
Ok,
Error,
Idle,
InitializingDevice,
Initialized,
Binding,
Bound,
Connecting,
DeviceReady,
InitializingTask,
Ready,
Running,
ResettingTask,
ResettingDevice,
Exiting
};
enum class DeviceStateTransition : int // transition event between DeviceStates
{
Auto,
InitDevice,
CompleteInit,
Bind,
Connect,
InitTask,
Run,
Stop,
ResetTask,
ResetDevice,
End,
ErrorFound
};
using DeviceState = fair::mq::State;
using DeviceStateTransition = fair::mq::Transition;
// Control API
@@ -98,29 +68,26 @@ class PluginServices
/// @param state to convert
/// @return DeviceState enum entry
/// @throw std::out_of_range if a string cannot be resolved to a DeviceState
static auto ToDeviceState(const std::string& state) -> DeviceState { return fkDeviceStateStrMap.at(state); }
static auto ToDeviceState(const std::string& state) -> DeviceState { return GetState(state); }
/// @brief Convert string to DeviceStateTransition
/// @param transition to convert
/// @return DeviceStateTransition enum entry
/// @throw std::out_of_range if a string cannot be resolved to a DeviceStateTransition
static auto ToDeviceStateTransition(const std::string& transition) -> DeviceStateTransition { return fkDeviceStateTransitionStrMap.at(transition); }
static auto ToDeviceStateTransition(const std::string& transition) -> DeviceStateTransition { return GetTransition(transition); }
/// @brief Convert DeviceState to string
/// @param state to convert
/// @return string representation of DeviceState enum entry
static auto ToStr(DeviceState state) -> std::string { return fkStrDeviceStateMap.at(state); }
static auto ToStr(DeviceState state) -> std::string { return GetStateName(state); }
/// @brief Convert DeviceStateTransition to string
/// @param transition to convert
/// @return string representation of DeviceStateTransition enum entry
static auto ToStr(DeviceStateTransition transition) -> std::string { return fkStrDeviceStateTransitionMap.at(transition); }
friend auto operator<<(std::ostream& os, const DeviceState& state) -> std::ostream& { return os << ToStr(state); }
friend auto operator<<(std::ostream& os, const DeviceStateTransition& transition) -> std::ostream& { return os << ToStr(transition); }
static auto ToStr(DeviceStateTransition transition) -> std::string { return GetTransitionName(transition); }
/// @return current device state
auto GetCurrentDeviceState() const -> DeviceState { return fkDeviceStateMap.at(static_cast<fair::mq::State>(fDevice.GetCurrentState())); }
auto GetCurrentDeviceState() const -> DeviceState { return fDevice.GetCurrentState(); }
/// @brief Become device controller
/// @param controller id
@@ -158,6 +125,8 @@ class PluginServices
/// If the device control role has not been taken yet, calling this function will take over control implicitely.
auto ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> bool;
void TransitionDeviceStateTo(const std::string& controller, DeviceState state);
/// @brief Subscribe with a callback to device state changes
/// @param subscriber id
/// @param callback
@@ -167,7 +136,7 @@ class PluginServices
auto SubscribeToDeviceStateChange(const std::string& subscriber, std::function<void(DeviceState /*newState*/)> callback) -> void
{
fDevice.SubscribeToStateChange(subscriber, [&,callback](fair::mq::State newState){
callback(fkDeviceStateMap.at(newState));
callback(newState);
});
}
@@ -176,62 +145,91 @@ class PluginServices
auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice.UnsubscribeFromStateChange(subscriber); }
// Config API
struct PropertyNotFoundError : std::runtime_error { using std::runtime_error::runtime_error; };
/// @brief Checks a property with the given key exist in the configuration
/// @param key
/// @return true if it exists, false otherwise
auto PropertyExists(const std::string& key) const -> bool { return fConfig.Count(key) > 0; }
/// @brief Set config property
/// @param key
/// @param val
/// @throws fair::mq::PluginServices::InvalidStateError if method is called in unsupported device states
///
/// Setting a config property will store the value in the FairMQ internal config store and notify any subscribers about the update.
/// It is property dependent, if the call to this method will have an immediate, delayed or any effect at all.
template<typename T>
auto SetProperty(const std::string& key, T val) -> void
{
auto currentState = GetCurrentDeviceState();
if ( (currentState == DeviceState::InitializingDevice)
|| (currentState == DeviceState::Initialized)
|| (currentState == DeviceState::Binding)
|| (currentState == DeviceState::Bound)
|| (currentState == DeviceState::Connecting)
|| (currentState == DeviceState::Idle && key == "channel-config")) {
fConfig.SetValue(key, val);
} else {
throw InvalidStateError{
tools::ToString("PluginServices::SetProperty is not supported in device state ", currentState, ". ",
"Supported state is ", DeviceState::InitializingDevice, ".")};
}
}
struct InvalidStateError : std::runtime_error { using std::runtime_error::runtime_error; };
/// @brief Read config property
auto SetProperty(const std::string& key, T val) -> void { fConfig.SetProperty(key, val); }
/// @brief Set multiple config properties
/// @param props fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any
void SetProperties(const fair::mq::Properties& props) { fConfig.SetProperties(props); }
/// @brief Updates an existing config property (or fails if it doesn't exist)
/// @param key
/// @return config property value
///
/// TODO Currently, if a non-existing key is requested and a default constructed object is returned.
/// This behaviour will be changed in the future to throw an exception in that case to provide a proper sentinel.
/// @param val
template<typename T>
auto GetProperty(const std::string& key) const -> T {
if (PropertyExists(key)) {
return fConfig.GetValue<T>(key);
}
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));
}
bool UpdateProperty(const std::string& key, T val) { return fConfig.UpdateProperty(key, val); }
/// @brief Updates multiple existing config properties (or fails of any of then do not exist, leaving property store unchanged)
/// @param props (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
bool UpdateProperties(const fair::mq::Properties& input) { return fConfig.UpdateProperties(input); }
/// @brief Read config property as string
/// @brief Deletes a property with the given key from the config store
/// @param key
/// @return config property value converted to string
///
/// If a type is not supported, the user can provide support by overloading the ostream operator for this type
auto GetPropertyAsString(const std::string& key) const -> std::string {
if (PropertyExists(key)) {
return fConfig.GetStringValue(key);
}
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));
}
void DeleteProperty(const std::string& key) { fConfig.DeleteProperty(key); }
/// @brief Read config property, throw if no property with this key exists
/// @param key
/// @return config property
template<typename T>
auto GetProperty(const std::string& key) const -> T { return fConfig.GetProperty<T>(key); }
/// @brief Read config property, return provided value if no property with this key exists
/// @param key
/// @param ifNotFound value to return if key is not found
/// @return config property
template<typename T>
T GetProperty(const std::string& key, const T& ifNotFound) const { return fConfig.GetProperty(key, ifNotFound); }
/// @brief Read config property as string, throw if no property with this key exists
/// @param key
/// @return config property converted to string
///
/// Supports conversion to string for a fixed set of types,
/// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`
/// the provided type must then be convertible to string via operator<<
auto GetPropertyAsString(const std::string& key) const -> std::string { return fConfig.GetPropertyAsString(key); }
/// @brief Read config property, return provided value if no property with this key exists
/// @param key
/// @param ifNotFound value to return if key is not found
/// @return config property converted to string
///
/// Supports conversion to string for a fixed set of types,
/// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`
/// the provided type must then be convertible to string via operator<<
auto GetPropertyAsString(const std::string& key, const std::string& ifNotFound) const -> std::string { return fConfig.GetPropertyAsString(key, ifNotFound); }
/// @brief Read several config properties whose keys match the provided regular expression
/// @param q regex string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
fair::mq::Properties GetProperties(const std::string& q) const { return fConfig.GetProperties(q); }
/// @brief Read several config properties whose keys start with the provided string
/// @param q string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
///
/// Typically more performant than GetProperties with regex
fair::mq::Properties GetPropertiesStartingWith(const std::string& q) const { return fConfig.GetPropertiesStartingWith(q); }
/// @brief Read several config properties as string whose keys match the provided regular expression
/// @param q regex string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
std::map<std::string, std::string> GetPropertiesAsString(const std::string& q) const { return fConfig.GetPropertiesAsString(q); }
/// @brief Read several config properties as string whose keys start with the provided string
/// @param q string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
///
/// Typically more performant than GetPropertiesAsString with regex
std::map<std::string, std::string> GetPropertiesAsStringStartingWith(const std::string& q) const { return fConfig.GetPropertiesAsStringStartingWith(q); }
/// @brief Retrieve current channel information
/// @return a map of <channel name, number of subchannels>
auto GetChannelInfo() const -> std::unordered_map<std::string, int> { return fConfig.GetChannelInfo(); }
/// @brief Discover the list of property keys
@@ -268,20 +266,17 @@ class PluginServices
/// @param subscriber
auto UnsubscribeFromPropertyChangeAsString(const std::string& subscriber) -> void { fConfig.UnsubscribeAsString(subscriber); }
/// @brief Increases console logging severity, or sets it to lowest if it is already highest
auto CycleLogConsoleSeverityUp() -> void { Logger::CycleConsoleSeverityUp(); }
/// @brief Decreases console logging severity, or sets it to highest if it is already lowest
auto CycleLogConsoleSeverityDown() -> void { Logger::CycleConsoleSeverityDown(); }
/// @brief Increases logging verbosity, or sets it to lowest if it is already highest
auto CycleLogVerbosityUp() -> void { Logger::CycleVerbosityUp(); }
/// @brief Decreases logging verbosity, or sets it to highest if it is already lowest
auto CycleLogVerbosityDown() -> void { Logger::CycleVerbosityDown(); }
static const std::unordered_map<std::string, DeviceState> fkDeviceStateStrMap;
static const std::unordered_map<DeviceState, std::string, tools::HashEnum<DeviceState>> fkStrDeviceStateMap;
static const std::unordered_map<std::string, DeviceStateTransition> fkDeviceStateTransitionStrMap;
static const std::unordered_map<DeviceStateTransition, std::string, tools::HashEnum<DeviceStateTransition>> fkStrDeviceStateTransitionMap;
static const std::unordered_map<fair::mq::State, DeviceState, tools::HashEnum<fair::mq::State>> fkDeviceStateMap;
static const std::unordered_map<DeviceStateTransition, fair::mq::Transition, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap;
private:
FairMQProgOptions& fConfig;
fair::mq::ProgOptions& fConfig;
FairMQDevice& fDevice;
boost::optional<std::string> fDeviceController;
mutable std::mutex fDeviceControllerMutex;

446
fairmq/ProgOptions.cxx Normal file
View File

@@ -0,0 +1,446 @@
/********************************************************************************
* Copyright (C) 2014-2018 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" *
********************************************************************************/
/*
* File: ProgOptions.cxx
* Author: winckler
*
* Created on March 11, 2015, 10:20 PM
*/
#include "FairMQLogger.h"
#include <fairmq/ProgOptions.h>
#include "tools/Unique.h"
#include <boost/any.hpp>
#include <boost/regex.hpp>
#include <algorithm>
#include <exception>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <utility> // pair
using namespace std;
using namespace fair::mq;
namespace po = boost::program_options;
struct ValInfo
{
string value;
string type;
string origin;
};
namespace fair
{
namespace mq
{
ValInfo ConvertVarValToValInfo(const po::variable_value& v)
{
string origin;
if (v.defaulted()) {
origin = "[default]";
} else if (v.empty()) {
origin = "[empty]";
} else {
origin = "[provided]";
}
try {
pair<string, string> info = PropertyHelper::GetPropertyInfo(v.value());
return {info.first, info.second, origin};
} catch (out_of_range& oor) {
return {string("[unidentified_type]"), string("[unidentified_type]"), origin};
}
};
string ConvertVarValToString(const po::variable_value& v)
{
return ConvertVarValToValInfo(v).value;
}
ProgOptions::ProgOptions()
: fVarMap()
, fAllOptions("FairMQ Command Line Options")
, fUnregisteredOptions()
, fEvents()
, fMtx()
{
fAllOptions.add_options()
("help,h", "Print help")
("version,v", "Print version")
("severity", po::value<string>()->default_value("debug"), "Log severity level (console): trace, debug, info, state, warn, error, fatal, nolog")
("file-severity", po::value<string>()->default_value("debug"), "Log severity level (file): trace, debug, info, state, warn, error, fatal, nolog")
("verbosity", po::value<string>()->default_value("medium"), "Log verbosity level: veryhigh, high, medium, low")
("color", po::value<bool >()->default_value(true), "Log color (true/false)")
("log-to-file", po::value<string>()->default_value(""), "Log output to a file.")
("print-options", po::value<bool >()->implicit_value(true), "Print options in machine-readable format (<option>:<computed-value>:<type>:<description>)");
ParseDefaults();
}
void ProgOptions::ParseDefaults()
{
vector<string> emptyArgs = {"dummy"};
vector<const char*> argv(emptyArgs.size());
transform(emptyArgs.begin(), emptyArgs.end(), argv.begin(), [](const string& str) {
return str.c_str();
});
po::store(po::parse_command_line(argv.size(), const_cast<char**>(argv.data()), fAllOptions), fVarMap);
}
void ProgOptions::ParseAll(const vector<string>& cmdArgs, bool allowUnregistered)
{
vector<const char*> argv(cmdArgs.size());
transform(cmdArgs.begin(), cmdArgs.end(), argv.begin(), [](const string& str) {
return str.c_str();
});
ParseAll(argv.size(), const_cast<char**>(argv.data()), allowUnregistered);
}
void ProgOptions::ParseAll(const int argc, char const* const* argv, bool allowUnregistered)
{
lock_guard<mutex> lock(fMtx);
// clear the container because it was filled with default values and subsequent calls to store() do not overwrite the existing values
fVarMap.clear();
if (allowUnregistered) {
po::command_line_parser parser(argc, argv);
parser.options(fAllOptions).allow_unregistered();
po::parsed_options parsed = parser.run();
fUnregisteredOptions = po::collect_unrecognized(parsed.options, po::include_positional);
po::store(parsed, fVarMap);
} else {
po::store(po::parse_command_line(argc, argv, fAllOptions), fVarMap);
}
}
void ProgOptions::Notify()
{
lock_guard<mutex> lock(fMtx);
po::notify(fVarMap);
}
void ProgOptions::AddToCmdLineOptions(const po::options_description optDesc, bool /* visible */)
{
lock_guard<mutex> lock(fMtx);
fAllOptions.add(optDesc);
}
po::options_description& ProgOptions::GetCmdLineOptions()
{
return fAllOptions;
}
int ProgOptions::Count(const string& key) const
{
lock_guard<mutex> lock(fMtx);
return fVarMap.count(key);
}
unordered_map<string, int> ProgOptions::GetChannelInfo() const
{
lock_guard<mutex> lock(fMtx);
return GetChannelInfoImpl();
}
unordered_map<string, int> ProgOptions::GetChannelInfoImpl() const
{
unordered_map<string, int> info;
boost::regex re("chans\\..*\\.type");
for (const auto& m : fVarMap) {
if (boost::regex_match(m.first, re)) {
string chan = m.first.substr(6);
string::size_type n = chan.find(".");
string chanName = chan.substr(0, n);
if (info.find(chanName) == info.end()) {
info.emplace(chanName, 1);
} else {
info[chanName] = info[chanName] + 1;
}
}
}
return info;
}
vector<string> ProgOptions::GetPropertyKeys() const
{
lock_guard<mutex> lock(fMtx);
vector<string> keys;
for (const auto& it : fVarMap) {
keys.push_back(it.first.c_str());
}
return keys;
}
string ProgOptions::GetPropertyAsString(const string& key) const
{
lock_guard<mutex> lock(fMtx);
if (fVarMap.count(key)) {
return ConvertVarValToString(fVarMap.at(key));
} else {
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));
}
}
string ProgOptions::GetStringValue(const string& key) const
{
lock_guard<mutex> lock(fMtx);
if (fVarMap.count(key)) {
return ConvertVarValToString(fVarMap.at(key));
} else {
LOG(warn) << "Config has no key: " << key << ". Returning default constructed object.";
return string();
}
}
string ProgOptions::GetPropertyAsString(const string& key, const string& ifNotFound) const
{
lock_guard<mutex> lock(fMtx);
if (fVarMap.count(key)) {
return ConvertVarValToString(fVarMap.at(key));
}
return ifNotFound;
}
Properties ProgOptions::GetProperties(const string& q) const
{
boost::regex re(q);
Properties properties;
lock_guard<mutex> lock(fMtx);
for (const auto& m : fVarMap) {
if (boost::regex_match(m.first, re)) {
properties.emplace(m.first, m.second.value());
}
}
if (properties.size() == 0) {
LOG(warn) << "could not find anything with \"" << q << "\"";
}
return properties;
}
Properties ProgOptions::GetPropertiesStartingWith(const string& q) const
{
Properties properties;
lock_guard<mutex> lock(fMtx);
for (const auto& m : fVarMap) {
if (m.first.compare(0, q.length(), q) == 0) {
properties.emplace(m.first, m.second.value());
}
}
return properties;
}
map<string, string> ProgOptions::GetPropertiesAsString(const string& q) const
{
boost::regex re(q);
map<string, string> properties;
lock_guard<mutex> lock(fMtx);
for (const auto& m : fVarMap) {
if (boost::regex_match(m.first, re)) {
properties.emplace(m.first, PropertyHelper::ConvertPropertyToString(m.second.value()));
}
}
if (properties.size() == 0) {
LOG(warn) << "could not find anything with \"" << q << "\"";
}
return properties;
}
map<string, string> ProgOptions::GetPropertiesAsStringStartingWith(const string& q) const
{
map<string, string> properties;
lock_guard<mutex> lock(fMtx);
for (const auto& m : fVarMap) {
if (m.first.compare(0, q.length(), q) == 0) {
properties.emplace(m.first, PropertyHelper::ConvertPropertyToString(m.second.value()));
}
}
return properties;
}
void ProgOptions::SetProperties(const Properties& input)
{
unique_lock<mutex> lock(fMtx);
map<string, boost::program_options::variable_value>& vm = fVarMap;
for (const auto& m : input) {
vm[m.first].value() = m.second;
}
lock.unlock();
for (const auto& m : input) {
PropertyHelper::fEventEmitters.at(m.second.type())(fEvents, m.first, m.second);
fEvents.Emit<PropertyChangeAsString, string>(m.first, PropertyHelper::ConvertPropertyToString(m.second));
}
}
bool ProgOptions::UpdateProperties(const Properties& input)
{
unique_lock<mutex> lock(fMtx);
for (const auto& m : input) {
if (fVarMap.count(m.first) == 0) {
LOG(debug) << "UpdateProperties failed, no property found with key '" << m.first << "'";
return false;
}
}
map<string, boost::program_options::variable_value>& vm = fVarMap;
for (const auto& m : input) {
vm[m.first].value() = m.second;
}
lock.unlock();
for (const auto& m : input) {
PropertyHelper::fEventEmitters.at(m.second.type())(fEvents, m.first, m.second);
fEvents.Emit<PropertyChangeAsString, string>(m.first, PropertyHelper::ConvertPropertyToString(m.second));
}
return true;
}
void ProgOptions::DeleteProperty(const string& key)
{
lock_guard<mutex> lock(fMtx);
map<string, boost::program_options::variable_value>& vm = fVarMap;
vm.erase(key);
}
void ProgOptions::AddChannel(const string& name, const FairMQChannel& channel)
{
lock_guard<mutex> lock(fMtx);
unordered_map<string, int> existingChannels = GetChannelInfoImpl();
int index = 0;
if (existingChannels.count(name) > 0) {
index = existingChannels.at(name);
}
string prefix = fair::mq::tools::ToString("chans.", name, ".", index, ".");
SetVarMapValue<string>(string(prefix + "type"), channel.GetType());
SetVarMapValue<string>(string(prefix + "method"), channel.GetMethod());
SetVarMapValue<string>(string(prefix + "address"), channel.GetAddress());
SetVarMapValue<string>(string(prefix + "transport"), channel.GetTransportName());
SetVarMapValue<int>(string(prefix + "sndBufSize"), channel.GetSndBufSize());
SetVarMapValue<int>(string(prefix + "rcvBufSize"), channel.GetRcvBufSize());
SetVarMapValue<int>(string(prefix + "sndKernelSize"), channel.GetSndKernelSize());
SetVarMapValue<int>(string(prefix + "rcvKernelSize"), channel.GetRcvKernelSize());
SetVarMapValue<int>(string(prefix + "linger"), channel.GetLinger());
SetVarMapValue<int>(string(prefix + "rateLogging"), channel.GetRateLogging());
SetVarMapValue<int>(string(prefix + "portRangeMin"), channel.GetPortRangeMin());
SetVarMapValue<int>(string(prefix + "portRangeMax"), channel.GetPortRangeMax());
SetVarMapValue<bool>(string(prefix + "autoBind"), channel.GetAutoBind());
}
void ProgOptions::PrintHelp() const
{
cout << fAllOptions << endl;
}
void ProgOptions::PrintOptions() const
{
map<string, ValInfo> mapinfo;
int maxLenKey = 0;
int maxLenValue = 0;
int maxLenType = 0;
int maxLenDefault = 0;
for (const auto& m : fVarMap) {
maxLenKey = max(maxLenKey, static_cast<int>(m.first.length()));
ValInfo valinfo = ConvertVarValToValInfo(m.second);
mapinfo[m.first] = valinfo;
maxLenValue = max(maxLenValue, static_cast<int>(valinfo.value.length()));
maxLenType = max(maxLenType, static_cast<int>(valinfo.type.length()));
maxLenDefault = max(maxLenDefault, static_cast<int>(valinfo.origin.length()));
}
if (maxLenValue > 100) {
maxLenValue = 100;
}
for (const auto& o : fUnregisteredOptions) {
LOG(debug) << "detected unregistered option: " << o;
}
stringstream ss;
ss << "Configuration: \n";
for (const auto& p : mapinfo) {
string type("<" + p.second.type + ">");
ss << setfill(' ') << left
<< setw(maxLenKey) << p.first << " = "
<< setw(maxLenValue) << p.second.value << " "
<< setw(maxLenType + 2) << type << " "
<< setw(maxLenDefault) << p.second.origin
<< "\n";
}
LOG(debug) << ss.str();
}
void ProgOptions::PrintOptionsRaw() const
{
const vector<boost::shared_ptr<po::option_description>>& options = fAllOptions.options();
for (const auto& o : options) {
ValInfo value;
if (fVarMap.count(o->canonical_display_name())) {
value = ConvertVarValToValInfo(fVarMap[o->canonical_display_name()]);
}
string description = o->description();
replace(description.begin(), description.end(), '\n', ' ');
cout << o->long_name() << ":" << value.value << ":" << (value.type == "" ? "<unknown>" : value.type) << ":" << description << endl;
}
}
} // namespace mq
} // namespace fair

276
fairmq/ProgOptions.h Normal file
View File

@@ -0,0 +1,276 @@
/********************************************************************************
* Copyright (C) 2014-2018 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_PROGOPTIONS_H
#define FAIR_MQ_PROGOPTIONS_H
#include "FairMQChannel.h"
#include "FairMQLogger.h"
#include <fairmq/EventManager.h>
#include <fairmq/ProgOptionsFwd.h>
#include <fairmq/Properties.h>
#include <fairmq/Tools.h>
#include <boost/program_options.hpp>
#include <functional>
#include <map>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <stdexcept>
namespace fair
{
namespace mq
{
struct PropertyNotFoundError : std::runtime_error { using std::runtime_error::runtime_error; };
class ProgOptions
{
public:
ProgOptions();
virtual ~ProgOptions() {}
void ParseAll(const std::vector<std::string>& cmdArgs, bool allowUnregistered);
void ParseAll(const int argc, char const* const* argv, bool allowUnregistered = true);
void Notify();
void AddToCmdLineOptions(const boost::program_options::options_description optDesc, bool visible = true);
boost::program_options::options_description& GetCmdLineOptions();
/// @brief Checks a property with the given key exist in the configuration
/// @param key
/// @return 1 if it exists, 0 otherwise
int Count(const std::string& key) const;
/// @brief Retrieve current channel information
/// @return a map of <channel name, number of subchannels>
std::unordered_map<std::string, int> GetChannelInfo() const;
/// @brief Discover the list of property keys
/// @return list of property keys
std::vector<std::string> GetPropertyKeys() const;
/// @brief Read config property, throw if no property with this key exists
/// @param key
/// @return config property
template<typename T>
T GetProperty(const std::string& key) const
{
std::lock_guard<std::mutex> lock(fMtx);
if (fVarMap.count(key)) {
return fVarMap[key].as<T>();
} else {
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));
}
}
/// @brief Read config property, return provided value if no property with this key exists
/// @param key
/// @param ifNotFound value to return if key is not found
/// @return config property
template<typename T>
T GetProperty(const std::string& key, const T& ifNotFound) const
{
std::lock_guard<std::mutex> lock(fMtx);
if (fVarMap.count(key)) {
return fVarMap[key].as<T>();
}
return ifNotFound;
}
/// @brief Read config property as string, throw if no property with this key exists
/// @param key
/// @return config property converted to string
///
/// Supports conversion to string for a fixed set of types,
/// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`
/// the provided type must then be convertible to string via operator<<
std::string GetPropertyAsString(const std::string& key) const;
/// @brief Read config property, return provided value if no property with this key exists
/// @param key
/// @param ifNotFound value to return if key is not found
/// @return config property converted to string
///
/// Supports conversion to string for a fixed set of types,
/// for custom/unsupported types add them via `fair::mq::PropertyHelper::AddType<MyType>("optional label")`
/// the provided type must then be convertible to string via operator<<
std::string GetPropertyAsString(const std::string& key, const std::string& ifNotFound) const;
/// @brief Read several config properties whose keys match the provided regular expression
/// @param q regex string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
fair::mq::Properties GetProperties(const std::string& q) const;
/// @brief Read several config properties whose keys start with the provided string
/// @param q string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
///
/// Typically more performant than GetProperties with regex
fair::mq::Properties GetPropertiesStartingWith(const std::string& q) const;
/// @brief Read several config properties as string whose keys match the provided regular expression
/// @param q regex string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
std::map<std::string, std::string> GetPropertiesAsString(const std::string& q) const;
/// @brief Read several config properties as string whose keys start with the provided string
/// @param q string to match for
/// @return container with properties (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
///
/// Typically more performant than GetPropertiesAsString with regex
std::map<std::string, std::string> GetPropertiesAsStringStartingWith(const std::string& q) const;
/// @brief Set config property
/// @param key
/// @param val
template<typename T>
void SetProperty(const std::string& key, T val)
{
std::unique_lock<std::mutex> lock(fMtx);
SetVarMapValue<typename std::decay<T>::type>(key, val);
lock.unlock();
fEvents.Emit<fair::mq::PropertyChange, typename std::decay<T>::type>(key, val);
fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetPropertyAsString(key));
}
/// @brief Updates an existing config property (or fails if it doesn't exist)
/// @param key
/// @param val
template<typename T>
bool UpdateProperty(const std::string& key, T val)
{
std::unique_lock<std::mutex> lock(fMtx);
if (fVarMap.count(key)) {
SetVarMapValue<typename std::decay<T>::type>(key, val);
lock.unlock();
fEvents.Emit<fair::mq::PropertyChange, typename std::decay<T>::type>(key, val);
fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetPropertyAsString(key));
return true;
} else {
LOG(debug) << "UpdateProperty failed, no property found with key '" << key << "'";
return false;
}
}
/// @brief Set multiple config properties
/// @param props fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any
void SetProperties(const fair::mq::Properties& input);
/// @brief Updates multiple existing config properties (or fails of any of then do not exist, leaving property store unchanged)
/// @param props (fair::mq::Properties as an alias for std::map<std::string, Property>, where property is boost::any)
bool UpdateProperties(const fair::mq::Properties& input);
/// @brief Deletes a property with the given key from the config store
/// @param key
void DeleteProperty(const std::string& key);
/// @brief Takes the provided channel and creates properties based on it
/// @param name channel name
/// @param channel FairMQChannel reference
void AddChannel(const std::string& name, const FairMQChannel& channel);
/// @brief Subscribe to property updates of type T
/// @param subscriber
/// @param callback function
///
/// Subscribe to property changes with a callback to monitor property changes in an event based fashion.
template<typename T>
void Subscribe(const std::string& subscriber, std::function<void(typename fair::mq::PropertyChange::KeyType, T)> func) const
{
std::lock_guard<std::mutex> lock(fMtx);
static_assert(!std::is_same<T,const char*>::value || !std::is_same<T, char*>::value,
"In template member ProgOptions::Subscribe<T>(key,Lambda) the types const char* or char* for the calback signatures are not supported.");
fEvents.Subscribe<fair::mq::PropertyChange, T>(subscriber, func);
}
/// @brief Unsubscribe from property updates of type T
/// @param subscriber
template<typename T>
void Unsubscribe(const std::string& subscriber) const
{
std::lock_guard<std::mutex> lock(fMtx);
fEvents.Unsubscribe<fair::mq::PropertyChange, T>(subscriber);
}
/// @brief Subscribe to property updates, with values converted to string
/// @param subscriber
/// @param callback function
///
/// Subscribe to property changes with a callback to monitor property changes in an event based fashion. Will convert the property to string.
void SubscribeAsString(const std::string& subscriber, std::function<void(typename fair::mq::PropertyChange::KeyType, std::string)> func) const
{
std::lock_guard<std::mutex> lock(fMtx);
fEvents.Subscribe<fair::mq::PropertyChangeAsString, std::string>(subscriber, func);
}
/// @brief Unsubscribe from property updates that convert to string
/// @param subscriber
void UnsubscribeAsString(const std::string& subscriber) const
{
std::lock_guard<std::mutex> lock(fMtx);
fEvents.Unsubscribe<fair::mq::PropertyChangeAsString, std::string>(subscriber);
}
/// @brief prints full options description
void PrintHelp() const;
/// @brief prints properties stored in the property container
void PrintOptions() const;
/// @brief prints full options description in a compact machine-readable format
void PrintOptionsRaw() const;
/// @brief returns the property container
const boost::program_options::variables_map& GetVarMap() const { return fVarMap; }
/// @brief Read config property, return default-constructed object if key doesn't exist
/// @param key
/// @return config property
template<typename T>
T GetValue(const std::string& key) const /* TODO: deprecate this */
{
std::lock_guard<std::mutex> lock(fMtx);
if (fVarMap.count(key)) {
return fVarMap[key].as<T>();
} else {
LOG(warn) << "Config has no key: " << key << ". Returning default constructed object.";
return T();
}
}
template<typename T>
int SetValue(const std::string& key, T val) /* TODO: deprecate this */ { SetProperty(key, val); return 0; }
/// @brief Read config property as string, return default-constructed object if key doesn't exist
/// @param key
/// @return config property
std::string GetStringValue(const std::string& key) const; /* TODO: deprecate this */
private:
void ParseDefaults();
std::unordered_map<std::string, int> GetChannelInfoImpl() const;
template<typename T>
void SetVarMapValue(const std::string& key, const T& val)
{
std::map<std::string, boost::program_options::variable_value>& vm = fVarMap;
vm[key].value() = boost::any(val);
}
boost::program_options::variables_map fVarMap; ///< options container
boost::program_options::options_description fAllOptions; ///< all options descriptions
std::vector<std::string> fUnregisteredOptions; ///< container with unregistered options
mutable fair::mq::EventManager fEvents;
mutable std::mutex fMtx;
};
} // namespace mq
} // namespace fair
#endif /* FAIR_MQ_PROGOPTIONS_H */

Some files were not shown because too many files have changed in this diff Show More