artdaq  v3_06_00
TransferWrapper.cc
1 #define TRACE_NAME "TransferWrapper"
2 
3 #include "artdaq/ArtModules/detail/TransferWrapper.hh"
4 #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
5 #include "artdaq/ExternalComms/MakeCommanderPlugin.hh"
6 #include "artdaq/DAQdata/NetMonHeader.hh"
7 #include "artdaq/DAQdata/Globals.hh"
8 #include "artdaq-core/Utilities/ExceptionHandler.hh"
9 #include "artdaq-core/Data/Fragment.hh"
10 
11 #include "cetlib/BasicPluginFactory.h"
12 #include "cetlib_except/exception.h"
13 #include "fhiclcpp/ParameterSet.h"
14 
15 #include <TBufferFile.h>
16 
17 #include <limits>
18 #include <iostream>
19 #include <string>
20 #include <sstream>
21 #include <csignal>
22 
23 namespace
24 {
25  volatile std::sig_atomic_t gSignalStatus = 0;
26 }
27 
32 void signal_handler(int signal)
33 {
34  gSignalStatus = signal;
35 }
36 
37 artdaq::TransferWrapper::TransferWrapper(const fhicl::ParameterSet& pset) :
38  timeoutInUsecs_(pset.get<std::size_t>("timeoutInUsecs", 100000))
39  , dispatcherHost_(pset.get<std::string>("dispatcherHost", "localhost"))
40  , dispatcherPort_(pset.get<std::string>("dispatcherPort", "5266"))
41  , serverUrl_(pset.get<std::string>("server_url", "http://" + dispatcherHost_ + ":" + dispatcherPort_ + "/RPC2"))
42  , maxEventsBeforeInit_(pset.get<std::size_t>("maxEventsBeforeInit", 5))
43  , allowedFragmentTypes_(pset.get<std::vector<int>>("allowedFragmentTypes", { 226, 227, 229 }))
44  , quitOnFragmentIntegrityProblem_(pset.get<bool>("quitOnFragmentIntegrityProblem", true))
45  , monitorRegistered_(false)
46 {
47  std::signal(SIGINT, signal_handler);
48 
49  try
50  {
51  transfer_ = MakeTransferPlugin(pset, "transfer_plugin", TransferInterface::Role::kReceive);
52  }
53  catch (...)
54  {
55  ExceptionHandler(ExceptionHandlerRethrow::yes,
56  "TransferWrapper: failure in call to MakeTransferPlugin");
57  }
58 
59  try {
60  if (metricMan) {
61  metricMan->initialize(pset.get<fhicl::ParameterSet>("metrics", fhicl::ParameterSet()), "Online Monitor");
62  metricMan->do_start();
63  }
64  }
65  catch (...)
66  {
67  ExceptionHandler(ExceptionHandlerRethrow::no, "TransferWrapper: could not configure metrics");
68  }
69 
70 
71  fhicl::ParameterSet new_pset(pset);
72  if (!new_pset.has_key("server_url")) {
73  new_pset.put<std::string>("server_url", serverUrl_);
74  }
75 
76  auto dispatcherConfig = pset.get<fhicl::ParameterSet>("dispatcher_config");
78  commander_ = MakeCommanderPlugin(new_pset, c);
79 
80  int retry = 3;
81 
82  while (retry > 0) {
83  TLOG(TLVL_INFO) << "Attempting to register this monitor (\"" << transfer_->uniqueLabel()
84  << "\") with the dispatcher aggregator" ;
85 
86  auto status = commander_->send_register_monitor(dispatcherConfig.to_string());
87 
88  TLOG(TLVL_INFO) << "Response from dispatcher is \"" << status << "\"" ;
89 
90  if (status == "Success")
91  {
92  monitorRegistered_ = true;
93  break;
94  }
95  else
96  {
97  TLOG(TLVL_WARNING) << "Error in TransferWrapper: attempt to register with dispatcher did not result in the \"Success\" response" ;
98  usleep(100000);
99  }
100  retry--;
101  }
102 }
103 
104 void artdaq::TransferWrapper::receiveMessage(std::unique_ptr<TBufferFile>& msg)
105 {
106  std::unique_ptr<artdaq::Fragment> fragmentPtr;
107  bool receivedFragment = false;
108  static bool initialized = false;
109  static size_t fragments_received = 0;
110 
111  while (true && !gSignalStatus)
112  {
113  fragmentPtr = std::make_unique<artdaq::Fragment>();
114 
115  while (!receivedFragment)
116  {
117  if (gSignalStatus)
118  {
119  TLOG(TLVL_INFO) << "Ctrl-C appears to have been hit" ;
120  unregisterMonitor();
121  return;
122  }
123 
124  try
125  {
126  auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
127 
129  {
130  receivedFragment = true;
131  fragments_received++;
132 
133  static size_t cntr = 0;
134  auto mod = ++cntr % 10;
135  auto suffix = "-th";
136  if (mod == 1) suffix = "-st";
137  if (mod == 2) suffix = "-nd";
138  if (mod == 3) suffix = "-rd";
139  TLOG(TLVL_INFO) << "Received " << cntr << suffix << " event, "
140  << "seqID == " << fragmentPtr->sequenceID()
141  << ", type == " << fragmentPtr->typeString() ;
142  continue;
143  }
144  else if (result == artdaq::TransferInterface::DATA_END)
145  {
146  TLOG(TLVL_ERROR) << "Transfer Plugin disconnected or other unrecoverable error. Shutting down.";
147  unregisterMonitor();
148  return;
149  }
150  else
151  {
152  // 02-Jun-2018, KAB: added status/result printout
153  // to-do: add another else clause that explicitly checks for RECV_TIMEOUT
154  TLOG(TLVL_WARNING) << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again"
155  << ", status = " << result;
156 
157  }
158  }
159  catch (...)
160  {
161  ExceptionHandler(ExceptionHandlerRethrow::yes,
162  "Problem receiving data in TransferWrapper::receiveMessage");
163  }
164  }
165 
166  if (fragmentPtr->type() == artdaq::Fragment::EndOfDataFragmentType)
167  {
168  //if (monitorRegistered_)
169  //{
170  // unregisterMonitor();
171  //}
172  return;
173  }
174 
175  try
176  {
177  extractTBufferFile(*fragmentPtr, msg);
178  }
179  catch (...)
180  {
181  ExceptionHandler(ExceptionHandlerRethrow::yes,
182  "Problem extracting TBufferFile from artdaq::Fragment in TransferWrapper::receiveMessage");
183  }
184 
185  checkIntegrity(*fragmentPtr);
186 
187  if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
188  {
189  initialized = true;
190  break;
191  }
192  else
193  {
194  receivedFragment = false;
195 
196  if (fragments_received > maxEventsBeforeInit_)
197  {
198  throw cet::exception("TransferWrapper") << "First " << maxEventsBeforeInit_ <<
199  " events received did not include the \"Init\" event containing necessary info for art; exiting...";
200  }
201  }
202  }
203 }
204 
205 
206 void
207 artdaq::TransferWrapper::extractTBufferFile(const artdaq::Fragment& fragment,
208  std::unique_ptr<TBufferFile>& tbuffer)
209 {
210  const artdaq::NetMonHeader* header = fragment.metadata<artdaq::NetMonHeader>();
211  char* buffer = (char *)malloc(header->data_length);
212  memcpy(buffer, fragment.dataBeginBytes(), header->data_length);
213 
214  // TBufferFile takes ownership of the contents of memory passed to it
215  tbuffer.reset(new TBufferFile(TBuffer::kRead, header->data_length, buffer, kTRUE, 0));
216 }
217 
218 void
219 artdaq::TransferWrapper::checkIntegrity(const artdaq::Fragment& fragment) const
220 {
221  const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
222  sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
223  const size_t payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
224  const size_t metadata = sizeof(artdaq::NetMonHeader);
225  const size_t totalsize = fragment.sizeBytes();
226 
227  const size_t type = static_cast<size_t>(fragment.type());
228 
229  if (totalsize != artdaqheader + metadata + payload)
230  {
231  std::stringstream errmsg;
232  errmsg << "Error: artdaq fragment of type " <<
233  fragment.typeString() << ", sequence ID " <<
234  fragment.sequenceID() <<
235  " has internally inconsistent measures of its size, signalling data corruption: in bytes," <<
236  " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader <<
237  ", metadata = " << metadata << ", payload = " << payload;
238 
239  TLOG(TLVL_ERROR) << errmsg.str() ;
240 
241  if (quitOnFragmentIntegrityProblem_)
242  {
243  throw cet::exception("TransferWrapper") << errmsg.str();
244  }
245  else
246  {
247  return;
248  }
249  }
250 
251  auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
252 
253  if (findloc == allowedFragmentTypes_.end())
254  {
255  std::stringstream errmsg;
256  errmsg << "Error: artdaq fragment appears to have type "
257  << type << ", not found in the allowed fragment types list";
258 
259  TLOG(TLVL_ERROR) << errmsg.str() ;
260  if (quitOnFragmentIntegrityProblem_)
261  {
262  throw cet::exception("TransferWrapper") << errmsg.str();
263  }
264  else
265  {
266  return;
267  }
268  }
269 }
270 
271 void
272 artdaq::TransferWrapper::unregisterMonitor()
273 {
274  if (!monitorRegistered_)
275  {
276  throw cet::exception("TransferWrapper") <<
277  "The function to unregister the monitor was called, but the monitor doesn't appear to be registered";
278  }
279 
280  int retry = 3;
281  while (retry > 0) {
282 
283  TLOG(TLVL_INFO) << "Requesting that this monitor (" << transfer_->uniqueLabel()
284  << ") be unregistered from the dispatcher aggregator";
285 
286  auto status = commander_->send_unregister_monitor(transfer_->uniqueLabel());
287 
288 
289  TLOG(TLVL_INFO) << "Response from dispatcher is \""
290  << status << "\"";
291 
292  if (status == "Success")
293  {
294  monitorRegistered_ = false;
295  break;
296  }
297  else if (status == "busy")
298  { }
299  else
300  {
301  throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to unregister with dispatcher did not result in the \"Success\" response";
302  }
303  retry--;
304  }
305 }
306 
307 
309 {
310  if (monitorRegistered_)
311  {
312  try
313  {
314  unregisterMonitor();
315  }
316  catch (...)
317  {
318  ExceptionHandler(ExceptionHandlerRethrow::no,
319  "An exception occurred when trying to unregister monitor during TransferWrapper's destruction");
320  }
321  }
323 }
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.
static void CleanUpGlobals()
Clean up statically-allocated Manager class instances.
Definition: Globals.hh:150
virtual ~TransferWrapper()
TransferWrapper Destructor.
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.
Value that is to be returned when a Transfer plugin determines that no more data will be arriving...
For code clarity, things checking for successful receive should check retval &gt;= NO_RANK_INFO.
uint64_t data_length
The length of the message.
Definition: NetMonHeader.hh:16