9 #ifndef FAIR_MQ_SDK_TOPOLOGY_H 10 #define FAIR_MQ_SDK_TOPOLOGY_H 12 #include <fairmq/sdk/AsioAsyncOp.h> 13 #include <fairmq/sdk/AsioBase.h> 14 #include <fairmq/sdk/commands/Commands.h> 15 #include <fairmq/sdk/DDSCollection.h> 16 #include <fairmq/sdk/DDSInfo.h> 17 #include <fairmq/sdk/DDSSession.h> 18 #include <fairmq/sdk/DDSTask.h> 19 #include <fairmq/sdk/DDSTopology.h> 20 #include <fairmq/sdk/Error.h> 21 #include <fairmq/States.h> 22 #include <fairmq/tools/Semaphore.h> 23 #include <fairmq/tools/Unique.h> 25 #include <fairlogger/Logger.h> 30 #include <asio/associated_executor.hpp> 31 #include <asio/async_result.hpp> 32 #include <asio/steady_timer.hpp> 33 #include <asio/system_executor.hpp> 37 #include <condition_variable> 47 #include <unordered_map> 55 using DeviceId = std::string;
56 using DeviceState = fair::mq::State;
57 using DeviceTransition = fair::mq::Transition;
59 const std::map<DeviceTransition, DeviceState> expectedState =
61 { DeviceTransition::InitDevice, DeviceState::InitializingDevice },
62 { DeviceTransition::CompleteInit, DeviceState::Initialized },
63 { DeviceTransition::Bind, DeviceState::Bound },
64 { DeviceTransition::Connect, DeviceState::DeviceReady },
65 { DeviceTransition::InitTask, DeviceState::Ready },
66 { DeviceTransition::Run, DeviceState::Running },
67 { DeviceTransition::Stop, DeviceState::Ready },
68 { DeviceTransition::ResetTask, DeviceState::DeviceReady },
69 { DeviceTransition::ResetDevice, DeviceState::Idle },
70 { DeviceTransition::End, DeviceState::Exiting }
75 bool subscribed_to_state_changes;
76 DeviceState lastState;
79 DDSCollection::Id collectionId;
82 using DeviceProperty = std::pair<std::string, std::string>;
83 using DeviceProperties = std::vector<DeviceProperty>;
84 using DevicePropertyQuery = std::string;
85 using FailedDevices = std::set<DeviceId>;
91 DeviceProperties props;
93 std::unordered_map<DeviceId, Device> devices;
97 using TopologyState = std::vector<DeviceStatus>;
98 using TopologyStateIndex = std::unordered_map<DDSTask::Id, int>;
99 using TopologyStateByTask = std::unordered_map<DDSTask::Id, DeviceStatus>;
100 using TopologyStateByCollection = std::unordered_map<DDSCollection::Id, std::vector<DeviceStatus>>;
101 using TopologyTransition = fair::mq::Transition;
103 inline DeviceState AggregateState(
const TopologyState& topologyState)
105 DeviceState first = topologyState.begin()->state;
107 if (std::all_of(topologyState.cbegin(), topologyState.cend(), [&](TopologyState::value_type i) {
108 return i.state == first;
116 inline bool StateEqualsTo(
const TopologyState& topologyState, DeviceState state)
118 return AggregateState(topologyState) == state;
121 inline TopologyStateByCollection GroupByCollectionId(
const TopologyState& topologyState)
123 TopologyStateByCollection state;
124 for (
const auto& ds : topologyState) {
125 if (ds.collectionId != 0) {
126 state[ds.collectionId].push_back(ds);
133 inline TopologyStateByTask GroupByTaskId(
const TopologyState& topologyState)
135 TopologyStateByTask state;
136 for (
const auto& ds : topologyState) {
137 state[ds.taskId] = ds;
153 template <
typename Executor,
typename Allocator>
172 Allocator alloc = DefaultAllocator())
173 :
AsioBase<Executor, Allocator>(ex,
std::move(alloc))
174 , fDDSSession(
std::move(session))
175 , fDDSTopo(
std::move(topo))
178 , fHeartbeatsTimer(
asio::system_executor())
179 , fHeartbeatInterval(600000)
183 std::string activeTopo(fDDSSession.RequestCommanderInfo().activeTopologyName);
184 std::string givenTopo(fDDSTopo.GetName());
185 if (activeTopo != givenTopo) {
186 throw RuntimeError(
"Given topology ", givenTopo,
" is not activated (active: ", activeTopo,
")");
189 SubscribeToCommands();
191 fDDSSession.StartDDSService();
192 SubscribeToStateChanges();
205 UnsubscribeFromStateChanges();
207 std::lock_guard<std::mutex> lk(fMtx);
208 fDDSSession.UnsubscribeFromCommands();
210 for (
auto& op : fChangeStateOps) {
211 op.second.Complete(MakeErrorCode(ErrorCode::OperationCanceled));
216 void SubscribeToStateChanges()
219 cmd::Cmds cmds(cmd::make<cmd::SubscribeToStateChange>(fHeartbeatInterval.count()));
220 fDDSSession.SendCommand(cmds.Serialize());
222 fHeartbeatsTimer.expires_after(fHeartbeatInterval);
223 fHeartbeatsTimer.async_wait(std::bind(&BasicTopology::SendSubscriptionHeartbeats,
this, std::placeholders::_1));
226 void SendSubscriptionHeartbeats(
const std::error_code& ec)
230 fDDSSession.SendCommand(
cmd::Cmds(cmd::make<cmd::SubscriptionHeartbeat>(fHeartbeatInterval.count())).Serialize());
232 fHeartbeatsTimer.expires_after(fHeartbeatInterval);
233 fHeartbeatsTimer.async_wait(std::bind(&BasicTopology::SendSubscriptionHeartbeats,
this, std::placeholders::_1));
234 }
else if (ec == asio::error::operation_aborted) {
237 FAIR_LOG(error) <<
"Timer error: " << ec;
241 void UnsubscribeFromStateChanges()
244 fHeartbeatsTimer.cancel();
247 fDDSSession.SendCommand(
cmd::Cmds(cmd::make<cmd::UnsubscribeFromStateChange>()).Serialize());
250 std::unique_lock<std::mutex> lk(fMtx);
251 fStateChangeUnsubscriptionCV.wait(lk, [&](){
252 unsigned int count = std::count_if(fStateIndex.cbegin(), fStateIndex.cend(), [=](
const auto& s) {
253 return fStateData.at(s.second).subscribed_to_state_changes ==
false;
255 return count == fStateIndex.size();
259 void SubscribeToCommands()
261 fDDSSession.SubscribeToCommands([&](
const std::string& msg,
const std::string& , DDSChannel::Id senderId) {
263 inCmds.Deserialize(msg);
266 for (
const auto& cmd : inCmds) {
268 switch (cmd->GetType()) {
269 case cmd::Type::state_change_subscription:
270 HandleCmd(static_cast<cmd::StateChangeSubscription&>(*cmd));
272 case cmd::Type::state_change_unsubscription:
273 HandleCmd(static_cast<cmd::StateChangeUnsubscription&>(*cmd));
275 case cmd::Type::state_change:
276 HandleCmd(static_cast<cmd::StateChange&>(*cmd), senderId);
278 case cmd::Type::transition_status:
279 HandleCmd(static_cast<cmd::TransitionStatus&>(*cmd));
281 case cmd::Type::properties:
282 HandleCmd(static_cast<cmd::Properties&>(*cmd));
284 case cmd::Type::properties_set:
285 HandleCmd(static_cast<cmd::PropertiesSet&>(*cmd));
288 FAIR_LOG(warn) <<
"Unexpected/unknown command received: " << cmd->GetType();
289 FAIR_LOG(warn) <<
"Origin: " << senderId;
298 if (cmd.GetResult() == cmd::Result::Ok) {
299 DDSTask::Id taskId(cmd.GetTaskId());
302 std::lock_guard<std::mutex> lk(fMtx);
303 DeviceStatus& task = fStateData.at(fStateIndex.at(taskId));
304 task.subscribed_to_state_changes =
true;
305 }
catch (
const std::exception& e) {
306 FAIR_LOG(error) <<
"Exception in HandleCmd(cmd::StateChangeSubscription const&): " << e.what();
309 FAIR_LOG(error) <<
"State change subscription failed for device: " << cmd.GetDeviceId() <<
", task id: " << cmd.GetTaskId();
315 if (cmd.GetResult() == cmd::Result::Ok) {
316 DDSTask::Id taskId(cmd.GetTaskId());
319 std::unique_lock<std::mutex> lk(fMtx);
320 DeviceStatus& task = fStateData.at(fStateIndex.at(taskId));
321 task.subscribed_to_state_changes =
false;
323 fStateChangeUnsubscriptionCV.notify_one();
324 }
catch (
const std::exception& e) {
325 FAIR_LOG(error) <<
"Exception in HandleCmd(cmd::StateChangeUnsubscription const&): " << e.what();
328 FAIR_LOG(error) <<
"State change unsubscription failed for device: " << cmd.GetDeviceId() <<
", task id: " << cmd.GetTaskId();
332 auto HandleCmd(
cmd::StateChange const& cmd, DDSChannel::Id
const& senderId) ->
void 334 if (cmd.GetCurrentState() == DeviceState::Exiting) {
335 fDDSSession.SendCommand(
cmd::Cmds(cmd::make<cmd::StateChangeExitingReceived>()).Serialize(), senderId);
338 DDSTask::Id taskId(cmd.GetTaskId());
341 std::lock_guard<std::mutex> lk(fMtx);
342 DeviceStatus& task = fStateData.at(fStateIndex.at(taskId));
343 task.lastState = cmd.GetLastState();
344 task.state = cmd.GetCurrentState();
346 if (task.state == DeviceState::Exiting) {
347 task.subscribed_to_state_changes =
false;
351 for (
auto& op : fChangeStateOps) {
352 op.second.Update(taskId, cmd.GetCurrentState());
354 for (
auto& op : fWaitForStateOps) {
355 op.second.Update(taskId, cmd.GetLastState(), cmd.GetCurrentState());
357 }
catch (
const std::exception& e) {
358 FAIR_LOG(error) <<
"Exception in HandleCmd(cmd::StateChange const&): " << e.what();
364 if (cmd.GetResult() != cmd::Result::Ok) {
365 FAIR_LOG(error) << cmd.GetTransition() <<
" transition failed for " << cmd.GetDeviceId();
366 DDSTask::Id taskId(cmd.GetTaskId());
367 std::lock_guard<std::mutex> lk(fMtx);
368 for (
auto& op : fChangeStateOps) {
369 if (!op.second.IsCompleted() && op.second.ContainsTask(taskId) &&
370 fStateData.at(fStateIndex.at(taskId)).state != op.second.GetTargetState()) {
371 op.second.Complete(MakeErrorCode(ErrorCode::DeviceChangeStateFailed));
379 std::unique_lock<std::mutex> lk(fMtx);
381 auto& op(fGetPropertiesOps.at(cmd.GetRequestId()));
383 op.Update(cmd.GetDeviceId(), cmd.GetResult(), cmd.GetProps());
384 }
catch (std::out_of_range& e) {
385 FAIR_LOG(debug) <<
"GetProperties operation (request id: " << cmd.GetRequestId()
386 <<
") not found (probably completed or timed out), " 387 <<
"discarding reply of device " << cmd.GetDeviceId();
393 std::unique_lock<std::mutex> lk(fMtx);
395 auto& op(fSetPropertiesOps.at(cmd.GetRequestId()));
397 op.Update(cmd.GetDeviceId(), cmd.GetResult());
398 }
catch (std::out_of_range& e) {
399 FAIR_LOG(debug) <<
"SetProperties operation (request id: " << cmd.GetRequestId()
400 <<
") not found (probably completed or timed out), " 401 <<
"discarding reply of device " << cmd.GetDeviceId();
405 using Duration = std::chrono::milliseconds;
406 using ChangeStateCompletionSignature = void(std::error_code, TopologyState);
411 using Id = std::size_t;
412 using Count =
unsigned int;
414 template<
typename Handler>
416 const TopologyTransition transition,
417 std::vector<DDSTask> tasks,
418 TopologyState& stateData,
422 Allocator
const & alloc,
425 , fOp(ex, alloc, std::move(handler))
426 , fStateData(stateData)
429 , fTasks(std::move(tasks))
430 , fTargetState(expectedState.at(transition))
433 if (timeout > std::chrono::milliseconds(0)) {
434 fTimer.expires_after(timeout);
435 fTimer.async_wait([&](std::error_code ec) {
437 std::lock_guard<std::mutex> lk(fMtx);
438 fOp.Timeout(fStateData);
443 ChangeStateOp() =
delete;
444 ChangeStateOp(
const ChangeStateOp&) =
delete;
445 ChangeStateOp& operator=(
const ChangeStateOp&) =
delete;
446 ChangeStateOp(ChangeStateOp&&) =
default;
447 ChangeStateOp& operator=(ChangeStateOp&&) =
default;
448 ~ChangeStateOp() =
default;
451 auto ResetCount(
const TopologyStateIndex& stateIndex,
const TopologyState& stateData) ->
void 453 fCount = std::count_if(stateIndex.cbegin(), stateIndex.cend(), [=](
const auto& s) {
454 if (ContainsTask(stateData.at(s.second).taskId)) {
455 return stateData.at(s.second).state == fTargetState;
463 auto Update(
const DDSTask::Id taskId,
const DeviceState currentState) ->
void 465 if (!fOp.IsCompleted() && ContainsTask(taskId)) {
466 if (currentState == fTargetState) {
474 auto TryCompletion() ->
void 476 if (!fOp.IsCompleted() && fCount == fTasks.size()) {
477 Complete(std::error_code());
482 auto Complete(std::error_code ec) ->
void 485 fOp.Complete(ec, fStateData);
489 auto ContainsTask(DDSTask::Id
id) ->
bool 491 auto it = std::find_if(fTasks.begin(), fTasks.end(), [id](
const DDSTask& t) {
return t.GetId() == id; });
492 return it != fTasks.end();
495 bool IsCompleted() {
return fOp.IsCompleted(); }
497 auto GetTargetState()
const -> DeviceState {
return fTargetState; }
502 TopologyState& fStateData;
503 asio::steady_timer fTimer;
505 std::vector<DDSTask> fTasks;
506 DeviceState fTargetState;
588 template<
typename CompletionToken>
590 const std::string& path,
592 CompletionToken&& token)
594 return asio::async_initiate<CompletionToken, ChangeStateCompletionSignature>([&](
auto handler) {
595 typename ChangeStateOp::Id
const id(tools::UuidHash());
597 std::lock_guard<std::mutex> lk(fMtx);
599 for (
auto it = begin(fChangeStateOps); it != end(fChangeStateOps);) {
600 if (it->second.IsCompleted()) {
601 it = fChangeStateOps.erase(it);
607 auto p = fChangeStateOps.emplace(
608 std::piecewise_construct,
609 std::forward_as_tuple(
id),
610 std::forward_as_tuple(
id,
612 fDDSTopo.GetTasks(path),
618 std::move(handler)));
620 cmd::Cmds cmds(cmd::make<cmd::ChangeState>(transition));
621 fDDSSession.SendCommand(cmds.Serialize(), path);
623 p.first->second.ResetCount(fStateIndex, fStateData);
625 p.first->second.TryCompletion();
636 template<
typename CompletionToken>
639 return AsyncChangeState(transition,
"", Duration(0), std::move(token));
648 template<
typename CompletionToken>
649 auto AsyncChangeState(
const TopologyTransition transition, Duration timeout, CompletionToken&& token)
651 return AsyncChangeState(transition,
"", timeout, std::move(token));
660 template<
typename CompletionToken>
661 auto AsyncChangeState(
const TopologyTransition transition,
const std::string& path, CompletionToken&& token)
663 return AsyncChangeState(transition, path, Duration(0), std::move(token));
671 auto ChangeState(
const TopologyTransition transition,
const std::string& path =
"", Duration timeout = Duration(0))
672 -> std::pair<std::error_code, TopologyState>
677 AsyncChangeState(transition, path, timeout, [&, blocker](std::error_code _ec, TopologyState _state)
mutable {
690 auto ChangeState(
const TopologyTransition transition, Duration timeout)
691 -> std::pair<std::error_code, TopologyState>
693 return ChangeState(transition,
"", timeout);
700 std::lock_guard<std::mutex> lk(fMtx);
704 auto AggregateState()
const -> DeviceState {
return sdk::AggregateState(GetCurrentState()); }
706 auto StateEqualsTo(DeviceState state)
const ->
bool {
return sdk::StateEqualsTo(GetCurrentState(), state); }
708 using WaitForStateCompletionSignature = void(std::error_code);
711 struct WaitForStateOp
713 using Id = std::size_t;
714 using Count =
unsigned int;
716 template<
typename Handler>
717 WaitForStateOp(Id
id,
718 DeviceState targetLastState,
719 DeviceState targetCurrentState,
720 std::vector<DDSTask> tasks,
724 Allocator
const & alloc,
727 , fOp(ex, alloc, std::move(handler))
730 , fTasks(std::move(tasks))
731 , fTargetLastState(targetLastState)
732 , fTargetCurrentState(targetCurrentState)
735 if (timeout > std::chrono::milliseconds(0)) {
736 fTimer.expires_after(timeout);
737 fTimer.async_wait([&](std::error_code ec) {
739 std::lock_guard<std::mutex> lk(fMtx);
745 WaitForStateOp() =
delete;
746 WaitForStateOp(
const WaitForStateOp&) =
delete;
747 WaitForStateOp& operator=(
const WaitForStateOp&) =
delete;
748 WaitForStateOp(WaitForStateOp&&) =
default;
749 WaitForStateOp& operator=(WaitForStateOp&&) =
default;
750 ~WaitForStateOp() =
default;
753 auto ResetCount(
const TopologyStateIndex& stateIndex,
const TopologyState& stateData) ->
void 755 fCount = std::count_if(stateIndex.cbegin(), stateIndex.cend(), [=](
const auto& s) {
756 if (ContainsTask(stateData.at(s.second).taskId)) {
757 return stateData.at(s.second).state == fTargetCurrentState
759 (stateData.at(s.second).lastState == fTargetLastState || fTargetLastState == DeviceState::Ok);
767 auto Update(
const DDSTask::Id taskId,
const DeviceState lastState,
const DeviceState currentState) ->
void 769 if (!fOp.IsCompleted() && ContainsTask(taskId)) {
770 if (currentState == fTargetCurrentState &&
771 (lastState == fTargetLastState ||
772 fTargetLastState == DeviceState::Ok)) {
780 auto TryCompletion() ->
void 782 if (!fOp.IsCompleted() && fCount == fTasks.size()) {
788 bool IsCompleted() {
return fOp.IsCompleted(); }
793 asio::steady_timer fTimer;
795 std::vector<DDSTask> fTasks;
796 DeviceState fTargetLastState;
797 DeviceState fTargetCurrentState;
801 auto ContainsTask(DDSTask::Id
id) ->
bool 803 auto it = std::find_if(fTasks.begin(), fTasks.end(), [id](
const DDSTask& t) {
return t.GetId() == id; });
804 return it != fTasks.end();
817 template<
typename CompletionToken>
819 const DeviceState targetCurrentState,
820 const std::string& path,
822 CompletionToken&& token)
824 return asio::async_initiate<CompletionToken, WaitForStateCompletionSignature>([&](
auto handler) {
825 typename GetPropertiesOp::Id
const id(tools::UuidHash());
827 std::lock_guard<std::mutex> lk(fMtx);
829 for (
auto it = begin(fWaitForStateOps); it != end(fWaitForStateOps);) {
830 if (it->second.IsCompleted()) {
831 it = fWaitForStateOps.erase(it);
837 auto p = fWaitForStateOps.emplace(
838 std::piecewise_construct,
839 std::forward_as_tuple(
id),
840 std::forward_as_tuple(
id,
843 fDDSTopo.GetTasks(path),
848 std::move(handler)));
849 p.first->second.ResetCount(fStateIndex, fStateData);
851 p.first->second.TryCompletion();
862 template<
typename CompletionToken>
863 auto AsyncWaitForState(
const DeviceState targetLastState,
const DeviceState targetCurrentState, CompletionToken&& token)
865 return AsyncWaitForState(targetLastState, targetCurrentState,
"", Duration(0), std::move(token));
873 template<
typename CompletionToken>
876 return AsyncWaitForState(DeviceState::Ok, targetCurrentState,
"", Duration(0), std::move(token));
885 auto WaitForState(
const DeviceState targetLastState,
const DeviceState targetCurrentState,
const std::string& path =
"", Duration timeout = Duration(0))
890 AsyncWaitForState(targetLastState, targetCurrentState, path, timeout, [&, blocker](std::error_code _ec)
mutable {
903 auto WaitForState(
const DeviceState targetCurrentState,
const std::string& path =
"", Duration timeout = Duration(0))
906 return WaitForState(DeviceState::Ok, targetCurrentState, path, timeout);
912 struct GetPropertiesOp
914 using Id = std::size_t;
915 using GetCount =
unsigned int;
917 template<
typename Handler>
918 GetPropertiesOp(Id
id,
919 GetCount expectedCount,
923 Allocator
const & alloc,
926 , fOp(ex, alloc, std::move(handler))
929 , fExpectedCount(expectedCount)
932 if (timeout > std::chrono::milliseconds(0)) {
933 fTimer.expires_after(timeout);
934 fTimer.async_wait([&](std::error_code ec) {
936 std::lock_guard<std::mutex> lk(fMtx);
937 fOp.Timeout(fResult);
943 GetPropertiesOp() =
delete;
944 GetPropertiesOp(
const GetPropertiesOp&) =
delete;
945 GetPropertiesOp& operator=(
const GetPropertiesOp&) =
delete;
946 GetPropertiesOp(GetPropertiesOp&&) =
default;
947 GetPropertiesOp& operator=(GetPropertiesOp&&) =
default;
948 ~GetPropertiesOp() =
default;
950 auto Update(
const std::string& deviceId, cmd::Result result, DeviceProperties props) ->
void 952 std::lock_guard<std::mutex> lk(fMtx);
953 if (cmd::Result::Ok != result) {
954 fResult.failed.insert(deviceId);
956 fResult.devices.insert({deviceId, {std::move(props)}});
962 bool IsCompleted() {
return fOp.IsCompleted(); }
967 asio::steady_timer fTimer;
969 GetCount
const fExpectedCount;
974 auto TryCompletion() ->
void 976 if (!fOp.IsCompleted() && fCount == fExpectedCount) {
978 if (fResult.failed.size() > 0) {
979 fOp.Complete(MakeErrorCode(ErrorCode::DeviceGetPropertiesFailed), std::move(fResult));
981 fOp.Complete(std::move(fResult));
995 template<
typename CompletionToken>
997 const std::string& path,
999 CompletionToken&& token)
1001 return asio::async_initiate<CompletionToken, GetPropertiesCompletionSignature>(
1003 typename GetPropertiesOp::Id
const id(tools::UuidHash());
1005 std::lock_guard<std::mutex> lk(fMtx);
1007 for (
auto it = begin(fGetPropertiesOps); it != end(fGetPropertiesOps);) {
1008 if (it->second.IsCompleted()) {
1009 it = fGetPropertiesOps.erase(it);
1015 fGetPropertiesOps.emplace(
1016 std::piecewise_construct,
1017 std::forward_as_tuple(
id),
1018 std::forward_as_tuple(
id,
1019 fDDSTopo.GetTasks(path).size(),
1024 std::move(handler)));
1026 cmd::Cmds const cmds(cmd::make<cmd::GetProperties>(
id, query));
1027 fDDSSession.SendCommand(cmds.Serialize(), path);
1037 template<
typename CompletionToken>
1040 return AsyncGetProperties(query,
"", Duration(0), std::move(token));
1048 auto GetProperties(DevicePropertyQuery
const& query,
const std::string& path =
"", Duration timeout = Duration(0))
1049 -> std::pair<std::error_code, GetPropertiesResult>
1054 AsyncGetProperties(query, path, timeout, [&, blocker](std::error_code _ec,
GetPropertiesResult _result)
mutable {
1060 return {ec, result};
1063 using SetPropertiesCompletionSignature = void(std::error_code, FailedDevices);
1066 struct SetPropertiesOp
1068 using Id = std::size_t;
1069 using SetCount =
unsigned int;
1071 template<
typename Handler>
1072 SetPropertiesOp(Id
id,
1073 SetCount expectedCount,
1076 Executor
const & ex,
1077 Allocator
const & alloc,
1080 , fOp(ex, alloc, std::move(handler))
1083 , fExpectedCount(expectedCount)
1087 if (timeout > std::chrono::milliseconds(0)) {
1088 fTimer.expires_after(timeout);
1089 fTimer.async_wait([&](std::error_code ec) {
1091 std::lock_guard<std::mutex> lk(fMtx);
1092 fOp.Timeout(fFailedDevices);
1098 SetPropertiesOp() =
delete;
1099 SetPropertiesOp(
const SetPropertiesOp&) =
delete;
1100 SetPropertiesOp& operator=(
const SetPropertiesOp&) =
delete;
1101 SetPropertiesOp(SetPropertiesOp&&) =
default;
1102 SetPropertiesOp& operator=(SetPropertiesOp&&) =
default;
1103 ~SetPropertiesOp() =
default;
1105 auto Update(
const std::string& deviceId, cmd::Result result) ->
void 1107 std::lock_guard<std::mutex> lk(fMtx);
1108 if (cmd::Result::Ok != result) {
1109 fFailedDevices.insert(deviceId);
1115 bool IsCompleted() {
return fOp.IsCompleted(); }
1120 asio::steady_timer fTimer;
1122 SetCount
const fExpectedCount;
1123 FailedDevices fFailedDevices;
1127 auto TryCompletion() ->
void 1129 if (!fOp.IsCompleted() && fCount == fExpectedCount) {
1131 if (fFailedDevices.size() > 0) {
1132 fOp.Complete(MakeErrorCode(ErrorCode::DeviceSetPropertiesFailed), fFailedDevices);
1134 fOp.Complete(fFailedDevices);
1148 template<
typename CompletionToken>
1150 const std::string& path,
1152 CompletionToken&& token)
1154 return asio::async_initiate<CompletionToken, SetPropertiesCompletionSignature>(
1156 typename SetPropertiesOp::Id
const id(tools::UuidHash());
1158 std::lock_guard<std::mutex> lk(fMtx);
1160 for (
auto it = begin(fGetPropertiesOps); it != end(fGetPropertiesOps);) {
1161 if (it->second.IsCompleted()) {
1162 it = fGetPropertiesOps.erase(it);
1168 fSetPropertiesOps.emplace(
1169 std::piecewise_construct,
1170 std::forward_as_tuple(
id),
1171 std::forward_as_tuple(
id,
1172 fDDSTopo.GetTasks(path).size(),
1177 std::move(handler)));
1179 cmd::Cmds const cmds(cmd::make<cmd::SetProperties>(
id, props));
1180 fDDSSession.SendCommand(cmds.Serialize(), path);
1190 template<
typename CompletionToken>
1193 return AsyncSetProperties(props,
"", Duration(0), std::move(token));
1201 auto SetProperties(DeviceProperties
const& properties,
const std::string& path =
"", Duration timeout = Duration(0))
1202 -> std::pair<std::error_code, FailedDevices>
1206 FailedDevices failed;
1207 AsyncSetProperties(properties, path, timeout, [&, blocker](std::error_code _ec, FailedDevices _failed)
mutable {
1213 return {ec, failed};
1216 Duration GetHeartbeatInterval()
const {
return fHeartbeatInterval; }
1217 void SetHeartbeatInterval(Duration duration) { fHeartbeatInterval = duration; }
1220 using TransitionedCount =
unsigned int;
1224 TopologyState fStateData;
1225 TopologyStateIndex fStateIndex;
1227 mutable std::mutex fMtx;
1229 std::condition_variable fStateChangeUnsubscriptionCV;
1230 asio::steady_timer fHeartbeatsTimer;
1231 Duration fHeartbeatInterval;
1233 std::unordered_map<typename ChangeStateOp::Id, ChangeStateOp> fChangeStateOps;
1234 std::unordered_map<typename WaitForStateOp::Id, WaitForStateOp> fWaitForStateOps;
1235 std::unordered_map<typename SetPropertiesOp::Id, SetPropertiesOp> fSetPropertiesOps;
1236 std::unordered_map<typename GetPropertiesOp::Id, GetPropertiesOp> fGetPropertiesOps;
1238 auto makeTopologyState() ->
void 1240 fStateData.reserve(fDDSTopo.
GetTasks().size());
1244 for (
const auto& task : fDDSTopo.
GetTasks()) {
1245 fStateData.push_back(
DeviceStatus{
false, DeviceState::Ok, DeviceState::Ok, task.GetId(), task.GetCollectionId()});
1246 fStateIndex.emplace(task.GetId(), index);
1252 auto GetCurrentStateUnsafe()
const -> TopologyState
1265 auto MakeTopology(dds::topology_api::CTopology nativeTopo,
1266 std::shared_ptr<dds::tools_api::CSession> nativeSession,
Represents a FairMQ topology.
Definition: Topology.h:154
Represents a DDS session.
Definition: DDSSession.h:56
auto AsyncChangeState(const TopologyTransition transition, CompletionToken &&token)
Initiate state transition on all FairMQ devices in this topology.
Definition: Topology.h:637
Definition: Topology.h:87
auto GetExecutor() const noexcept -> ExecutorType
Get associated I/O executor.
Definition: AsioBase.h:41
Definition: Commands.h:233
auto AsyncSetProperties(DeviceProperties const &props, CompletionToken &&token)
Initiate property update on selected FairMQ devices in this topology.
Definition: Topology.h:1191
Definition: Commands.h:189
auto GetAllocator() const noexcept -> AllocatorType
Get associated default allocator.
Definition: AsioBase.h:46
Base for creating Asio-enabled I/O objects.
Definition: AsioBase.h:35
auto AsyncWaitForState(const DeviceState targetCurrentState, CompletionToken &&token)
Initiate waiting for selected FairMQ devices to reach given current state in this topology...
Definition: Topology.h:874
auto AsyncWaitForState(const DeviceState targetLastState, const DeviceState targetCurrentState, CompletionToken &&token)
Initiate waiting for selected FairMQ devices to reach given last & current state in this topology...
Definition: Topology.h:863
Definition: Topology.h:89
auto WaitForState(const DeviceState targetLastState, const DeviceState targetCurrentState, const std::string &path="", Duration timeout=Duration(0)) -> std::error_code
Wait for selected FairMQ devices to reach given last & current state in this topology.
Definition: Topology.h:885
auto AsyncWaitForState(const DeviceState targetLastState, const DeviceState targetCurrentState, const std::string &path, Duration timeout, CompletionToken &&token)
Initiate waiting for selected FairMQ devices to reach given last & current state in this topology...
Definition: Topology.h:818
Represents a DDS task.
Definition: DDSTask.h:25
auto AsyncChangeState(const TopologyTransition transition, Duration timeout, CompletionToken &&token)
Initiate state transition on all FairMQ devices in this topology with a timeout.
Definition: Topology.h:649
Definition: Commands.h:303
auto AsyncGetProperties(DevicePropertyQuery const &query, CompletionToken &&token)
Initiate property query on selected FairMQ devices in this topology.
Definition: Topology.h:1038
auto AsyncChangeState(const TopologyTransition transition, const std::string &path, Duration timeout, CompletionToken &&token)
Initiate state transition on all FairMQ devices in this topology.
Definition: Topology.h:589
auto ChangeState(const TopologyTransition transition, const std::string &path="", Duration timeout=Duration(0)) -> std::pair< std::error_code, TopologyState >
Perform state transition on FairMQ devices in this topology for a specified topology path...
Definition: Topology.h:671
auto ChangeState(const TopologyTransition transition, Duration timeout) -> std::pair< std::error_code, TopologyState >
Perform state transition on all FairMQ devices in this topology with a timeout.
Definition: Topology.h:690
Definition: Topology.h:73
auto AsyncSetProperties(const DeviceProperties &props, const std::string &path, Duration timeout, CompletionToken &&token)
Initiate property update on selected FairMQ devices in this topology.
Definition: Topology.h:1149
auto AsyncGetProperties(DevicePropertyQuery const &query, const std::string &path, Duration timeout, CompletionToken &&token)
Initiate property query on selected FairMQ devices in this topology.
Definition: Topology.h:996
auto GetTasks(const std::string &="") const -> std::vector< DDSTask >
Get list of tasks in this topology, optionally matching provided path.
Definition: DDSTopology.cxx:67
Definition: Commands.h:329
Definition: Commands.h:356
auto GetCurrentState() const -> TopologyState
Returns the current state of the topology.
Definition: Topology.h:698
BasicTopology(const Executor &ex, DDSTopology topo, DDSSession session, Allocator alloc=DefaultAllocator())
(Re)Construct a FairMQ topology from an existing DDS topology
Definition: Topology.h:169
auto GetProperties(DevicePropertyQuery const &query, const std::string &path="", Duration timeout=Duration(0)) -> std::pair< std::error_code, GetPropertiesResult >
Query properties on selected FairMQ devices in this topology.
Definition: Topology.h:1048
Definition: Commands.h:277
Tools for interfacing containers to the transport via polymorphic allocators.
Definition: DeviceRunner.h:23
auto SetProperties(DeviceProperties const &properties, const std::string &path="", Duration timeout=Duration(0)) -> std::pair< std::error_code, FailedDevices >
Set properties on selected FairMQ devices in this topology.
Definition: Topology.h:1201
BasicTopology(DDSTopology topo, DDSSession session)
(Re)Construct a FairMQ topology from an existing DDS topology
Definition: Topology.h:160
auto WaitForState(const DeviceState targetCurrentState, const std::string &path="", Duration timeout=Duration(0)) -> std::error_code
Wait for selected FairMQ devices to reach given current state in this topology.
Definition: Topology.h:903
Sets up the DDS environment (object helper)
Definition: DDSEnvironment.h:24
Definition: Commands.h:255
Represents a DDS topology.
Definition: DDSTopology.h:29
auto AsyncChangeState(const TopologyTransition transition, const std::string &path, CompletionToken &&token)
Initiate state transition on all FairMQ devices in this topology with a timeout.
Definition: Topology.h:661