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