LCOV - code coverage report
Current view: top level - artdaq/ArtModules/detail - TransferWrapper.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 234 0
Test Date: 2026-10-29 00:35:58 Functions: 0.0 % 36 0

            Line data    Source code
       1              : #include "TRACE/tracemf.h"  // Pre-empt TRACE/trace.h from Fragment.hh.
       2              : #include "artdaq-core/Data/Fragment.hh"
       3              : 
       4              : #define TRACE_NAME "TransferWrapper"
       5              : 
       6              : #include "artdaq/ArtModules/detail/TransferWrapper.hh"
       7              : 
       8              : #include "artdaq-core/Utilities/ExceptionHandler.hh"
       9              : #include "artdaq-core/Utilities/TimeUtils.hh"
      10              : #include "artdaq/DAQdata/NetMonHeader.hh"
      11              : #include "artdaq/ExternalComms/MakeCommanderPlugin.hh"
      12              : #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
      13              : 
      14              : #include "cetlib_except/exception.h"
      15              : #include "fhiclcpp/ParameterSet.h"
      16              : 
      17              : #include <csignal>
      18              : #include <iostream>
      19              : #include <limits>
      20              : #include <memory>
      21              : #include <sstream>
      22              : #include <string>
      23              : 
      24              : namespace {
      25              : volatile std::sig_atomic_t gSignalStatus = 0;  ///< Stores singal from signal handler
      26              : }
      27              : 
      28              : /**
      29              :  * \brief Handle a Unix signal
      30              :  * \param signal Signal to handle
      31              :  */
      32            0 : void signal_handler(int signal)
      33              : {
      34            0 :         gSignalStatus = signal;
      35            0 : }
      36              : 
      37            0 : artdaq::TransferWrapper::TransferWrapper(const fhicl::ParameterSet& pset)
      38            0 :     : timeoutInUsecs_(pset.get<std::size_t>("timeoutInUsecs", 100000))
      39            0 :     , last_received_data_()
      40            0 :     , last_report_(std::chrono::steady_clock::now())
      41            0 :     , transfer_(nullptr)
      42            0 :     , commander_(nullptr)
      43            0 :     , pset_(pset)
      44            0 :     , dispatcherHost_(pset.get<std::string>("dispatcherHost", "localhost"))
      45            0 :     , dispatcherPort_(pset.get<std::string>("dispatcherPort", "5266"))
      46            0 :     , serverUrl_(pset.get<std::string>("server_url", "http://" + dispatcherHost_ + ":" + dispatcherPort_ + "/RPC2"))
      47            0 :     , maxEventsBeforeInit_(pset.get<std::size_t>("maxEventsBeforeInit", 5))
      48            0 :     , allowedFragmentTypes_(pset.get<std::vector<int>>("allowedFragmentTypes", {static_cast<int>(artdaq::Fragment::DataFragmentType),
      49              :                                                                                 static_cast<int>(artdaq::Fragment::InitFragmentType),
      50              :                                                                                 static_cast<int>(artdaq::Fragment::EndOfRunFragmentType),
      51              :                                                                                 static_cast<int>(artdaq::Fragment::EndOfSubrunFragmentType),
      52              :                                                                                 static_cast<int>(artdaq::Fragment::RunDataFragmentType),
      53              :                                                                                 static_cast<int>(artdaq::Fragment::SubrunDataFragmentType)}))
      54            0 :     , runningStateTimeout_(pset.get<double>("dispatcherConnectTimeout", 0))
      55            0 :     , runningStateInterval_us_(pset.get<size_t>("dispatcherConnectRetryInterval_us", 1000000))
      56            0 :     , quitOnFragmentIntegrityProblem_(pset.get<bool>("quitOnFragmentIntegrityProblem", true))
      57            0 :     , multi_run_mode_(pset.get<bool>("multi_run_mode", false))
      58            0 :     , monitorRegistered_(false)
      59              : {
      60            0 :         std::signal(SIGINT, signal_handler);
      61              : 
      62              :         try
      63              :         {
      64            0 :                 if (metricMan)
      65              :                 {
      66            0 :                         metricMan->initialize(pset.get<fhicl::ParameterSet>("metrics", fhicl::ParameterSet()), "Online Monitor");
      67            0 :                         metricMan->do_start();
      68              :                 }
      69              :         }
      70            0 :         catch (...)
      71              :         {
      72            0 :                 ExceptionHandler(ExceptionHandlerRethrow::no, "TransferWrapper: could not configure metrics");
      73            0 :         }
      74              : 
      75              :         // Clamp possible values
      76            0 :         if (runningStateInterval_us_ < 1000)
      77              :         {
      78            0 :                 TLOG(TLVL_WARNING) << "Invalid value " << runningStateInterval_us_ << " us detected for dispatcherConnectRetryInterval_us. Setting to 1000 us";
      79            0 :                 runningStateInterval_us_ = 1000;
      80              :         }
      81            0 :         if (runningStateInterval_us_ > 30000000)
      82              :         {
      83            0 :                 TLOG(TLVL_WARNING) << "Invalid value " << runningStateInterval_us_ << " us detected for dispatcherConnectRetryInterval_us. Setting to 30,000,000 us";
      84            0 :                 runningStateInterval_us_ = 30000000;
      85              :         }
      86              : 
      87            0 :         fhicl::ParameterSet new_pset(pset);
      88            0 :         if (!new_pset.has_key("server_url"))
      89              :         {
      90            0 :                 new_pset.put<std::string>("server_url", serverUrl_);
      91              :         }
      92              : 
      93            0 :         artdaq::Commandable c;
      94            0 :         commander_ = MakeCommanderPlugin(new_pset, c);
      95            0 : }
      96              : 
      97            0 : artdaq::FragmentPtrs artdaq::TransferWrapper::receiveMessage()
      98              : {
      99            0 :         artdaq::FragmentPtrs fragmentPtrs;
     100            0 :         bool receivedFragment = false;
     101              :         static bool initialized = false;
     102              :         static size_t fragments_received = 0;
     103              : 
     104            0 :         while (gSignalStatus == 0)
     105              :         {
     106            0 :                 receivedFragment = false;
     107            0 :                 auto fragmentPtr = std::make_unique<artdaq::Fragment>();
     108              : 
     109            0 :                 while (!receivedFragment)
     110              :                 {
     111            0 :                         if (gSignalStatus != 0)
     112              :                         {
     113            0 :                                 TLOG(TLVL_INFO) << "Ctrl-C appears to have been hit";
     114            0 :                                 return fragmentPtrs;
     115              :                         }
     116            0 :                         if (!monitorRegistered_)
     117              :                         {
     118            0 :                                 registerMonitor();
     119            0 :                                 if (!monitorRegistered_)
     120              :                                 {
     121            0 :                                         return fragmentPtrs;
     122              :                                 }
     123              :                         }
     124              : 
     125              :                         try
     126              :                         {
     127            0 :                                 auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
     128              : 
     129            0 :                                 if (result >= artdaq::TransferInterface::RECV_SUCCESS)
     130              :                                 {
     131            0 :                                         receivedFragment = true;
     132            0 :                                         fragments_received++;
     133              : 
     134              :                                         static size_t cntr = 0;
     135            0 :                                         ++cntr;
     136              : 
     137              :                                         // Report the first 10 events, then every 10th, then every 100th, and so
     138              :                                         // on, so a long run does not put one line per event into the log.
     139            0 :                                         size_t report_interval = 1;
     140            0 :                                         while (cntr / report_interval >= 10)
     141              :                                         {
     142            0 :                                                 report_interval *= 10;
     143              :                                         }
     144              : 
     145            0 :                                         if (cntr % report_interval == 0)
     146              :                                         {
     147            0 :                                                 auto mod = cntr % 10;
     148            0 :                                                 auto suffix = "-th";
     149            0 :                                                 if (mod == 1)
     150              :                                                 {
     151            0 :                                                         suffix = "-st";
     152              :                                                 }
     153            0 :                                                 if (mod == 2)
     154              :                                                 {
     155            0 :                                                         suffix = "-nd";
     156              :                                                 }
     157            0 :                                                 if (mod == 3)
     158              :                                                 {
     159            0 :                                                         suffix = "-rd";
     160              :                                                 }
     161            0 :                                                 TLOG(TLVL_INFO) << "Received " << cntr << suffix << " event, "
     162            0 :                                                                 << "seqID == " << fragmentPtr->sequenceID()
     163            0 :                                                                 << ", type == " << fragmentPtr->typeString();
     164              :                                         }
     165            0 :                                         last_received_data_ = std::chrono::steady_clock::now();
     166            0 :                                         continue;
     167            0 :                                 }
     168            0 :                                 if (result == artdaq::TransferInterface::DATA_END)
     169              :                                 {
     170            0 :                                         TLOG(TLVL_ERROR) << "Transfer Plugin disconnected or other unrecoverable error. Shutting down.";
     171            0 :                                         return fragmentPtrs;
     172              :                                 }
     173              :                                 else
     174              :                                 {
     175            0 :                                         auto tlvl = TLVL_DEBUG + 33;
     176            0 :                                         if (artdaq::TimeUtils::GetElapsedTime(last_report_) > 1.0 && artdaq::TimeUtils::GetElapsedTime(last_received_data_) > 1.0)
     177              :                                         {
     178            0 :                                                 tlvl = TLVL_WARNING;
     179            0 :                                                 last_report_ = std::chrono::steady_clock::now();
     180              :                                         }
     181              : 
     182            0 :                                         auto last_received_milliseconds = artdaq::TimeUtils::GetElapsedTimeMilliseconds(last_received_data_);
     183              : 
     184              :                                         // 02-Jun-2018, KAB: added status/result printout
     185              :                                         // to-do: add another else clause that explicitly checks for RECV_TIMEOUT
     186            0 :                                         TLOG(tlvl) << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again"
     187            0 :                                                    << ", status = " << result << ", last received data " << last_received_milliseconds << " ms ago.";
     188              :                                 }
     189              :                         }
     190            0 :                         catch (...)
     191              :                         {
     192            0 :                                 ExceptionHandler(ExceptionHandlerRethrow::yes,
     193              :                                                  "Problem receiving data in TransferWrapper::receiveMessage");
     194            0 :                         }
     195              :                 }
     196              : 
     197            0 :                 if (fragmentPtr->type() == artdaq::Fragment::EndOfDataFragmentType)
     198              :                 {
     199            0 :                         if (!multi_run_mode_)
     200              :                         {
     201            0 :                                 TLOG(TLVL_DEBUG + 32) << "Received shutdown message, returning";
     202            0 :                                 fragmentPtrs.push_back(std::move(fragmentPtr));
     203              :                         }
     204            0 :                         return fragmentPtrs;
     205              :                 }
     206              : 
     207            0 :                 checkIntegrity(*fragmentPtr);
     208              : 
     209            0 :                 if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
     210              :                 {
     211            0 :                         initialized = true;
     212            0 :                         fragmentPtrs.push_back(std::move(fragmentPtr));
     213            0 :                         break;
     214              :                 }
     215              : 
     216            0 :                 if (fragments_received > maxEventsBeforeInit_)
     217              :                 {
     218            0 :                         TLOG(TLVL_ERROR) << "First " << maxEventsBeforeInit_ << " events received did not include the \"Init\" event containing necessary info for art; exiting...";
     219            0 :                         throw cet::exception("TransferWrapper") << "First " << maxEventsBeforeInit_ << " events received did not include the \"Init\" event containing necessary info for art; exiting...";  // NOLINT(cert-err60-cpp)
     220              :                 }
     221            0 :         }
     222              : 
     223            0 :         return fragmentPtrs;
     224            0 : }
     225              : 
     226            0 : std::shared_ptr<ArtdaqEvent> artdaq::TransferWrapper::receiveMessages()
     227              : {
     228            0 :         std::shared_ptr<ArtdaqEvent> output = std::make_shared<ArtdaqEvent>();
     229              : 
     230            0 :         auto ptrs = receiveMessage();
     231            0 :         for (auto& ptr : ptrs)
     232              :         {
     233            0 :                 auto fragType = ptr->type();
     234            0 :                 auto fragPtr = ptr.release();
     235            0 :                 ptr.reset(nullptr);
     236              : 
     237            0 :                 if (output->fragments.count(fragType) == 0u)
     238              :                 {
     239            0 :                         output->fragments[fragType] = std::make_unique<artdaq::Fragments>();
     240              :                 }
     241              : 
     242            0 :                 output->fragments[fragType]->emplace_back(std::move(*fragPtr));
     243              :         }
     244              : 
     245            0 :         return output;
     246            0 : }
     247              : 
     248            0 : void artdaq::TransferWrapper::checkIntegrity(const artdaq::Fragment& fragment) const
     249              : {
     250            0 :         const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
     251              :                                     sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
     252            0 :         const auto payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
     253            0 :         const size_t metadata = sizeof(artdaq::NetMonHeader);
     254            0 :         const size_t totalsize = fragment.sizeBytes();
     255              : 
     256            0 :         const auto type = static_cast<size_t>(fragment.type());
     257              : 
     258            0 :         if (totalsize != artdaqheader + metadata + payload)
     259              :         {
     260            0 :                 std::stringstream errmsg;
     261            0 :                 errmsg << "Error: artdaq fragment of type " << fragment.typeString() << ", sequence ID " << fragment.sequenceID() << " has internally inconsistent measures of its size, signalling data corruption: in bytes,"
     262            0 :                        << " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader << ", metadata = " << metadata << ", payload = " << payload;
     263              : 
     264            0 :                 TLOG(TLVL_ERROR) << errmsg.str();
     265              : 
     266            0 :                 if (quitOnFragmentIntegrityProblem_)
     267              :                 {
     268            0 :                         throw cet::exception("TransferWrapper") << errmsg.str();  // NOLINT(cert-err60-cpp)
     269              :                 }
     270              : 
     271            0 :                 return;
     272            0 :         }
     273              : 
     274            0 :         auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
     275              : 
     276            0 :         if (findloc == allowedFragmentTypes_.end())
     277              :         {
     278            0 :                 std::stringstream errmsg;
     279            0 :                 errmsg << "Error: artdaq fragment appears to have type "
     280            0 :                        << type << ", not found in the allowed fragment types list";
     281              : 
     282            0 :                 TLOG(TLVL_ERROR) << errmsg.str();
     283            0 :                 if (quitOnFragmentIntegrityProblem_)
     284              :                 {
     285            0 :                         throw cet::exception("TransferWrapper") << errmsg.str();  // NOLINT(cert-err60-cpp)
     286              :                 }
     287              : 
     288            0 :                 return;
     289            0 :         }
     290              : }
     291              : 
     292            0 : void artdaq::TransferWrapper::registerMonitor(bool setup_transfer)
     293              : {
     294            0 :         if (setup_transfer)
     295              :         {
     296              :                 try
     297              :                 {
     298            0 :                         transfer_.reset(nullptr);
     299            0 :                         transfer_ = MakeTransferPlugin(pset_, "transfer_plugin", TransferInterface::Role::kReceive);
     300              :                 }
     301            0 :                 catch (...)
     302              :                 {
     303            0 :                         ExceptionHandler(ExceptionHandlerRethrow::yes,
     304              :                                          "TransferWrapper: failure in call to MakeTransferPlugin");
     305            0 :                 }
     306              :         }
     307              : 
     308            0 :         auto start = std::chrono::steady_clock::now();
     309            0 :         auto sts = getDispatcherStatus();
     310            0 :         while (sts != "Running" && (runningStateTimeout_ == 0 || TimeUtils::GetElapsedTime(start) < runningStateTimeout_))
     311              :         {
     312            0 :                 TLOG(TLVL_DEBUG + 32) << "Dispatcher state: " << sts;
     313            0 :                 if (gSignalStatus != 0)
     314              :                 {
     315            0 :                         TLOG(TLVL_INFO) << "Ctrl-C appears to have been hit";
     316            0 :                         return;
     317              :                 }
     318            0 :                 TLOG(TLVL_INFO) << "Waited " << std::fixed << std::setprecision(2) << TimeUtils::GetElapsedTime(start) << " s / " << runningStateTimeout_ << " s for Dispatcher to enter the Running state (state=" << sts << ")";
     319            0 :                 usleep(runningStateInterval_us_);
     320            0 :                 sts = getDispatcherStatus();
     321              :         }
     322            0 :         if (sts != "Running")
     323              :         {
     324            0 :                 return;
     325              :         }
     326              : 
     327            0 :         auto dispatcherConfig = pset_.get<fhicl::ParameterSet>("dispatcher_config");
     328              : 
     329            0 :         int retry = 3;
     330              : 
     331            0 :         while (retry > 0)
     332              :         {
     333            0 :                 label_ = dispatcherConfig.get<std::string>("unique_label") + "T" + std::to_string(time(0));
     334            0 :                 dispatcherConfig.erase("unique_label");
     335            0 :                 dispatcherConfig.put<std::string>("unique_label", label_);
     336            0 :                 TLOG(TLVL_INFO) << "Attempting to register this monitor (\"" << label_
     337            0 :                                 << "\") with the dispatcher aggregator";
     338              : 
     339            0 :                 auto status = commander_->send_register_monitor(dispatcherConfig.to_string());
     340              : 
     341            0 :                 TLOG(TLVL_INFO) << "Response from dispatcher is \"" << status << "\"";
     342              : 
     343            0 :                 if (status == "Success")
     344              :                 {
     345            0 :                         monitorRegistered_ = true;
     346            0 :                         break;
     347              :                 }
     348              : 
     349            0 :                 TLOG(TLVL_WARNING) << "Error in TransferWrapper: attempt to register with dispatcher did not result in the \"Success\" response";
     350            0 :                 usleep(100000);
     351              : 
     352            0 :                 retry--;
     353            0 :         }
     354            0 : }
     355              : 
     356            0 : void artdaq::TransferWrapper::unregisterMonitor(bool force, std::string label)
     357              : {
     358            0 :         if (!monitorRegistered_ && !force)
     359              :         {
     360            0 :                 TLOG(TLVL_WARNING) << "The function to unregister the monitor was called, but the monitor doesn't appear to be registered";
     361            0 :                 return;
     362              :         }
     363              : 
     364            0 :         if (label == "")
     365              :         {
     366            0 :                 label = label_;
     367              :         }
     368              : 
     369            0 :         auto start_time = std::chrono::steady_clock::now();
     370            0 :         bool waiting = true;
     371            0 :         while (artdaq::TimeUtils::GetElapsedTime(start_time) < 5.0 && waiting)
     372              :         {
     373            0 :                 std::string sts = getDispatcherStatus();
     374              : 
     375            0 :                 if (sts.empty())
     376            0 :                         return;
     377              : 
     378            0 :                 if (sts == "busy")
     379              :                 {
     380            0 :                         TLOG(TLVL_INFO) << "The Dispatcher returned \"busy\", will wait 0.5s and retry";
     381            0 :                         usleep(500000);
     382            0 :                         continue;
     383            0 :                 }
     384              : 
     385            0 :                 if (sts != "Running" && sts != "Ready")
     386              :                 {
     387            0 :                         TLOG(TLVL_WARNING) << "The Dispatcher is not in the Running or Ready state, will not attempt to unregister (state: " << sts << ")";
     388            0 :                         return;
     389              :                 }
     390            0 :                 waiting = false;
     391            0 :         }
     392            0 :         if (waiting)
     393              :         {
     394            0 :                 TLOG(TLVL_WARNING) << "A timeout occurred waiting for the Dispatcher to leave the \"busy\" state, will not attempt to unregister";
     395            0 :                 return;
     396              :         }
     397              : 
     398            0 :         int retry = 3;
     399            0 :         while (retry > 0)
     400              :         {
     401            0 :                 TLOG(TLVL_INFO) << "Requesting that this monitor (" << label
     402            0 :                                 << ") be unregistered from the dispatcher aggregator";
     403              : 
     404            0 :                 auto status = commander_->send_unregister_monitor(label);
     405              : 
     406            0 :                 TLOG(TLVL_INFO) << "Response from dispatcher is \"" << status << "\"";
     407              : 
     408            0 :                 if (status == "Success")
     409              :                 {
     410            0 :                         break;
     411              :                 }
     412            0 :                 else if (status == "busy")
     413              :                 {
     414            0 :                         TLOG(TLVL_DEBUG + 32) << "The Dispatcher returned \"busy\", will retry in 0.5s";
     415              :                 }
     416              :                 else
     417              :                 {
     418            0 :                         TLOG(TLVL_WARNING) << "The Dispatcher returned status " << status << " when attempting to unregister this monitor!";
     419              :                         // throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to unregister with dispatcher did not result in the \"Success\" response";
     420              :                 }
     421            0 :                 retry--;
     422            0 :                 usleep(500000);
     423            0 :         }
     424              : 
     425            0 :         TLOG(TLVL_INFO) << "Successfully unregistered the monitor from the Dispatcher";
     426            0 :         monitorRegistered_ = false;
     427              : }
     428              : 
     429            0 : std::string artdaq::TransferWrapper::getDispatcherStatus()
     430              : {
     431              :         try
     432              :         {
     433            0 :                 return commander_->send_status();
     434              :         }
     435            0 :         catch (std::exception const& ex)
     436              :         {
     437            0 :                 TLOG(TLVL_WARNING) << "An exception was thrown trying to collect the Dispatcher's status. Most likely cause is the application is no longer running.";
     438            0 :                 return "";
     439            0 :         }
     440              : }
     441              : 
     442            0 : artdaq::TransferWrapper::~TransferWrapper()
     443              : {
     444            0 :         if (monitorRegistered_)
     445              :         {
     446              :                 try
     447              :                 {
     448            0 :                         unregisterMonitor();
     449              :                 }
     450            0 :                 catch (...)
     451              :                 {
     452            0 :                         ExceptionHandler(ExceptionHandlerRethrow::no,
     453              :                                          "An exception occurred when trying to unregister monitor during TransferWrapper's destruction");
     454            0 :                 }
     455              :         }
     456            0 :         artdaq::Globals::CleanUpGlobals();
     457            0 : }
        

Generated by: LCOV version 2.0-1