Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-06 10:24:10

0001 
0002 // Copyright 2023, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 #include <JANA/JFactory.h>
0006 #include <JANA/JEvent.h>
0007 #include <JANA/JEventSource.h>
0008 #include <JANA/Utils/JTypeInfo.h>
0009 
0010 
0011 class FlagGuard {
0012     bool* m_flag;
0013 public:
0014     FlagGuard(bool* flag) : m_flag(flag) {
0015         *m_flag = true;
0016     }
0017     ~FlagGuard() {
0018         *m_flag = false;
0019     }
0020 };
0021 
0022 void JFactory::Create(const std::shared_ptr<const JEvent>& event) {
0023     Create(*event.get());
0024 }
0025 
0026 void JFactory::Create(const JEvent& event) {
0027 
0028     if (mInsideCreate && (mStatus != Status::Inserted)) {
0029         // Ideally, we disallow any calls to Create() that end up calling it right back. However, we do allow
0030         // calls that go down to GetObjects, who inserts the data, but then RETRIEVES the same data it just inserted,
0031         // so that it can subsequently calculate and insert OTHER data. Once we refactor JEventSourceEVIOpp, we can consider
0032         // removing this weird edge case.
0033         throw JException("Encountered a cycle in the factory dependency graph! Hint: Maybe this data was supposed to be inserted in the JEventSource");
0034     }
0035     FlagGuard insideCreateFlagGuard (&mInsideCreate); // No matter how we exit from Create() (particularly with exceptions) mInsideCreate will be set back to false
0036 
0037     if (m_app == nullptr && event.GetJApplication() != nullptr) {
0038         // These are usually set by JFactoryGeneratorT, but some user code has custom JFactoryGenerators which don't!
0039         // The design of JFactoryGenerator doesn't give us a better place to inject things
0040         m_app = event.GetJApplication();
0041         m_logger = m_app->GetJParameterManager()->GetLogger(GetLoggerName());
0042     }
0043 
0044     if (mStatus == Status::Uninitialized) {
0045         DoInit();
0046     }
0047 
0048     // How do we obtain our data? The priority is as follows:
0049     // 1. JFactory::Process() if REGENERATE flag is set
0050     // 2. JEvent::Insert()
0051     // 3. JEventSource::GetObjects() if source has GetObjects() enabled
0052     // 4. JFactory::Process()
0053 
0054     // ---------------------------------------------------------------------
0055     // 1. JFactory::Process() if REGENERATE flag is set
0056     // ---------------------------------------------------------------------
0057 
0058     if (mRegenerate) {
0059         if (mStatus == Status::Inserted) {
0060             // Status::Inserted indicates that the data came from either src->GetObjects() or evt->Insert()
0061             ClearData(); 
0062             // ClearData() resets mStatus to Unprocessed so that the data will be regenerated exactly once.
0063         }
0064         // After this point, control flow falls through to "4. JFactory::Process"
0065     }
0066     else {
0067 
0068         // ---------------------------------------------------------------------
0069         // 2. JEvent::Insert()
0070         // ---------------------------------------------------------------------
0071 
0072         if (mStatus == Status::Inserted) {
0073             // This may include data cached from eventsource->GetObjects().
0074             // Either way, short-circuit here, because the data is present.
0075             return;
0076         }
0077 
0078         // ---------------------------------------------------------------------
0079         // 3. JEventSource::GetObjects() if source has GetObjects() enabled
0080         // ---------------------------------------------------------------------
0081 
0082         auto src = event.GetJEventSource();
0083         if (src != nullptr && src->IsGetObjectsEnabled()) {
0084             bool found_data = false;
0085 
0086             CallWithJExceptionWrapper("JEventSource::GetObjects", [&](){ 
0087                 found_data = src->GetObjects(event.shared_from_this(), this); });
0088 
0089             if (found_data) {
0090                 mStatus = Status::Inserted;
0091                 mCreationStatus = CreationStatus::InsertedViaGetObjects;
0092                 return;
0093             }
0094         }
0095         // If neither "2. JEvent::Insert()" nor "3. JEventSource::GetObjects()" succeeded, fall through to "4. JFactory::Process()"
0096     }
0097 
0098     // ---------------------------------------------------------------------
0099     // 4. JFactory::Process()
0100     // ---------------------------------------------------------------------
0101 
0102     // If the data was Processed (instead of Inserted), it will be in cache, and we can just exit.
0103     // Otherwise we call Process() to create the data in the first place.
0104     // If we already ran Process() but it excepted, we re-run Process() to trigger the same exception, so that every consumer
0105     // is forced to handle it. Otherwise one "fault-tolerant" consumer will swallow the exception for everybody else.
0106     if (mStatus == Status::Unprocessed || mStatus == Status::Excepted) {
0107         auto run_number = event.GetRunNumber();
0108         if (mPreviousRunNumber != run_number) {
0109             if (m_callback_style == CallbackStyle::LegacyMode) {
0110                 if (mPreviousRunNumber != -1) {
0111                     CallWithJExceptionWrapper("JFactory::EndRun", [&](){ EndRun(); });
0112                 }
0113                 CallWithJExceptionWrapper("JFactory::ChangeRun", [&](){ ChangeRun(event.shared_from_this()); });
0114                 CallWithJExceptionWrapper("JFactory::BeginRun", [&](){ BeginRun(event.shared_from_this()); });
0115             }
0116             else if (m_callback_style == CallbackStyle::ExpertMode) {
0117                 CallWithJExceptionWrapper("JFactory::ChangeRun", [&](){ ChangeRun(event); });
0118             }
0119             mPreviousRunNumber = run_number;
0120         }
0121         try {
0122             for (auto* input : GetInputs()) {
0123                 input->Populate(event);
0124             }
0125             for (auto* input : GetVariadicInputs()) {
0126                 input->Populate(event);
0127             }
0128             if (m_callback_style == CallbackStyle::LegacyMode) {
0129                 CallWithJExceptionWrapper("JFactory::Process", [&](){ Process(event.shared_from_this()); });
0130             }
0131             else if (m_callback_style == CallbackStyle::ExpertMode) {
0132                 CallWithJExceptionWrapper("JFactory::Process", [&](){ Process(event); });
0133             }
0134             else {
0135                 throw JException("Invalid callback style");
0136             }
0137         }
0138         catch (...) {
0139             // Save everything already created even if we throw an exception
0140             // This is so that we leave everything in a valid state just in case someone tries to catch the exception recover,
0141             // such as EICrecon. (Remember that a missing collection in the podio frame will segfault if anyone tries to write that frame)
0142             // Note that the collections themselves won't know that they exited early
0143 
0144             LOG << "Exception in JFactory::Create, prefix=" << GetPrefix();
0145             mStatus = Status::Excepted;
0146             mCreationStatus = CreationStatus::Created;
0147             for (auto* output : GetOutputs()) {
0148                 output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0149             }
0150             for (auto* output : GetVariadicOutputs()) {
0151                 output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Excepted);
0152             }
0153             throw;
0154         }
0155         mStatus = Status::Processed;
0156         mCreationStatus = CreationStatus::Created;
0157         for (auto* output : GetOutputs()) {
0158             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Created);
0159         }
0160         for (auto* output : GetVariadicOutputs()) {
0161             output->LagrangianStore(*event.GetFactorySet(), JDatabundle::Status::Created);
0162         }
0163     }
0164 }
0165 
0166 void JFactory::DoInit() {
0167     if (mStatus != Status::Uninitialized) {
0168         return;
0169     }
0170     for (auto* parameter : m_parameters) {
0171         parameter->Init(*(m_app->GetJParameterManager()), m_prefix);
0172     }
0173     for (auto* service : m_services) {
0174         service->Fetch(m_app);
0175     }
0176     CallWithJExceptionWrapper("JFactory::Init", [&](){ Init(); });
0177     mStatus = Status::Unprocessed;
0178 }
0179 
0180 void JFactory::DoFinish() {
0181     if (mStatus == Status::Unprocessed || mStatus == Status::Processed) {
0182         if (mPreviousRunNumber != -1) {
0183             CallWithJExceptionWrapper("JFactory::EndRun", [&](){ EndRun(); });
0184         }
0185         CallWithJExceptionWrapper("JFactory::Finish", [&](){ Finish(); });
0186         mStatus = Status::Finished;
0187     }
0188 }
0189 
0190 void JFactory::Summarize(JComponentSummary& summary) const {
0191 
0192     auto fs = new JComponentSummary::Component(
0193             "Factory",
0194             GetPrefix(),
0195             GetTypeName(),
0196             GetLevel(),
0197             GetPluginName());
0198 
0199     SummarizeInputs(*fs);
0200     SummarizeOutputs(*fs);
0201     summary.Add(fs);
0202 }
0203 
0204