diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index a01d14b6632a9..9ac78c0933600 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -358,14 +358,14 @@ template constexpr auto tableRef2InputSpec() { std::vector metadata; - auto m = getInputMetadata>::metadata>(); - metadata.insert(metadata.end(), m.begin(), m.end()); - auto ccdbMetadata = getCCDBMetadata>::metadata>(); - metadata.insert(metadata.end(), ccdbMetadata.begin(), ccdbMetadata.end()); - auto p = getExpressionMetadata>::metadata>(); - metadata.insert(metadata.end(), p.begin(), p.end()); - auto idx = getIndexMetadata>::metadata>(); - metadata.insert(metadata.end(), idx.begin(), idx.end()); + auto sources = getInputMetadata>::metadata>(); + metadata.insert(metadata.end(), sources.begin(), sources.end()); + auto ccdbURLs = getCCDBMetadata>::metadata>(); + metadata.insert(metadata.end(), ccdbURLs.begin(), ccdbURLs.end()); + auto expressions = getExpressionMetadata>::metadata>(); + metadata.insert(metadata.end(), expressions.begin(), expressions.end()); + auto indices = getIndexMetadata>::metadata>(); + metadata.insert(metadata.end(), indices.begin(), indices.end()); if constexpr (!soa::with_ccdb_urls>::metadata>) { metadata.emplace_back(framework::ConfigParamSpec{"schema", framework::VariantType::String, framework::serializeSchema(o2::aod::MetadataTrait>::metadata::getSchema()), {"\"\""}}); } @@ -382,11 +382,22 @@ constexpr auto tableRef2InputSpec() template constexpr auto tableRef2OutputSpec() { + std::vector metadata; + using md = typename o2::aod::MetadataTrait>::metadata; + if constexpr (soa::with_ccdb_urls) { + metadata.emplace_back("ccdb:", framework::VariantType::Bool, true, framework::ConfigParamSpec::HelpString{"\"\""}); + } else if constexpr (soa::with_expression_pack) { + metadata.emplace_back("projectors", framework::VariantType::Bool, true, framework::ConfigParamSpec::HelpString{"\"\""}); + } else if constexpr (soa::with_index_pack) { + metadata.emplace_back("index-records", framework::VariantType::Bool, true, framework::ConfigParamSpec::HelpString{"\"\""}); + } return framework::OutputSpec{ framework::OutputLabel{o2::aod::label()}, o2::aod::origin(), o2::aod::description(o2::aod::signature()), - R.version}; + R.version, + framework::Lifetime::Timeframe, + metadata}; } template @@ -504,14 +515,14 @@ struct OutputForTable { using table_t = decltype(typeWithRef()); using metadata = aod::MetadataTrait>::metadata; - static OutputSpec const spec() + static constexpr auto spec() { - return OutputSpec{OutputLabel{aod::label()}, o2::aod::origin(), o2::aod::description(o2::aod::signature()), table_t::ref.version}; + return soa::tableRef2OutputSpec(); } - static OutputRef ref() + static constexpr auto ref() { - return OutputRef{aod::label(), table_t::ref.version}; + return soa::tableRef2OutputRef(); } }; diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 121ce7f4b4a77..a411bd6eefb56 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -183,20 +183,20 @@ bool newDataframeCondition(InputRecord& record, C& conditionGroup) /// Outputs handling template -bool appendOutput(std::vector&, T&, uint32_t) +constexpr bool appendOutput(std::vector&, T&, uint32_t) { return false; } template -bool appendOutput(std::vector& outputs, T&, uint32_t) +constexpr bool appendOutput(std::vector& outputs, T&, uint32_t) { - outputs.emplace_back(OutputForTable::spec()); + outputs.emplace_back(soa::tableRef2OutputSpec()); return true; } template -bool appendOutput(std::vector& outputs, T& producesGroup, uint32_t hash) +constexpr bool appendOutput(std::vector& outputs, T& producesGroup, uint32_t hash) { homogeneous_apply_refs([&outputs, hash](auto& produces) { return appendOutput(outputs, produces, hash); }, producesGroup); return true; @@ -261,7 +261,7 @@ bool prepareOutput(ProcessingContext&, T&) template bool prepareOutput(ProcessingContext& context, T& produces) { - produces.resetCursor(std::move(context.outputs().make(OutputForTable::ref()))); + produces.resetCursor(std::move(context.outputs().make(soa::tableRef2OutputRef()))); return true; } diff --git a/Framework/Core/include/Framework/DanglingEdgesContext.h b/Framework/Core/include/Framework/DanglingEdgesContext.h index 90a88974db038..c5f54297ee746 100644 --- a/Framework/Core/include/Framework/DanglingEdgesContext.h +++ b/Framework/Core/include/Framework/DanglingEdgesContext.h @@ -33,15 +33,24 @@ struct OutputObjectInfo { // been requested and for which we will need to inject // some source device. struct DanglingEdgesContext { + // generic AOD tables std::vector requestedAODs; std::vector providedAODs; + // extension tables std::vector requestedDYNs; std::vector providedDYNs; + // index tables std::vector requestedIDXs; + std::vector providedIDXs; + // ccdb tables std::vector providedTIMs; std::vector requestedTIMs; + // output objects std::vector providedOutputObjHist; + // inputs for the extension spawner std::vector spawnerInputs; + // inputs for the index builder + std::vector builderInputs; // These are the timestamped tables which are required to // inject the the CCDB objecs. diff --git a/Framework/Core/include/Framework/DataSpecViews.h b/Framework/Core/include/Framework/DataSpecViews.h index b38866d8aa6fd..63da68ab5d53e 100644 --- a/Framework/Core/include/Framework/DataSpecViews.h +++ b/Framework/Core/include/Framework/DataSpecViews.h @@ -14,8 +14,31 @@ #include "Framework/DataSpecUtils.h" #include +namespace o2::framework::checks +{ +static auto has_params_with_name(std::string&& name) +{ + return [name](ConfigParamSpec const& p) { return p.name.compare(name) == 0; }; +} + +static auto has_params_with_name_starting(std::string&& name) +{ + return [name](ConfigParamSpec const& p) { return p.name.starts_with(name); }; +} +} // namespace o2::framework::checks + namespace o2::framework::views { +static auto filter_with_params_by_name(std::string&& name) +{ + return std::views::filter([name = std::move(name)](auto const& spec) mutable { return std::ranges::any_of(spec.metadata, checks::has_params_with_name(std::move(name))); }); +} + +static auto filter_with_params_by_name_starting(std::string&& name) +{ + return std::views::filter([name = std::move(name)](auto const& spec) mutable { return std::ranges::any_of(spec.metadata, checks::has_params_with_name_starting(std::move(name))); }); +} + static auto partial_match_filter(auto what) { return std::views::filter([what](auto const& t) -> bool { return DataSpecUtils::partialMatch(t, what); }); diff --git a/Framework/Core/src/AnalysisSupportHelpers.cxx b/Framework/Core/src/AnalysisSupportHelpers.cxx index 7453751315626..21f312cd576e0 100644 --- a/Framework/Core/src/AnalysisSupportHelpers.cxx +++ b/Framework/Core/src/AnalysisSupportHelpers.cxx @@ -175,9 +175,14 @@ void AnalysisSupportHelpers::addMissingOutputsToBuilder(std::vector c // FIXME: until we have a single list of pairs additionalInputs | views::partial_match_filter(AODOrigins) | + std::ranges::views::filter([](InputSpec const& input) { + return std::ranges::none_of(input.metadata, [](ConfigParamSpec const& p) { return (p.name.compare("projectors") == 0) || (p.name.compare("index-records") == 0); }); + }) | sinks::update_input_list{requestedAODs}; // update requestedAODs additionalInputs | - views::partial_match_filter(header::DataOrigin{"DYN"}) | + std::ranges::views::filter([](InputSpec const& input) { + return std::ranges::any_of(input.metadata, [](ConfigParamSpec const& p) { return p.name.compare("projectors") == 0; }); + }) | sinks::update_input_list{requestedDYNs}; // update requestedDYNs } diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index c5cc021a53478..1819307e26806 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -50,7 +50,6 @@ O2_DECLARE_DYNAMIC_LOG(rate_limiting); namespace o2::framework { - class EndOfStreamContext; class ProcessingContext; @@ -578,45 +577,80 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() } }, .adjustTopology = [](WorkflowSpecNode& node, ConfigContext const& ctx) { auto& workflow = node.specs; - auto spawner = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-spawner"); }); - auto analysisCCDB = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-ccdb"); }); - auto builder = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-index-builder"); }); - auto writer = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-writer"); }); auto& dec = ctx.services().get(); dec.requestedAODs.clear(); dec.requestedDYNs.clear(); - dec.providedDYNs.clear(); - dec.providedTIMs.clear(); - dec.requestedTIMs.clear(); auto inputSpecLessThan = [](InputSpec const& lhs, InputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; auto outputSpecLessThan = [](OutputSpec const& lhs, OutputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; + auto builder = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-index-builder"); }); if (builder != workflow.end()) { // collect currently requested IDXs dec.requestedIDXs.clear(); + dec.providedIDXs.clear(); for (auto& d : workflow | views::exclude_by_name(builder->name)) { d.inputs | - views::partial_match_filter(header::DataOrigin{"IDX"}) | + views::filter_with_params_by_name("index-records") | sinks::update_input_list{dec.requestedIDXs}; + d.outputs | + views::filter_with_params_by_name("index-records") | + sinks::update_output_list{dec.providedIDXs}; } + std::ranges::sort(dec.requestedIDXs, inputSpecLessThan); + std::ranges::sort(dec.providedIDXs, outputSpecLessThan); + dec.builderInputs.clear(); + dec.requestedIDXs | + views::filter_not_matching(dec.providedIDXs) | + sinks::append_to{dec.builderInputs}; // recreate inputs and outputs builder->inputs.clear(); builder->outputs.clear(); + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.builderInputs, dec.requestedAODs, dec.requestedDYNs, *builder); + if (!builder->inputs.empty()) { + // load real AlgorithmSpec before deployment + builder->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "IndexTableBuilder", ctx); + } + } + + auto analysisCCDB = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-ccdb"); }); + if (analysisCCDB != workflow.end()) { + dec.requestedTIMs.clear(); + dec.providedTIMs.clear(); + for (auto& d : workflow | views::exclude_by_name(analysisCCDB->name)) { + d.inputs | + views::filter_with_params_by_name_starting("ccdb:") | + sinks::update_input_list{dec.requestedTIMs}; + d.outputs | + views::filter_with_params_by_name_starting("ccdb:") | + sinks::append_to{dec.providedTIMs}; + } + std::ranges::sort(dec.requestedTIMs, inputSpecLessThan); + std::ranges::sort(dec.providedTIMs, outputSpecLessThan); + // Use ranges::to> in C++23... + dec.analysisCCDBInputs.clear(); + dec.requestedTIMs | + views::filter_not_matching(dec.providedTIMs) | + sinks::append_to{dec.analysisCCDBInputs}; + // recreate inputs and outputs + analysisCCDB->outputs.clear(); + analysisCCDB->inputs.clear(); + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.analysisCCDBInputs, dec.requestedAODs, dec.requestedDYNs, *analysisCCDB); // load real AlgorithmSpec before deployment - builder->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "IndexTableBuilder", ctx); - AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.requestedIDXs, dec.requestedAODs, dec.requestedDYNs, *builder); + analysisCCDB->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "AnalysisCCDBFetcherPlugin", ctx); } + auto spawner = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-spawner"); }); if (spawner != workflow.end()) { + dec.providedDYNs.clear(); // collect currently requested DYNs for (auto& d : workflow | views::exclude_by_name(spawner->name)) { d.inputs | - views::partial_match_filter(header::DataOrigin{"DYN"}) | + views::filter_with_params_by_name("projectors") | sinks::update_input_list{dec.requestedDYNs}; d.outputs | - views::partial_match_filter(header::DataOrigin{"DYN"}) | + views::filter_with_params_by_name("projectors") | sinks::append_to{dec.providedDYNs}; } std::ranges::sort(dec.requestedDYNs, inputSpecLessThan); @@ -628,32 +662,14 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // recreate inputs and outputs spawner->outputs.clear(); spawner->inputs.clear(); - - // load real AlgorithmSpec before deployment - spawner->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "ExtendedTableSpawner", ctx); AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, *spawner); - } - - if (analysisCCDB != workflow.end()) { - for (auto& d : workflow | views::exclude_by_name(analysisCCDB->name)) { - d.inputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::update_input_list{dec.requestedTIMs}; - d.outputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::append_to{dec.providedTIMs}; + if (!spawner->inputs.empty()) { + // load real AlgorithmSpec before deployment + spawner->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "ExtendedTableSpawner", ctx); } - std::ranges::sort(dec.requestedTIMs, inputSpecLessThan); - std::ranges::sort(dec.providedTIMs, outputSpecLessThan); - // Use ranges::to> in C++23... - dec.analysisCCDBInputs.clear(); - dec.requestedTIMs | views::filter_not_matching(dec.providedTIMs) | sinks::append_to{dec.analysisCCDBInputs}; - - // recreate inputs and outputs - analysisCCDB->outputs.clear(); - analysisCCDB->inputs.clear(); - // load real AlgorithmSpec before deployment - // FIXME how can I make the lookup depend on DYN tables as well?? - analysisCCDB->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "AnalysisCCDBFetcherPlugin", ctx); - AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.analysisCCDBInputs, dec.requestedAODs, dec.requestedDYNs, *analysisCCDB); } + auto writer = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-writer"); }); if (writer != workflow.end()) { workflow.erase(writer); } diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index abe566e239618..03ad3bd4b8829 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -234,6 +234,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext ctx.services().registerService(ServiceRegistryHelpers::handleForService(new DanglingEdgesContext)); auto& dec = ctx.services().get(); + std::vector DYNs; + std::vector requestedCCDBs; std::vector providedCCDBs; @@ -279,6 +281,24 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext bool hasConditionOption = false; for (size_t ii = 0; ii < processor.inputs.size(); ++ii) { auto& input = processor.inputs[ii]; + bool hasProjectors = false; + bool hasIndexRecords = false; + bool hasCCDBURLs = false; + // all three options are exclusive + for (auto const& p : input.metadata) { + if (p.name.compare("projectors") == 0) { + hasProjectors = true; + break; + } + if (p.name.compare("index-records") == 0) { + hasIndexRecords = true; + break; + } + if (p.name.starts_with("ccdb:")) { + hasCCDBURLs = true; + break; + } + } switch (input.lifetime) { case Lifetime::Timer: { auto concrete = DataSpecUtils::asConcreteDataMatcher(input); @@ -318,29 +338,49 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext case Lifetime::Optional: break; } - if (DataSpecUtils::partialMatch(input, AODOrigins)) { - DataSpecUtils::updateInputList(dec.requestedAODs, InputSpec{input}); - } - if (DataSpecUtils::partialMatch(input, header::DataOrigin{"DYN"})) { + if (hasProjectors) { DataSpecUtils::updateInputList(dec.requestedDYNs, InputSpec{input}); - } - if (DataSpecUtils::partialMatch(input, header::DataOrigin{"IDX"})) { + } else if (hasIndexRecords) { DataSpecUtils::updateInputList(dec.requestedIDXs, InputSpec{input}); - } - if (DataSpecUtils::partialMatch(input, header::DataOrigin{"ATIM"})) { + } else if (hasCCDBURLs) { DataSpecUtils::updateInputList(dec.requestedTIMs, InputSpec{input}); + } else if (DataSpecUtils::partialMatch(input, AODOrigins)) { + DataSpecUtils::updateInputList(dec.requestedAODs, InputSpec{input}); } } std::ranges::stable_sort(timer.outputs, [](OutputSpec const& a, OutputSpec const& b) { return *DataSpecUtils::getOptionalSubSpec(a) < *DataSpecUtils::getOptionalSubSpec(b); }); for (auto& output : processor.outputs) { - if (DataSpecUtils::partialMatch(output, AODOrigins)) { - dec.providedAODs.emplace_back(output); - } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"DYN"})) { + bool hasProjectors = false; + bool hasIndexRecords = false; + bool hasCCDBURLs = false; + // all three options are exclusive + for (auto const& p : output.metadata) { + if (p.name.compare("projectors") == 0) { + hasProjectors = true; + break; + } + if (p.name.compare("index-records") == 0) { + hasIndexRecords = true; + break; + } + if (p.name.starts_with("ccdb:")) { + hasCCDBURLs = true; + break; + } + } + if (DataSpecUtils::partialMatch(output, header::DataOrigin{"DYN"})) { + DYNs.emplace_back(output); + } + if (hasProjectors) { dec.providedDYNs.emplace_back(output); - } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"ATIM"})) { + } else if (hasCCDBURLs) { dec.providedTIMs.emplace_back(output); + } else if (hasIndexRecords) { + dec.providedIDXs.emplace_back(output); + } else if (DataSpecUtils::partialMatch(output, AODOrigins)) { + dec.providedAODs.emplace_back(output); } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"ATSK"})) { dec.providedOutputObjHist.emplace_back(output); auto it = std::ranges::find_if(dec.outObjHistMap, [&](auto&& x) { return x.id == hash; }); @@ -350,6 +390,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext it->bindings.push_back(output.binding.value); } } + if (output.lifetime == Lifetime::Condition) { providedCCDBs.push_back(output); } @@ -358,10 +399,6 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext auto inputSpecLessThan = [](InputSpec const& lhs, InputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; auto outputSpecLessThan = [](OutputSpec const& lhs, OutputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; - std::ranges::sort(dec.requestedDYNs, inputSpecLessThan); - std::ranges::sort(dec.requestedTIMs, inputSpecLessThan); - std::ranges::sort(dec.providedDYNs, outputSpecLessThan); - std::ranges::sort(dec.providedTIMs, outputSpecLessThan); DataProcessorSpec indexBuilder{ "internal-dpl-aod-index-builder", @@ -369,14 +406,18 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext {}, AlgorithmSpec::dummyAlgorithm(), // real algorithm will be set in adjustTopology {}}; - AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.requestedIDXs, dec.requestedAODs, dec.requestedDYNs, indexBuilder); + std::ranges::sort(dec.requestedIDXs, inputSpecLessThan); + std::ranges::sort(dec.providedIDXs, outputSpecLessThan); + dec.requestedIDXs | views::filter_not_matching(dec.providedIDXs) | sinks::append_to{dec.builderInputs}; + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.builderInputs, dec.requestedAODs, dec.requestedDYNs, indexBuilder); + std::ranges::sort(dec.requestedTIMs, inputSpecLessThan); + std::ranges::sort(dec.providedTIMs, outputSpecLessThan); dec.requestedTIMs | views::filter_not_matching(dec.providedTIMs) | sinks::append_to{dec.analysisCCDBInputs}; - DeploymentMode deploymentMode = DefaultsHelpers::deploymentMode(); - if (deploymentMode != DeploymentMode::OnlineDDS && deploymentMode != DeploymentMode::OnlineECS) { - AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.analysisCCDBInputs, dec.requestedAODs, dec.requestedTIMs, analysisCCDBBackend); - } + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.analysisCCDBInputs, dec.requestedAODs, dec.requestedDYNs, analysisCCDBBackend); + std::ranges::sort(dec.requestedDYNs, inputSpecLessThan); + std::ranges::sort(dec.providedDYNs, outputSpecLessThan); dec.requestedDYNs | views::filter_not_matching(dec.providedDYNs) | sinks::append_to{dec.spawnerInputs}; DataProcessorSpec aodSpawner{ @@ -386,6 +427,9 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext AlgorithmSpec::dummyAlgorithm(), // real algorithm will be set in adjustTopology {}}; AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, aodSpawner); + + std::ranges::sort(dec.requestedAODs, inputSpecLessThan); + std::ranges::sort(dec.providedAODs, outputSpecLessThan); AnalysisSupportHelpers::addMissingOutputsToReader(dec.providedAODs, dec.requestedAODs, aodReader); std::ranges::sort(requestedCCDBs, inputSpecLessThan); @@ -409,6 +453,14 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext extraSpecs.push_back(indexBuilder); } + // add the Analysys CCDB backend which reads CCDB objects using a provided table + DeploymentMode deploymentMode = DefaultsHelpers::deploymentMode(); + if (deploymentMode != DeploymentMode::OnlineDDS && deploymentMode != DeploymentMode::OnlineECS) { + if (analysisCCDBBackend.outputs.empty() == false) { + extraSpecs.push_back(analysisCCDBBackend); + } + } + // add the reader if (aodReader.outputs.empty() == false) { auto mctracks2aod = std::ranges::find_if(workflow, [](auto const& x) { return x.name == "mctracks-to-aod"; }); @@ -511,11 +563,6 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext DataSpecUtils::updateOutputList(workflow[enumCandidate].outputs, OutputSpec{{"ccdb-diststf"}, dstf, Lifetime::Timeframe}); } - // add the Analysys CCDB backend which reads CCDB objects using a provided table - if (analysisCCDBBackend.outputs.empty() == false) { - extraSpecs.push_back(analysisCCDBBackend); - } - // add the timer if (timer.outputs.empty() == false) { extraSpecs.push_back(timer); diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 815fce47544d0..a919cd863df57 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1678,15 +1678,15 @@ int runStateMachine(DataProcessorSpecs const& workflow, continue; } // ignore devices with no metadata in inputs - auto hasMetadata = std::any_of(device.inputs.begin(), device.inputs.end(), [](InputSpec const& spec) { + auto hasMetadata = std::ranges::any_of(device.inputs, [](InputSpec const& spec) { return spec.metadata.empty() == false; }); if (!hasMetadata) { continue; } // ignore devices with no control options - auto hasControls = std::any_of(device.inputs.begin(), device.inputs.end(), [](InputSpec const& spec) { - return std::any_of(spec.metadata.begin(), spec.metadata.end(), [](ConfigParamSpec const& param) { + auto hasControls = std::ranges::any_of(device.inputs, [](InputSpec const& spec) { + return std::ranges::any_of(spec.metadata, [](ConfigParamSpec const& param) { return param.type == VariantType::Bool && param.name.find("control:") != std::string::npos; }); });