artdaq  v3_11_01
ArtdaqInputHelper.hh
1 #ifndef ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQINPUTHELPER_HH_
2 #define ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQINPUTHELPER_HH_
3 
4 #include "art/Framework/Core/FileBlock.h"
5 #include "art/Framework/Core/InputSourceMacros.h"
6 #include "art/Framework/Core/ProductRegistryHelper.h"
7 #include "art/Framework/IO/Sources/Source.h"
8 #include "art/Framework/IO/Sources/SourceHelper.h"
9 #include "art/Framework/IO/Sources/SourceTraits.h"
10 #include "art/Framework/IO/Sources/put_product_in_principal.h"
11 #include "art/Framework/Principal/EventPrincipal.h"
12 #include "art/Framework/Principal/RunPrincipal.h"
13 #include "art/Framework/Principal/SubRunPrincipal.h"
14 #include "art/Framework/Services/Registry/ServiceHandle.h"
15 
16 #include "art/Persistency/Provenance/ProcessHistoryRegistry.h"
17 #include "art_root_io/setup.h"
18 
19 #include "canvas/Persistency/Common/EDProduct.h"
20 #include "canvas/Persistency/Common/Wrapper.h"
21 #include "canvas/Persistency/Provenance/BranchDescription.h"
22 #include "canvas/Persistency/Provenance/BranchKey.h"
23 #include "canvas/Persistency/Provenance/FileFormatVersion.h"
24 #include "canvas/Persistency/Provenance/History.h"
25 #include "canvas/Persistency/Provenance/ParentageRegistry.h"
26 #include "canvas/Persistency/Provenance/ProcessConfiguration.h"
27 #include "canvas/Persistency/Provenance/ProcessHistory.h"
28 #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
29 #include "canvas/Persistency/Provenance/ProductList.h"
30 #include "canvas/Persistency/Provenance/ProductProvenance.h"
31 #include "canvas/Persistency/Provenance/ProductTables.h"
32 #include "canvas/Utilities/DebugMacros.h"
33 
34 #include "artdaq-utilities/Plugins/MakeParameterSet.hh"
35 #include "fhiclcpp/ParameterSet.h"
36 #include "fhiclcpp/ParameterSetID.h"
37 #include "fhiclcpp/ParameterSetRegistry.h"
38 
39 #include <TBufferFile.h>
40 #include <TClass.h>
41 #include <TList.h>
42 #include <TStreamerInfo.h>
43 
44 #include "artdaq-core/Data/ContainerFragment.hh"
45 #include "artdaq-core/Data/Fragment.hh"
46 #include "artdaq-core/Data/detail/ParentageMap.hh"
47 #include "artdaq-core/Utilities/ExceptionHandler.hh"
48 #include "artdaq-core/Utilities/TimeUtils.hh"
49 #include "artdaq/ArtModules/ArtdaqFragmentNamingService.h"
50 #include "artdaq/ArtModules/ArtdaqSharedMemoryService.h"
51 #include "artdaq/ArtModules/InputUtilities.hh"
52 #include "artdaq/DAQdata/Globals.hh"
53 #include "artdaq/DAQdata/NetMonHeader.hh"
54 
55 #include <sys/time.h>
56 #include <cstdio>
57 #include <iomanip>
58 #include <iostream>
59 #include <list>
60 #include <map>
61 #include <memory>
62 #include <set>
63 #include <sstream>
64 #include <string>
65 #include <unordered_map>
66 #include <utility>
67 #include <vector>
68 
69 namespace art {
70 template<typename U>
72 } // namespace art
73 
88 template<typename U>
90 {
91 public:
95  ArtdaqInputHelper(const ArtdaqInputHelper&) = delete;
96 
102 
107 
114  ArtdaqInputHelper(const fhicl::ParameterSet& ps, art::ProductRegistryHelper& helper, art::SourceHelper const& pm);
115 
119  void closeCurrentFile();
120 
125  void readFile(const std::string&, art::FileBlock*& fb);
126 
131  bool hasMoreData() const;
132 
142  bool readNext(art::RunPrincipal* const inR, art::SubRunPrincipal* const inSR, art::RunPrincipal*& outR,
143  art::SubRunPrincipal*& outSR, art::EventPrincipal*& outE);
144 
145 private:
148 
149  void readAndConstructPrincipal(std::unique_ptr<TBufferFile>&, ULong_t, art::RunPrincipal* const,
150  art::SubRunPrincipal* const, art::RunPrincipal*&, art::SubRunPrincipal*&,
151  art::EventPrincipal*&);
152 
153  bool constructPrincipal(artdaq::Fragment::type_t, art::RunPrincipal* const,
154  art::SubRunPrincipal* const, art::RunPrincipal*&, art::SubRunPrincipal*&,
155  art::EventPrincipal*&);
156 
157  template<class T>
158  void readDataProducts(std::list<std::unique_ptr<TBufferFile>>&, T*&);
159 
160  void putInPrincipal(RunPrincipal*&, std::unique_ptr<EDProduct>&&, const BranchDescription&,
161  std::unique_ptr<const ProductProvenance>&&);
162 
163  void putInPrincipal(SubRunPrincipal*&, std::unique_ptr<EDProduct>&&, const BranchDescription&,
164  std::unique_ptr<const ProductProvenance>&&);
165 
166  void putInPrincipal(EventPrincipal*&, std::unique_ptr<EDProduct>&&, const BranchDescription&,
167  std::unique_ptr<const ProductProvenance>&&);
168 
169  void readFragments(std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> const& eventMap, art::EventPrincipal*& outE);
170 
171  bool shutdownMsgReceived_;
172  bool outputFileCloseNeeded_;
173  art::SourceHelper const& pm_;
174  U communicationWrapper_;
175  ProductList* productList_;
176  std::unique_ptr<art::History> history_to_use_;
177  bool fragmentsOnlyMode_;
178  std::string pretend_module_name;
179  size_t bytesRead;
180  std::chrono::steady_clock::time_point last_read_time;
181 };
182 
183 template<typename U>
184 art::ArtdaqInputHelper<U>::ArtdaqInputHelper(const fhicl::ParameterSet& ps, art::ProductRegistryHelper& helper,
185  art::SourceHelper const& pm)
186  : shutdownMsgReceived_(false)
187  , outputFileCloseNeeded_(false)
188  , pm_(pm)
189  , communicationWrapper_(ps)
190  , productList_()
191  , fragmentsOnlyMode_(false)
192  , pretend_module_name(ps.get<std::string>("raw_data_label", "daq"))
193  , bytesRead(0)
194  , last_read_time(std::chrono::steady_clock::now())
195 {
196  root::setup();
197  // Instantiate ArtdaqSharedMemoryService to set up artdaq Globals and MetricManager
198  art::ServiceHandle<ArtdaqSharedMemoryServiceInterface> shm;
199 
200 #if 0
201  volatile bool loop = true;
202  while (loop)
203  {
204  usleep(1000);
205  }
206 #endif
207 
208  // JCF, May-27-2016
209 
210  // Something will have to be done about the labeling of this class,
211  // since it's just a template class- the user will care about the
212  // specific instantiation when it comes to messages
213 
214  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "Begin: ArtdaqInputHelper::ArtdaqInputHelper("
215  << "const fhicl::ParameterSet& ps, "
216  << "art::ProductRegistryHelper& helper, "
217  << "const art::SourceHelper& pm)";
218 
219  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "Going to receive init message";
220  artdaq::FragmentPtrs initFrags = communicationWrapper_.receiveInitMessage();
221  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "Init message received";
222 
223  if (!initFrags.empty() && initFrags.front().get()->type() == artdaq::Fragment::EndOfDataFragmentType)
224  {
225  TLOG_ERROR("ArtdaqInputHelper") << "Received EndOfData as first broadcast! This process neveer received any data!";
226  shutdownMsgReceived_ = true;
227  outputFileCloseNeeded_ = true;
228  }
229  else
230  {
231  if (initFrags.empty() || initFrags.back().get()->dataSize() == 0)
232  {
233  TLOG_DEBUG("ArtdaqInputHelper") << "No init message received or zero-size init message: Fragments-only mode activated! This is an EventBuilder!";
234  fragmentsOnlyMode_ = true;
235  }
236  else
237  {
238  std::list<std::unique_ptr<TBufferFile>> msgs;
239  for (auto& initFrag : initFrags)
240  {
241  auto header = initFrag->metadata<artdaq::NetMonHeader>();
242  msgs.emplace_back(new TBufferFile(TBuffer::kRead, header->data_length, initFrag->dataBegin(), kFALSE, nullptr));
243  }
244 
245  std::list<History*> processHistories;
246 
247  for (auto& msg : msgs)
248  {
249  // This first unsigned long is the message type code, ignored here in the constructor
250  ULong_t dummy = 0;
251  msg->ReadULong(dummy);
252 
253  // ELF: 6/11/2019: This code is taken from TSocket::RecvStreamerInfos
254  auto list = dynamic_cast<TList*>(msg->ReadObject(TList::Class()));
255 
256  TIter next(list);
257  TStreamerInfo* info;
258  TObjLink* lnk = list->FirstLink();
259  // First call BuildCheck for regular class
260  while (lnk)
261  {
262  info = dynamic_cast<TStreamerInfo*>(lnk->GetObject());
263  TObject* element = info->GetElements()->UncheckedAt(0);
264  Bool_t isstl = element && strcmp("This", element->GetName()) == 0;
265  if (!isstl)
266  {
267  info->BuildCheck();
268  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: importing TStreamerInfo: " << info->GetName() << ", version = " << info->GetClassVersion();
269  }
270  lnk = lnk->Next();
271  }
272  // Then call BuildCheck for stl class
273  lnk = list->FirstLink();
274  while (lnk)
275  {
276  info = dynamic_cast<TStreamerInfo*>(lnk->GetObject());
277  TObject* element = info->GetElements()->UncheckedAt(0);
278  Bool_t isstl = element && strcmp("This", element->GetName()) == 0;
279  if (isstl)
280  {
281  info->BuildCheck();
282  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: importing TStreamerInfo: " << info->GetName() << ", version = " << info->GetClassVersion();
283  }
284  lnk = lnk->Next();
285  }
286  // ELF: 6/11/2019: End TSocket snippet
287 
288  //
289  // Read the ParameterSetRegistry.
290  //
291  ULong_t ps_cnt = 0;
292  msg->ReadULong(ps_cnt);
293  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: parameter set count: " << ps_cnt;
294  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: reading parameter sets ...";
295  for (ULong_t I = 0; I < ps_cnt; ++I)
296  {
297  std::string pset_str = ""; // = ReadObjectAny<std::string>(msg, "std::string", "ArtdaqInputHelper::ArtdaqInputHelper");
298  msg->ReadStdString(pset_str);
299 
300  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: parameter set: " << pset_str;
301 
302  fhicl::ParameterSet pset;
303  pset = artdaq::make_pset(pset_str);
304  // Force id calculation.
305  pset.id();
306  fhicl::ParameterSetRegistry::put(pset);
307  }
308  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: finished reading parameter sets.";
309 
310  //
311  // Read the MasterProductRegistry.
312  //
313  auto thisProductList = ReadObjectAny<art::ProductList>(
314  msg, "std::map<art::BranchKey,art::BranchDescription>", "ArtdaqInputHelper::ArtdaqInputHelper");
315  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: Input Product list sz=" << thisProductList->size();
316 
317  bool productListInitialized = productList_ != nullptr;
318  if (!productListInitialized) productList_ = thisProductList;
319  for (auto I = thisProductList->begin(), E = thisProductList->end(); I != E; ++I)
320  {
321 #ifndef __OPTIMIZE__
322  TLOG(50, "ArtdaqInputHelper") << "Branch key: class: '" << I->first.friendlyClassName_ << "' modlbl: '"
323  << I->first.moduleLabel_ << "' instnm: '" << I->first.productInstanceName_ << "' procnm: '"
324  << I->first.processName_ << "', branch description name: " << I->second.wrappedName()
325  << ", TClass = " << static_cast<void*>(TClass::GetClass(I->second.wrappedName().c_str()));
326 #endif
327  if (productListInitialized)
328  {
329  productList_->emplace(*I);
330  }
331  }
332 
333  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: Reading ProcessHistory";
334  auto phm = ReadObjectAny<art::ProcessHistoryMap>(
335  msg, "std::map<const art::Hash<2>,art::ProcessHistory>", "ArtdaqInputHelper::ArtdaqInputHelper");
336  printProcessMap(*phm, "ArtdaqInputHelper's ProcessHistoryMap");
337 
338  ProcessHistoryRegistry::put(*phm);
339  printProcessMap(ProcessHistoryRegistry::get(), "ArtdaqInputHelper's ProcessHistoryRegistry");
340 
341  //
342  // Read the ParentageRegistry.
343  //
344  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: Reading ParentageMap";
345  auto parentageMap = ReadObjectAny<ParentageMap>(msg, "art::ParentageMap", "ArtdaqInputHelper::ArtdaqInputHelper");
346  ParentageRegistry::put(*parentageMap);
347 
348  //
349  // Read the History
350  //
351  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: Reading History";
352  processHistories.push_back(ReadObjectAny<History>(msg, "art::History", "ArtdaqInputHelper::ArtdaqInputHelper"));
353  }
354 
355  // We're going to make a fake History using the collected process histories!
356  art::ProcessHistory fake_process_history;
357  for (auto& hist : processHistories)
358  {
359  auto const& id = hist->processHistoryID();
360  ProcessHistory thisProcessHistory;
361  if (ProcessHistoryRegistry::get(id, thisProcessHistory))
362  {
363  for (auto& conf : thisProcessHistory)
364  fake_process_history.push_back(conf);
365  }
366  }
367  art::ProcessHistoryMap fake_process_history_map;
368  fake_process_history_map[fake_process_history.id()] = fake_process_history;
369  ProcessHistoryRegistry::put(fake_process_history_map);
370  history_to_use_.reset(new History());
371  history_to_use_->setProcessHistoryID(fake_process_history.id());
372  for (auto& hist : processHistories)
373  {
374  for (auto& es : hist->eventSelectionIDs())
375  {
376  history_to_use_->addEventSelectionEntry(es);
377  }
378  }
379 
380  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper")
381  << "ArtdaqInputHelper: Product list sz=" << productList_->size();
382 
383  // helper now owns productList_!
384 
385  helper.productList(std::unique_ptr<art::ProductList>(productList_));
386  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "ArtdaqInputHelper: got product list";
387  }
388 
389  helper.reconstitutes<artdaq::detail::RawEventHeader, art::InEvent>(pretend_module_name, "RawEventHeader");
390 
391  if (ps.get<bool>("register_fragment_types", true))
392  {
393  TLOG_DEBUG("ArtdaqInputHelper") << "Registering known Fragment labels from ArtdaqFragmentNamingServiceInterface";
394 
395  art::ServiceHandle<ArtdaqFragmentNamingServiceInterface> translator;
396  helper.reconstitutes<artdaq::Fragments, art::InEvent>(pretend_module_name, translator->GetUnidentifiedInstanceName());
397  // Workaround for #22979
398  helper.reconstitutes<artdaq::Fragments, art::InRun>(pretend_module_name, translator->GetUnidentifiedInstanceName());
399  helper.reconstitutes<artdaq::Fragments, art::InSubRun>(pretend_module_name, translator->GetUnidentifiedInstanceName());
400 
401  std::set<std::string> instance_names = translator->GetAllProductInstanceNames();
402  for (const auto& set_iter : instance_names)
403  {
404  helper.reconstitutes<artdaq::Fragments, art::InEvent>(pretend_module_name, set_iter);
405  }
406  }
407  //
408  // Finished with init message.
409  //
410  TLOG(TLVL_DEBUG + 2, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::ArtdaqInputHelper("
411  << "const fhicl::ParameterSet& ps, "
412  << "art::ProductRegistryHelper& helper, "
413  << "const art::SourceHelper& pm)";
414  }
415 }
416 
417 template<typename U>
419 {}
420 
421 template<typename U>
423 {
424  TLOG(11, "ArtdaqInputHelper") << "Begin/End: ArtdaqInputHelper::closeCurrentFile()";
425 }
426 
427 template<typename U>
428 void art::ArtdaqInputHelper<U>::readFile(const std::string&, art::FileBlock*& fb)
429 {
430  TLOG(12, "ArtdaqInputHelper") << "Begin: ArtdaqInputHelper::"
431  "readFile(const std::string& name, art::FileBlock*& fb)";
432  fb = new art::FileBlock(art::FileFormatVersion(1, "ArtdaqInputHelper2013"), "");
433  TLOG(12, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::"
434  "readFile(const std::string& name, art::FileBlock*& fb)";
435 }
436 
437 template<typename U>
439 {
440  TLOG(13, "ArtdaqInputHelper") << "Begin: ArtdaqInputHelper::hasMoreData()";
441  if (shutdownMsgReceived_)
442  {
443  TLOG(13, "ArtdaqInputHelper") << "ArtdaqInputHelper::hasMoreData(): "
444  "returning false on shutdownMsgReceived_.";
445  TLOG(13, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::hasMoreData()";
446  return false;
447  }
448  TLOG(8, "ArtdaqInputHelper") << "ArtdaqInputHelper::hasMoreData(): "
449  "returning true on not shutdownMsgReceived_.";
450  TLOG(13, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::hasMoreData()";
451  return true;
452 }
453 
454 template<typename U>
455 void art::ArtdaqInputHelper<U>::readAndConstructPrincipal(std::unique_ptr<TBufferFile>& msg, ULong_t msg_type_code,
456  art::RunPrincipal* const inR, art::SubRunPrincipal* const inSR,
457  art::RunPrincipal*& outR, art::SubRunPrincipal*& outSR,
458  art::EventPrincipal*& outE)
459 {
460  //
461  // Process the message.
462  //
463  std::unique_ptr<art::RunAuxiliary> run_aux;
464  std::unique_ptr<art::SubRunAuxiliary> subrun_aux;
465  std::unique_ptr<art::EventAuxiliary> event_aux;
466 
467  std::unique_ptr<art::History> history_from_event;
468 
469  // Establish default 'results'
470  outR = nullptr;
471  outSR = nullptr;
472  outE = nullptr;
473 
474  if (msg_type_code == 2)
475  { // EndRun message.
476 
477  TLOG(14, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
478  << "processing EndRun message ...";
479 
480  run_aux.reset(ReadObjectAny<art::RunAuxiliary>(msg, "art::RunAuxiliary", "ArtdaqInputHelper::readAndConstructPrincipal"));
481  printProcessHistoryID("readAndConstructPrincipal", run_aux.get());
482 
483  TLOG(14, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
484  << "making flush RunPrincipal ...";
485  outR = pm_.makeRunPrincipal(RunID::flushRun(), run_aux->beginTime());
486 
487  TLOG(14, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
488  << "making flush SubRunPrincipal ...";
489  outSR = pm_.makeSubRunPrincipal(SubRunID::flushSubRun(), run_aux->beginTime());
490 
491  TLOG(14, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
492  << "making flush EventPrincipal ...";
493  outE = pm_.makeEventPrincipal(EventID::flushEvent(), run_aux->endTime(), true, EventAuxiliary::Any);
494 
495  TLOG(14, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
496  << "finished processing EndRun message.";
497  }
498  else if (msg_type_code == 3)
499  { // EndSubRun message.
500 
501  TLOG(15, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
502  << "processing EndSubRun message ...";
503 
504  subrun_aux.reset(
505  ReadObjectAny<art::SubRunAuxiliary>(msg, "art::SubRunAuxiliary", "ArtdaqInputHelper::readAndConstructPrincipal"));
506  printProcessHistoryID("readAndConstructPrincipal", subrun_aux.get());
507 
508  TLOG(15, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
509  << "making flush RunPrincipal ...";
510  outR = pm_.makeRunPrincipal(RunID::flushRun(), subrun_aux->beginTime());
511 
512  // 28-Feb-2014, KAB: added the setting of the end time in the *current*
513  // run and subrun. This is how we set the endTime in the RunPrincipal
514  // and SubRunPrincipal objects that are written to the disk file.
515  // This needs to happen here because:
516  // A) setting them in every event doesn't work because the RunPrincipal
517  // only allows us to set an end time value once
518  // B) setting them in the "outputFileCloseNeeded_" block in the readNext()
519  // method below doesn't work because that is too late. When this
520  // method returns an outR with a different run number (flushRun),
521  // the art output system closes the current file then.
522  // C) setting them in the EndRun message block immediately above this
523  // block wouldn't work because a) we're not currently sending endRun
524  // events from the EBs to the AG, and b) because presumably that would
525  // be too late, also.
526 
527  art::Timestamp currentTime = time(nullptr);
528  if (inR != nullptr)
529  {
530  inR->endTime(currentTime);
531  }
532  if (inSR != nullptr)
533  {
534  inSR->endTime(currentTime);
535  }
536 
537  TLOG(15, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
538  << "making flush SubRunPrincipal ...";
539  outSR = pm_.makeSubRunPrincipal(SubRunID::flushSubRun(), subrun_aux->beginTime());
540 
541  TLOG(15, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
542  << "making flush EventPrincipal ...";
543  outE = pm_.makeEventPrincipal(EventID::flushEvent(), subrun_aux->endTime(), true, EventAuxiliary::Any);
544 
545  TLOG(15, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
546  << "finished processing EndSubRun message.";
547  }
548  else if (msg_type_code == 4)
549  { // Event message.
550 
551  TLOG(16, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
552  << "processing Event message ...";
553 
554  run_aux.reset(ReadObjectAny<art::RunAuxiliary>(msg, "art::RunAuxiliary", "ArtdaqInputHelper::readAndConstructPrincipal"));
555  printProcessHistoryID("readAndConstructPrincipal", run_aux.get());
556 
557  subrun_aux.reset(
558  ReadObjectAny<art::SubRunAuxiliary>(msg, "art::SubRunAuxiliary", "ArtdaqInputHelper::readAndConstructPrincipal"));
559  printProcessHistoryID("readAndConstructPrincipal", subrun_aux.get());
560 
561  event_aux.reset(
562  ReadObjectAny<art::EventAuxiliary>(msg, "art::EventAuxiliary", "ArtdaqInputHelper::readAndConstructPrincipal"));
563 
564  history_from_event.reset(ReadObjectAny<art::History>(msg, "art::History", "ArtdaqInputHelper::readAndConstructPrincipal"));
565  printProcessHistoryID("readAndConstructPrincipal", history_from_event.get());
566 
567  // Every event should have a valid history
568  if (!history_from_event->processHistoryID().isValid())
569  {
570  throw art::Exception(art::errors::Unknown) // NOLINT(cert-err60-cpp)
571  << "readAndConstructPrincipal: processHistoryID of history in Event message is invalid!";
572  }
573 
574  TLOG(16, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
575  << "inR: " << static_cast<void*>(inR) << " run/expected "
576  << (inR ? std::to_string(inR->run()) : "invalid") << "/" << event_aux->run();
577  TLOG(16, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
578  << "inSR: " << static_cast<void*>(inSR) << " run/expected "
579  << (inSR ? std::to_string(inSR->run()) : "invalid") << "/" << event_aux->run()
580  << ", subrun/expected " << (inSR ? std::to_string(inSR->subRun()) : "invalid") << "/"
581  << event_aux->subRun();
582  if ((inR == nullptr) || !inR->runID().isValid() || (inR->run() != event_aux->run()))
583  {
584  // New run, either we have no input RunPrincipal, or the
585  // input run number does not match the event run number.
586  TLOG(16, "ArtdaqInputHelper") << "readAndConstructPrincipal: making RunPrincipal ...";
587  outR = pm_.makeRunPrincipal(*run_aux);
588  }
589  art::SubRunID subrun_check(event_aux->run(), event_aux->subRun());
590  if (inSR == nullptr || subrun_check != inSR->subRunID())
591  {
592  // New SubRun, either we have no input SubRunPrincipal, or the
593  // input subRun number does not match the event subRun number.
594  TLOG(16, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
595  << "making SubRunPrincipal ...";
596  outSR = pm_.makeSubRunPrincipal(*subrun_aux);
597  }
598  TLOG(11, "ArtdaqInputHelper") << "readAndConstructPrincipal: making EventPrincipal ...";
599  auto historyPtr = std::unique_ptr<art::History>(new History(*(history_to_use_.get())));
600  if (!art::ProcessHistoryRegistry::get().count(history_to_use_->processHistoryID()))
601  {
602  TLOG_WARNING("ArtdaqInputHelper") << "Stored history is not in ProcessHistoryRegistry, this event may have issues!";
603  }
604  outE = pm_.makeEventPrincipal(*event_aux, std::move(historyPtr));
605 
606  TLOG(16, "ArtdaqInputHelper") << "readAndConstructPrincipal: "
607  << "finished processing Event message.";
608  }
609 }
610 
611 template<typename U>
612 bool art::ArtdaqInputHelper<U>::constructPrincipal(artdaq::Fragment::type_t firstFragmentType, art::RunPrincipal* const inR, art::SubRunPrincipal* const inSR, art::RunPrincipal*& outR, art::SubRunPrincipal*& outSR, art::EventPrincipal*& outE)
613 {
614  // We return false, indicating we're done reading, if:
615  // 1) we did not obtain an event, because we timed out and were
616  // configured NOT to keep trying after a timeout, or
617  // 2) the event we read was the end-of-data marker: a null
618  // pointer
619  if (firstFragmentType == artdaq::Fragment::EndOfDataFragmentType)
620  {
621  TLOG_DEBUG("ArtdaqInputHelper") << "Received shutdown message, returning false";
622  shutdownMsgReceived_ = true;
623  return false;
624  }
625 
626  auto evtHeader = communicationWrapper_.getEventHeader();
627  if (!evtHeader)
628  {
629  TLOG_ERROR("ArtdaqInputHelper") << "No RawEventHeader received, cannot construct principals!";
630  shutdownMsgReceived_ = true;
631  return false;
632  }
633 
634  // Check the number of fragments in the RawEvent. If we have a single
635  // fragment and that fragment is marked as EndRun or EndSubrun we'll create
636  // the special principals for that.
637  art::Timestamp currentTime = 0;
638 #if 0
639  art::TimeValue_t lo_res_time = time(0);
640  TLOG(20, "ArtdaqInputHelper") << "lo_res_time = " << lo_res_time;
641  currentTime = ((lo_res_time & 0xffffffff) << 32);
642 #endif
643  timespec hi_res_time;
644  int retcode = clock_gettime(CLOCK_REALTIME, &hi_res_time);
645  TLOG(20, "ArtdaqInputHelper") << "hi_res_time tv_sec = " << hi_res_time.tv_sec
646  << " tv_nsec = " << hi_res_time.tv_nsec << " (retcode = " << retcode << ")";
647  if (retcode == 0)
648  {
649  currentTime = ((hi_res_time.tv_sec & 0xffffffff) << 32) | (hi_res_time.tv_nsec & 0xffffffff);
650  }
651  else
652  {
653  TLOG_ERROR("ArtdaqInputHelper")
654  << "Unable to fetch a high-resolution time with clock_gettime for art::Event Timestamp. "
655  << "The art::Event Timestamp will be zero for event " << evtHeader->event_id;
656  }
657 
658  // make new run if inR is 0 or if the run has changed
659  if (inR == nullptr || inR->run() != evtHeader->run_id)
660  {
661  TLOG(20, "ArtdaqInputHelper") << "Making run principal with run_id " << evtHeader->run_id;
662  outR = pm_.makeRunPrincipal(evtHeader->run_id, currentTime);
663  }
664 
665  if (firstFragmentType == artdaq::Fragment::EndOfRunFragmentType)
666  {
667  TLOG(20, "ArtdaqInputHelper") << "EndOfRunFragment received, returning Flush event";
668  art::EventID const evid(art::EventID::flushEvent());
669  outR = pm_.makeRunPrincipal(evid.runID(), currentTime);
670  outSR = pm_.makeSubRunPrincipal(evid.subRunID(), currentTime);
671  outE = pm_.makeEventPrincipal(evid, currentTime);
672  return true;
673  }
674  else if (firstFragmentType == artdaq::Fragment::EndOfSubrunFragmentType)
675  {
676  TLOG(20, "ArtdaqInputHelper") << "EndOfSubrunFragment received, creating new Subrun Principal";
677  // Check if inR == 0 or is a new run
678  if (inR == nullptr || inR->run() != evtHeader->run_id)
679  {
680  TLOG(20, "ArtdaqInputHelper") << "Making subrun principal with subrun_id " << evtHeader->subrun_id;
681  outSR = pm_.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
682  art::EventID const evid(art::EventID::flushEvent(outSR->subRunID()));
683  outE = pm_.makeEventPrincipal(evid, currentTime);
684  }
685  else
686  {
687  // If the previous subrun was neither 0 nor flush and was identical with the current
688  // subrun, then it must have been associated with a data event. In that case, we need
689  // to generate a flush event with a valid run but flush subrun and event number in order
690  // to end the subrun.
691  if (inSR != nullptr && !inSR->subRunID().isFlush() && inSR->subRun() == evtHeader->subrun_id)
692  {
693  TLOG(20, "ArtdaqInputHelper") << "Flushing old run id " << inR->runID();
694  art::EventID const evid(art::EventID::flushEvent(inR->runID()));
695  outSR = pm_.makeSubRunPrincipal(evid.subRunID(), currentTime);
696  outE = pm_.makeEventPrincipal(evid, currentTime);
697  // If this is either a new or another empty subrun, then generate a flush event with
698  // valid run and subrun numbers but flush event number
699  //} else if(inSR==0 || inSR->id().isFlush()){
700  }
701  else
702  {
703  TLOG(20, "ArtdaqInputHelper") << "Making subrun principal with subrun_id " << evtHeader->subrun_id;
704  outSR = pm_.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
705  art::EventID const evid(art::EventID::flushEvent(outSR->subRunID()));
706  outE = pm_.makeEventPrincipal(evid, currentTime);
707  // Possible error condition
708  //} else {
709  }
710  outR = nullptr;
711  }
712  // outputFileCloseNeeded = true;
713  return true;
714  }
715 
716  // make new subrun if inSR is 0 or if the subrun has changed
717  art::SubRunID subrun_check(evtHeader->run_id, evtHeader->subrun_id);
718  if (inSR == nullptr || subrun_check != inSR->subRunID())
719  {
720  TLOG(20, "ArtdaqInputHelper") << "Making subrun principal with subrun_id " << evtHeader->subrun_id;
721  outSR = pm_.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
722  }
723  TLOG(20, "ArtdaqInputHelper") << "Making event principal with event_id " << evtHeader->event_id;
724  outE = pm_.makeEventPrincipal(evtHeader->run_id, evtHeader->subrun_id, evtHeader->event_id, currentTime);
725  return true;
726 }
727 
728 template<typename U>
729 template<class T>
730 void art::ArtdaqInputHelper<U>::readDataProducts(std::list<std::unique_ptr<TBufferFile>>& msgs, T*& outPrincipal)
731 {
732  for (auto& msg : msgs)
733  {
734  ULong_t prd_cnt = 0;
735  {
736  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: reading data product count ...";
737  msg->ReadULong(prd_cnt);
738  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: product count: " << prd_cnt;
739  }
740  //
741  // Read the data products.
742  //
743  for (ULong_t I = 0; I < prd_cnt; ++I)
744  {
745  std::unique_ptr<BranchKey> bk;
746  {
747  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: Reading branch key.";
748  bk.reset(ReadObjectAny<BranchKey>(msg, "art::BranchKey", "ArtdaqInputHelper::readDataProducts"));
749  }
750 
751 #ifndef __OPTIMIZE__
752  TLOG(18, "ArtdaqInputHelper") << "readDataProducts: got product class: '" << bk->friendlyClassName_ << "' modlbl: '"
753  << bk->moduleLabel_ << "' instnm: '" << bk->productInstanceName_ << "' procnm: '"
754  << bk->processName_;
755 #endif
756  ProductList::const_iterator iter;
757  {
758  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: looking up product ...";
759  iter = productList_->find(*bk);
760  if (iter == productList_->end())
761  {
762  throw art::Exception(art::errors::ProductNotFound) // NOLINT(cert-err60-cpp)
763  << "No product is registered for\n"
764  << " process name: '" << bk->processName_ << "'\n"
765  << " module label: '" << bk->moduleLabel_ << "'\n"
766  << " product friendly class name: '" << bk->friendlyClassName_ << "'\n"
767  << " product instance name: '" << bk->productInstanceName_ << "'\n";
768  }
769  }
770  // Note: This must be a reference to the unique copy in
771  // the master product registry!
772  const BranchDescription& bd = iter->second;
773  std::unique_ptr<EDProduct> prd;
774  {
775  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: Reading product with wrapped name: " << bd.wrappedName()
776  << ", TClass = " << static_cast<void*>(TClass::GetClass(bd.wrappedName().c_str()));
777 
778  // JCF, May-25-2016
779  // Currently unclear why the templatized version of ReadObjectAny doesn't work here...
780 
781  // prd.reset(ReadObjectAny<EDProduct>(msg, bd.wrappedName()));
782 
783  void* p = msg->ReadObjectAny(TClass::GetClass(bd.wrappedName().c_str()));
784  auto pp = reinterpret_cast<EDProduct*>(p); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
785 
786  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: After ReadObjectAny(prd): p=" << p << ", EDProduct::isPresent: " << pp->isPresent();
787  prd.reset(pp);
788  p = nullptr;
789  }
790  std::unique_ptr<const ProductProvenance> prdprov;
791  {
792  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: Reading product provenance.";
793  prdprov.reset(ReadObjectAny<ProductProvenance>(msg, "art::ProductProvenance", "ArtdaqInputHelper::readDataProducts"));
794  }
795 
796  {
797  TLOG(17, "ArtdaqInputHelper") << "readDataProducts: inserting product: class: '" << bd.friendlyClassName()
798  << "' modlbl: '" << bd.moduleLabel() << "' instnm: '" << bd.productInstanceName()
799  << "' procnm: '" << bd.processName() << "' id: '" << bd.productID() << "'";
800  putInPrincipal(outPrincipal, std::move(prd), bd, std::move(prdprov));
801  }
802  }
803  }
804 }
805 
806 template<typename U>
807 void art::ArtdaqInputHelper<U>::putInPrincipal(RunPrincipal*& rp, std::unique_ptr<EDProduct>&& prd,
808  const BranchDescription& bd,
809  std::unique_ptr<const ProductProvenance>&& prdprov)
810 {
811  rp->put(bd, std::move(prdprov), std::move(prd), std::make_unique<RangeSet>(RangeSet::forRun(rp->runID())));
812 }
813 
814 template<typename U>
815 void art::ArtdaqInputHelper<U>::putInPrincipal(SubRunPrincipal*& srp, std::unique_ptr<EDProduct>&& prd,
816  const BranchDescription& bd,
817  std::unique_ptr<const ProductProvenance>&& prdprov)
818 {
819  srp->put(bd, std::move(prdprov), std::move(prd), std::make_unique<RangeSet>(RangeSet::forSubRun(srp->subRunID())));
820 }
821 
822 template<typename U>
823 void art::ArtdaqInputHelper<U>::putInPrincipal(EventPrincipal*& ep, std::unique_ptr<EDProduct>&& prd,
824  const BranchDescription& bd,
825  std::unique_ptr<const ProductProvenance>&& prdprov)
826 {
827  TLOG(19, "ArtdaqInputHelper") << "EventPrincipal size before put: " << ep->size();
828 
829  ep->put(bd, std::move(prdprov), std::move(prd), std::make_unique<RangeSet>(RangeSet::invalid()));
830 
831  TLOG(19, "ArtdaqInputHelper") << "EventPrincipal size after put: " << ep->size();
832 }
833 
834 template<typename U>
835 void art::ArtdaqInputHelper<U>::readFragments(std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> const& eventMap, art::EventPrincipal*& outE)
836 {
837  // Now read in Fragments
838  double fragmentLatency = 0;
839  double fragmentLatencyMax = 0.0;
840  size_t fragmentCount = 0;
841 
842  art::ServiceHandle<ArtdaqFragmentNamingServiceInterface> translator;
843 
844  // insert the Fragments of each type into the EventPrincipal
845  for (auto& fragmentTypePair : eventMap)
846  {
847  auto type_code = fragmentTypePair.first;
848  if (type_code == artdaq::Fragment::DataFragmentType || type_code == artdaq::Fragment::EndOfDataFragmentType || type_code == artdaq::Fragment::InitFragmentType || type_code == artdaq::Fragment::EndOfRunFragmentType || type_code == artdaq::Fragment::EndOfSubrunFragmentType || type_code == artdaq::Fragment::ShutdownFragmentType)
849  {
850  TLOG_TRACE("ArtdaqInputHelper") << "Skipping system Fragment with type " << static_cast<int>(type_code) << " ( " << translator->GetInstanceNameForType(type_code) << " )";
851  continue;
852  }
853  TLOG_TRACE("ArtdaqInputHelper") << "type is " << static_cast<int>(type_code) << ", number of fragments is " << fragmentTypePair.second->size();
854 
855  std::unordered_map<std::string, std::unique_ptr<artdaq::Fragments>> derived_fragments;
856  for (auto& frag : *fragmentTypePair.second)
857  {
858  TLOG(21, "ArtdaqInputHelper") << "Processing Fragment with ID " << frag.fragmentID();
859  bytesRead += frag.sizeBytes();
860  auto latency_s = frag.getLatency(true);
861  double latency = latency_s.tv_sec + (latency_s.tv_nsec / 1000000000.0);
862 
863  fragmentLatency += latency;
864  fragmentCount++;
865  if (latency > fragmentLatencyMax) fragmentLatencyMax = latency;
866 
867  std::pair<bool, std::string> instance_name_result =
868  translator->GetInstanceNameForFragment(frag);
869  std::string label = instance_name_result.second;
870  if (!instance_name_result.first)
871  {
872  TLOG_WARNING("ArtdaqInputHelper")
873  << "UnknownFragmentType: The product instance name mapping for fragment type \"" << static_cast<int>(type_code)
874  << "\" is not known. Fragments of this "
875  << "type will be stored in the event with an instance name of \"" << label << "\".";
876  }
877  if (!derived_fragments.count(label))
878  {
879  TLOG(21, "ArtdaqInputHelper") << "Creating output Fragment storage for label " << label;
880  derived_fragments[label] = std::make_unique<artdaq::Fragments>();
881  }
882  TLOG(21, "ArtdaqInputHelper") << "Adding Fragment " << frag.fragmentID() << " to storage with label " << label << " (sz=" << derived_fragments[label]->size() + 1 << ")";
883  derived_fragments[label]->emplace_back(std::move(frag));
884  }
885  for (auto& type : derived_fragments)
886  {
887  TLOG(21, "ArtdaqInputHelper") << "Adding " << type.second->size() << " Fragments with label " << type.first << " to event.";
888  put_product_in_principal(std::move(type.second), *outE, pretend_module_name, type.first);
889  }
890  }
891  if (metricMan)
892  {
893  metricMan->sendMetric("bytesRead", bytesRead, "B", 3, artdaq::MetricMode::LastPoint);
894 
895  metricMan->sendMetric("ArtdaqInputHelper Latency", fragmentLatency / fragmentCount, "s", 4, artdaq::MetricMode::Average);
896  metricMan->sendMetric("ArtdaqInputHelper Maximum Latency", fragmentLatencyMax, "s", 4, artdaq::MetricMode::Maximum);
897  }
898 }
899 
900 template<typename U>
901 bool art::ArtdaqInputHelper<U>::readNext(art::RunPrincipal* const inR, art::SubRunPrincipal* const inSR,
902  art::RunPrincipal*& outR, art::SubRunPrincipal*& outSR, art::EventPrincipal*& outE)
903 {
904  TLOG(20, "ArtdaqInputHelper") << "Begin: ArtdaqInputHelper::readNext";
905  bool ret = false;
906 
907  if (outputFileCloseNeeded_)
908  {
909  outputFileCloseNeeded_ = false;
910  // Signal that we need the output file closed by returning false,
911  // but answering true to the hasMoreData() query.
912  TLOG(20, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext: "
913  << "returning false on outputFileCloseNeeded_";
914  TLOG(20, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::readNext";
915  return false;
916  }
917  auto read_start_time = std::chrono::steady_clock::now();
918 
919  std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> eventMap = communicationWrapper_.receiveMessages();
920  auto got_event_time = std::chrono::steady_clock::now();
921 
922  if (eventMap.empty())
923  {
924  TLOG(TLVL_ERROR, "ArtdaqInputHelper") << "No Fragments received! Aborting...";
925  shutdownMsgReceived_ = true;
926  TLOG(22, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::readNext";
927  return false;
928  }
929 
930  if (!fragmentsOnlyMode_ && !eventMap.count(artdaq::Fragment::DataFragmentType))
931  {
932  TLOG(20, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext got a message without a DataFragment";
933  shutdownMsgReceived_ = true;
934  TLOG(22, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::readNext";
935  return false;
936  }
937 
938  if (fragmentsOnlyMode_)
939  {
940  if (eventMap.count(artdaq::Fragment::DataFragmentType))
941  {
942  TLOG(20, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext unexpectedly got a message with a DataFragment. This art Event will NOT be reconstructed!";
943  }
944 
945  auto firstFragmentType = eventMap.begin()->first;
946  TLOG_DEBUG("ArtdaqInputHelper") << "First Fragment type is " << static_cast<int>(firstFragmentType);
947  if (constructPrincipal(firstFragmentType, inR, inSR, outR, outSR, outE))
948  {
949  readFragments(eventMap, outE);
950  ret = true;
951  }
952  else
953  {
954  ret = false;
955  }
956  }
957  else
958  {
959  std::list<std::unique_ptr<TBufferFile>> msgs;
960  for (auto& dataFrag : *(eventMap[artdaq::Fragment::DataFragmentType]))
961  {
962  auto header = dataFrag.metadata<artdaq::NetMonHeader>();
963  msgs.emplace_back(new TBufferFile(TBuffer::kRead, header->data_length, dataFrag.dataBegin(), kFALSE, nullptr));
964  }
965 
966  //
967  // Read message type code.
968  //
969  ULong_t msg_type_code = 0;
970  ULong_t msg_type_code_tmp = 0;
971  for (auto& msg : msgs)
972  {
973  TLOG(20, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext: "
974  << "getting message type code ...";
975  msg->ReadULong(msg_type_code_tmp);
976  TLOG(20, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext: "
977  << "message type: " << msg_type_code_tmp;
978 
979  if (msg_type_code == 0)
980  msg_type_code = msg_type_code_tmp;
981  else if (msg_type_code != msg_type_code_tmp)
982  {
983  TLOG(TLVL_ERROR, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext: Received conflicting message type codes! Aborting...";
984 
985  shutdownMsgReceived_ = true;
986  TLOG(22, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::readNext";
987  return false;
988  }
989  }
990  if (msg_type_code == 5)
991  {
992  // Shutdown message.
993  shutdownMsgReceived_ = true;
994  TLOG(21, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext: "
995  << "returning false on Shutdown message.";
996  TLOG(21, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::readNext";
997  return false;
998  }
999 
1000  for (auto& msg : msgs)
1001  {
1002  readAndConstructPrincipal(msg, msg_type_code, inR, inSR, outR, outSR, outE);
1003  }
1004  //
1005  // Read per-event metadata needed to construct principal.
1006  //
1007  if (msg_type_code == 2)
1008  {
1009  // EndRun message.
1010  // FIXME: We need to merge these into the input RunPrincipal.
1011  readDataProducts(msgs, outR);
1012  // Signal that we should close the input and output file.
1013  TLOG(22, "ArtdaqInputHelper") << "ArtdaqInputHelper::readNext: "
1014  << "returning false on EndRun message.";
1015  TLOG(22, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::readNext";
1016  return false;
1017  }
1018  else if (msg_type_code == 3)
1019  {
1020  // EndSubRun message.
1021  // From the code above, EndRun and EndSubRun messages cause
1022  // the construction of principals that have:
1023  // Run:Subrun:Event=flush:flush:flush.
1024  // This is a problem when you have two neighboring EndSubRuns
1025  // which are both associated with empty subruns because art will
1026  // complain that you a new subrun with a subrun number identical
1027  // to that of the previous subrun. So the solution is to not
1028  // return new principals.
1029  if (inR != nullptr && inSR != nullptr && outR != nullptr && outSR != nullptr)
1030  {
1031  if (inR->runID().isFlush() && inSR->subRunID().isFlush() && outR->runID().isFlush() &&
1032  outSR->subRunID().isFlush())
1033  {
1034  outR = nullptr;
1035  outSR = nullptr;
1036  outputFileCloseNeeded_ = true;
1037  return true;
1038  }
1039  }
1040  // FIXME: We need to merge these into the input SubRunPrincipal.
1041  readDataProducts(msgs, outSR);
1042  // Remember that we should ask for file close next time
1043  // we are called.
1044  outputFileCloseNeeded_ = true;
1045  TLOG(23, "ArtdaqInputHelper") << "readNext: returning true on EndSubRun message.";
1046  ret = true;
1047  }
1048  else if (msg_type_code == 4)
1049  {
1050  // Event message.
1051  readDataProducts(msgs, outE);
1052 
1053  if (eventMap.size() > 1)
1054  {
1055  readFragments(eventMap, outE);
1056  }
1057 
1058  TLOG(24, "ArtdaqInputHelper") << "readNext: returning true on Event message.";
1059  ret = true;
1060  }
1061  }
1062 
1063  if (outE != nullptr)
1064  {
1065  auto artHdrPtr = std::make_unique<artdaq::detail::RawEventHeader>();
1066  auto daqHdrPtr = communicationWrapper_.getEventHeader();
1067 
1068  if (daqHdrPtr != nullptr)
1069  {
1070  memcpy(artHdrPtr.get(), daqHdrPtr.get(), sizeof(artdaq::detail::RawEventHeader));
1071  put_product_in_principal(std::move(artHdrPtr), *outE, pretend_module_name, "RawEventHeader");
1072  }
1073  }
1074 
1075  auto read_finish_time = std::chrono::steady_clock::now();
1076  TLOG(20, "ArtdaqInputHelper") << "readNext: bytesRead=" << bytesRead
1077  << " metricMan=" << static_cast<void*>(metricMan.get());
1078  if (metricMan)
1079  {
1080  metricMan->sendMetric("Avg Processing Time", artdaq::TimeUtils::GetElapsedTime(last_read_time, read_start_time),
1081  "s", 2, artdaq::MetricMode::Average);
1082  metricMan->sendMetric("Avg Input Wait Time", artdaq::TimeUtils::GetElapsedTime(read_start_time, got_event_time),
1083  "s", 3, artdaq::MetricMode::Average);
1084  metricMan->sendMetric("Avg Read Time", artdaq::TimeUtils::GetElapsedTime(got_event_time, read_finish_time), "s",
1085  3, artdaq::MetricMode::Average);
1086  }
1087 
1088  TLOG(25, "ArtdaqInputHelper") << "End: ArtdaqInputHelper::readNext ret=" << std::boolalpha << ret;
1089  last_read_time = std::chrono::steady_clock::now();
1090  return ret;
1091 }
1092 
1093 #endif // ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQINPUTHELPER_HH_
void printProcessHistoryID(const std::string &label, const T &object)
Print the processHistoryID from the object.
~ArtdaqInputHelper()
ArtdaqInputHelper Destructor.
bool hasMoreData() const
Whether additional events are expected from the source.
bool readNext(art::RunPrincipal *const inR, art::SubRunPrincipal *const inSR, art::RunPrincipal *&outR, art::SubRunPrincipal *&outSR, art::EventPrincipal *&outE)
Read the next event from the communication wrapper.
void readFile(const std::string &, art::FileBlock *&fb)
Emulate reading a file.
void printProcessMap(const T &mappable, const std::string &description)
Print data from a map-like class.
void closeCurrentFile()
Called by art to close the input source. No-Op.
ArtdaqInputHelper & operator=(const ArtdaqInputHelper &)=delete
Copy Assignment operator is deleted.
Header with length information for NetMonTransport messages.
Definition: NetMonHeader.hh:13
ArtdaqInputHelper(const ArtdaqInputHelper &)=delete
Copy Constructor is deleted.
This template class provides a unified interface for reading data into art.