LCOV - code coverage report
Current view: top level - confmodel/src - dalMethods.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 31.6 % 244 77
Test Date: 2026-10-11 15:05:20 Functions: 45.7 % 35 16

            Line data    Source code
       1              : /**
       2              :  * @file dalMethods.cxx
       3              :  *
       4              :  * Implementations of Methods defined in confmodel schema classes
       5              :  *
       6              :  * This is part of the DUNE DAQ Software Suite, copyright 2020.
       7              :  * Licensing/copyright details are in the COPYING file that you should have
       8              :  * received with this code.
       9              :  */
      10              : 
      11              : #include "confmodel/Application.hpp"
      12              : #include "confmodel/DaqApplication.hpp"
      13              : #include "confmodel/DaqModule.hpp"
      14              : #include "confmodel/DetDataReceiver.hpp"
      15              : #include "confmodel/DetDataSender.hpp"
      16              : #include "confmodel/DetectorStream.hpp"
      17              : #include "confmodel/DetectorToDaqConnection.hpp"
      18              : #include "confmodel/ExcludableEntity.hpp"
      19              : #include "confmodel/ExcludableEntitySet.hpp"
      20              : #include "confmodel/Jsonable.hpp"
      21              : #include "confmodel/OpMonURI.hpp"
      22              : #include "confmodel/PhysicalHost.hpp"
      23              : #include "confmodel/RCApplication.hpp"
      24              : #include "confmodel/Segment.hpp"
      25              : #include "confmodel/Service.hpp"
      26              : #include "confmodel/Session.hpp"
      27              : #include "confmodel/VirtualHost.hpp"
      28              : #include "confmodel/confmodelIssues.hpp"
      29              : 
      30              : #include "confmodel/test_circular_dependency.hpp"
      31              : 
      32              : #include "conffwk/ConfigObject.hpp"
      33              : #include "conffwk/Configuration.hpp"
      34              : #include "conffwk/Schema.hpp"
      35              : #include "nlohmann/json.hpp"
      36              : 
      37              : #include <iostream>
      38              : #include <list>
      39              : #include <set>
      40              : 
      41              : using namespace dunedaq::conffwk;
      42              : 
      43              : // Stolen from ATLAS dal package
      44              : namespace {
      45              : /**
      46              :  *  Static function to calculate list of components
      47              :  *  from the root segment to the lowest component which
      48              :  *  the child object (a segment or a resource) belongs.
      49              :  */
      50              : 
      51              : void
      52            0 : make_parents_list(const ConfigObjectImpl* child,
      53              :                   const dunedaq::confmodel::ExcludableEntitySet* resource_set,
      54              :                   std::vector<const dunedaq::confmodel::ExcludableEntity*>& p_list,
      55              :                   std::list<std::vector<const dunedaq::confmodel::ExcludableEntity*>>& out,
      56              :                   dunedaq::confmodel::TestCircularDependency& cd_fuse)
      57              : {
      58            0 :   dunedaq::confmodel::AddTestOnCircularDependency add_fuse_test(cd_fuse, resource_set);
      59              : 
      60              :   // add the resource set to the path
      61            0 :   p_list.push_back(resource_set);
      62              : 
      63              :   // check if the application is in the resource relationship, i.e. is a resource or belongs to resource set(s)
      64            0 :   for (const auto& i : resource_set->contained_excludable_entities()) {
      65            0 :     if (i->config_object().implementation() == child) {
      66            0 :       out.push_back(p_list);
      67            0 :     } else if (const dunedaq::confmodel::ExcludableEntitySet* rs = i->cast<dunedaq::confmodel::ExcludableEntitySet>()) {
      68            0 :       make_parents_list(child, rs, p_list, out, cd_fuse);
      69              :     }
      70            0 :   }
      71              : 
      72              :   // remove the resource set from the path
      73            0 :   p_list.pop_back();
      74            0 : }
      75              : 
      76              : void
      77            0 : make_parents_list(const dunedaq::conffwk::ConfigObjectImpl* child,
      78              :                   const dunedaq::confmodel::Segment* segment,
      79              :                   std::vector<const dunedaq::confmodel::ExcludableEntity*>& p_list,
      80              :                   std::list<std::vector<const dunedaq::confmodel::ExcludableEntity*>>& out,
      81              :                   bool is_segment,
      82              :                   dunedaq::confmodel::TestCircularDependency& cd_fuse)
      83              : {
      84            0 :   dunedaq::confmodel::AddTestOnCircularDependency add_fuse_test(cd_fuse, segment);
      85              : 
      86              :   // add the segment to the path
      87            0 :   p_list.push_back(segment);
      88              : 
      89              :   // check if the application is in the nested segment
      90            0 :   for (const auto& seg : segment->get_segments()) {
      91            0 :     if (seg->config_object().implementation() == child)
      92            0 :       out.push_back(p_list);
      93              :     else
      94            0 :       make_parents_list(child, seg, p_list, out, is_segment, cd_fuse);
      95              :   }
      96            0 :   if (!is_segment) {
      97            0 :     for (const auto& app : segment->get_applications()) {
      98            0 :       if (app->config_object().implementation() == child)
      99            0 :         out.push_back(p_list);
     100            0 :       else if (const auto resource_set = app->cast<dunedaq::confmodel::ExcludableEntitySet>())
     101            0 :         make_parents_list(child, resource_set, p_list, out, cd_fuse);
     102              :     }
     103              :   }
     104              : 
     105              :   // remove the segment from the path
     106              : 
     107            0 :   p_list.pop_back();
     108            0 : }
     109              : 
     110              : void
     111            0 : check_segment(std::list<std::vector<const dunedaq::confmodel::ExcludableEntity*>>& out,
     112              :               const dunedaq::confmodel::Segment* segment,
     113              :               const dunedaq::conffwk::ConfigObjectImpl* child,
     114              :               bool is_segment,
     115              :               dunedaq::confmodel::TestCircularDependency& cd_fuse)
     116              : {
     117            0 :   dunedaq::confmodel::AddTestOnCircularDependency add_fuse_test(cd_fuse, segment);
     118              : 
     119            0 :   std::vector<const dunedaq::confmodel::ExcludableEntity*> compList;
     120              : 
     121            0 :   if (segment->config_object().implementation() == child) {
     122            0 :     out.push_back(compList);
     123              :   }
     124            0 :   make_parents_list(child, segment, compList, out, is_segment, cd_fuse);
     125            0 : }
     126              : } // namespace
     127              : 
     128              : namespace dunedaq::confmodel {
     129              : 
     130              : void
     131            0 : ExcludableEntity::parents(const Session& session, std::list<std::vector<const ExcludableEntity*>>& parents) const
     132              : {
     133            0 :   const ConfigObjectImpl* obj_impl = config_object().implementation();
     134              : 
     135            0 :   const bool is_segment = castable(Segment::s_class_name);
     136              : 
     137            0 :   try {
     138            0 :     TestCircularDependency cd_fuse("component parents", &session);
     139              : 
     140              :     // check session's segment
     141            0 :     check_segment(parents, session.get_segment(), obj_impl, is_segment, cd_fuse);
     142              : 
     143            0 :     if (parents.empty()) {
     144            0 :       TLOG_DEBUG(1) << "cannot find segment/resource path(s) between ExcludableEntity " << this << " and session "
     145            0 :                     << &session << " objects (check this object is linked with the session as a segment or a resource)";
     146              :     }
     147            0 :   } catch (ers::Issue& ex) {
     148            0 :     ers::error(CannotGetParents(ERS_HERE, full_name(), ex));
     149            0 :   }
     150            0 : }
     151              : 
     152              : // ========================================================================
     153              : 
     154              : std::vector<const Application*>
     155           32 : Session::getSegmentApps(const Segment* segment, bool included_only) const
     156              : {
     157           32 :   std::vector<const Application*> apps;
     158           32 :   auto segapps = segment->get_applications();
     159           32 :   if (included_only) {
     160            0 :     for (auto app : segapps) {
     161            0 :       auto comp = app->cast<ExcludableEntity>();
     162            0 :       if (comp == nullptr || !comp->is_excluded(*this)) {
     163            0 :         apps.insert(apps.end(), app);
     164              :       }
     165              :     }
     166              :   } else {
     167           32 :     apps.swap(segapps);
     168              :   }
     169           48 :   for (auto seg : segment->get_segments()) {
     170           16 :     if (!included_only || !seg->is_excluded(*this)) {
     171           16 :       auto segapps = getSegmentApps(seg, included_only);
     172           16 :       apps.insert(apps.end(), segapps.begin(), segapps.end());
     173           16 :     }
     174              :   }
     175           32 :   return apps;
     176           32 : }
     177              : 
     178              : std::vector<const Application*>
     179           16 : Session::all_applications() const
     180              : {
     181           16 :   std::vector<const Application*> apps;
     182           16 :   auto segapps = getSegmentApps(get_segment(), false);
     183           16 :   apps.insert(apps.end(), segapps.begin(), segapps.end());
     184           16 :   return apps;
     185           16 : }
     186              : 
     187              : std::vector<const Application*>
     188            0 : Session::included_applications() const
     189              : {
     190            0 :   std::vector<const Application*> apps;
     191            0 :   auto segapps = getSegmentApps(get_segment(), true);
     192            0 :   apps.insert(apps.end(), segapps.begin(), segapps.end());
     193            0 :   return apps;
     194            0 : }
     195              : 
     196              : // ========================================================================
     197              : 
     198              : std::set<const HostComponent*>
     199            0 : DaqApplication::get_used_host_components() const
     200              : {
     201            0 :   std::set<const HostComponent*> res;
     202            0 :   for (auto module : get_modules()) {
     203            0 :     for (auto hostresource : module->get_used_host_components()) {
     204            0 :       res.insert(hostresource);
     205              :     }
     206              :   }
     207            0 :   return res;
     208            0 : }
     209              : 
     210              : namespace {
     211              : nlohmann::json
     212            0 : get_json_config(conffwk::Configuration& confdb,
     213              :                 const std::string& class_name,
     214              :                 const std::string& uid,
     215              :                 bool direct_only,
     216              :                 bool skip_object_name)
     217              : {
     218            0 :   using nlohmann::json;
     219            0 :   using namespace conffwk;
     220            0 :   TLOG_DBG(9) << "Getting attributes for " << uid << " of class " << class_name;
     221            0 :   json attributes;
     222            0 :   auto class_info = confdb.get_class_info(class_name);
     223            0 :   ConfigObject obj;
     224            0 :   confdb.get(class_name, uid, obj);
     225            0 :   for (auto attr : class_info.p_attributes) {
     226            0 :     if (attr.p_type == type_t::u8_type) {
     227            0 :       add_json_value<uint8_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     228              :     } else if (attr.p_type == type_t::u16_type) {
     229            0 :       add_json_value<uint16_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     230              :     } else if (attr.p_type == type_t::u32_type) {
     231            0 :       add_json_value<uint32_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     232              :     } else if (attr.p_type == type_t::u64_type) {
     233            0 :       add_json_value<uint64_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     234              :     } else if (attr.p_type == type_t::s8_type) {
     235            0 :       add_json_value<int8_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     236              :     } else if (attr.p_type == type_t::s16_type) {
     237            0 :       add_json_value<int16_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     238              :     } else if (attr.p_type == type_t::s32_type || attr.p_type == type_t::s16_type) {
     239            0 :       add_json_value<int32_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     240              :     } else if (attr.p_type == type_t::s64_type) {
     241            0 :       add_json_value<int64_t>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     242              :     } else if (attr.p_type == type_t::float_type) {
     243            0 :       add_json_value<float>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     244              :     } else if (attr.p_type == type_t::double_type) {
     245            0 :       add_json_value<double>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     246              :     } else if (attr.p_type == type_t::bool_type) {
     247            0 :       add_json_value<bool>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     248              :     } else if ((attr.p_type == type_t::string_type) || (attr.p_type == type_t::enum_type) ||
     249              :                (attr.p_type == type_t::date_type) || (attr.p_type == type_t::time_type)) {
     250            0 :       add_json_value<std::string>(obj, attr.p_name, attr.p_is_multi_value, attributes);
     251              :     }
     252            0 :   }
     253            0 :   if (!direct_only) {
     254            0 :     TLOG_DBG(9) << "Processing  relationships";
     255            0 :     for (auto iter : class_info.p_relationships) {
     256            0 :       std::string rel_name = iter.p_name;
     257            0 :       if (iter.p_cardinality == cardinality_t::zero_or_one || iter.p_cardinality == cardinality_t::only_one) {
     258            0 :         ConfigObject rel_obj;
     259            0 :         obj.get(rel_name, rel_obj);
     260            0 :         if (!rel_obj.is_null()) {
     261            0 :           TLOG_DBG(9) << "Getting attibute of relationship " << rel_name;
     262            0 :           attributes[rel_name] =
     263            0 :             get_json_config(confdb, rel_obj.class_name(), rel_obj.UID(), direct_only, skip_object_name);
     264              :         } else {
     265            0 :           TLOG_DBG(9) << "Relationship " << rel_name << " not set";
     266              :         }
     267            0 :       } else {
     268            0 :         TLOG_DBG(9) << "Relationship " << rel_name << " is multi value. "
     269            0 :                     << "Getting attibutes for relationship.";
     270            0 :         std::vector<ConfigObject> rel_vec;
     271            0 :         obj.get(rel_name, rel_vec);
     272            0 :         std::vector<json> configs;
     273            0 :         for (auto rel_obj : rel_vec) {
     274            0 :           TLOG_DBG(9) << "Getting attibute of relationship " << rel_obj.UID();
     275            0 :           auto rel_conf = get_json_config(confdb, rel_obj.class_name(), rel_obj.UID(), direct_only, skip_object_name);
     276            0 :           configs.push_back(rel_conf);
     277            0 :         }
     278            0 :         attributes[rel_name] = configs;
     279            0 :       }
     280            0 :     }
     281              :   }
     282              : 
     283            0 :   if (skip_object_name) {
     284            0 :     return attributes;
     285              :   }
     286            0 :   json json_config;
     287            0 :   json_config[uid] = attributes;
     288            0 :   return json_config;
     289            0 : }
     290              : } // namespace
     291              : 
     292              : nlohmann::json
     293            0 : Jsonable::to_json(bool direct_only, bool skip_object_name) const
     294              : {
     295            0 :   return get_json_config(p_registry.configuration(), class_name(), UID(), direct_only, skip_object_name);
     296              : }
     297              : 
     298              : const std::vector<std::string>
     299            0 : DaqApplication::construct_commandline_parameters(const conffwk::Configuration& confdb,
     300              :                                                  const dunedaq::confmodel::Session* session) const
     301              : {
     302              : 
     303            0 :   return construct_commandline_parameters_appfwk<dunedaq::confmodel::DaqApplication>(this, confdb, session);
     304              : }
     305              : 
     306              : const std::vector<std::string>
     307            0 : RCApplication::construct_commandline_parameters(const conffwk::Configuration& confdb,
     308              :                                                 const dunedaq::confmodel::Session* session) const
     309              : {
     310              : 
     311            0 :   const std::string configuration_uri = confdb.get_impl_spec();
     312            0 :   const dunedaq::confmodel::Service* control_service = nullptr;
     313              : 
     314            0 :   const std::string controller_log_level = session->get_controller_log_level();
     315              : 
     316            0 :   for (auto const* as : get_exposes_service()) {
     317            0 :     if (as->UID().ends_with("_control")) {
     318            0 :       if (control_service)
     319            0 :         throw DuplicatedControlService(ERS_HERE, as->UID());
     320              :       control_service = as;
     321              :     }
     322              :   }
     323              : 
     324            0 :   if (control_service == nullptr)
     325            0 :     throw NoControlServiceDefined(ERS_HERE, UID());
     326              : 
     327            0 :   const std::string control_uri = control_service->get_protocol() + "://" + get_runs_on()->get_runs_on()->UID() + ":" +
     328            0 :                                   std::to_string(control_service->get_port());
     329              : 
     330            0 :   std::vector<std::string> ret = { "-l", controller_log_level };
     331            0 :   ret.push_back(configuration_uri);
     332            0 :   ret.push_back(control_uri);
     333            0 :   ret.push_back(UID());
     334            0 :   ret.push_back(session->UID());
     335            0 :   return ret;
     336            0 : }
     337              : 
     338              : std::vector<const confmodel::DetectorStream*>
     339           64 : DetectorToDaqConnection::streams() const
     340              : {
     341           64 :   std::vector<const confmodel::DetectorStream*> all_streams;
     342              :   // Loop over senders
     343          128 :   for (auto sender : this->senders()) {
     344           64 :     auto sender_streams = sender->get_streams();
     345           64 :     all_streams.insert(all_streams.end(), sender_streams.begin(), sender_streams.end());
     346          128 :   }
     347           64 :   return all_streams;
     348            0 : }
     349              : 
     350              : std::string
     351           10 : OpMonURI::get_URI(const std::string& /* app */) const
     352              : {
     353              : 
     354           10 :   auto type = get_type();
     355           10 :   if (type == "file") {
     356           10 :     return type + "://" + get_path();
     357              :   }
     358              : 
     359            0 :   if (type == "stream") {
     360            0 :     return type + "://" + get_path();
     361              :   }
     362              : 
     363            0 :   return "stdout://";
     364           10 : }
     365              : 
     366              : // ========================================================================
     367              : void
     368            0 : ExcludableEntityTree::exclude(const ExcludableEntity* res)
     369              : {
     370            0 :   auto excluded_vec = get_excluded();
     371            0 :   for (auto excluded_resource : excluded_vec) {
     372            0 :     if (excluded_resource == res) {
     373            0 :       return;
     374              :     }
     375              :   }
     376            0 :   excluded_vec.push_back(res);
     377              : 
     378            0 :   set_excluded(excluded_vec);
     379            0 :   configuration().update<ExcludableEntityTree>({ UID() }, {}, {});
     380              : 
     381            0 :   m_excluded_entities.update(root_entity(), excluded_vec);
     382            0 : }
     383              : void
     384            0 : ExcludableEntityTree::include(const ExcludableEntity* res)
     385              : {
     386            0 :   auto excluded_vec = get_excluded();
     387            0 :   auto count = std::erase(excluded_vec, res);
     388            0 :   if (count == 0) {
     389            0 :     return;
     390              :   }
     391            0 :   set_excluded(excluded_vec);
     392            0 :   configuration().update<ExcludableEntityTree>({ UID() }, {}, {});
     393              : 
     394            0 :   m_excluded_entities.update(root_entity(), excluded_vec);
     395            0 : }
     396              : 
     397              : bool
     398          263 : ExcludableEntity::is_excluded(const dunedaq::confmodel::ExcludableEntityTree& holder) const
     399              : {
     400          263 :   return (!holder.excluded_entities().is_included(this));
     401              : }
     402              : bool
     403          236 : ExcludableEntity::compute_excluded_state(const std::set<std::string>& excluded_resources) const
     404              : {
     405          236 :   TLOG_DEBUG(6) << "No compute_excluded_state method defined for ExcludableEntity " << class_name();
     406          236 :   if (excluded_resources.contains(UID())) {
     407              :     return true;
     408              :   }
     409              :   return false;
     410              : }
     411              : 
     412              : std::vector<const ExcludableEntity*>
     413          109 : DetDataSender::contained_excludable_entities() const
     414              : {
     415          109 :   return to_resources(get_streams());
     416              : }
     417              : 
     418              : std::vector<const ExcludableEntity*>
     419           32 : DetectorToDaqConnection::contained_excludable_entities() const
     420              : {
     421           32 :   auto res = to_resources(senders());
     422           32 :   auto rec = receiver();
     423           32 :   if (rec)
     424           32 :     res.push_back(rec);
     425           32 :   return res;
     426            0 : }
     427              : 
     428              : bool
     429           35 : DetectorToDaqConnection::compute_excluded_state(const std::set<std::string>& excluded_resources) const
     430              : {
     431           35 :   if (excluded_resources.contains(UID())) {
     432              :     return true;
     433              :   }
     434           35 :   bool send_excluded = true;
     435           43 :   for (auto sender : senders()) {
     436           40 :     if (!sender->compute_excluded_state(excluded_resources)) {
     437           32 :       send_excluded = false;
     438           32 :       break;
     439              :     }
     440           35 :   }
     441           35 :   TLOG_DBG(6) << "receiver excluded=" << receiver()->compute_excluded_state(excluded_resources)
     442           35 :               << " senders excluded=" << send_excluded;
     443           35 :   auto rec = receiver();
     444           35 :   if (!rec)
     445            0 :     return send_excluded;
     446              : 
     447           35 :   return (rec->compute_excluded_state(excluded_resources) || send_excluded);
     448              : }
     449              : 
     450              : std::vector<const ExcludableEntity*>
     451           25 : Segment::contained_excludable_entities() const
     452              : {
     453              :   // All our contained segments are resources
     454           25 :   std::vector<const ExcludableEntity*> resources = to_resources(get_segments());
     455              : 
     456              :   // Only a subset of our applications might be resources so check individually
     457           64 :   for (auto app : get_applications()) {
     458           39 :     TLOG_DBG(6) << "Checking " << app->UID();
     459           39 :     auto res = app->cast<const ExcludableEntity>();
     460           39 :     if (res != nullptr) {
     461           33 :       TLOG_DBG(6) << "Adding " << app->UID();
     462           33 :       resources.push_back(res);
     463              :     }
     464              :   }
     465           25 :   TLOG_DBG(6) << "Returning vector of " << resources.size() << " resources";
     466           25 :   return resources;
     467            0 : }
     468              : 
     469              : bool
     470           21 : Segment::compute_excluded_state(const std::set<std::string>& excluded) const
     471              : {
     472           21 :   if (excluded.contains(UID())) {
     473              :     return true;
     474              :   }
     475           36 :   for (auto app : get_applications()) {
     476           27 :     auto res = app->cast<const ExcludableEntity>();
     477           27 :     if (res == nullptr) {
     478           12 :       return false;
     479              :     }
     480              :   }
     481           13 :   for (auto res : contained_excludable_entities()) {
     482           12 :     if (!res->compute_excluded_state(excluded)) {
     483            8 :       return false;
     484              :     }
     485            9 :   }
     486            1 :   return true;
     487              : }
     488              : 
     489              : } // namespace dunedaq::confmodel
        

Generated by: LCOV version 2.0-1