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