artdaq  v3_02_01
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  fhicl::ParameterSet new_pset(pset);
60  if (!new_pset.has_key("server_url")) {
61  new_pset.put<std::string>("server_url", serverUrl_);
62  }
63 
64  auto dispatcherConfig = pset.get<fhicl::ParameterSet>("dispatcher_config");
66  commander_ = MakeCommanderPlugin(new_pset, c);
67 
68  int retry = 3;
69 
70  while (retry > 0) {
71  TLOG(TLVL_INFO) << "Attempting to register this monitor (\"" << transfer_->uniqueLabel()
72  << "\") with the dispatcher aggregator" ;
73 
74  auto status = commander_->send_register_monitor(dispatcherConfig.to_string());
75 
76  TLOG(TLVL_INFO) << "Response from dispatcher is \"" << status << "\"" ;
77 
78  if (status == "Success")
79  {
80  monitorRegistered_ = true;
81  break;
82  }
83  else
84  {
85  TLOG(TLVL_WARNING) << "Error in TransferWrapper: attempt to register with dispatcher did not result in the \"Success\" response" ;
86  usleep(100000);
87  }
88  retry--;
89  }
90 }
91 
92 void artdaq::TransferWrapper::receiveMessage(std::unique_ptr<TBufferFile>& msg)
93 {
94  std::unique_ptr<artdaq::Fragment> fragmentPtr;
95  bool receivedFragment = false;
96  static bool initialized = false;
97  static size_t fragments_received = 0;
98 
99  while (true && !gSignalStatus)
100  {
101  fragmentPtr = std::make_unique<artdaq::Fragment>();
102 
103  while (!receivedFragment)
104  {
105  if (gSignalStatus)
106  {
107  TLOG(TLVL_INFO) << "Ctrl-C appears to have been hit" ;
108  unregisterMonitor();
109  return;
110  }
111 
112  try
113  {
114  auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
115 
117  {
118  receivedFragment = true;
119  fragments_received++;
120 
121  static size_t cntr = 1;
122  auto mod = ++cntr % 10;
123  auto suffix = "-th";
124  if (mod == 1) suffix = "-st";
125  if (mod == 2) suffix = "-nd";
126  if (mod == 3) suffix = "-rd";
127  TLOG(TLVL_INFO) << "Received " << cntr << suffix << " event, "
128  << "seqID == " << fragmentPtr->sequenceID()
129  << ", type == " << fragmentPtr->typeString() ;
130  continue;
131  }
132  else if (result == artdaq::TransferInterface::DATA_END)
133  {
134  TLOG(TLVL_ERROR) << "Transfer Plugin disconnected or other unrecoverable error. Shutting down.";
135  unregisterMonitor();
136  return;
137  }
138  else
139  {
140  TLOG(TLVL_WARNING) << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again" ;
141 
142  }
143  }
144  catch (...)
145  {
146  ExceptionHandler(ExceptionHandlerRethrow::yes,
147  "Problem receiving data in TransferWrapper::receiveMessage");
148  }
149  }
150 
151  if (fragmentPtr->type() == artdaq::Fragment::EndOfDataFragmentType)
152  {
153  //if (monitorRegistered_)
154  //{
155  // unregisterMonitor();
156  //}
157  return;
158  }
159 
160  try
161  {
162  extractTBufferFile(*fragmentPtr, msg);
163  }
164  catch (...)
165  {
166  ExceptionHandler(ExceptionHandlerRethrow::yes,
167  "Problem extracting TBufferFile from artdaq::Fragment in TransferWrapper::receiveMessage");
168  }
169 
170  checkIntegrity(*fragmentPtr);
171 
172  if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
173  {
174  initialized = true;
175  break;
176  }
177  else
178  {
179  receivedFragment = false;
180 
181  if (fragments_received > maxEventsBeforeInit_)
182  {
183  throw cet::exception("TransferWrapper") << "First " << maxEventsBeforeInit_ <<
184  " events received did not include the \"Init\" event containing necessary info for art; exiting...";
185  }
186  }
187  }
188 }
189 
190 
191 void
192 artdaq::TransferWrapper::extractTBufferFile(const artdaq::Fragment& fragment,
193  std::unique_ptr<TBufferFile>& tbuffer)
194 {
195  const artdaq::NetMonHeader* header = fragment.metadata<artdaq::NetMonHeader>();
196  char* buffer = (char *)malloc(header->data_length);
197  memcpy(buffer, fragment.dataBeginBytes(), header->data_length);
198 
199  // TBufferFile takes ownership of the contents of memory passed to it
200  tbuffer.reset(new TBufferFile(TBuffer::kRead, header->data_length, buffer, kTRUE, 0));
201 }
202 
203 void
204 artdaq::TransferWrapper::checkIntegrity(const artdaq::Fragment& fragment) const
205 {
206  const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
207  sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
208  const size_t payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
209  const size_t metadata = sizeof(artdaq::NetMonHeader);
210  const size_t totalsize = fragment.sizeBytes();
211 
212  const size_t type = static_cast<size_t>(fragment.type());
213 
214  if (totalsize != artdaqheader + metadata + payload)
215  {
216  std::stringstream errmsg;
217  errmsg << "Error: artdaq fragment of type " <<
218  fragment.typeString() << ", sequence ID " <<
219  fragment.sequenceID() <<
220  " has internally inconsistent measures of its size, signalling data corruption: in bytes," <<
221  " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader <<
222  ", metadata = " << metadata << ", payload = " << payload;
223 
224  TLOG(TLVL_ERROR) << errmsg.str() ;
225 
226  if (quitOnFragmentIntegrityProblem_)
227  {
228  throw cet::exception("TransferWrapper") << errmsg.str();
229  }
230  else
231  {
232  return;
233  }
234  }
235 
236  auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
237 
238  if (findloc == allowedFragmentTypes_.end())
239  {
240  std::stringstream errmsg;
241  errmsg << "Error: artdaq fragment appears to have type "
242  << type << ", not found in the allowed fragment types list";
243 
244  TLOG(TLVL_ERROR) << errmsg.str() ;
245  if (quitOnFragmentIntegrityProblem_)
246  {
247  throw cet::exception("TransferWrapper") << errmsg.str();
248  }
249  else
250  {
251  return;
252  }
253  }
254 }
255 
256 void
257 artdaq::TransferWrapper::unregisterMonitor()
258 {
259  if (!monitorRegistered_)
260  {
261  throw cet::exception("TransferWrapper") <<
262  "The function to unregister the monitor was called, but the monitor doesn't appear to be registered";
263  }
264 
265  int retry = 3;
266  while (retry > 0) {
267 
268  TLOG(TLVL_INFO) << "Requesting that this monitor (" << transfer_->uniqueLabel()
269  << ") be unregistered from the dispatcher aggregator";
270 
271  auto status = commander_->send_unregister_monitor(transfer_->uniqueLabel());
272 
273 
274  TLOG(TLVL_INFO) << "Response from dispatcher is \""
275  << status << "\"";
276 
277  if (status == "Success")
278  {
279  monitorRegistered_ = false;
280  break;
281  }
282  else if (status == "busy")
283  { }
284  else
285  {
286  throw cet::exception("TransferWrapper") << "Error in TransferWrapper: attempt to unregister with dispatcher did not result in the \"Success\" response";
287  }
288  retry--;
289  }
290 }
291 
292 
294 {
295  if (monitorRegistered_)
296  {
297  try
298  {
299  unregisterMonitor();
300  }
301  catch (...)
302  {
303  ExceptionHandler(ExceptionHandlerRethrow::no,
304  "An exception occurred when trying to unregister monitor during TransferWrapper's destruction");
305  }
306  }
307 }
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.
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;= RECV_SUCCESS.
uint64_t data_length
The length of the message.
Definition: NetMonHeader.hh:16