From d6393fc9ce36f03cbef6ce39ab5055cbac45c31e Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 4 Dec 2025 11:35:58 +0100 Subject: [PATCH 1/3] DPL: refactor ccdb-fetcher service devic injection --- Framework/Core/src/WorkflowHelpers.cxx | 154 ++++++++++--------------- 1 file changed, 61 insertions(+), 93 deletions(-) diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 61443f5f71616..034524ff0af8e 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -488,116 +488,84 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext extraSpecs.push_back(timePipeline(aodReader, ctx.options().get("readers"))); } - ConcreteDataMatcher dstf{"FLP", "DISTSUBTIMEFRAME", 0xccdb}; - if (ccdbBackend.outputs.empty() == false) { - ccdbBackend.outputs.push_back(OutputSpec{"CTP", "OrbitReset", 0}); - InputSpec matcher{"dstf", "FLP", "DISTSUBTIMEFRAME", 0xccdb}; - bool providesDISTSTF = false; - // Check if any of the provided outputs is a DISTSTF - // Check if any of the requested inputs is for a 0xccdb message - for (auto& dp : workflow) { - for (auto& output : dp.outputs) { - if (DataSpecUtils::match(matcher, output)) { - providesDISTSTF = true; - dstf = DataSpecUtils::asConcreteDataMatcher(output); - break; - } - } - if (providesDISTSTF) { - break; - } + // ConcreteDataMatcher dstf{"FLP", "DISTSUBTIMEFRAME", 0xccdb}; + InputSpec matcher{"dstf", "FLP", "DISTSUBTIMEFRAME", 0xccdb}; + auto& dstf = std::get(matcher.matcher); + // Check if any of the provided outputs is a DISTSTF + // Check if any of the requested inputs is for a 0xccdb message + bool providesDISTSTF = std::any_of(workflow.begin(), workflow.end(), + [&matcher](auto const& dp) { + return std::any_of(dp.outputs.begin(), dp.outputs.end(), [&matcher](auto const& output){ + return DataSpecUtils::match(matcher, output); + }); + }); + + // If there is no CCDB requested, but we still ask for a FLP/DISTSUBTIMEFRAME/0xccdb + // we add to the first data processor which has no inputs (apart from + // enumerations / timers) the responsibility to provide the DISTSUBTIMEFRAME + bool requiresDISTSUBTIMEFRAME = std::any_of(workflow.begin(), workflow.end(), + [&dstf](auto const& dp) { + return std::any_of(dp.inputs.begin(), dp.inputs.end(), [&dstf](auto const& input){ + return DataSpecUtils::match(input, dstf); + }); + }); + + // We find the first device which has either just enumerations or + // just timers, and we will add the DISTSUBTIMEFRAME to it. + // Notice how we do so in a stable manner by sorting the devices + // by name. + int enumCandidate = -1; + int timerCandidate = -1; + for (auto wi = 0U; wi < workflow.size(); ++wi) { + auto& dp = workflow[wi]; + if (dp.inputs.size() != 1) { + continue; + } + auto lifetime = dp.inputs[0].lifetime; + if (lifetime == Lifetime::Enumeration && (enumCandidate == -1 || workflow[enumCandidate].name > dp.name)) { + enumCandidate = wi; } - // * If there are AOD outputs we use TFNumber as the CCDB clock - // * If one device provides a DISTSTF we use that as the CCDB clock - // * If one of the devices provides a timer we use that as the CCDB clock - // * If none of the above apply add to the first data processor - // which has no inputs apart from enumerations the responsibility - // to provide the DISTSUBTIMEFRAME. + if (lifetime == Lifetime::Timer && (timerCandidate == -1 || workflow[timerCandidate].name > dp.name)) { + timerCandidate = wi; + } + } + + // * If there are AOD outputs we use TFNumber as the CCDB clock + // * If one device provides a DISTSTF we use that as the CCDB clock + // * If one of the devices provides a timer we use that as the CCDB clock + // * If none of the above apply, add to the first data processor + // which has no inputs apart from enumerations the responsibility + // to provide the DISTSUBTIMEFRAME. + if (ccdbBackend.outputs.empty() == false) { if (aodReader.outputs.empty() == false) { + // fetcher clock follows AOD source (TFNumber) ccdbBackend.inputs.push_back(InputSpec{"tfn", "TFN", "TFNumber"}); } else if (providesDISTSTF) { + // fetcher clock follows DSTF/ccdb source (DISTSUBTIMEFRAME) ccdbBackend.inputs.push_back(InputSpec{"tfn", dstf, Lifetime::Timeframe}); } else { - // We find the first device which has either just enumerations or - // just timers, and we add the DISTSUBTIMEFRAME to it. - // Notice how we do so in a stable manner by sorting the devices - // by name. - int enumCandidate = -1; - int timerCandidate = -1; - for (size_t wi = 0; wi < workflow.size(); wi++) { - auto& dp = workflow[wi]; - if (dp.inputs.size() != 1) { - continue; - } - auto lifetime = dp.inputs[0].lifetime; - if (lifetime == Lifetime::Enumeration && (enumCandidate == -1 || workflow[enumCandidate].name > dp.name)) { - enumCandidate = wi; - } - if (lifetime == Lifetime::Timer && (timerCandidate == -1 || workflow[timerCandidate].name > dp.name)) { - timerCandidate = wi; - } - } if (enumCandidate != -1) { - auto& dp = workflow[enumCandidate]; - DataSpecUtils::updateOutputList(dp.outputs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); + // add DSTF/ccdb source to the enumeration-driven source explicitly + // fetcher clock is provided by enumeration-driven source (DISTSUBTIMEFRAME) + DataSpecUtils::updateOutputList(workflow[enumCandidate].outputs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); ccdbBackend.inputs.push_back(InputSpec{"tfn", dstf, Lifetime::Timeframe}); } else if (timerCandidate != -1) { - auto& dp = workflow[timerCandidate]; - dstf = DataSpecUtils::asConcreteDataMatcher(dp.outputs[0]); - ccdbBackend.inputs.push_back(InputSpec{{"tfn"}, dstf, Lifetime::Timeframe}); + // fetcher clock is proived by timer source + auto timer_dstf = DataSpecUtils::asConcreteDataMatcher(workflow[timerCandidate].outputs[0]); + ccdbBackend.inputs.push_back(InputSpec{"tfn", timer_dstf, Lifetime::Timeframe}); } } + ccdbBackend.outputs.push_back(OutputSpec{"CTP", "OrbitReset", 0}); // Load the CCDB backend from the plugin ccdbBackend.algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "CCDBFetcherPlugin", ctx); extraSpecs.push_back(ccdbBackend); - } else { - // If there is no CCDB requested, but we still ask for a FLP/DISTSUBTIMEFRAME/0xccdb - // we add to the first data processor which has no inputs (apart from - // enumerations / timers) the responsibility to provide the DISTSUBTIMEFRAME - bool requiresDISTSUBTIMEFRAME = false; - for (auto& dp : workflow) { - for (auto& input : dp.inputs) { - if (DataSpecUtils::match(input, dstf)) { - requiresDISTSUBTIMEFRAME = true; - break; - } - } - } - if (requiresDISTSUBTIMEFRAME) { - // We find the first device which has either just enumerations or - // just timers, and we add the DISTSUBTIMEFRAME to it. - // Notice how we do so in a stable manner by sorting the devices - // by name. - int enumCandidate = -1; - int timerCandidate = -1; - for (size_t wi = 0; wi < workflow.size(); wi++) { - auto& dp = workflow[wi]; - if (dp.inputs.size() != 1) { - continue; - } - auto lifetime = dp.inputs[0].lifetime; - if (lifetime == Lifetime::Enumeration && (enumCandidate == -1 || workflow[enumCandidate].name > dp.name)) { - enumCandidate = wi; - } - if (lifetime == Lifetime::Timer && (timerCandidate == -1 || workflow[timerCandidate].name > dp.name)) { - timerCandidate = wi; - } - } - if (enumCandidate != -1) { - auto& dp = workflow[enumCandidate]; - DataSpecUtils::updateOutputList(dp.outputs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); - ccdbBackend.inputs.push_back(InputSpec{"tfn", dstf, Lifetime::Timeframe}); - } else if (timerCandidate != -1) { - auto& dp = workflow[timerCandidate]; - dstf = DataSpecUtils::asConcreteDataMatcher(dp.outputs[0]); - ccdbBackend.inputs.push_back(InputSpec{{"tfn"}, dstf, Lifetime::Timeframe}); - } - } + } else if (requiresDISTSUBTIMEFRAME && enumCandidate != -1) { + // add DSTF/ccdb source to the enumeration-driven source explicitly if it is required in the workflow + DataSpecUtils::updateOutputList(workflow[enumCandidate].outputs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); } - // add the Analysys CCDB backend which reads CCDB objects using a provided - // table + // add the Analysys CCDB backend which reads CCDB objects using a provided table if (analysisCCDBBackend.outputs.empty() == false) { // add normal reader auto&& algo = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "AnalysisCCDBFetcherPlugin", ctx); From add19cb13f413704e0fcb2ac4420bde20139d1ca Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Mon, 8 Dec 2025 10:14:57 +0100 Subject: [PATCH 2/3] remove commented code --- Framework/Core/src/WorkflowHelpers.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 034524ff0af8e..8d273b2f33273 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -488,7 +488,6 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext extraSpecs.push_back(timePipeline(aodReader, ctx.options().get("readers"))); } - // ConcreteDataMatcher dstf{"FLP", "DISTSUBTIMEFRAME", 0xccdb}; InputSpec matcher{"dstf", "FLP", "DISTSUBTIMEFRAME", 0xccdb}; auto& dstf = std::get(matcher.matcher); // Check if any of the provided outputs is a DISTSTF From b432e078b57a2a3f1acfbcec983581deccaf8eaa Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Mon, 8 Dec 2025 09:21:45 +0000 Subject: [PATCH 3/3] Please consider the following formatting changes --- Framework/Core/src/WorkflowHelpers.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 8d273b2f33273..17f6c9eb7ddb6 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -494,7 +494,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // Check if any of the requested inputs is for a 0xccdb message bool providesDISTSTF = std::any_of(workflow.begin(), workflow.end(), [&matcher](auto const& dp) { - return std::any_of(dp.outputs.begin(), dp.outputs.end(), [&matcher](auto const& output){ + return std::any_of(dp.outputs.begin(), dp.outputs.end(), [&matcher](auto const& output) { return DataSpecUtils::match(matcher, output); }); }); @@ -503,8 +503,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // we add to the first data processor which has no inputs (apart from // enumerations / timers) the responsibility to provide the DISTSUBTIMEFRAME bool requiresDISTSUBTIMEFRAME = std::any_of(workflow.begin(), workflow.end(), - [&dstf](auto const& dp) { - return std::any_of(dp.inputs.begin(), dp.inputs.end(), [&dstf](auto const& input){ + [&dstf](auto const& dp) { + return std::any_of(dp.inputs.begin(), dp.inputs.end(), [&dstf](auto const& input) { return DataSpecUtils::match(input, dstf); }); }); @@ -522,7 +522,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } auto lifetime = dp.inputs[0].lifetime; if (lifetime == Lifetime::Enumeration && (enumCandidate == -1 || workflow[enumCandidate].name > dp.name)) { - enumCandidate = wi; + enumCandidate = wi; } if (lifetime == Lifetime::Timer && (timerCandidate == -1 || workflow[timerCandidate].name > dp.name)) { timerCandidate = wi;