00001 #define TRACE_NAME "TransferWrapper"
00002
00003 #include "artdaq/ArtModules/detail/TransferWrapper.hh"
00004 #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
00005 #include "artdaq/ExternalComms/MakeCommanderPlugin.hh"
00006 #include "artdaq/DAQdata/NetMonHeader.hh"
00007 #include "artdaq/DAQdata/Globals.hh"
00008 #include "artdaq-core/Utilities/ExceptionHandler.hh"
00009 #include "artdaq-core/Data/Fragment.hh"
00010
00011 #include "cetlib/BasicPluginFactory.h"
00012 #include "cetlib_except/exception.h"
00013 #include "fhiclcpp/ParameterSet.h"
00014
00015 #include <TBufferFile.h>
00016
00017 #include <limits>
00018 #include <iostream>
00019 #include <string>
00020 #include <sstream>
00021 #include <csignal>
00022
00023 namespace
00024 {
00025 volatile std::sig_atomic_t gSignalStatus = 0;
00026 }
00027
00032 void signal_handler(int signal)
00033 {
00034 gSignalStatus = signal;
00035 }
00036
00037 artdaq::TransferWrapper::TransferWrapper(const fhicl::ParameterSet& pset) :
00038 timeoutInUsecs_(pset.get<std::size_t>("timeoutInUsecs", 100000))
00039 , dispatcherHost_(pset.get<std::string>("dispatcherHost", "localhost"))
00040 , dispatcherPort_(pset.get<std::string>("dispatcherPort", "5266"))
00041 , serverUrl_(pset.get<std::string>("server_url", "http://" + dispatcherHost_ + ":" + dispatcherPort_ + "/RPC2"))
00042 , maxEventsBeforeInit_(pset.get<std::size_t>("maxEventsBeforeInit", 5))
00043 , allowedFragmentTypes_(pset.get<std::vector<int>>("allowedFragmentTypes", { 226, 227, 229 }))
00044 , quitOnFragmentIntegrityProblem_(pset.get<bool>("quitOnFragmentIntegrityProblem", true))
00045 , monitorRegistered_(false)
00046 {
00047 std::signal(SIGINT, signal_handler);
00048
00049 try
00050 {
00051 transfer_ = MakeTransferPlugin(pset, "transfer_plugin", TransferInterface::Role::kReceive);
00052 }
00053 catch (...)
00054 {
00055 ExceptionHandler(ExceptionHandlerRethrow::yes,
00056 "TransferWrapper: failure in call to MakeTransferPlugin");
00057 }
00058
00059 fhicl::ParameterSet new_pset(pset);
00060 if (!new_pset.has_key("server_url")) {
00061 new_pset.put<std::string>("server_url", serverUrl_);
00062 }
00063
00064 auto dispatcherConfig = pset.get<fhicl::ParameterSet>("dispatcher_config");
00065 artdaq::Commandable c;
00066 commander_ = MakeCommanderPlugin(new_pset, c);
00067
00068 int retry = 3;
00069
00070 while (retry > 0) {
00071 TLOG(TLVL_INFO) << "Attempting to register this monitor (\"" << transfer_->uniqueLabel()
00072 << "\") with the dispatcher aggregator" ;
00073
00074 auto status = commander_->send_register_monitor(dispatcherConfig.to_string());
00075
00076 TLOG(TLVL_INFO) << "Response from dispatcher is \"" << status << "\"" ;
00077
00078 if (status == "Success")
00079 {
00080 monitorRegistered_ = true;
00081 break;
00082 }
00083 else
00084 {
00085 TLOG(TLVL_WARNING) << "Error in TransferWrapper: attempt to register with dispatcher did not result in the \"Success\" response" ;
00086 usleep(100000);
00087 }
00088 retry--;
00089 }
00090 }
00091
00092 void artdaq::TransferWrapper::receiveMessage(std::unique_ptr<TBufferFile>& msg)
00093 {
00094 std::unique_ptr<artdaq::Fragment> fragmentPtr;
00095 bool receivedFragment = false;
00096 static bool initialized = false;
00097 static size_t fragments_received = 0;
00098
00099 while (true && !gSignalStatus)
00100 {
00101 fragmentPtr = std::make_unique<artdaq::Fragment>();
00102
00103 while (!receivedFragment)
00104 {
00105 if (gSignalStatus)
00106 {
00107 TLOG(TLVL_INFO) << "Ctrl-C appears to have been hit" ;
00108 unregisterMonitor();
00109 return;
00110 }
00111
00112 try
00113 {
00114 auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
00115
00116 if (result >= artdaq::TransferInterface::RECV_SUCCESS)
00117 {
00118 receivedFragment = true;
00119 fragments_received++;
00120
00121 static size_t cntr = 1;
00122 auto mod = ++cntr % 10;
00123 auto suffix = "-th";
00124 if (mod == 1) suffix = "-st";
00125 if (mod == 2) suffix = "-nd";
00126 if (mod == 3) suffix = "-rd";
00127 TLOG(TLVL_INFO) << "Received " << cntr << suffix << " event, "
00128 << "seqID == " << fragmentPtr->sequenceID()
00129 << ", type == " << fragmentPtr->typeString() ;
00130 continue;
00131 }
00132 else if (result == artdaq::TransferInterface::DATA_END)
00133 {
00134 TLOG(TLVL_ERROR) << "Transfer Plugin disconnected or other unrecoverable error. Shutting down.";
00135 unregisterMonitor();
00136 return;
00137 }
00138 else
00139 {
00140 TLOG(TLVL_WARNING) << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again" ;
00141
00142 }
00143 }
00144 catch (...)
00145 {
00146 ExceptionHandler(ExceptionHandlerRethrow::yes,
00147 "Problem receiving data in TransferWrapper::receiveMessage");
00148 }
00149 }
00150
00151 if (fragmentPtr->type() == artdaq::Fragment::EndOfDataFragmentType)
00152 {
00153
00154
00155
00156
00157 return;
00158 }
00159
00160 try
00161 {
00162 extractTBufferFile(*fragmentPtr, msg);
00163 }
00164 catch (...)
00165 {
00166 ExceptionHandler(ExceptionHandlerRethrow::yes,
00167 "Problem extracting TBufferFile from artdaq::Fragment in TransferWrapper::receiveMessage");
00168 }
00169
00170 checkIntegrity(*fragmentPtr);
00171
00172 if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
00173 {
00174 initialized = true;
00175 break;
00176 }
00177 else
00178 {
00179 receivedFragment = false;
00180
00181 if (fragments_received > maxEventsBeforeInit_)
00182 {
00183 throw cet::exception("TransferWrapper") << "First " << maxEventsBeforeInit_ <<
00184 " events received did not include the \"Init\" event containing necessary info for art; exiting...";
00185 }
00186 }
00187 }
00188 }
00189
00190
00191 void
00192 artdaq::TransferWrapper::extractTBufferFile(const artdaq::Fragment& fragment,
00193 std::unique_ptr<TBufferFile>& tbuffer)
00194 {
00195 const artdaq::NetMonHeader* header = fragment.metadata<artdaq::NetMonHeader>();
00196 char* buffer = (char *)malloc(header->data_length);
00197 memcpy(buffer, fragment.dataBeginBytes(), header->data_length);
00198
00199
00200 tbuffer.reset(new TBufferFile(TBuffer::kRead, header->data_length, buffer, kTRUE, 0));
00201 }
00202
00203 void
00204 artdaq::TransferWrapper::checkIntegrity(const artdaq::Fragment& fragment) const
00205 {
00206 const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
00207 sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
00208 const size_t payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
00209 const size_t metadata = sizeof(artdaq::NetMonHeader);
00210 const size_t totalsize = fragment.sizeBytes();
00211
00212 const size_t type = static_cast<size_t>(fragment.type());
00213
00214 if (totalsize != artdaqheader + metadata + payload)
00215 {
00216 std::stringstream errmsg;
00217 errmsg << "Error: artdaq fragment of type " <<
00218 fragment.typeString() << ", sequence ID " <<
00219 fragment.sequenceID() <<
00220 " has internally inconsistent measures of its size, signalling data corruption: in bytes," <<
00221 " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader <<
00222 ", metadata = " << metadata << ", payload = " << payload;
00223
00224 TLOG(TLVL_ERROR) << errmsg.str() ;
00225
00226 if (quitOnFragmentIntegrityProblem_)
00227 {
00228 throw cet::exception("TransferWrapper") << errmsg.str();
00229 }
00230 else
00231 {
00232 return;
00233 }
00234 }
00235
00236 auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
00237
00238 if (findloc == allowedFragmentTypes_.end())
00239 {
00240 std::stringstream errmsg;
00241 errmsg << "Error: artdaq fragment appears to have type "
00242 << type << ", not found in the allowed fragment types list";
00243
00244 TLOG(TLVL_ERROR) << errmsg.str() ;
00245 if (quitOnFragmentIntegrityProblem_)
00246 {
00247 throw cet::exception("TransferWrapper") << errmsg.str();
00248 }
00249 else
00250 {
00251 return;
00252 }
00253 }
00254 }
00255
00256 void
00257 artdaq::TransferWrapper::unregisterMonitor()
00258 {
00259 if (!monitorRegistered_)
00260 {
00261 throw cet::exception("TransferWrapper") <<
00262 "The function to unregister the monitor was called, but the monitor doesn't appear to be registered";
00263 }
00264
00265 int retry = 3;
00266 while (retry > 0) {
00267
00268 TLOG(TLVL_INFO) << "Requesting that this monitor (" << transfer_->uniqueLabel()
00269 << ") be unregistered from the dispatcher aggregator";
00270
00271 auto status = commander_->send_unregister_monitor(transfer_->uniqueLabel());
00272
00273
00274 TLOG(TLVL_INFO) << "Response from dispatcher is \""
00275 << status << "\"";
00276
00277 if (status == "Success")
00278 {
00279 monitorRegistered_ = false;
00280 break;
00281 }
00282 else if (status == "busy")
00283 { }
00284 else
00285 {
00286 throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to unregister with dispatcher did not result in the \"Success\" response";
00287 }
00288 retry--;
00289 }
00290 }
00291
00292
00293 artdaq::TransferWrapper::~TransferWrapper()
00294 {
00295 if (monitorRegistered_)
00296 {
00297 try
00298 {
00299 unregisterMonitor();
00300 }
00301 catch (...)
00302 {
00303 ExceptionHandler(ExceptionHandlerRethrow::no,
00304 "An exception occurred when trying to unregister monitor during TransferWrapper's destruction");
00305 }
00306 }
00307 }