artdaq  v3_00_01
TransferWrapper.cc
1 #include "artdaq/ArtModules/detail/TransferWrapper.hh"
2 #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
3 #include "artdaq/ExternalComms/MakeCommanderPlugin.hh"
4 #include "artdaq/DAQdata/NetMonHeader.hh"
5 #include "artdaq/DAQdata/Globals.hh"
6 #include "artdaq-core/Utilities/ExceptionHandler.hh"
7 #include "artdaq-core/Data/Fragment.hh"
8 
9 #include "cetlib/BasicPluginFactory.h"
10 #include "cetlib_except/exception.h"
11 #include "fhiclcpp/ParameterSet.h"
12 
13 #include <TBufferFile.h>
14 
15 #include <limits>
16 #include <iostream>
17 #include <string>
18 #include <sstream>
19 #include <csignal>
20 
21 namespace
22 {
23  volatile std::sig_atomic_t gSignalStatus = 0;
24 }
25 
30 void signal_handler(int signal)
31 {
32  gSignalStatus = signal;
33 }
34 
35 artdaq::TransferWrapper::TransferWrapper(const fhicl::ParameterSet& pset) :
36  timeoutInUsecs_(pset.get<std::size_t>("timeoutInUsecs", 100000))
37  , dispatcherHost_(pset.get<std::string>("dispatcherHost", "localhost"))
38  , dispatcherPort_(pset.get<std::string>("dispatcherPort", "5266"))
39  , serverUrl_(pset.get<std::string>("server_url", "http://" + dispatcherHost_ + ":" + dispatcherPort_ + "/RPC2"))
40  , maxEventsBeforeInit_(pset.get<std::size_t>("maxEventsBeforeInit", 5))
41  , allowedFragmentTypes_(pset.get<std::vector<int>>("allowedFragmentTypes", { 226, 227, 229 }))
42  , quitOnFragmentIntegrityProblem_(pset.get<bool>("quitOnFragmentIntegrityProblem", true))
43  , monitorRegistered_(false)
44 {
45  std::signal(SIGINT, signal_handler);
46 
47  try
48  {
49  transfer_ = MakeTransferPlugin(pset, "transfer_plugin", TransferInterface::Role::kReceive);
50  }
51  catch (...)
52  {
53  ExceptionHandler(ExceptionHandlerRethrow::yes,
54  "TransferWrapper: failure in call to MakeTransferPlugin");
55  }
56 
57  fhicl::ParameterSet new_pset(pset);
58  if (!new_pset.has_key("server_url")) {
59  new_pset.put<std::string>("server_url", serverUrl_);
60  }
61 
62  auto dispatcherConfig = pset.get<fhicl::ParameterSet>("dispatcher_config");
64  commander_ = MakeCommanderPlugin(new_pset, c);
65 
66  int retry = 3;
67 
68  while (retry > 0) {
69  TLOG_INFO("TransferWrapper") << "Attempting to register this monitor (\"" << transfer_->uniqueLabel()
70  << "\") with the dispatcher aggregator" << TLOG_ENDL;
71 
72  auto status = commander_->send_register_monitor(dispatcherConfig.to_string());
73 
74  TLOG_INFO("TransferWrapper") << "Response from dispatcher is \"" << status << "\"" << TLOG_ENDL;
75 
76  if (status == "Success")
77  {
78  monitorRegistered_ = true;
79  break;
80  }
81  else
82  {
83  TLOG_WARNING("TransferWrapper") << "Error in TransferWrapper: attempt to register with dispatcher did not result in the \"Success\" response" << TLOG_ENDL;
84  usleep(100000);
85  }
86  retry--;
87  }
88 }
89 
90 void artdaq::TransferWrapper::receiveMessage(std::unique_ptr<TBufferFile>& msg)
91 {
92  std::unique_ptr<artdaq::Fragment> fragmentPtr;
93  bool receivedFragment = false;
94  static bool initialized = false;
95  static size_t fragments_received = 0;
96 
97  while (true && !gSignalStatus)
98  {
99  fragmentPtr = std::make_unique<artdaq::Fragment>();
100 
101  while (!receivedFragment)
102  {
103  if (gSignalStatus)
104  {
105  TLOG_INFO("TransferWrapper") << "Ctrl-C appears to have been hit" << TLOG_ENDL;
106  unregisterMonitor();
107  return;
108  }
109 
110  try
111  {
112  auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
113 
115  {
116  receivedFragment = true;
117  fragments_received++;
118 
119  static size_t cntr = 1;
120 
121  TLOG_INFO("TransferWrapper") << "Received " << cntr++ << "-th event, "
122  << "seqID == " << fragmentPtr->sequenceID()
123  << ", type == " << fragmentPtr->typeString() << TLOG_ENDL;
124  continue;
125  }
126  else
127  {
128  TLOG_WARNING("TransferWrapper") << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again" << TLOG_ENDL;
129 
130  }
131  }
132  catch (...)
133  {
134  ExceptionHandler(ExceptionHandlerRethrow::yes,
135  "Problem receiving data in TransferWrapper::receiveMessage");
136  }
137  }
138 
139  if (fragmentPtr->type() == artdaq::Fragment::EndOfDataFragmentType)
140  {
141  //if (monitorRegistered_)
142  //{
143  // unregisterMonitor();
144  //}
145  return;
146  }
147 
148  try
149  {
150  extractTBufferFile(*fragmentPtr, msg);
151  }
152  catch (...)
153  {
154  ExceptionHandler(ExceptionHandlerRethrow::yes,
155  "Problem extracting TBufferFile from artdaq::Fragment in TransferWrapper::receiveMessage");
156  }
157 
158  checkIntegrity(*fragmentPtr);
159 
160  if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
161  {
162  initialized = true;
163  break;
164  }
165  else
166  {
167  receivedFragment = false;
168 
169  if (fragments_received > maxEventsBeforeInit_)
170  {
171  throw cet::exception("TransferWrapper") << "First " << maxEventsBeforeInit_ <<
172  " events received did not include the \"Init\" event containing necessary info for art; exiting...";
173  }
174  }
175  }
176 }
177 
178 
179 void
180 artdaq::TransferWrapper::extractTBufferFile(const artdaq::Fragment& fragment,
181  std::unique_ptr<TBufferFile>& tbuffer)
182 {
183  const artdaq::NetMonHeader* header = fragment.metadata<artdaq::NetMonHeader>();
184  char* buffer = (char *)malloc(header->data_length);
185  memcpy(buffer, fragment.dataBeginBytes(), header->data_length);
186 
187  // TBufferFile takes ownership of the contents of memory passed to it
188  tbuffer.reset(new TBufferFile(TBuffer::kRead, header->data_length, buffer, kTRUE, 0));
189 }
190 
191 void
192 artdaq::TransferWrapper::checkIntegrity(const artdaq::Fragment& fragment) const
193 {
194  const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
195  sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
196  const size_t payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
197  const size_t metadata = sizeof(artdaq::NetMonHeader);
198  const size_t totalsize = fragment.sizeBytes();
199 
200  const size_t type = static_cast<size_t>(fragment.type());
201 
202  if (totalsize != artdaqheader + metadata + payload)
203  {
204  std::stringstream errmsg;
205  errmsg << "Error: artdaq fragment of type " <<
206  fragment.typeString() << ", sequence ID " <<
207  fragment.sequenceID() <<
208  " has internally inconsistent measures of its size, signalling data corruption: in bytes," <<
209  " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader <<
210  ", metadata = " << metadata << ", payload = " << payload;
211 
212  TLOG_ERROR("TransferWrapper") << errmsg.str() << TLOG_ENDL;
213 
214  if (quitOnFragmentIntegrityProblem_)
215  {
216  throw cet::exception("TransferWrapper") << errmsg.str();
217  }
218  else
219  {
220  return;
221  }
222  }
223 
224  auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
225 
226  if (findloc == allowedFragmentTypes_.end())
227  {
228  std::stringstream errmsg;
229  errmsg << "Error: artdaq fragment appears to have type "
230  << type << ", not found in the allowed fragment types list";
231 
232  TLOG_ERROR("TransferWrapper") << errmsg.str() << TLOG_ENDL;
233  if (quitOnFragmentIntegrityProblem_)
234  {
235  throw cet::exception("TransferWrapper") << errmsg.str();
236  }
237  else
238  {
239  return;
240  }
241  }
242 }
243 
244 void
245 artdaq::TransferWrapper::unregisterMonitor()
246 {
247  if (!monitorRegistered_)
248  {
249  throw cet::exception("TransferWrapper") <<
250  "The function to unregister the monitor was called, but the monitor doesn't appear to be registered";
251  }
252 
253  TLOG_INFO("TransferWrapper") << "Requesting that this monitor (" << transfer_->uniqueLabel()
254  << ") be unregistered from the dispatcher aggregator" << TLOG_ENDL;
255 
256  auto status = commander_->send_unregister_monitor(transfer_->uniqueLabel());
257 
258 
259  TLOG_INFO("TransferWrapper") << "Response from dispatcher is \""
260  << status << "\"" << TLOG_ENDL;
261 
262  if (status == "Success")
263  {
264  monitorRegistered_ = false;
265  }
266  else
267  {
268  throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to unregister with dispatcher did not result in the \"Success\" response";
269  }
270 }
271 
272 
274 {
275  if (monitorRegistered_)
276  {
277  try
278  {
279  unregisterMonitor();
280  }
281  catch (...)
282  {
283  ExceptionHandler(ExceptionHandlerRethrow::no,
284  "An exception occurred when trying to unregister monitor during TransferWrapper's destruction");
285  }
286  }
287 }
Commandable is the base class for all artdaq components which implement the artdaq state machine...
Definition: Commandable.hh:20
void receiveMessage(std::unique_ptr< TBufferFile > &msg)
Receive a Fragment from the TransferInterface, and send it to art.
TransferWrapper(const fhicl::ParameterSet &pset)
TransferWrapper Constructor.
virtual ~TransferWrapper()
TransferWrapper Destructor.
static const int RECV_TIMEOUT
Value to be returned upon receive timeout. Because receivers otherwise return rank, this is also the limit on the number of ranks that artdaq currently supports.
This TransferInterface is a Receiver.
std::unique_ptr< artdaq::TransferInterface > MakeTransferPlugin(const fhicl::ParameterSet &pset, std::string plugin_label, TransferInterface::Role role)
Load a TransferInterface plugin.
Header with length information for NetMonTransport messages.
Definition: NetMonHeader.hh:14
volatile std::sig_atomic_t gSignalStatus
Stores singal from signal handler.
std::unique_ptr< artdaq::CommanderInterface > MakeCommanderPlugin(const fhicl::ParameterSet &commander_pset, artdaq::Commandable &commandable)
Load a CommanderInterface plugin.
uint64_t data_length
The length of the message.
Definition: NetMonHeader.hh:16