ATLAS Offline Software
Loading...
Searching...
No Matches
EventSelectorAthenaPool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
9
12#include "Collection.h"
13
18#include "PoolSvc/IPoolSvc.h"
22
23// Framework
24#include "GaudiKernel/ClassID.h"
25#include "GaudiKernel/FileIncident.h"
26#include "GaudiKernel/IIncidentSvc.h"
27#include "GaudiKernel/IIoComponentMgr.h"
28#include "GaudiKernel/GaudiException.h"
29#include "GaudiKernel/GenericAddress.h"
30#include "GaudiKernel/StatusCode.h"
32
33// Pool
34#include "CollectionCursor.h"
35#include "CollectionRowBuffer.h"
36#include "StorageSvc/DbType.h"
37
39#include <algorithm>
40#include <format>
41#include <vector>
42
43//________________________________________________________________________________
44EventSelectorAthenaPool::EventSelectorAthenaPool(const std::string& name, ISvcLocator* pSvcLocator) :
45 base_class(name, pSvcLocator)
46{
47 // TODO: validate if those are even used
48 m_runNo.verifier().setLower(0);
49 m_oldRunNo.verifier().setLower(0);
50 m_eventsPerRun.verifier().setLower(0);
51 m_firstEventNo.verifier().setLower(1);
52 m_firstLBNo.verifier().setLower(0);
53 m_eventsPerLB.verifier().setLower(0);
54 m_initTimeStamp.verifier().setLower(0);
55
57 m_inputCollectionsChanged = false;
58}
59//________________________________________________________________________________
60void EventSelectorAthenaPool::inputCollectionsHandler(Gaudi::Details::PropertyBase&) {
61 if (this->FSMState() != Gaudi::StateMachine::OFFLINE) {
62 m_inputCollectionsChanged = true;
63 }
64}
65//________________________________________________________________________________
68//________________________________________________________________________________
72//________________________________________________________________________________
74
75 m_autoRetrieveTools = false;
76 m_checkToolDeps = false;
77
78 if (m_isSecondary.value()) {
79 ATH_MSG_DEBUG("Initializing secondary event selector " << name());
80 } else {
81 ATH_MSG_DEBUG("Initializing " << name());
82 }
83
84 ATH_CHECK(::AthService::initialize());
85 // Check for input collection
86 if (m_inputCollectionsProp.value().empty()) {
87 ATH_MSG_FATAL("Use the property: EventSelector.InputCollections = "
88 << "[ \"<collectionName>\" ] (list of collections)");
89 return StatusCode::FAILURE;
90 }
91 auto ranges = CxxUtils::tokenize(m_skipEventRangesProp.value(), ',');
92 for( const std::string& r: ranges ) {
93 auto fromto = CxxUtils::tokenize(r, '-');
94 auto from_iter = fromto.begin();
95 long from = std::stol(*from_iter);
96 long to = from;
97 if( ++from_iter != fromto.end() ) {
98 to = std::stol(*from_iter);
99 }
100 m_skipEventRanges.emplace_back(from, to);
101 }
102
103 for( auto v : m_skipEventSequenceProp.value() ) {
104 m_skipEventRanges.emplace_back(v, v);
105 }
106 std::sort(m_skipEventRanges.begin(), m_skipEventRanges.end());
107 if( msgLvl(MSG::DEBUG) ) {
108 std::string skip_ranges_str;
109 for( const auto& [first, second] : m_skipEventRanges ) {
110 if( !skip_ranges_str.empty() ) skip_ranges_str += ", ";
111 skip_ranges_str += std::to_string(first);
112 if( first != second) skip_ranges_str += std::format("-{}", second);
113 }
114 if( !skip_ranges_str.empty() )
115 ATH_MSG_DEBUG("Events to skip: " << skip_ranges_str);
116 }
117
118 // Get AthenaPoolCnvSvc
119 ATH_CHECK(m_athenaPoolCnvSvc.retrieve());
120 ATH_CHECK(m_poolSvc.retrieve());
121 // Get CounterTool (if configured)
122 if (!m_counterTool.empty()) {
123 ATH_CHECK(m_counterTool.retrieve());
124 }
125 // Get HelperTools
126 ATH_CHECK(m_helperTools.retrieve());
127
128 // Ensure the xAODCnvSvc is listed in the EventPersistencySvc
129 ServiceHandle<IProperty> epSvc("EventPersistencySvc", name());
130 std::vector<std::string> propVal;
131 ATH_CHECK(Gaudi::Parsers::parse(propVal , epSvc->getProperty("CnvServices").toString()));
132 bool foundCnvSvc = false;
133 for (const auto& property : propVal) {
134 if (property == m_athenaPoolCnvSvc.type()) { foundCnvSvc = true; }
135 }
136 if (!foundCnvSvc) {
137 propVal.push_back(m_athenaPoolCnvSvc.type());
138 if (!epSvc->setProperty("CnvServices", Gaudi::Utils::toString(propVal)).isSuccess()) {
139 ATH_MSG_FATAL("Cannot set EventPersistencySvc Property for CnvServices");
140 return StatusCode::FAILURE;
141 }
142 }
143
144 // Register this service for 'I/O' events
145 ServiceHandle<IIoComponentMgr> iomgr("IoComponentMgr", name());
146 ATH_CHECK(iomgr.retrieve());
147 ATH_CHECK(iomgr->io_register(this));
148 // Register input file's names with the I/O manager
149 const std::vector<std::string>& incol = m_inputCollectionsProp.value();
150 bool allGood = true;
151 for (const auto& inputCollection : incol) {
152 if (!iomgr->io_register(this, IIoComponentMgr::IoMode::READ, inputCollection, inputCollection).isSuccess()) {
153 ATH_MSG_FATAL("could not register [" << inputCollection << "] for output !");
154 allGood = false;
155 } else {
156 ATH_MSG_VERBOSE("io_register[" << this->name() << "](" << inputCollection << ") [ok]");
157 }
158 }
159 if (!allGood) {
160 return StatusCode::FAILURE;
161 }
162
163 // Connect to PersistencySvc
164 if (!m_poolSvc->connect(Io::READ, IPoolSvc::kInputStream).isSuccess()) {
165 ATH_MSG_FATAL("Cannot connect to POOL PersistencySvc.");
166 return StatusCode::FAILURE;
167 }
168 // Jump to reinit() to execute common init/reinit actions
169 m_guid = Guid::null();
170 if (!reinit().isSuccess()) {
171 return StatusCode::FAILURE;
172 }
173 // Get IncidentSvc
174 ATH_CHECK(m_incidentSvc.retrieve());
175 // Listen to the Event Processing incidents
176 m_incidentSvc->addListener(this, IncidentType::BeginProcessing, 0);
177 m_incidentSvc->addListener(this, IncidentType::EndProcessing, 0);
178 return StatusCode::SUCCESS;
179}
180//________________________________________________________________________________
182 ATH_MSG_DEBUG("reinitialization...");
183
184 // reset markers
185 m_numEvt.resize(m_inputCollectionsProp.value().size(), -1);
186 m_firstEvt.resize(m_inputCollectionsProp.value().size(), -1);
187
188 // Initialize InputCollectionsIterator
189 m_inputCollectionsIterator = m_inputCollectionsProp.value().begin();
190 m_curCollection = 0;
191 if (!m_firstEvt.empty()) {
192 m_firstEvt[0] = 0;
193 }
194 m_inputCollectionsChanged = false;
195 m_evtCount = 0;
196 m_headerIterator = 0;
197 bool retError = false;
198 for (auto& tool : m_helperTools) {
199 if (!tool->postInitialize().isSuccess()) {
200 ATH_MSG_FATAL("Failed to postInitialize() " << tool->name());
201 retError = true;
202 }
203 }
204 if (retError) {
205 ATH_MSG_FATAL("Failed to postInitialize() helperTools");
206 return StatusCode::FAILURE;
207 }
208
209 // Create an m_poolCollection to read the objects in
210 m_poolCollection = getCollection();
211 if (!m_poolCollection) {
212 ATH_MSG_INFO("No Events found in any Input Collections");
213 if (m_processMetadata.value()) {
214 m_inputCollectionsIterator = m_inputCollectionsProp.value().end();
215 if (!m_inputCollectionsProp.value().empty()) --m_inputCollectionsIterator;
216 //NOTE (wb may 2016): this will make the FirstInputFile incident correspond to last file in the collection ... if want it to be first file then move iterator to begin and then move above two lines below this incident firing
217 if( !m_firedIncident && !m_inputCollectionsProp.value().empty() ) {
218 FileIncident firstInputFileIncident(name(), "FirstInputFile", *m_inputCollectionsIterator);
219 m_incidentSvc->fireIncident(firstInputFileIncident);
220 m_firedIncident = true;
221 }
222 }
223 return StatusCode::SUCCESS;
224 }
225 // Get DataHeader iterator
226 try {
227 m_headerIterator = m_poolCollection->cursor();
228 } catch (std::exception &e) {
229 ATH_MSG_FATAL("Cannot open input collection - check data/software version.");
230 ATH_MSG_ERROR(e.what());
231 return StatusCode::FAILURE;
232 }
233 while (m_headerIterator == nullptr || m_headerIterator->next() == 0) { // no selected events
235 if (m_inputCollectionsIterator == m_inputCollectionsProp.value().end()) {
236 m_poolCollection = nullptr;
237 }
238 else {
239 ++m_inputCollectionsIterator;
240 m_poolCollection = getCollection();
241 }
242 if (m_poolCollection) {
243 m_headerIterator = m_poolCollection->cursor();
244 } else {
245 break;
246 }
247 }
248 if (!m_poolCollection || m_headerIterator == nullptr) { // no event selected in any collection
249 m_inputCollectionsIterator = m_inputCollectionsProp.value().begin();
250 m_curCollection = 0;
251 m_poolCollection = getCollection();
252 if (!m_poolCollection) {
253 return StatusCode::SUCCESS;
254 }
255 m_headerIterator = m_poolCollection->cursor();
256 while (m_headerIterator == nullptr || m_headerIterator->next() == 0) { // empty collection
258 ++m_inputCollectionsIterator;
259 m_poolCollection = getCollection();
260 if (m_poolCollection) {
261 m_headerIterator = m_poolCollection->cursor();
262 } else {
263 break;
264 }
265 }
266 }
267 if (!m_poolCollection || m_headerIterator == nullptr) {
268 return StatusCode::SUCCESS;
269 }
270 const Token& headRef = m_headerIterator->eventRef();
271 const std::string fid = headRef.dbID().toString();
272 const int tech = headRef.technology();
273 ATH_MSG_VERBOSE("reinit(): First DataHeder Token=" << headRef.toString() );
274
275 // Check if File is BS, for which Incident is thrown by SingleEventInputSvc
276 if (tech != 0x00001000 && m_processMetadata.value() && !m_firedIncident) {
277 FileIncident firstInputFileIncident(name(), "FirstInputFile", "FID:" + fid, fid);
278 m_incidentSvc->fireIncident(firstInputFileIncident);
279 m_firedIncident = true;
280 }
281 return StatusCode::SUCCESS;
282}
283//________________________________________________________________________________
286 m_inputCollectionsIterator = m_inputCollectionsProp.value().begin();
287 m_curCollection = 0;
288 m_poolCollection = getCollection(true);
289 if (!m_poolCollection) {
290 ATH_MSG_INFO("No Events found in any Input Collections");
291 m_inputCollectionsIterator = m_inputCollectionsProp.value().end();
292 if (!m_inputCollectionsProp.value().empty()) {
293 --m_inputCollectionsIterator; //leave iterator in state of last input file
294 }
295 } else {
296 m_headerIterator = m_poolCollection->cursor();
297 }
298 m_evtCount = 0;
299 delete m_endIter;
300 m_endIter = nullptr;
301 m_endIter = new EventContextAthenaPool(nullptr);
302 return StatusCode::SUCCESS;
303}
304//________________________________________________________________________________
306 // Fire EndInputFile for any file still open (the event loop may end
307 // before the file is fully read).
308 m_inputFileGuard.reset();
309
310 IEvtSelector::Context* ctxt(nullptr);
311 if (!releaseContext(ctxt).isSuccess()) {
312 ATH_MSG_WARNING("Cannot release context");
313 }
314 return StatusCode::SUCCESS;
315}
316
317//________________________________________________________________________________
319 if (!m_counterTool.empty() && !m_counterTool->preFinalize().isSuccess()) {
320 ATH_MSG_WARNING("Failed to preFinalize() CounterTool");
321 }
322 for (auto& tool : m_helperTools) {
323 if (!tool->preFinalize().isSuccess()) {
324 ATH_MSG_WARNING("Failed to preFinalize() " << tool->name());
325 }
326 }
327 delete m_endIter; m_endIter = nullptr;
328 m_headerIterator = nullptr;
329 m_poolCollection.reset();
330 m_curCollectionName.clear();
331 // Finalize the Service base class.
332 return ::AthService::finalize();
333}
334
335//________________________________________________________________________________
336StatusCode EventSelectorAthenaPool::createContext(IEvtSelector::Context*& ctxt) const {
337 ctxt = new EventContextAthenaPool(this);
338 return StatusCode::SUCCESS;
339}
340//________________________________________________________________________________
341StatusCode EventSelectorAthenaPool::next(IEvtSelector::Context& ctxt) const {
342 std::lock_guard<CallMutex> lockGuard(m_callLock);
343 for (const auto& tool : m_helperTools) {
344 if (!tool->preNext().isSuccess()) {
345 ATH_MSG_WARNING("Failed to preNext() " << tool->name());
346 }
347 }
348 for (;;) {
349 // Handle possible file transition
350 StatusCode sc = nextHandleFileTransition(ctxt);
351 if (sc.isRecoverable()) {
352 continue; // handles empty files
353 }
354 if (sc.isFailure()) {
355 return StatusCode::FAILURE;
356 }
357 // Increase event count
358 ++m_evtCount;
359 if (!m_counterTool.empty() && !m_counterTool->preNext().isSuccess()) {
360 ATH_MSG_WARNING("Failed to preNext() CounterTool.");
361 }
363 && (m_skipEventRanges.empty() || m_evtCount < m_skipEventRanges.front().first))
364 {
365 if (!m_isSecondary.value()) {
366 if (!this->recordAttributeList().isSuccess()) {
367 ATH_MSG_ERROR("Failed to record AttributeList.");
368 return StatusCode::FAILURE;
369 }
370 }
371 StatusCode status = StatusCode::SUCCESS;
372 for (const auto& tool : m_helperTools) {
373 StatusCode toolStatus = tool->postNext();
374 if (toolStatus.isRecoverable()) {
375 ATH_MSG_INFO("Request skipping event from: " << tool->name());
376 if (status.isSuccess()) {
377 status = StatusCode::RECOVERABLE;
378 }
379 } else if (toolStatus.isFailure()) {
380 ATH_MSG_WARNING("Failed to postNext() " << tool->name());
381 status = StatusCode::FAILURE;
382 }
383 }
384 if (status.isRecoverable()) {
385 ATH_MSG_INFO("skipping event " << m_evtCount);
386 } else if (status.isFailure()) {
387 ATH_MSG_WARNING("Failed to postNext() HelperTool.");
388 } else {
389 if (!m_counterTool.empty() && !m_counterTool->postNext().isSuccess()) {
390 ATH_MSG_WARNING("Failed to postNext() CounterTool.");
391 }
392 break;
393 }
394 } else {
395 while( !m_skipEventRanges.empty() && m_evtCount >= m_skipEventRanges.front().second ) {
396 m_skipEventRanges.erase(m_skipEventRanges.begin());
397 }
398 ATH_MSG_INFO("skipping event " << m_evtCount);
399 }
400 }
401 return StatusCode::SUCCESS;
402}
403//________________________________________________________________________________
404StatusCode EventSelectorAthenaPool::next(IEvtSelector::Context& ctxt, int jump) const {
405 if (jump > 0) {
406 for (int i = 0; i < jump; i++) {
407 ATH_CHECK(next(ctxt));
408 }
409 return StatusCode::SUCCESS;
410 }
411 return StatusCode::FAILURE;
412}
413//________________________________________________________________________________
414StatusCode EventSelectorAthenaPool::nextHandleFileTransition(IEvtSelector::Context& ctxt) const
415{
416 if( m_inputCollectionsChanged ) {
417 StatusCode rc = reinit();
418 if( rc != StatusCode::SUCCESS ) return rc;
419 }
420 else { // advance to the next (not needed after reinit)
421 // Check if we're at the end of file
422 if (m_headerIterator == nullptr || m_headerIterator->next() == 0) {
423 m_headerIterator = nullptr;
424 // Close previous collection.
425 m_poolCollection.reset();
426
427 // Fire EndInputFile while data is still accessible, then disconnect
428 m_inputFileGuard.reset();
429 const SG::SourceID old_guid = m_guid.toString();
430 m_guid = Guid::null();
431 disconnectIfFinished( old_guid );
432
433 // check if somebody updated Inputs in the EOF incident (like VP1 does)
434 if( m_inputCollectionsChanged ) {
435 StatusCode rc = reinit();
436 if( rc != StatusCode::SUCCESS ) return rc;
437 } else {
438 // Open next file from inputCollections list.
439 if (m_inputCollectionsIterator == m_inputCollectionsProp.value().end()) {
440 m_poolCollection = nullptr;
441 }
442 else {
443 ++m_inputCollectionsIterator;
444 // Create Collection for input file
445 m_poolCollection = getCollection(true);
446 }
447 if (!m_poolCollection) {
448 // Return end iterator
449 ctxt = *m_endIter;
450 // This is not a real failure but a Gaudi way of handling "end of job"
451 return StatusCode::FAILURE;
452 }
453 // Get DataHeader iterator
454 m_headerIterator = m_poolCollection->cursor();
455
456 // Return RECOVERABLE to mark we should still continue
457 return StatusCode::RECOVERABLE;
458 }
459 }
460 }
461 const Token& headRef = m_headerIterator->eventRef();
462 const Guid guid = headRef.dbID();
463 ATH_MSG_VERBOSE("next(): DataHeder Token=" << headRef.toString() );
464
465 if (guid != m_guid) {
466 // we are starting reading from a new DB. Check if the old one needs to be retired
467 if (m_guid != Guid::null()) {
468 // zero the current DB ID (m_guid) before trying disconnect() to indicate it is no longer in use
469 const SG::SourceID old_guid = m_guid.toString();
470 m_guid = Guid::null();
471 // EndInputFile is fired by the guard transition() below; just disconnect here
472 disconnectIfFinished( old_guid );
473 }
474 m_guid = guid;
475 m_activeEventsPerSource[guid.toString()] = 0;
476 if (!m_athenaPoolCnvSvc->setInputAttributes(*m_inputCollectionsIterator).isSuccess()) {
477 ATH_MSG_ERROR("Failed to set input attributes.");
478 return StatusCode::FAILURE;
479 }
480 if(m_processMetadata.value()) {
481 InputFileIncidentGuard::transition(m_inputFileGuard, *m_incidentSvc, name(),
482 *m_inputCollectionsIterator, m_guid.toString(),
483 /*endFileName=*/{});
484 }
485 } // end if (guid != m_guid)
486 return StatusCode::SUCCESS;
487}
488//________________________________________________________________________________
489StatusCode EventSelectorAthenaPool::nextWithSkip(IEvtSelector::Context& ctxt) const {
490 ATH_MSG_DEBUG("EventSelectorAthenaPool::nextWithSkip");
491
492 for (;;) {
493 // Check if we're at the end of file
494 StatusCode sc = nextHandleFileTransition(ctxt);
495 if (sc.isRecoverable()) {
496 continue; // handles empty files
497 }
498 if (sc.isFailure()) {
499 return StatusCode::FAILURE;
500 }
501
502 // Increase event count
503 ++m_evtCount;
504
505 if (!m_counterTool.empty() && !m_counterTool->preNext().isSuccess()) {
506 ATH_MSG_WARNING("Failed to preNext() CounterTool.");
507 }
509 && (m_skipEventRanges.empty() || m_evtCount < m_skipEventRanges.front().first))
510 {
511 return StatusCode::SUCCESS;
512 } else {
513 while( !m_skipEventRanges.empty() && m_evtCount >= m_skipEventRanges.front().second ) {
514 m_skipEventRanges.erase(m_skipEventRanges.begin());
515 }
516 if (m_isSecondary.value()) {
517 ATH_MSG_INFO("skipping secondary event " << m_evtCount);
518 } else {
519 ATH_MSG_INFO("skipping event " << m_evtCount);
520 }
521 }
522 }
523
524 return StatusCode::SUCCESS;
525}
526//________________________________________________________________________________
527StatusCode EventSelectorAthenaPool::previous(IEvtSelector::Context& /*ctxt*/) const {
528 ATH_MSG_ERROR("previous() not implemented");
529 return StatusCode::FAILURE;
530}
531//________________________________________________________________________________
532StatusCode EventSelectorAthenaPool::previous(IEvtSelector::Context& ctxt, int jump) const {
533 if (jump > 0) {
534 for (int i = 0; i < jump; i++) {
535 ATH_CHECK(previous(ctxt));
536 }
537 return StatusCode::SUCCESS;
538 }
539 return StatusCode::FAILURE;
540}
541//________________________________________________________________________________
542StatusCode EventSelectorAthenaPool::last(IEvtSelector::Context& ctxt) const {
543 if (ctxt.identifier() == m_endIter->identifier()) {
544 ATH_MSG_DEBUG("last(): Last event in InputStream.");
545 return StatusCode::SUCCESS;
546 }
547 return StatusCode::FAILURE;
548}
549//________________________________________________________________________________
550StatusCode EventSelectorAthenaPool::rewind(IEvtSelector::Context& ctxt) const {
551 ATH_CHECK(reinit());
552 ctxt = EventContextAthenaPool(this);
553 return StatusCode::SUCCESS;
554}
555//________________________________________________________________________________
556StatusCode EventSelectorAthenaPool::createAddress(const IEvtSelector::Context& /*ctxt*/,
557 IOpaqueAddress*& iop) const {
558 std::string tokenStr;
560 if (attrList.isValid()) {
561 try {
562 tokenStr = (*attrList)["eventRef"].data<std::string>();
563 ATH_MSG_DEBUG("found AthenaAttribute, name = eventRef = " << tokenStr);
564 } catch (std::exception &e) {
565 ATH_MSG_ERROR(e.what());
566 return StatusCode::FAILURE;
567 }
568 } else {
569 ATH_MSG_WARNING("Cannot find AthenaAttribute, key = " << m_attrListKey);
570 tokenStr = m_headerIterator->eventRef().toString();
571 }
572 auto token = std::make_unique<Token>();
573 token->fromString(tokenStr);
574 m_incidentSvc->fireIncident(Incident(tokenStr, "ProcessEventAttributes"));
575 iop = new TokenAddress(pool::POOL_StorageType.type(), ClassID_traits<DataHeader>::ID(), "", "EventSelector", IPoolSvc::kInputStream, std::move(token));
576 return StatusCode::SUCCESS;
577}
578//________________________________________________________________________________
579StatusCode EventSelectorAthenaPool::releaseContext(IEvtSelector::Context*& /*ctxt*/) const {
580 return StatusCode::SUCCESS;
581}
582//________________________________________________________________________________
583StatusCode EventSelectorAthenaPool::resetCriteria(const std::string& /*criteria*/,
584 IEvtSelector::Context& /*ctxt*/) const {
585 return StatusCode::SUCCESS;
586}
587//__________________________________________________________________________
588StatusCode EventSelectorAthenaPool::seek(Context& /*ctxt*/, int evtNum) const {
589
590 if( m_inputCollectionsChanged ) {
591 StatusCode rc = reinit();
592 if( rc != StatusCode::SUCCESS ) return rc;
593 }
594
595 long newColl = findEvent(evtNum);
596 if (newColl == -1 && evtNum >= m_firstEvt[m_curCollection] && evtNum < m_evtCount - 1) {
597 newColl = m_curCollection;
598 }
599 if (newColl == -1) {
600 m_headerIterator = nullptr;
601 ATH_MSG_INFO("seek: Reached end of Input.");
602 m_inputFileGuard.reset();
603 return StatusCode::RECOVERABLE;
604 }
605 if (newColl != m_curCollection) {
606 if (!m_keepInputFilesOpen.value()) {
608 } else {
609 m_poolCollection.reset();
610 }
611 m_curCollection = newColl;
612 try {
613 ATH_MSG_DEBUG("Seek to item: \""
615 << "\" from the collection list.");
616 // Reset input collection iterator to the right place
617 m_inputCollectionsIterator = m_inputCollectionsProp.value().begin();
618 m_inputCollectionsIterator += m_curCollection;
619 std::string collName = m_inputCollectionsProp.value()[m_curCollection];
620 StatusCode sc = openCollection(collName, m_poolCollection);
621 if (!sc.isSuccess() || !m_poolCollection) {
622 m_headerIterator = nullptr;
623 ATH_MSG_ERROR("seek: Unable to initialize Collection.");
624 return StatusCode::FAILURE;
625 }
626 m_curCollectionName = collName;
627 // Create DataHeader iterators
628 m_headerIterator = m_poolCollection->cursor();
629 EventContextAthenaPool* beginIter = new EventContextAthenaPool(this);
630 m_evtCount = m_firstEvt[m_curCollection];
631 next(*beginIter).ignore();
632 ATH_MSG_DEBUG("Token " << m_headerIterator->eventRef().toString());
633 } catch (std::exception &e) {
634 m_headerIterator = nullptr;
635 ATH_MSG_ERROR(e.what());
636 return StatusCode::FAILURE;
637 }
638 }
639
640 if (m_headerIterator->seek(evtNum - m_firstEvt[m_curCollection]) == 0) {
641 m_headerIterator = nullptr;
642 ATH_MSG_ERROR("Did not find event, evtNum = " << evtNum);
643 return StatusCode::FAILURE;
644 } else {
645 m_evtCount = evtNum + 1;
646 }
647 return StatusCode::SUCCESS;
648}
649//__________________________________________________________________________
650int EventSelectorAthenaPool::curEvent (const Context& /*ctxt*/) const {
651 return(m_evtCount);
652}
653//__________________________________________________________________________
654// Search for event number evtNum.
655// Return the index of the collection containing it, or -1 if not found.
656// Note: passing -1 for evtNum will always yield failure,
657// but this can be used to force filling in the entire m_numEvt array.
659 for (std::size_t i = 0, imax = m_numEvt.size(); i < imax; i++) {
660 if (m_numEvt[i] == -1) {
661 std::string collName = m_inputCollectionsProp.value()[i];
662 std::string lastError;
663 std::unique_ptr<pool::Collection> coll;
664 StatusCode status = openCollection(collName, coll, &lastError);
665 if (!status.isSuccess()) {
666 break;
667 }
668 int collection_size = 0;
669 if (coll) {
670 std::unique_ptr<pool::CollectionCursor> hi = coll->cursor();
671 collection_size = hi->size();
672 }
673 else {
674 ATH_MSG_ERROR( lastError );
675 }
676 if (i > 0) {
677 m_firstEvt[i] = m_firstEvt[i - 1] + m_numEvt[i - 1];
678 } else {
679 m_firstEvt[i] = 0;
680 }
681 m_numEvt[i] = collection_size;
682 }
683 if (evtNum >= m_firstEvt[i] && evtNum < m_firstEvt[i] + m_numEvt[i]) {
684 return(i);
685 }
686 }
687 return(-1);
688}
689
690//__________________________________________________________________________
691int EventSelectorAthenaPool::size(Context& /*ctxt*/) const {
692 // Fetch sizes of all collections.
693 findEvent(-1);
694 return std::accumulate(m_numEvt.begin(), m_numEvt.end(), 0);
695}
696//__________________________________________________________________________
697StatusCode EventSelectorAthenaPool::openCollection(std::string& inputCollection,
698 std::unique_ptr<pool::Collection>& poolCollection,
699 std::string* lastError) const {
700 if (!inputCollection.starts_with("PFN:")
701 && !inputCollection.starts_with("LFN:")
702 && !inputCollection.starts_with("FID:")) {
703 inputCollection = std::format("PFN:{}", inputCollection);
704 }
705 StatusCode sc = m_poolSvc->connectCollection(inputCollection, "Input", IPoolSvc::kInputStream);
706 try {
707 auto fileDescr = m_poolSvc->getInputFileDescriptor(IPoolSvc::kInputStream, inputCollection);
708 poolCollection = std::make_unique<pool::Collection>(fileDescr);
709 if (lastError) lastError->clear();
710 } catch (const std::exception &e) {
711 if (lastError) {
712 *lastError = std::format("Failed to open collection '{}': {}", inputCollection, e.what());
713 }
714 poolCollection.reset();
715 }
716 if (sc.isRecoverable() || poolCollection == nullptr) {
717 return m_poolSvc->checkCollection(inputCollection, IPoolSvc::kInputStream, poolCollection == nullptr);
718 }
719 return StatusCode::SUCCESS;
720}
721//__________________________________________________________________________
723 if (m_poolCollection) {
724 if (!m_curCollectionName.empty()) {
725 m_poolSvc->disconnectDb(m_curCollectionName).ignore();
726 m_curCollectionName.clear();
727 }
728 m_poolCollection.reset();
729 }
730}
731//__________________________________________________________________________
732std::unique_ptr<pool::Collection>
733EventSelectorAthenaPool::getCollection(bool throwIncidents) const {
734 while (m_inputCollectionsIterator != m_inputCollectionsProp.value().end()) {
735 if (m_curCollection != 0) {
736 m_numEvt[m_curCollection] = m_evtCount - m_firstEvt[m_curCollection];
738 m_firstEvt[m_curCollection] = m_evtCount;
739 }
740 ATH_MSG_DEBUG("Try item: \"" << *m_inputCollectionsIterator << "\" from the collection list.");
741 std::string collName = *m_inputCollectionsIterator;
742 std::unique_ptr<pool::Collection> coll;
743 StatusCode status = openCollection(collName, coll);
744 if (!status.isSuccess()) {
745 if (!status.isRecoverable()) {
746 ATH_MSG_ERROR("Unable to initialize Collection.");
747 throw GaudiException("Unable to read: " + *m_inputCollectionsIterator, name(), StatusCode::FAILURE);
748 } else {
749 ATH_MSG_ERROR("Unable to open: " << *m_inputCollectionsIterator);
750 throw GaudiException("Unable to open: " + *m_inputCollectionsIterator, name(), StatusCode::FAILURE);
751 }
752 } else {
753 if (!coll) {
754 ATH_MSG_DEBUG("No events found in: " << *m_inputCollectionsIterator << " skipped!!!");
755 if (throwIncidents && m_processMetadata.value()) {
756 // Scoped guard: fires BeginInputFile now, EndInputFile at scope exit
757 auto guard = InputFileIncidentGuard::begin(*m_incidentSvc, name(),
758 *m_inputCollectionsIterator, {},
759 "eventless " + *m_inputCollectionsIterator);
760 }
761 m_poolSvc->disconnectDb(*m_inputCollectionsIterator).ignore();
762 ++m_inputCollectionsIterator;
763 } else {
764 m_curCollectionName = collName;
765 return coll;
766 }
767 }
768 }
769 return nullptr;
770}
771//__________________________________________________________________________
773 if (!eventStore()->clearStore().isSuccess()) {
774 ATH_MSG_WARNING("Cannot clear Store");
775 }
776 // Get access to AttributeList
777 ATH_MSG_DEBUG("Get AttributeList from the collection");
778 // MN: accessing only attribute list, ignoring token list
779 const coral::AttributeList& attrList = m_headerIterator->currentRow().attributeList();
780 ATH_MSG_DEBUG("AttributeList size " << attrList.size());
781 std::unique_ptr<AthenaAttributeList> athAttrList(new AthenaAttributeList(attrList));
782 // Fill the new attribute list
783 ATH_CHECK(fillAttributeList(athAttrList.get(), "", false));
784 // Write the AttributeList
786 ATH_CHECK(wh.record(std::move(athAttrList)));
787 return StatusCode::SUCCESS;
788}
789//__________________________________________________________________________
790StatusCode EventSelectorAthenaPool::fillAttributeList(coral::AttributeList *attrList, const std::string &suffix, bool copySource) const
791{
792 const auto& row = m_headerIterator->currentRow();
793 attrList->extend( row.tokenName() + suffix, "string" );
794 (*attrList)[ row.tokenName() + suffix ].data<std::string>() = row.token().toString();
795 ATH_MSG_DEBUG("record AthenaAttribute, name = " << row.tokenName() + suffix << " = " << row.token().toString() << ".");
796
797 std::string eventRef = "eventRef";
798 if (m_isSecondary.value()) {
799 eventRef.append(suffix);
800 }
801 attrList->extend(eventRef, "string");
802 (*attrList)[eventRef].data<std::string>() = m_headerIterator->eventRef().toString();
803 ATH_MSG_DEBUG("record AthenaAttribute, name = " + eventRef + " = " << m_headerIterator->eventRef().toString() << ".");
804
805 if (copySource) {
806 const coral::AttributeList& sourceAttrList = m_headerIterator->currentRow().attributeList();
807 for (const auto &attr : sourceAttrList) {
808 attrList->extend(attr.specification().name() + suffix, attr.specification().type());
809 (*attrList)[attr.specification().name() + suffix] = attr;
810 }
811 }
812
813 return StatusCode::SUCCESS;
814}
815//__________________________________________________________________________
817 ATH_MSG_INFO("I/O reinitialization...");
819 m_headerIterator = nullptr;
820 ServiceHandle<IIoComponentMgr> iomgr("IoComponentMgr", name());
821 if (!iomgr.retrieve().isSuccess()) {
822 ATH_MSG_FATAL("Could not retrieve IoComponentMgr !");
823 return StatusCode::FAILURE;
824 }
825 if (!iomgr->io_hasitem(this)) {
826 ATH_MSG_FATAL("IoComponentMgr does not know about myself !");
827 return StatusCode::FAILURE;
828 }
829 std::vector<std::string> inputCollections = m_inputCollectionsProp.value();
830 std::set<std::size_t> updatedIndexes;
831 for (std::size_t i = 0, imax = m_inputCollectionsProp.value().size(); i < imax; i++) {
832 if (updatedIndexes.find(i) != updatedIndexes.end()) continue;
833 std::string savedName = inputCollections[i];
834 std::string &fname = inputCollections[i];
835 if (!iomgr->io_contains(this, fname)) {
836 ATH_MSG_ERROR("IoComponentMgr does not know about [" << fname << "] !");
837 return StatusCode::FAILURE;
838 }
839 if (!iomgr->io_retrieve(this, fname).isSuccess()) {
840 ATH_MSG_FATAL("Could not retrieve new value for [" << fname << "] !");
841 return StatusCode::FAILURE;
842 }
843 updatedIndexes.insert(i);
844 for (std::size_t j = i + 1; j < imax; j++) {
845 if (inputCollections[j] == savedName) {
846 inputCollections[j] = fname;
847 updatedIndexes.insert(j);
848 }
849 }
850 }
851 // all good... copy over.
852 m_inputCollectionsProp = inputCollections;
853 m_guid = Guid::null();
854 return reinit();
855}
856//__________________________________________________________________________
858 ATH_MSG_INFO("I/O finalization...");
859 // Fire EndInputFile before disconnecting — file data is still accessible here
860 m_inputFileGuard.reset();
862 return StatusCode::SUCCESS;
863}
864
865//__________________________________________________________________________
866/* Listen to IncidentType::BeginProcessing and EndProcessing
867 Maintain counters of how many events from a given file are being processed.
868 Files are identified by SG::SourceID (string GUID).
869 When there are no more events from a file, see if it can be closed.
870*/
871void EventSelectorAthenaPool::handle(const Incident& inc)
872{
873 SG::SourceID fid;
874 if (inc.type() == IncidentType::BeginProcessing) {
875 if ( Atlas::hasExtendedEventContext(inc.context()) ) {
876 fid = Atlas::getExtendedEventContext(inc.context()).proxy()->sourceID();
877 }
878 *m_sourceID.get(inc.context()) = fid;
879 }
880 else {
881 fid = *m_sourceID.get(inc.context());
882 }
883
884 if( fid.empty() ) {
885 ATH_MSG_WARNING("could not read event source ID from incident event context");
886 return;
887 }
888 if( m_activeEventsPerSource.find( fid ) == m_activeEventsPerSource.end()) {
889 ATH_MSG_DEBUG("Incident handler ignoring unknown input FID: " << fid );
890 return;
891 }
892 ATH_MSG_DEBUG("** MN Incident handler " << inc.type() << " Event source ID=" << fid );
893 if( inc.type() == IncidentType::BeginProcessing ) {
894 // increment the events-per-file counter for FID
895 m_activeEventsPerSource[fid]++;
896 } else if( inc.type() == IncidentType::EndProcessing ) {
897 m_activeEventsPerSource[fid]--;
899 *m_sourceID.get(inc.context()) = "";
900 }
901 if( msgLvl(MSG::DEBUG) ) {
902 for( auto& source: m_activeEventsPerSource )
903 msg(MSG::DEBUG) << "SourceID: " << source.first << " active events: " << source.second << endmsg;
904 }
905}
906
907//__________________________________________________________________________
908/* Disconnect Database identifieed by a SG::SourceID when it is no longer in use:
909 m_guid is not pointing to it and there are no events from it being processed
910 (if the EventLoopMgr was not firing Begin/End incidents, this will just close the DB)
911*/
913{
914 if( m_activeEventsPerSource.find(fid) != m_activeEventsPerSource.end()
915 && m_activeEventsPerSource[fid] <= 0 && m_guid != fid ) {
916 // Explicitly disconnect file corresponding to old FID to release memory.
917 // EndInputFile is handled by the InputFileIncidentGuard.
918 if( !m_keepInputFilesOpen.value() ) {
919 ATH_MSG_INFO("Disconnecting input sourceID: " << fid );
920 m_poolSvc->disconnectDb("FID:" + fid, IPoolSvc::kInputStream).ignore();
921 m_activeEventsPerSource.erase( fid );
922 return true;
923 }
924 }
925 return false;
926}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
This file contains the class definition for the DataHeader and DataHeaderElement classes.
This file contains the class definition for the EventContextAthenaPool class.
This file contains the class definition for the EventSelectorAthenaPool class.
This file contains the class definition for the IPoolSvc interface class.
static Double_t sc
static Double_t rc
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
int imax(int i, int j)
This file contains the class definition for the TokenAddress class.
This file contains the class definition for the Token class (migrated from POOL).
An AttributeList represents a logical row of attributes in a metadata table.
This class provides the context to access an event from POOL persistent store.
EventSelectorAthenaPool(const std::string &name, ISvcLocator *pSvcLocator)
Standard Service Constructor.
Gaudi::CheckedProperty< uint64_t > m_firstEventNo
virtual StatusCode start() override
Gaudi::Property< bool > m_isSecondary
IsSecondary, know if this is an instance of secondary event selector.
virtual StatusCode nextWithSkip(IEvtSelector::Context &ctxt) const override
Go to next event and skip if necessary.
std::unique_ptr< pool::Collection > getCollection(bool throwIncidents=false) const
Return pointer to new Collection.
virtual StatusCode initialize() override
Required of all Gaudi Services.
Gaudi::Property< int > m_skipEvents
SkipEvents, numbers of events to skip: default = 0.
Gaudi::Property< bool > m_processMetadata
ProcessMetadata, switch on firing of FileIncidents which will trigger processing of metadata: default...
virtual int curEvent(const Context &ctxt) const override
Return the current event number.
virtual StatusCode createContext(IEvtSelector::Context *&ctxt) const override
create context
virtual StatusCode io_finalize() override
Callback method to finalize the internal state of the component for I/O purposes (e....
Gaudi::Property< std::vector< long > > m_skipEventSequenceProp
Gaudi::CheckedProperty< uint32_t > m_initTimeStamp
void inputCollectionsHandler(Gaudi::Details::PropertyBase &)
virtual StatusCode io_reinit() override
Callback method to reinitialize the internal state of the component for I/O purposes (e....
virtual StatusCode resetCriteria(const std::string &criteria, IEvtSelector::Context &ctxt) const override
Set a selection criteria.
StatusCode reinit() const
Reinitialize the service when a fork() occurred/was-issued.
StoreGateSvc * eventStore() const
Return pointer to active event SG.
virtual StatusCode releaseContext(IEvtSelector::Context *&ctxt) const override
virtual StatusCode stop() override
ServiceHandle< IIncidentSvc > m_incidentSvc
virtual StatusCode next(IEvtSelector::Context &ctxt) const override
virtual ~EventSelectorAthenaPool()
Destructor.
ToolHandle< IAthenaSelectorTool > m_counterTool
ServiceHandle< IPoolSvc > m_poolSvc
virtual StatusCode fillAttributeList(coral::AttributeList *attrList, const std::string &suffix, bool copySource) const override
Fill AttributeList with specific items from the selector and a suffix.
std::string m_attrListKey
AttributeList SG key.
virtual StatusCode seek(Context &ctxt, int evtnum) const override
Seek to a given event number.
SG::SlotSpecificObj< SG::SourceID > m_sourceID
virtual StatusCode last(IEvtSelector::Context &ctxt) const override
Gaudi::CheckedProperty< uint64_t > m_eventsPerRun
Gaudi::CheckedProperty< uint32_t > m_eventsPerLB
virtual StatusCode createAddress(const IEvtSelector::Context &ctxt, IOpaqueAddress *&iop) const override
virtual void handle(const Incident &incident) override
Incident service handle listening for BeginProcessing and EndProcessing.
virtual StatusCode previous(IEvtSelector::Context &ctxt) const override
ServiceHandle< IAthenaPoolCnvSvc > m_athenaPoolCnvSvc
virtual StatusCode rewind(IEvtSelector::Context &ctxt) const override
Gaudi::Property< bool > m_keepInputFilesOpen
KeepInputFilesOpen, boolean flag to keep files open after PoolCollection reaches end: default = false...
void disconnectCollection() const
Disconnect current collection DB if open.
Gaudi::CheckedProperty< uint32_t > m_oldRunNo
virtual StatusCode finalize() override
virtual bool disconnectIfFinished(const SG::SourceID &fid) const override
Disconnect DB if all events from the source FID were processed and the Selector moved to another file...
Gaudi::Property< std::vector< std::string > > m_inputCollectionsProp
InputCollections, vector with names of the input collections.
EventContextAthenaPool * m_endIter
StatusCode openCollection(std::string &inputCollection, std::unique_ptr< pool::Collection > &poolCollection, std::string *lastError=nullptr) const
Open a collection by name.
virtual StatusCode nextHandleFileTransition(IEvtSelector::Context &ctxt) const override
Handle file transition at the next iteration.
virtual StatusCode recordAttributeList() const override
Record AttributeList in StoreGate.
Gaudi::CheckedProperty< uint32_t > m_runNo
The following are included for compatibility with McEventSelector and are not really used.
virtual int size(Context &ctxt) const override
Return the size of the collection.
int findEvent(int evtNum) const
Search for event with number evtNum.
Gaudi::Property< std::string > m_skipEventRangesProp
Skip Events - comma separated list of event to skip, ranges with '-': <start> - <end>.
Gaudi::CheckedProperty< uint32_t > m_firstLBNo
This class provides a encapsulation of a GUID/UUID/CLSID/IID data structure (128 bit number).
Definition Guid.h:25
static const Guid & null() noexcept
NULL-Guid: static class method.
Definition Guid.cxx:14
constexpr void toString(std::span< char, StrLen > buf, bool uppercase=true) const noexcept
Automatic conversion to string representation.
@ kInputStream
Definition IPoolSvc.h:37
static InputFileIncidentGuard begin(IIncidentSvc &incSvc, std::string_view source, std::string_view beginFileName, std::string_view guid, std::string_view endFileName={}, std::string_view beginType=IncidentType::BeginInputFile, std::string_view endType=IncidentType::EndInputFile)
Factory: fire the begin incident and return a guard whose destructor fires the matching end incident.
static void transition(std::optional< InputFileIncidentGuard > &guard, IIncidentSvc &incSvc, std::string_view source, std::string_view beginFileName, std::string_view guid, std::string_view endFileName={}, std::string_view beginType=IncidentType::BeginInputFile, std::string_view endType=IncidentType::EndInputFile)
Replace the guard in an optional, with strict End-before-Begin ordering.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
The Athena Transient Store API.
static StoreGateSvc * currentStoreGate()
get current StoreGate
This class provides a Generic Transient Address for POOL tokens.
This class provides a token that identifies in a unique way objects on the persistent storage.
Definition Token.h:22
const std::string toString() const
Retrieve the string representation of the token.
Definition Token.cxx:135
int technology() const
Access technology type.
Definition Token.h:78
const Guid & dbID() const
Access database identifier.
Definition Token.h:65
int r
Definition globals.cxx:22
const ExtendedEventContext & getExtendedEventContext(const EventContext &ctx)
Retrieve an extended context from a context object.
bool hasExtendedEventContext(const EventContext &ctx)
Test whether a context object has an extended context installed.
std::vector< std::string > tokenize(std::string_view the_str, std::string_view delimiters)
Splits the string into smaller substrings.
StatusCode parse(std::tuple< Tup... > &tup, const Gaudi::Parsers::InputData &input)
static const DbType POOL_StorageType
Definition DbType.h:84
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
MsgStream & msg
Definition testRead.cxx:32