Project
Loading...
Searching...
No Matches
AnalysisTask.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#ifndef FRAMEWORK_ANALYSIS_TASK_H_
13#define FRAMEWORK_ANALYSIS_TASK_H_
14
30#include <fairmq/Version.h>
31
32#include <arrow/compute/kernel.h>
33#include <arrow/table.h>
34#include <gandiva/node.h>
35#include <type_traits>
36#include <utility>
37#include <memory>
38#include <tuple> // IWYU pragma: export
39
40namespace o2::framework
41{
43std::string type_to_task_name(std::string_view const& camelCase);
44
53};
54
55template <int64_t BEGIN, int64_t END, int64_t STEP = 1>
57 static constexpr int64_t begin = BEGIN;
58 static constexpr int64_t end = END;
59 static constexpr int64_t step = STEP;
60};
61
62template <typename T>
63static constexpr bool is_enumeration_v = false;
64
65template <int64_t BEGIN, int64_t END, int64_t STEP>
66static constexpr bool is_enumeration_v<Enumeration<BEGIN, END, STEP>> = true;
67
68template <typename T>
69concept is_enumeration = is_enumeration_v<std::decay_t<T>>;
70
71template <typename T>
73
74// Helper struct which builds a DataProcessorSpec from
75// the contents of an AnalysisTask...
76namespace
77{
78// One closure type for every argument index. Written inline inside the pack
79// expansion in bindAssociatedTables() below, the predicate lambda would get a
80// fresh closure type per Args, and with it its own std::ranges::filter_view,
81// __bind_back and __perfect_forward_impl instantiation -- paid once per
82// associated table per process function. Taking the index as a runtime capture
83// instead lets every call site share a single filter_view specialisation.
84inline auto matchersForArgument(int argumentIndex)
85{
86 return std::views::filter([argumentIndex](auto const& pair) { return pair.first == argumentIndex; });
87}
88
89struct AnalysisDataProcessorBuilder {
90 template <soa::is_iterator G, soa::is_table... Args>
91 static void addGroupingCandidates(Cache& bk, Cache& bku, bool enabled)
92 {
93 []<soa::is_table... As>(framework::pack<As...>, Cache& bk, Cache& bku, bool enabled) {
94 auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType<std::decay_t<G>>());
95 ([](Cache& bk, Cache& bku, bool enabled, std::string const& key) {
96 if constexpr (soa::relatedByIndex<std::decay_t<G>, std::decay_t<As>>()) {
97 Entry e{soa::getLabelFromTypeForKey<std::decay_t<As>>(key), soa::getMatcherFromTypeForKey<std::decay_t<As>>(key), key, enabled};
100 } else {
102 }
103 }
104 }(bk, bku, enabled, key),
105 ...);
106 }(framework::pack<Args...>{}, bk, bku, enabled);
107 }
108
109 template <soa::TableRef R>
110 static void addOriginalRef(const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<InputInfo>& iInfos, int ai, uint32_t hash, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
111 {
112 auto spec = soa::tableRef2InputSpec<R>(newOrigin);
113 if (R.origin_hash != "AOD"_h) {
114 spec.metadata.emplace_back(ConfigParamSpec{"aod-origin-replaced", VariantType::Bool, true, {"\"\""}});
115 }
116 spec.metadata.emplace_back(ConfigParamSpec{std::string{"control:"} + name, VariantType::Bool, value, {"\"\""}});
117 auto matcher = DataSpecUtils::asConcreteDataMatcher(spec);
118 DataSpecUtils::updateInputList(inputs, std::move(spec));
119 auto locate = std::ranges::find_if(iInfos, [&hash](auto const& info) { return info.hash == hash; });
120 if (locate == iInfos.end()) {
121 iInfos.emplace_back(hash, std::vector{std::pair{ai, matcher}});
122 } else {
123 if (std::ranges::none_of(locate->matchers, [&ai, &matcher](auto const& match) { return (match.first == ai) && (match.second == matcher); })) {
124 locate->matchers.emplace_back(std::pair{ai, matcher});
125 }
126 }
127 }
128
130 template <soa::is_table A>
132 static void addExpression(int, uint32_t, std::vector<ExpressionInfo>&)
133 {
134 }
135
136 template <soa::is_filtered_table A>
137 static void addExpression(int ai, uint32_t hash, std::vector<ExpressionInfo>& eInfos)
138 {
139 auto fields = soa::createFieldsFromColumns(typename std::decay_t<A>::persistent_columns_t{});
140 eInfos.emplace_back(ai, hash, std::span{std::decay_t<A>::column_hashes}, std::make_shared<arrow::Schema>(fields));
141 }
142
143 template <soa::is_iterator A>
144 static void addExpression(int ai, uint32_t hash, std::vector<ExpressionInfo>& eInfos)
145 {
146 addExpression<typename std::decay_t<A>::parent_t>(ai, hash, eInfos);
147 }
148
150 template <soa::is_table A>
151 static void addInput(const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<InputInfo>& iInfos, int ai, uint32_t hash, header::DataOrigin&& newOrigin = header::DataOrigin{"AOD"})
152 {
153 [&name, &value, &inputs, &iInfos, &ai, &hash, newOrigin = std::move(newOrigin)]<size_t N, std::array<soa::TableRef, N> refs, size_t... Is>(std::index_sequence<Is...>) mutable {
154 (addOriginalRef<refs[Is]>(name, value, inputs, iInfos, ai, hash, newOrigin), ...);
155 }.template operator()<A::originals.size(), std::decay_t<A>::originals>(std::make_index_sequence<std::decay_t<A>::originals.size()>());
156 }
157
159 template <soa::is_table... As>
160 static void addInputsAndExpressions(uint32_t hash, const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, std::vector<InputInfo>& iInfos, header::DataOrigin&& newOrigin = header::DataOrigin{"AOD"})
161 {
162 int ai = -1;
163 ([&ai, &hash, &eInfos, &name, &value, &inputs, &iInfos, newOrigin]() mutable {
164 ++ai;
165 using T = std::decay_t<As>;
166 addExpression<T>(ai, hash, eInfos);
167 addInput<T>(name, value, inputs, iInfos, ai, hash, std::move(newOrigin));
168 }(),
169 ...);
170 }
171
173 template <typename T>
174 inline static bool requestInputsFromArgs(T&, std::string const&, std::vector<InputSpec>&, std::vector<ExpressionInfo>&, std::vector<InputInfo>&, header::DataOrigin)
175 {
176 return false;
177 }
178 template <is_process_configurable T>
179 inline static bool requestInputsFromArgs(T& pc, std::string const& name, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eis, std::vector<InputInfo>& iifs, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
180 {
181 AnalysisDataProcessorBuilder::inputsFromArgs(pc.process, (name + "/" + pc.name).c_str(), pc.value, inputs, eis, iifs, newOrigin);
182 return true;
183 }
184 template <typename T>
185 inline static bool requestCacheFromArgs(T&, Cache&, Cache&)
186 {
187 return false;
188 }
189 template <is_process_configurable T>
190 inline static bool requestCacheFromArgs(T& pc, Cache& bk, Cache& bku)
191 {
192 AnalysisDataProcessorBuilder::cacheFromArgs(pc.process, pc.value, bk, bku);
193 return true;
194 }
196 template <typename C, is_enumeration A>
197 static void inputsFromArgs(void (C::*)(A), const char* /*name*/, bool /*value*/, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>&, std::vector<InputInfo>&, header::DataOrigin)
198 {
199 std::vector<ConfigParamSpec> inputMetadata;
200 // FIXME: for the moment we do not support begin, end and step.
201 DataSpecUtils::updateInputList(inputs, InputSpec{"enumeration", "DPL", "ENUM", 0, Lifetime::Enumeration, inputMetadata});
202 }
203
205 template <typename C, soa::is_iterator A, soa::is_table... Args>
206 static void inputsFromArgs(void (C::*)(A, Args...), const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, std::vector<InputInfo>& iInfos, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
207 requires(std::is_lvalue_reference_v<A> && (std::is_lvalue_reference_v<Args> && ...))
208 {
209 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(A, Args...)>();
210 addInputsAndExpressions<typename std::decay_t<A>::parent_t, Args...>(hash, name, value, inputs, eInfos, iInfos, std::move(newOrigin));
211 }
212
214 template <typename C, soa::is_table... Args>
215 static void inputsFromArgs(void (C::*)(Args...), const char* name, bool value, std::vector<InputSpec>& inputs, std::vector<ExpressionInfo>& eInfos, std::vector<InputInfo>& iInfos, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
216 requires(std::is_lvalue_reference_v<Args> && ...)
217 {
218 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Args...)>();
219 addInputsAndExpressions<Args...>(hash, name, value, inputs, eInfos, iInfos, std::move(newOrigin));
220 }
221
223 template <typename C, is_enumeration A>
224 static void cacheFromArgs(void (C::*)(A), bool, Cache&, Cache&)
225 {
226 }
228 template <typename C, soa::is_iterator A, soa::is_table... Args>
229 static void cacheFromArgs(void (C::*)(A, Args...), bool value, Cache& bk, Cache& bku)
230 {
231 addGroupingCandidates<A, Args...>(bk, bku, value);
232 }
234 template <typename C, soa::is_table A, soa::is_table... Args>
235 static void cacheFromArgs(void (C::*)(A, Args...), bool, Cache&, Cache&)
236 {
237 }
238
239 template <std::ranges::input_range R>
240 static auto extractTablesFromRecord(InputRecord& record, R matchers)
241 {
242 std::vector<soa::ArrowTableRef> tables;
243 std::ranges::transform(matchers, std::back_inserter(tables), [&record](auto const& m) {
244 return record.get<TableConsumer>(m.second)->asArrowTable();
245 });
246 return tables;
247 }
248
249 template <soa::is_table T, std::ranges::input_range R>
250 static auto extractFromRecord(InputRecord& record, R matchers)
251 {
252 return T{extractTablesFromRecord(record, matchers)};
253 }
254
255 template <soa::is_iterator T, std::ranges::input_range R>
256 static auto extractFromRecord(InputRecord& record, R matchers)
257 {
258 return typename T::parent_t{extractTablesFromRecord(record, matchers)};
259 }
260
261 template <soa::is_filtered T, std::ranges::input_range R>
262 static auto extractFilteredFromRecord(InputRecord& record, R matchers, ExpressionInfo& info)
263 {
264 auto table = soa::ArrowHelpers::joinTables(extractTablesFromRecord(record, matchers));
265 expressions::updateFilterInfo(info, table.tablePtr);
267 if (info.selection == nullptr) {
268 soa::missingFilterDeclaration(info.processHash, info.argumentIndex);
269 }
270 }
271 if constexpr (soa::is_iterator<T>) {
272 return typename T::parent_t({table}, info.selection);
273 } else {
274 return T({table}, info.selection);
275 }
276 }
277
278 template <is_enumeration T, int AI, std::ranges::input_range R>
279 static auto extract(InputRecord&, R, std::vector<ExpressionInfo>&, size_t)
280 {
281 return T{};
282 }
283
284 template <soa::is_table_or_iterator T, int AI, std::ranges::input_range R>
285 static auto extract(InputRecord& record, R matchers, std::vector<ExpressionInfo>& infos, size_t phash)
286 {
287 // auto matchers = std::ranges::find_if(iInfos, [&phash](auto const& info) { return info.hash == phash; })->matchers | std::views::filter([](auto const& pair) { return pair.first == AI; });
288 if constexpr (soa::is_filtered<T>) {
289 return extractFilteredFromRecord<T>(record, matchers, *std::ranges::find_if(infos, [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }));
290 } else {
291 return extractFromRecord<T>(record, matchers);
292 }
293 }
294
295 template <std::ranges::input_range R, typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
296 static auto bindGroupingTable(InputRecord& record, R matchers, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
297 requires(!std::same_as<Grouping, void>)
298 {
299 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Grouping, Args...)>();
300 return extract<std::decay_t<Grouping>, 0>(record, matchers | matchersForArgument(0), infos, hash);
301 }
302
303 template <std::ranges::input_range R, typename C, is_table_iterator_or_enumeration Grouping, soa::is_table... Args>
304 static auto bindAssociatedTables(InputRecord& record, R matchers, void (C::*)(Grouping, Args...), std::vector<ExpressionInfo>& infos)
305 requires(!std::same_as<Grouping, void> && sizeof...(Args) > 0)
306 {
307 constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId<void (C::*)(Grouping, Args...)>();
308 return std::make_tuple(extract<std::decay_t<Args>, has_type_at_v<Args>(pack<Args...>{}) + 1>(record, matchers | matchersForArgument(has_type_at_v<Args>(pack<Args...>{}) + 1), infos, hash)...);
309 }
310
311 template <soa::is_table... As>
312 static void overwriteInternalIndices(std::tuple<As...>& dest, std::tuple<As...> const& src)
313 {
314 (std::get<As>(dest).bindInternalIndicesTo(&std::get<As>(src)), ...);
315 }
316
317 template <typename Task, is_table_iterator_or_enumeration Grouping, std::ranges::input_range R, soa::is_table... Associated>
318 static void invokeProcess(Task& task, InputRecord& inputs, R matchers, PointerReconstructor const& pointerReconstructor, void (Task::*processingFunction)(Grouping, Associated...), std::vector<ExpressionInfo>& infos, ArrowTableSlicingCache& slices, header::DataOrigin newOrigin = header::DataOrigin{"AOD"})
319 {
320 using G = std::decay_t<Grouping>;
321 auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, matchers, processingFunction, infos);
322
323 if constexpr (!is_enumeration<G>) {
324 groupingTable.setPointerReconstructor(pointerReconstructor);
325 }
326
327 constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<Task>>();
328
329 // set filtered tables for partitions with grouping
330 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& element) {
333 return true;
334 },
335 task);
336
337 if constexpr (sizeof...(Associated) == 0) {
338 // single argument to process
339 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& element) {
342 return true;
343 },
344 task);
345 if constexpr (soa::is_iterator<G>) {
346 for (auto& element : groupingTable) {
347 std::invoke(processingFunction, task, *element);
348 }
349 } else {
350 std::invoke(processingFunction, task, groupingTable);
351 }
352 } else {
353 // multiple arguments to process
354 auto associatedTables = AnalysisDataProcessorBuilder::bindAssociatedTables(inputs, matchers, processingFunction, infos);
355 // pre-bind self indices
356 std::apply(
357 [&task](auto&... t) mutable {
358 (homogeneous_apply_refs_sized<numElements>(
359 [&t](auto& p) {
361 return true;
362 },
363 task),
364 ...);
365 },
366 associatedTables);
367 std::apply([&pointerReconstructor](auto&... table) {
368 (table.setPointerReconstructor(pointerReconstructor), ...);
369 },
370 associatedTables);
371
372 auto binder = [&task, &groupingTable, &associatedTables](auto& x) mutable {
373 x.bindExternalIndices(&groupingTable, &std::get<std::decay_t<Associated>>(associatedTables)...);
374 homogeneous_apply_refs_sized<numElements>([&x](auto& t) mutable {
377 return true;
378 },
379 task);
380 };
381 groupingTable.bindExternalIndices(&std::get<std::decay_t<Associated>>(associatedTables)...);
382
383 // always pre-bind full tables to support index hierarchy
384 std::apply(
385 [&binder](auto&... x) mutable {
386 (binder(x), ...);
387 },
388 associatedTables);
389
390 // GroupedCombinations bound separately, as they should be set once for all associated tables
391 homogeneous_apply_refs_sized<numElements>([&groupingTable, &associatedTables](auto& t) {
392 analysis_task_parsers::setGroupedCombination(t, groupingTable, associatedTables);
393 return true;
394 },
395 task);
396 overwriteInternalIndices(associatedTables, associatedTables);
397 if constexpr (soa::is_iterator<G>) {
398 auto slicer = GroupSlicer(groupingTable, associatedTables, slices, newOrigin);
399 for (auto& slice : slicer) {
400 auto associatedSlices = slice.associatedTables();
401 std::apply([&pointerReconstructor](auto&... table) {
402 (table.setPointerReconstructor(pointerReconstructor), ...);
403 },
404 associatedSlices);
405
406 overwriteInternalIndices(associatedSlices, associatedTables);
407 std::apply(
408 [&binder](auto&... x) mutable {
409 (binder(x), ...);
410 },
411 associatedSlices);
412
413 // bind partitions and grouping table
414 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& x) {
416 return true;
417 },
418 task);
419
420 [](Task& task, void (Task::*processingFunction)(Grouping, Associated...), Grouping g, std::tuple<std::decay_t<Associated>...>& at) {
421 std::invoke(processingFunction, task, g, std::get<std::decay_t<Associated>>(at)...);
422 }(task, processingFunction, slice.groupingElement(), associatedSlices);
423 }
424 } else {
425 // bind partitions and grouping table
426 homogeneous_apply_refs_sized<numElements>([&groupingTable](auto& x) {
428 return true;
429 },
430 task);
431
432 [](Task& task, void (Task::*processingFunction)(Grouping, Associated...), Grouping g, std::tuple<std::decay_t<Associated>...>& at) {
433 std::invoke(processingFunction, task, g, std::get<std::decay_t<Associated>>(at)...);
434 }(task, processingFunction, groupingTable, associatedTables);
435 }
436 }
437 }
438};
439} // namespace
440
442 std::vector<std::pair<std::string, bool>> map;
443};
444
446struct TaskName {
447 TaskName(std::string name) : value{std::move(name)} {}
448 std::string value;
449};
450
451namespace
452{
453template <typename T, typename... A>
454auto getTaskNameSetProcesses(std::string& outputName, TaskName first, SetDefaultProcesses second, A... args)
455{
456 auto task = std::make_shared<T>(std::forward<A>(args)...);
457 for (auto& setting : second.map) {
459 [&](auto& element) {
460 return analysis_task_parsers::setProcessSwitch(setting, element);
461 },
462 *task.get());
463 }
464 outputName = first.value;
465 return task;
466}
467
468template <typename T, typename... A>
469auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses first, TaskName second, A... args)
470{
471 auto task = std::make_shared<T>(std::forward<A>(args)...);
472 for (auto& setting : first.map) {
474 [&](auto& element) {
475 return analysis_task_parsers::setProcessSwitch(setting, element);
476 },
477 *task.get());
478 }
479 outputName = second.value;
480 return task;
481}
482
483template <typename T, typename... A>
484auto getTaskNameSetProcesses(std::string& outputName, SetDefaultProcesses first, A... args)
485{
486 auto task = std::make_shared<T>(std::forward<A>(args)...);
487 for (auto& setting : first.map) {
489 [&](auto& element) {
490 return analysis_task_parsers::setProcessSwitch(setting, element);
491 },
492 *task.get());
493 }
494 auto type_name_str = type_name<T>();
495 outputName = type_to_task_name(type_name_str);
496 return task;
497}
498
499template <typename T, typename... A>
500auto getTaskNameSetProcesses(std::string& outputName, TaskName first, A... args)
501{
502 auto task = std::make_shared<T>(std::forward<A>(args)...);
503 outputName = first.value;
504 return task;
505}
506
507template <typename T, typename... A>
508auto getTaskNameSetProcesses(std::string& outputName, A... args)
509{
510 auto task = std::make_shared<T>(std::forward<A>(args)...);
511 auto type_name_str = type_name<T>();
512 outputName = type_to_task_name(type_name_str);
513 return task;
514}
515} // namespace
516
519template <typename T, typename... Args>
521{
522 TH1::AddDirectory(false);
523
524 std::string name_str;
525 auto task = getTaskNameSetProcesses<T>(name_str, args...);
526
527 auto suffix = ctx.options().get<std::string>("workflow-suffix");
528 if (!suffix.empty()) {
529 name_str += suffix;
530 }
531 const char* name = name_str.c_str();
532
533 auto hash = runtime_hash(name);
534
535 std::vector<OutputSpec> outputs;
536 std::vector<InputSpec> inputs;
537 std::vector<ConfigParamSpec> options;
538 std::vector<ExpressionInfo> expressionInfos;
539 std::vector<InputInfo> inputInfos;
540
541 std::string newOriginStr;
542 header::DataOrigin newOrigin{"AOD"};
543 if (ctx.options().hasOption("aod-origin-replace")) {
544 newOriginStr = ctx.options().get<std::string>("aod-origin-replace");
545 if (newOriginStr.size() > 4UL) {
546 wrongOriginReplacement(newOriginStr);
547 }
548 }
549 if (!newOriginStr.empty()) {
550 newOrigin.runtimeInit(newOriginStr.c_str(), std::min(newOriginStr.size(), 4UL));
551 }
552
553 constexpr const int numElements = homogeneous_apply_refs_size<false, std::decay_t<T>>();
554
556 homogeneous_apply_refs_sized<numElements>([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get());
558 homogeneous_apply_refs_sized<numElements>([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get());
559
561 if constexpr (requires { &T::process; }) {
562 AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos, inputInfos, newOrigin);
563 }
564 homogeneous_apply_refs_sized<numElements>(
565 [name = name_str, &expressionInfos, &inputs, &inputInfos, &newOrigin](auto& x) mutable {
566 // this pushes (argumentIndex, processHash, schemaPtr, nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators
567 return AnalysisDataProcessorBuilder::requestInputsFromArgs(x, name, inputs, expressionInfos, inputInfos, newOrigin);
568 },
569 *task.get());
570
571 // request base tables for spawnable extended tables and indices to be built
572 // this checks for duplications
573 homogeneous_apply_refs_sized<numElements>([&inputs, &newOrigin](auto& element) {
574 return analysis_task_parsers::requestInputs(inputs, element, newOrigin);
575 },
576 *task.get());
577
578 // no static way to check if the task defines any processing, we can only make sure it subscribes to at least something
579 if (inputs.empty() == true) {
580 LOG(warn) << "Task " << name_str << " has no inputs";
581 }
582
583 // update OutputSpecs in output declarations
584 homogeneous_apply_refs_sized<numElements>([&newOrigin](auto& element) { return analysis_task_parsers::updateOutputSpec(element, newOrigin); }, *task.get());
585
586 // Auto-register default ccdb: path options from subscribed timestamped-table inputs.
587 // This allows tasks to accept --ccdb:fXxx overrides without requiring an explicit
588 // ConfigurableCCDBPath<> member for every column in the subscribed table.
589 for (auto& input : inputs) {
590 for (auto& meta : input.metadata) {
591 if (meta.name.starts_with("ccdb:") && meta.name != "ccdb:") {
593 }
594 }
595 }
596
597 // append outputs
598 homogeneous_apply_refs_sized<numElements>([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get());
599
600 // request services
601 auto requiredServices = CommonServices::defaultServices();
602 auto arrowServices = CommonServices::arrowServices();
603 requiredServices.insert(requiredServices.end(), arrowServices.begin(), arrowServices.end());
604 homogeneous_apply_refs_sized<numElements>([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get());
605
606 // replace origins in Preslice declarations
607 homogeneous_apply_refs_sized<numElements>([&newOrigin](auto& element) { return analysis_task_parsers::replaceOrigin(element, newOrigin); }, *task.get());
608
609 auto algo = AlgorithmSpec::InitCallback{
610 [task = task, expressionInfos, inputInfos, newOrigin, newOriginStr](InitContext& ic) mutable {
611 Cache bindingsKeys;
612 Cache bindingsKeysUnsorted;
613 // add preslice declarations to slicing cache definition
614 homogeneous_apply_refs_sized<numElements>([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get());
615
616 homogeneous_apply_refs_sized<numElements>([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get());
617 homogeneous_apply_refs_sized<numElements>([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get());
618
619 auto& callbacks = ic.services().get<CallbackService>();
620 auto eoscb = [task](EndOfStreamContext& eosContext) {
621 homogeneous_apply_refs_sized<numElements>([&eosContext](auto& element) {
624 return true; },
625 *task.get());
626 eosContext.services().get<ControlService>().readyToQuit(QuitRequest::Me);
627 };
628
629 callbacks.set<CallbackService::Id::EndOfStream>(eoscb);
630
632 if constexpr (requires { task->init(ic); }) {
633 task->init(ic);
634 }
635
637 homogeneous_apply_refs_sized<numElements>(
638 [&ic](auto& element) -> bool { return analysis_task_parsers::updatePlaceholders(ic, element); },
639 *task.get());
641 homogeneous_apply_refs_sized<numElements>([&expressionInfos](auto& element) {
643 },
644 *task.get());
645
647 if constexpr (requires { &T::process; }) {
648 AnalysisDataProcessorBuilder::cacheFromArgs(&T::process, true, bindingsKeys, bindingsKeysUnsorted);
649 }
650 homogeneous_apply_refs_sized<numElements>(
651 [&bindingsKeys, &bindingsKeysUnsorted](auto& x) {
652 return AnalysisDataProcessorBuilder::requestCacheFromArgs(x, bindingsKeys, bindingsKeysUnsorted);
653 },
654 *task.get());
655
657 std::ranges::transform(bindingsKeys, bindingsKeys.begin(), [&newOrigin](Entry& entry) {
658 if ((entry.matcher.origin == header::DataOrigin{"AOD"}) && (newOrigin != header::DataOrigin{"AOD"})) {
659 entry.matcher = replaceOrigin(entry.matcher, newOrigin);
660 }
661 return entry;
662 });
663 std::ranges::transform(bindingsKeysUnsorted, bindingsKeysUnsorted.begin(), [&newOrigin](Entry& entry) {
664 if ((entry.matcher.origin == header::DataOrigin{"AOD"}) && (newOrigin != header::DataOrigin{"AOD"})) {
665 entry.matcher = replaceOrigin(entry.matcher, newOrigin);
666 }
667 return entry;
668 });
669
670 ic.services().get<ArrowTableSlicingCacheDef>().setCaches(std::move(bindingsKeys));
671 ic.services().get<ArrowTableSlicingCacheDef>().setCachesUnsorted(std::move(bindingsKeysUnsorted));
672 ic.services().get<ArrowTableSlicingCacheDef>().setOrigin(newOrigin);
673 PointerReconstructor pointerReconstructor(nullptr);
674 bool hasCCDBTables = !ic.services().get<DanglingEdgesContext>().requestedTIMs.empty();
675
676 return [task, expressionInfos, inputInfos, newOrigin, hasCCDBTables, pointerReconstructor](ProcessingContext& pc) mutable {
677 if (hasCCDBTables && (!pointerReconstructor)) {
678 auto& proxy = pc.services().get<FairMQDeviceProxy>();
679 auto& spec = pc.services().get<DanglingEdgesContext>().requestedTIMs.front();
680 pointerReconstructor = proxy.getShmPointerReconstructor(spec, 0);
681 }
682 // load the ccdb object from their cache
683 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get());
684 // reset partitions once per dataframe
685 homogeneous_apply_refs_sized<numElements>([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get());
686 // reset selections for the next dataframe
687 std::ranges::for_each(expressionInfos, [](auto& info) { info.resetSelection = true; });
688 // reset pre-slice for the next dataframe
689 auto& slices = pc.services().get<ArrowTableSlicingCache>();
690 homogeneous_apply_refs_sized<numElements>([&slices](auto& element) {
692 },
693 *(task.get()));
694 // initialize local caches
695 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get()));
696 // prepare outputs
697 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get());
698 // execute run()
699 if constexpr (requires { task->run(pc); }) {
700 task->run(pc);
701 }
702 // execute process()
703 if constexpr (requires { &T::process; }) {
704 auto loc = std::ranges::find_if(inputInfos, [](auto const& info) { return info.hash == o2::framework::TypeIdHelpers::uniqueId<decltype(&T::process)>(); });
705 auto matchers = loc == inputInfos.end() ? std::vector<std::pair<int, ConcreteDataMatcher>>{} : loc->matchers;
706 AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), matchers, pointerReconstructor, &T::process, expressionInfos, slices, newOrigin);
707 }
708 // execute optional process()
709 homogeneous_apply_refs_sized<numElements>(
710 [&pc, &expressionInfos, &task, &slices, &inputInfos, &newOrigin, &pointerReconstructor](auto& x) {
711 if constexpr (is_process_configurable<decltype(x)>) {
712 if (x.value == true) {
713 auto loc = std::ranges::find_if(inputInfos, [](auto const& info) { return info.hash == o2::framework::TypeIdHelpers::uniqueId<decltype(x.process)>(); });
714 auto matchers = loc == inputInfos.end() ? std::vector<std::pair<int, ConcreteDataMatcher>>{} : loc->matchers;
715 AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), matchers, pointerReconstructor, x.process, expressionInfos, slices, newOrigin);
716 return true;
717 }
718 return false;
719 }
720 return false;
721 },
722 *task.get());
723 // prepare delayed outputs
724 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get());
725 // finalize outputs
726 homogeneous_apply_refs_sized<numElements>([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get());
727 };
728 }};
729
730 return {
731 name,
732 inputs,
733 outputs,
734 algo,
735 options,
736 requiredServices};
737}
738
739} // namespace o2::framework
740#endif // FRAMEWORK_ANALYSISTASK_H_
std::vector< framework::ConcreteDataMatcher > matchers
uint32_t hash
atype::type element
std::vector< std::shared_ptr< arrow::Field > > fields
int32_t i
constexpr uint32_t runtime_hash(char const *str)
StringRef key
Definition A.h:16
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
GLenum src
Definition glcorearb.h:1767
GLuint entry
Definition glcorearb.h:5735
GLuint GLuint end
Definition glcorearb.h:469
GLuint const GLchar * name
Definition glcorearb.h:781
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition glcorearb.h:2513
GLint first
Definition glcorearb.h:399
GLsizei const GLfloat * value
Definition glcorearb.h:819
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLboolean GLboolean g
Definition glcorearb.h:1233
bool prepareService(InitContext &, T &)
void setGroupedCombination(C &, TG &, Ts &...)
Combinations handling.
bool initializeCache(ProcessingContext &, T &)
Cache handling.
bool replaceOrigin(T &, header::DataOrigin const &)
Preslice handling.
bool requestInputs(std::vector< InputSpec > &, T &, header::DataOrigin)
bool prepareDelayedOutput(ProcessingContext &, T &)
bool prepareOption(InitContext &, O &)
bool finalizeOutput(ProcessingContext &, T &)
bool registerCache(T &, Cache &, Cache &)
bool postRunOutput(EndOfStreamContext &, T &)
bool createExpressionTrees(std::vector< ExpressionInfo > &, T &)
bool prepareOutput(ProcessingContext &, T &)
bool appendOption(std::vector< ConfigParamSpec > &, O &)
Options handling.
bool updateSliceInfo(T &, ArrowTableSlicingCache &)
bool appendCondition(std::vector< InputSpec > &, C &)
Conditions handling.
bool postRunService(EndOfStreamContext &, T &)
bool addService(std::vector< ServiceSpec > &, T &)
Service handling.
bool updatePlaceholders(InitContext &, T &)
Filter handling.
constexpr bool appendOutput(std::vector< OutputSpec > &, T &, uint32_t)
Outputs handling.
bool newDataframeCondition(InputRecord &, C &)
bool updateOutputSpec(T &, header::DataOrigin)
void updateFilterInfo(ExpressionInfo &info, std::shared_ptr< arrow::Table > &table)
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
void updatePairList(Cache &list, Entry &entry)
std::function< std::byte *(fair::mq::shmem::MetaHeader &&)> PointerReconstructor
Definition ASoA.h:52
DataProcessorSpec adaptAnalysisTask(ConfigContext const &ctx, Args &&... args)
std::vector< Entry > Cache
std::string type_to_task_name(std::string_view const &camelCase)
Convert a CamelCase task struct name to snake-case task name.
@ Me
Only quit this data processor.
constexpr auto homogeneous_apply_refs(L l, T &&object)
ConfigParamSpec replaceOrigin(ConfigParamSpec &source, std::string const &originStr)
void wrongOriginReplacement(std::string_view replacement)
std::string cutString(std::string &&str)
Definition ASoA.cxx:322
Descriptor< gSizeDataOriginString > DataOrigin
Definition DataHeader.h:553
auto createFieldsFromColumns(framework::pack< C... >)
Definition ASoA.h:77
void missingFilterDeclaration(int hash, int ai)
Definition ASoA.cxx:33
std::function< ProcessCallback(InitContext &)> InitCallback
static std::vector< ServiceSpec > defaultServices(std::string extraPlugins="", int numWorkers=0)
Split a string into a vector of strings using : as a separator.
static std::vector< ServiceSpec > arrowServices()
static void addOptionIfMissing(std::vector< ConfigParamSpec > &specs, const ConfigParamSpec &spec)
static ConcreteDataMatcher asConcreteDataMatcher(InputSpec const &input)
static void updateInputList(std::vector< InputSpec > &list, InputSpec &&input)
Updates list of InputSpecs by merging metadata.
static constexpr int64_t step
static constexpr int64_t begin
std::vector< std::pair< std::string, bool > > map
Struct to differentiate task names from possible task string arguments.
TaskName(std::string name)
static constexpr uint32_t uniqueId()
static o2::soa::ArrowTableRef joinTables(std::vector< std::shared_ptr< arrow::Table > > &&tables)
Definition ASoA.cxx:149
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"