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