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