Project
Loading...
Searching...
No Matches
ASoA.cxx
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#include "Framework/ASoA.h"
13#include "ArrowDebugHelpers.h"
15#include <arrow/util/key_value_metadata.h>
16#include <arrow/util/config.h>
17#include <TMemFile.h>
18#include <TClass.h>
19#include <TTree.h>
20#include <TH1.h>
21#include <TError.h>
22
23namespace o2::soa
24{
25void accessingInvalidIndexFor(const char* getter)
26{
27 throw o2::framework::runtime_error_f("Accessing invalid index for %s", getter);
28}
29void dereferenceWithWrongType(const char* getter, const char* target)
30{
31 throw o2::framework::runtime_error_f("Trying to dereference index with a wrong type in %s_as<T> for base target \"%s\". Note that if you have several compatible index targets in your process() signature, the last one will be the one actually bound.", getter, target);
32}
34{
35 throw o2::framework::runtime_error_f("Null selection for %d (arg %d), missing Filter declaration?", hash, ai);
36}
37
38void getterNotFound(const char* targetColumnLabel)
39{
40 throw o2::framework::runtime_error_f("Getter for \"%s\" not found", targetColumnLabel);
41}
42
44{
45 throw framework::runtime_error("columnLabel: must not be empty");
46}
47
49{
51 rows.resize(sel->GetNumSlots());
52 for (auto i = 0; i < sel->GetNumSlots(); ++i) {
53 rows[i] = sel->GetIndex(i);
54 }
55 return rows;
56}
57
58SelectionVector sliceSelection(std::span<int64_t const> const& mSelectedRows, int64_t nrows, uint64_t offset)
59{
60 auto start = offset;
61 auto end = start + nrows;
62 auto start_iterator = std::lower_bound(mSelectedRows.begin(), mSelectedRows.end(), start);
63 auto stop_iterator = std::lower_bound(start_iterator, mSelectedRows.end(), end);
64 SelectionVector slicedSelection{start_iterator, stop_iterator};
65 std::ranges::transform(slicedSelection.begin(), slicedSelection.end(), slicedSelection.begin(),
66 [&start](int64_t idx) {
67 return idx - static_cast<int64_t>(start);
68 });
69 return slicedSelection;
70}
71
72namespace
73{
74template <typename T>
75 requires(std::same_as<T, std::string>)
76auto makeString(T const& str)
77{
78 return str.c_str();
79}
80template <typename T>
81 requires(std::same_as<T, const char*>)
82auto makeString(T const& str)
83{
84 return str;
85}
86
87template <typename T>
88void canNotJoin(std::vector<std::shared_ptr<arrow::Table>> const& tables, std::span<T> labels)
89{
90 for (auto i = 0U; i < tables.size() - 1; ++i) {
91 if (tables[i]->num_rows() != tables[i + 1]->num_rows()) {
92 throw o2::framework::runtime_error_f("Tables %s and %s have different sizes (%lld vs %lld) and cannot be joined!",
93 makeString(labels[i]), makeString(labels[i + 1]), (long long)tables[i]->num_rows(), (long long)tables[i + 1]->num_rows());
94 }
95 }
96}
97
98template <typename T>
99void IncompatibleRanges(std::vector<ArrowTableRef> const& tables, std::span<T> labels)
100{
101 auto loc = std::ranges::adjacent_find(tables, [](auto const& l, auto const& r) { return l.range != r.range; });
102 if (loc != std::ranges::cend(tables)) {
103 auto pos = std::distance(tables.begin(), loc);
104 auto next = loc + 1;
105 if (loc->range.size != next->range.size) {
106 if (labels.empty()) {
107 throw o2::framework::runtime_error_f("Tables at positions %d and %d have different sizes (%lld vs %lld) and cannot be joined!",
108 (int)pos, (int)pos + 1, (long long)loc->range.size, (long long)next->range.size);
109 }
110 throw o2::framework::runtime_error_f("Tables %s and %s have different sizes (%lld vs %lld) and cannot be joined!",
111 makeString(labels[pos]), makeString(labels[pos + 1]), (long long)loc->range.size, (long long)next->range.size);
112 }
113 if (labels.empty()) {
114 throw o2::framework::runtime_error_f("Incompatible ranges at %d: (%llu, %lld) vs. (%llu, %lld)",
115 (int)pos, (unsigned long long)loc->range.offset, (long long)loc->range.size, (unsigned long long)next->range.offset, (long long)next->range.size);
116 }
117 throw o2::framework::runtime_error_f("Incompatible ranges at %d between %s and %s: (%llu, %lld) vs. (%llu, %lld)",
118 (int)pos, makeString(labels[pos]), makeString(labels[pos + 1]), (unsigned long long)loc->range.offset, (long long)loc->range.size, (unsigned long long)next->range.offset, (long long)next->range.size);
119 }
120}
121
122std::shared_ptr<arrow::Table> joinTablesImpl(std::ranges::input_range auto tables)
123{
124 std::vector<std::shared_ptr<arrow::Field>> fields;
125 std::vector<std::shared_ptr<arrow::ChunkedArray>> columns;
126 bool notEmpty = (tables.front()->num_rows() != 0);
127 std::ranges::for_each(tables, [&fields, &columns, notEmpty](auto const& t) {
128 std::ranges::copy(t->fields(), std::back_inserter(fields));
129 if (notEmpty) {
130 std::ranges::copy(t->columns(), std::back_inserter(columns));
131 }
132 });
133 auto schema = std::make_shared<arrow::Schema>(fields);
134 return arrow::Table::Make(schema, columns);
135}
136
137template <typename T>
138ArrowTableRef joinTablesImpl(std::ranges::input_range auto tables, std::span<T> labels)
139{
140 if (tables.size() == 1) {
141 return tables.front();
142 }
143 IncompatibleRanges(tables, labels);
144 ArrowRange commonRange{tables.front().range};
145 return {joinTablesImpl(tables), commonRange};
146}
147} // namespace
148
149o2::soa::ArrowTableRef ArrowHelpers::joinTables(std::vector<std::shared_ptr<arrow::Table>>&& tables)
150{
151 std::vector<ArrowTableRef> refs;
152 std::ranges::transform(tables, std::back_inserter(refs), [](auto const& table) { return ArrowTableRef{table}; });
153 return joinTablesImpl(refs, std::span<const char* const>());
154}
155
156o2::soa::ArrowTableRef ArrowHelpers::joinTables(std::vector<o2::soa::ArrowTableRef>&& tables)
157{
158 return joinTablesImpl(tables, std::span<const char* const>());
159}
160
161o2::soa::ArrowTableRef ArrowHelpers::joinTables(std::vector<o2::soa::ArrowTableRef>&& tables, std::span<const char* const> labels)
162{
163 return joinTablesImpl(tables, labels);
164}
165
166o2::soa::ArrowTableRef ArrowHelpers::joinTables(std::vector<o2::soa::ArrowTableRef>&& tables, std::span<const std::string> labels)
167{
168 return joinTablesImpl(tables, labels);
169}
170
171o2::soa::ArrowTableRef ArrowHelpers::joinTables(std::vector<std::shared_ptr<arrow::Table>>&& tables, std::span<const char* const> labels)
172{
173 canNotJoin(tables, labels);
174 return o2::soa::ArrowTableRef{joinTablesImpl(tables)};
175}
176
177o2::soa::ArrowTableRef ArrowHelpers::joinTables(std::vector<std::shared_ptr<arrow::Table>>&& tables, std::span<const std::string> labels)
178{
179 canNotJoin(tables, labels);
180 return o2::soa::ArrowTableRef{joinTablesImpl(tables)};
181}
182
183o2::soa::ArrowTableRef ArrowHelpers::concatTables(std::vector<o2::soa::ArrowTableRef>&& tables)
184{
185 if (tables.size() == 1) {
186 return tables.front();
187 }
188 std::vector<std::shared_ptr<arrow::ChunkedArray>> columns;
189 std::vector<std::shared_ptr<arrow::Field>> resultFields = tables.front()->schema()->fields();
190 auto compareFields = [](std::shared_ptr<arrow::Field> const& f1, std::shared_ptr<arrow::Field> const& f2) {
191 // Let's do this with stable sorting.
192 return (!f1->Equals(f2)) && (f1->name() < f2->name());
193 };
194
195 for (auto i = 1; i < tables.size(); ++i) {
196 auto const& fields = tables[i]->fields();
197 std::vector<std::shared_ptr<arrow::Field>> intersection;
198 std::ranges::set_intersection(resultFields, fields, std::back_inserter(intersection), compareFields);
199 resultFields.swap(intersection);
200 }
201
202 for (auto const& field : resultFields) {
203 arrow::ArrayVector chunks;
204 for (auto const& table : tables) {
205 auto ci = table->schema()->GetFieldIndex(field->name());
206 if (ci == -1) {
207 throw framework::runtime_error_f("Unable to find field {}", field->name().c_str());
208 }
209 auto column = table->column(ci);
210 auto otherChunks = column->chunks();
211 chunks.insert(chunks.end(), otherChunks.begin(), otherChunks.end());
212 }
213 columns.push_back(std::make_shared<arrow::ChunkedArray>(chunks));
214 }
215
216 return {arrow::Table::Make(std::make_shared<arrow::Schema>(resultFields), columns)};
217}
218
219arrow::ChunkedArray* getIndexFromLabel(arrow::Table* table, std::string_view label)
220{
221 // Take the exact-match common case first (string_view comparison checks length
222 // then memcmp), and fall back to a case-insensitive scan only when the labels
223 // differ in case.
224 auto field = std::ranges::find_if(table->schema()->fields(), [label](std::shared_ptr<arrow::Field> const& f) {
225 std::string_view name = f->name();
226 return label == name ||
227 std::ranges::equal(label, name, [](char c1, char c2) {
228 return asciiToLower(c1) == asciiToLower(c2);
229 });
230 });
231 if (field == table->schema()->fields().end()) {
232 o2::framework::throw_error(o2::framework::runtime_error_f("Unable to find column with label %s.", label));
233 }
234 return table->column(std::distance(table->schema()->fields().begin(), field)).get();
235}
236
237void notBoundTable(const char* tableName)
238{
239 throw o2::framework::runtime_error_f("Index pointing to %s is not bound! Did you subscribe to the table?", tableName);
240}
241
242void notFoundColumn(const char* label, const char* key)
243{
244 throw o2::framework::runtime_error_f(R"(Preslice not valid: table "%s" (or join based on it) does not have column "%s")", label, key);
245}
246
247void missingOptionalPreslice(const char* label, const char* key)
248{
249 throw o2::framework::runtime_error_f(R"(Optional Preslice with missing binding used: table "%s" (or join based on it) does not have column "%s")", label, key);
250}
251
252void* extractCCDBPayload(char* payload, size_t size, TClass const* cl, const char* what)
253{
254 Int_t previousErrorLevel = gErrorIgnoreLevel;
255 gErrorIgnoreLevel = kFatal;
256 // does it have a flattened headers map attached in the end?
257 TMemFile file("name", (char*)payload, size, "READ");
258 gErrorIgnoreLevel = previousErrorLevel;
259 if (file.IsZombie()) {
260 return nullptr;
261 }
262
263 if (!cl) {
264 return nullptr;
265 }
266 auto object = file.GetObjectChecked(what, cl);
267 if (!object) {
268 // it could be that object was stored with previous convention
269 // where the classname was taken as key
270 std::string objectName(cl->GetName());
271 objectName.erase(std::find_if(objectName.rbegin(), objectName.rend(), [](unsigned char ch) {
272 return !std::isspace(ch);
273 }).base(),
274 objectName.end());
275 objectName.erase(objectName.begin(), std::find_if(objectName.begin(), objectName.end(), [](unsigned char ch) {
276 return !std::isspace(ch);
277 }));
278
279 object = file.GetObjectChecked(objectName.c_str(), cl);
280 LOG(warn) << "Did not find object under expected name " << what;
281 if (!object) {
282 return nullptr;
283 }
284 LOG(warn) << "Found object under deprecated name " << cl->GetName();
285 }
286 auto result = object;
287 // We need to handle some specific cases as ROOT ties them deeply
288 // to the file they are contained in
289 if (cl->InheritsFrom("TObject")) {
290 // make a clone
291 // detach from the file
292 auto tree = dynamic_cast<TTree*>((TObject*)object);
293 if (tree) {
294 tree->LoadBaskets(0x1L << 32); // make tree memory based
295 tree->SetDirectory(nullptr);
296 result = tree;
297 } else {
298 auto h = dynamic_cast<TH1*>((TObject*)object);
299 if (h) {
300 h->SetDirectory(nullptr);
301 result = h;
302 }
303 }
304 }
305 return result;
306}
307
309{
310 return [newOrigin](framework::ConcreteDataMatcher&& m) {
311 if ((m.origin == header::DataOrigin{"AOD"}) && (newOrigin != header::DataOrigin{"AOD"})) {
312 m.origin = newOrigin;
313 }
314 return m;
315 };
316}
317
318} // namespace o2::soa
319
320namespace o2::framework
321{
322std::string cutString(std::string&& str)
323{
324 auto pos = str.find('_');
325 if (pos != std::string::npos) {
326 str.erase(pos);
327 }
328 return str;
329}
330
331std::string strToUpper(std::string&& str)
332{
333 std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); });
334 return str;
335}
336
338{
339 return binding == "[MISSING]";
340}
341
343{
344 return bindingKey;
345}
346
351
356
358{
359 auto [offset_, count] = this->sliceInfo.getSliceFor(value);
360 return input.slice({static_cast<uint64_t>(offset_), count});
361}
362
363std::span<const int64_t> PreslicePolicyGeneral::getSliceFor(int value) const
364{
365 return this->sliceInfo.getSliceFor(value);
366}
367} // namespace o2::framework
uint32_t hash
std::shared_ptr< arrow::Schema > schema
std::vector< std::shared_ptr< arrow::Field > > fields
int32_t i
std::vector< o2::MCCompLabel > labels
uint16_t pos
Definition RawData.h:3
uint32_t c
Definition RawData.h:2
StringRef key
Class for time synchronization of RawReader instances.
const GLfloat * m
Definition glcorearb.h:4066
GLint GLsizei count
Definition glcorearb.h:399
GLuint64EXT * result
Definition glcorearb.h:5662
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLdouble f
Definition glcorearb.h:310
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum target
Definition glcorearb.h:1641
GLintptr offset
Definition glcorearb.h:660
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLuint object
Definition glcorearb.h:4041
GLboolean r
Definition glcorearb.h:1233
GLuint start
Definition glcorearb.h:469
std::shared_ptr< gandiva::SelectionVector > Selection
Definition Expressions.h:45
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
RuntimeErrorRef runtime_error(const char *)
void throw_error(RuntimeErrorRef)
std::string strToUpper(std::string &&str)
Definition ASoA.cxx:331
RuntimeErrorRef runtime_error_f(const char *,...)
std::string cutString(std::string &&str)
Definition ASoA.cxx:322
void * extractCCDBPayload(char *payload, size_t size, TClass const *cl, const char *what)
Definition ASoA.cxx:252
SelectionVector selectionToVector(gandiva::Selection const &sel)
Definition ASoA.cxx:48
void notBoundTable(const char *tableName)
Definition ASoA.cxx:237
SelectionVector sliceSelection(std::span< int64_t const > const &mSelectedRows, int64_t nrows, uint64_t offset)
Definition ASoA.cxx:58
std::vector< int64_t > SelectionVector
Definition ASoA.h:444
void missingFilterDeclaration(int hash, int ai)
Definition ASoA.cxx:33
void accessingInvalidIndexFor(const char *getter)
Definition ASoA.cxx:25
void dereferenceWithWrongType(const char *getter, const char *target)
Definition ASoA.cxx:29
void emptyColumnLabel()
Definition ASoA.cxx:43
void getterNotFound(const char *targetColumnLabel)
Definition ASoA.cxx:38
void missingOptionalPreslice(const char *label, const char *key)
Definition ASoA.cxx:247
std::function< framework::ConcreteDataMatcher(framework::ConcreteDataMatcher &&)> originReplacement(header::DataOrigin newOrigin)
Definition ASoA.cxx:308
arrow::ChunkedArray * getIndexFromLabel(arrow::Table *table, std::string_view label)
Definition ASoA.cxx:219
void notFoundColumn(const char *label, const char *key)
Definition ASoA.cxx:242
const std::string binding
Definition ASoA.h:1424
Entry const & getBindingKey() const
Definition ASoA.cxx:342
SliceInfoUnsortedPtr sliceInfo
Definition ASoA.h:1441
std::span< const int64_t > getSliceFor(int value) const
Definition ASoA.cxx:363
void updateSliceInfo(SliceInfoUnsortedPtr &&si)
Definition ASoA.cxx:352
o2::soa::ArrowTableRef getSliceFor(int value, o2::soa::ArrowTableRef const &input) const
Definition ASoA.cxx:357
void updateSliceInfo(SliceInfoPtr &&si)
Definition ASoA.cxx:347
std::pair< int64_t, int64_t > getSliceFor(int value) const
std::span< int64_t const > getSliceFor(int value) const
static o2::soa::ArrowTableRef joinTables(std::vector< std::shared_ptr< arrow::Table > > &&tables)
Definition ASoA.cxx:149
static o2::soa::ArrowTableRef concatTables(std::vector< o2::soa::ArrowTableRef > &&tables)
Definition ASoA.cxx:183
ArrowTableRef slice(ArrowRange newRange) const
Definition ArrowTypes.h:52
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))
std::vector< ReadoutWindowData > rows
const std::string str