Project
Loading...
Searching...
No Matches
Plugin.cxx
Go to the documentation of this file.
1// Copyright 2019-2024 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#include "Framework/Plugins.h"
15#include "Framework/Logger.h"
17#include "Framework/Signpost.h"
20#include <TBufferFile.h>
21#include <TDirectory.h>
22#include <TTree.h>
23#include <TDirectoryFile.h>
24#include <TClass.h>
25#include <arrow/dataset/file_base.h>
26#include <arrow/filesystem/filesystem.h>
27#include <cstddef>
28#include <memory>
29#include <string_view>
30
32namespace o2::framework
33{
34auto lookForAodFile = [](ConfigParamRegistry& registry, int argc, char** argv) -> bool {
35 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
36 if (registry.hasOption("aod-file") && registry.isSet("aod-file")) {
37 for (size_t i = 0; i < argc; i++) {
38 std::string_view arg = argv[i];
39 if (arg.starts_with("--aod-metadata-")) {
40 return false;
41 }
42 }
43 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInAODCapability", "Metadata not found in arguments. Checking in AOD file.");
44 return true;
45 }
46 return false;
47};
48
49auto lookForCommandLineOptions = [](ConfigParamRegistry& registry, int argc, char** argv) -> bool {
50 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
51 for (size_t i = 0; i < argc; i++) {
52 std::string_view arg = argv[i];
53 if (arg.starts_with("--aod-metadata-")) {
54 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInCommandLineCapability", "Metadata found in arguments. Populating from them.");
55 return true;
56 }
57 }
58 return false;
59};
60
61auto lookForCommandLineAODOptions = [](ConfigParamRegistry& registry, int argc, char** argv) -> bool {
62 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
63 // If one of the options for aod-writer is specified, we should allow configuring compression.
64 for (size_t i = 0; i < argc; i++) {
65 std::string_view arg = argv[i];
66 if (arg.starts_with("--aod-writer-")) {
67 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLineCapability", "AOD options found in arguments. Populating from them.");
68 return true;
69 }
70 if (arg.starts_with("--aod-parent-")) {
71 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLineCapability", "AOD options found in arguments. Populating from them.");
72 return true;
73 }
74 if (arg.starts_with("--aod-origin-")) {
75 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLineCapability", "AOD options found in arguments. Populating from them.");
76 return true;
77 }
78 }
79 return false;
80};
81
82struct DiscoverMetadataInAODCapability : o2::framework::CapabilityPlugin {
83 Capability* create() override
84 {
85 return new Capability{
86 .name = "DiscoverMetadataInAODCapability",
87 .checkIfNeeded = lookForAodFile,
88 .requiredPlugin = "O2FrameworkAnalysisSupport:DiscoverMetadataInAOD"};
89 }
90};
91
92// Trigger discovery of metadata from command line, if needed.
93struct DiscoverMetadataInCommandLineCapability : o2::framework::CapabilityPlugin {
94 Capability* create() override
95 {
96 return new Capability{
97 .name = "DiscoverMetadataInCommandLineCapability",
98 .checkIfNeeded = lookForCommandLineOptions,
99 .requiredPlugin = "O2Framework:DiscoverMetadataInCommandLine"};
100 }
101};
102
103struct DiscoverAODOptionsInCommandLineCapability : o2::framework::CapabilityPlugin {
104 Capability* create() override
105 {
106 return new Capability{
107 .name = "DiscoverAODOptionsInCommandLineCapability",
108 .checkIfNeeded = lookForCommandLineAODOptions,
109 .requiredPlugin = "O2Framework:DiscoverAODOptionsInCommandLine"};
110 }
111};
112
113struct DiscoverMetadataInCommandLine : o2::framework::ConfigDiscoveryPlugin {
114 ConfigDiscovery* create() override
115 {
116 return new ConfigDiscovery{
117 .init = []() {},
118 .discover = [](ConfigParamRegistry& registry, int argc, char** argv) -> std::vector<ConfigParamSpec> {
119 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
120 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInCommandLine",
121 "Discovering metadata for analysis from well known environment variables.");
122 std::vector<ConfigParamSpec> results;
123 for (size_t i = 0; i < argc; i++) {
124 std::string_view arg = argv[i];
125 if (!arg.starts_with("--aod-metadata")) {
126 continue;
127 }
128 std::string key = arg.data() + 2;
129 std::string value = argv[i + 1];
130 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverMetadataInCommandLine",
131 "Found %{public}s with value %{public}s.", key.c_str(), value.c_str());
132 if (key == "aod-metadata-tables") {
133 std::stringstream is(value);
134 auto arrayValue = VariantJSONHelpers::read<VariantType::ArrayString>(is);
135 results.push_back(ConfigParamSpec{key, VariantType::ArrayString, arrayValue, {"Metadata in command line"}});
136 } else {
137 results.push_back(ConfigParamSpec{key, VariantType::String, value, {"Metadata in command line"}});
138 }
139 }
140 return results;
141 }};
142 }
143};
144
145struct DiscoverAODOptionsInCommandLine : o2::framework::ConfigDiscoveryPlugin {
146 ConfigDiscovery* create() override
147 {
148 return new ConfigDiscovery{
149 .init = []() {},
150 .discover = [](ConfigParamRegistry& registry, int argc, char** argv) -> std::vector<ConfigParamSpec> {
151 O2_SIGNPOST_ID_GENERATE(sid, capabilities);
152 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLine",
153 "Discovering AOD handling related options in commandline arguments.");
154 std::vector<ConfigParamSpec> results;
155 bool injectOption = true;
156 for (size_t i = 0; i < argc; i++) {
157 std::string_view arg = argv[i];
158 if (!arg.starts_with("--aod-writer-") && !arg.starts_with("--aod-parent-") && !arg.starts_with("--aod-origin-")) {
159 continue;
160 }
161 std::string key = arg.data() + 2;
162 std::string value = argv[i + 1];
163 O2_SIGNPOST_EVENT_EMIT(capabilities, sid, "DiscoverAODOptionsInCommandLine",
164 "Found %{public}s with value %{public}s.", key.c_str(), value.c_str());
165 if (key == "aod-writer-compression") {
166 int numericValue = std::stoi(value);
167 results.push_back(ConfigParamSpec{"aod-writer-compression", VariantType::Int, numericValue, {"AOD Compression options"}});
168 injectOption = false;
169 }
170 if (key == "aod-parent-base-path-replacement") {
171 results.push_back(ConfigParamSpec{"aod-parent-base-path-replacement", VariantType::String, value, {R"(Replace base path of parent files. Syntax: FROM;TO. E.g. "alien:///path/in/alien;/local/path". Enclose in "" on the command line.)"}});
172 }
173 if (key == "aod-parent-access-level") {
174 results.push_back(ConfigParamSpec{"aod-parent-access-level", VariantType::String, value, {"Allow parent file access up to specified level. Default: no (0)"}});
175 }
176 if (key == "aod-origin-level-mapping") {
177 results.push_back(ConfigParamSpec{"aod-origin-level-mapping", VariantType::String, value, {"Map origin to parent level for AOD reading. Syntax: ORIGIN:LEVEL[,ORIGIN2:LEVEL2,...]. E.g. \"DYN:1\"."}});
178 }
179 }
180 if (injectOption) {
181 results.push_back(ConfigParamSpec{"aod-writer-compression", VariantType::Int, 505, {"AOD Compression options"}});
182 }
183 return results;
184 }};
185 }
186};
187
188struct ImplementationContext {
189 std::vector<RootArrowFactory> implementations;
190};
191
192std::function<void*(std::shared_ptr<arrow::fs::FileSystem>, std::string const&)> getHandleByClass(char const* classname)
193{
194 return [c = TClass::GetClass(classname)](std::shared_ptr<arrow::fs::FileSystem> fs, std::string const& path) -> void* {
195 if (auto tfileFS = std::dynamic_pointer_cast<TFileFileSystem>(fs)) {
196 return tfileFS->GetFile()->GetObjectChecked(path.c_str(), c);
197 } else if (auto tbufferFS = std::dynamic_pointer_cast<TBufferFileFS>(fs)) {
198 tbufferFS->GetBuffer()->Reset();
199 return tbufferFS->GetBuffer()->ReadObjectAny(c);
200 }
201 return nullptr;
202 };
203}
204
205std::function<bool(char const*)> matchClassByName(std::string_view classname)
206{
207 return [c = classname](char const* attempt) -> bool {
208 return c == attempt;
209 };
210}
211
212void lazyLoadFactory(std::vector<RootArrowFactory>& implementations, char const* specs)
213{
214 // Lazy loading of the plugin so that we do not bring in RNTuple / TTree if not needed
215 if (implementations.empty()) {
216 std::vector<LoadablePlugin> plugins;
217 auto morePlugins = PluginManager::parsePluginSpecString(specs);
218 for (auto& extra : morePlugins) {
219 plugins.push_back(extra);
220 }
221 PluginManager::loadFromPlugin<RootArrowFactory, RootArrowFactoryPlugin>(plugins, implementations);
222 if (implementations.empty()) {
223 return;
224 }
225 }
226}
227
228struct RNTupleObjectReadingCapability : o2::framework::RootObjectReadingCapabilityPlugin {
230 {
231 auto context = new ImplementationContext;
232
234 {
235 .name = "rntuple",
236 .lfn2objectPath = [](std::string s) -> std::string {
237 std::replace(s.begin()+1, s.end(), '/', '-');
238#if __has_include(<ROOT/RFieldBase.hxx>)
239 if (s.starts_with("/")) {
240 return std::string(s.begin() + 1, s.end());
241 } else {
242 return s;
243 } },
244#else
245 if (s.starts_with("/")) {
246 return s;
247 } else {
248 return "/" + s;
249 } },
250#endif
251#if __has_include(<ROOT/RFieldBase.hxx>)
252 .getHandle = getHandleByClass("ROOT::RNTuple"),
253 .checkSupport = matchClassByName("ROOT::RNTuple"),
254#else
255 .getHandle = getHandleByClass("ROOT::Experimental::RNTuple"),
256 .checkSupport = matchClassByName("ROOT::Experimental::RNTuple"),
257#endif
258 .factory = [context]() -> RootArrowFactory& {
259 lazyLoadFactory(context->implementations, "O2FrameworkAnalysisRNTupleSupport:RNTupleObjectReadingImplementation");
260 return context->implementations.back();
261 }
262 };
263 }
264};
265
266struct TTreeObjectReadingCapability : o2::framework::RootObjectReadingCapabilityPlugin {
268 {
269 auto context = new ImplementationContext;
270
272 .name = "ttree",
273 .lfn2objectPath = [](std::string s) { return s; },
274 .getHandle = getHandleByClass("TTree"),
275 .checkSupport = matchClassByName("TTree"),
276 .accountBytes = [](void* handle, size_t& compressed, size_t& uncompressed) {
277 auto* tree = (TTree*)handle;
278 compressed += tree->GetZipBytes();
279 uncompressed += tree->GetTotBytes(); },
280 .factory = [context]() -> RootArrowFactory& {
281 lazyLoadFactory(context->implementations, "O2FrameworkAnalysisTTreeSupport:TTreeObjectReadingImplementation");
282 return context->implementations.back();
283 }};
284 }
285};
286
288DEFINE_DPL_PLUGIN_INSTANCE(DiscoverMetadataInAODCapability, Capability);
289DEFINE_DPL_PLUGIN_INSTANCE(DiscoverMetadataInCommandLineCapability, Capability);
290DEFINE_DPL_PLUGIN_INSTANCE(DiscoverAODOptionsInCommandLineCapability, Capability);
291DEFINE_DPL_PLUGIN_INSTANCE(DiscoverMetadataInCommandLine, ConfigDiscovery);
292DEFINE_DPL_PLUGIN_INSTANCE(DiscoverAODOptionsInCommandLine, ConfigDiscovery);
293DEFINE_DPL_PLUGIN_INSTANCE(RNTupleObjectReadingCapability, RootObjectReadingCapability);
294DEFINE_DPL_PLUGIN_INSTANCE(TTreeObjectReadingCapability, RootObjectReadingCapability);
296} // namespace o2::framework
int32_t i
#define DEFINE_DPL_PLUGIN_INSTANCE(NAME, KIND)
Definition Plugins.h:112
#define DEFINE_DPL_PLUGINS_END
Definition Plugins.h:115
#define DEFINE_DPL_PLUGINS_BEGIN
Definition Plugins.h:107
uint32_t c
Definition RawData.h:2
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:490
#define O2_SIGNPOST_ID_GENERATE(name, log)
Definition Signpost.h:507
#define O2_SIGNPOST_EVENT_EMIT(log, id, name, format,...)
Definition Signpost.h:523
StringRef key
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
ConcreteParserVariants< PageSize, BOUNDS_CHECKS > create(T const *buffer, size_t size)
create a raw parser depending on version of RAWDataHeader found at beginning of data
Definition RawParser.h:378
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
static std::vector< LoadablePlugin > parsePluginSpecString(char const *str)
Parse a comma separated list of <library>:<plugin-name> plugin declarations.
virtual RootObjectReadingCapability * create()=0
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))