Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleProcessor.cxx
Go to the documentation of this file.
1/// \file RNTupleProcessor.cxx
2/// \author Florine de Geus <florine.de.geus@cern.ch>
3/// \date 2024-03-26
4/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
5/// is welcome!
6
7/*************************************************************************
8 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
9 * All rights reserved. *
10 * *
11 * For the licensing terms see $ROOTSYS/LICENSE. *
12 * For the list of contributors see $ROOTSYS/README/CREDITS. *
13 *************************************************************************/
14
16
17#include <ROOT/RFieldBase.hxx>
18#include <ROOT/RNTuple.hxx>
20#include <ROOT/StringUtils.hxx>
21
22#include <TDirectory.h>
23
24#include <iomanip>
25
26std::unique_ptr<ROOT::Internal::RPageSource> ROOT::Experimental::RNTupleOpenSpec::CreatePageSource() const
27{
28 if (const std::string *storagePath = std::get_if<std::string>(&fStorage))
30
31 auto dir = std::get<TDirectory *>(fStorage);
32 auto ntuple = std::unique_ptr<ROOT::RNTuple>(dir->Get<ROOT::RNTuple>(fNTupleName.c_str()));
34}
35
36std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
38{
39 return std::unique_ptr<RNTupleSingleProcessor>(new RNTupleSingleProcessor(std::move(ntuple), options));
40}
41
42std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
43ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<RNTupleOpenSpec> ntuples,
44 const RNTupleProcessorOptions &options)
45{
46 if (ntuples.empty())
47 throw RException(R__FAIL("at least one RNTuple must be provided"));
48
49 std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors;
50 innerProcessors.reserve(ntuples.size());
51
52 for (auto &ntuple : ntuples) {
53 innerProcessors.emplace_back(Create(std::move(ntuple)));
54 }
55
56 return CreateChain(std::move(innerProcessors), options);
57}
58
59std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
60ROOT::Experimental::RNTupleProcessor::CreateChain(std::vector<std::unique_ptr<RNTupleProcessor>> innerProcessors,
61 const RNTupleProcessorOptions &options)
62{
63 if (innerProcessors.empty())
64 throw RException(R__FAIL("at least one inner processor must be provided"));
65
66 return std::unique_ptr<RNTupleChainProcessor>(new RNTupleChainProcessor(std::move(innerProcessors), options));
67}
68
69std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
71 const std::vector<std::string> &joinFields,
72 const RNTupleProcessorOptions &options)
73{
74 if (joinFields.size() > 4) {
75 throw RException(R__FAIL("a maximum of four join fields is allowed"));
76 }
77
78 if (std::unordered_set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
79 throw RException(R__FAIL("join fields must be unique"));
80 }
81
82 std::unique_ptr<RNTupleProcessor> primaryProcessor = Create(std::move(primaryNTuple), options);
83
84 std::unique_ptr<RNTupleProcessor> auxProcessor = Create(std::move(auxNTuple));
85
86 return CreateJoin(std::move(primaryProcessor), std::move(auxProcessor), joinFields, options);
87}
88
89std::unique_ptr<ROOT::Experimental::RNTupleProcessor>
90ROOT::Experimental::RNTupleProcessor::CreateJoin(std::unique_ptr<RNTupleProcessor> primaryProcessor,
91 std::unique_ptr<RNTupleProcessor> auxProcessor,
92 const std::vector<std::string> &joinFields,
93 const RNTupleProcessorOptions &options)
94{
95 if (joinFields.size() > 4) {
96 throw RException(R__FAIL("a maximum of four join fields is allowed"));
97 }
98
99 if (std::unordered_set(joinFields.begin(), joinFields.end()).size() < joinFields.size()) {
100 throw RException(R__FAIL("join fields must be unique"));
101 }
102
103 return std::unique_ptr<RNTupleJoinProcessor>(
104 new RNTupleJoinProcessor(std::move(primaryProcessor), std::move(auxProcessor), joinFields, options));
105}
106
107//------------------------------------------------------------------------------
108
117
119 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
120{
121 // The processor has already been initialized.
122 if (IsInitialized() && fPageSource)
123 return;
124
125 if (!entry)
126 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
127 else
128 fEntry = std::move(entry);
129
130 fPageSource = fNTupleSpec.CreatePageSource();
131 fPageSource->Attach();
132
133 fNEntries = fPageSource->GetNEntries();
134}
135
137{
138 Initialize();
139 auto desc = fPageSource->GetSharedDescriptorGuard();
140 auto fieldZeroId = desc->GetFieldZeroId();
141
142 // TODO handle subfields
143 return desc->FindFieldId(fieldName, fieldZeroId) != ROOT::kInvalidDescriptorId;
144}
145
146std::unique_ptr<ROOT::RFieldBase>
148 const std::string &typeName)
149{
150 assert(fPageSource);
151
152 // Strip the "R_rntproc_join_" prefix (for join fields) from the field name, if present.
153 const std::string onDiskFieldName =
154 qualifiedFieldName.find("R_rntproc_join_") == 0 ? qualifiedFieldName.substr(15) : qualifiedFieldName;
155
156 auto descGuard = fPageSource->GetSharedDescriptorGuard();
157 const auto &desc = descGuard.GetRef();
158 ROOT::RFieldZero fieldZero;
160
161 const auto onDiskFieldId = desc.FindFieldId(onDiskFieldName);
162
163 if (onDiskFieldId == kInvalidDescriptorId) {
164 return nullptr;
165 }
166
167 std::unique_ptr<ROOT::RFieldBase> field;
168 if (typeName.empty()) {
169 const auto &fieldDesc = desc.GetFieldDescriptor(onDiskFieldId);
170 field = fieldDesc.CreateField(desc);
171 } else {
172 // Strip the parent field name prefix(es), if present.
173 std::string subfieldName = onDiskFieldName;
174 auto posDot = onDiskFieldName.find_last_of('.');
175 if (posDot != std::string::npos)
176 subfieldName = onDiskFieldName.substr(posDot + 1);
177
178 field = ROOT::RFieldBase::Create(subfieldName, typeName).Unwrap();
179 }
180
181 field->SetOnDiskId(onDiskFieldId);
182 fieldZero.Attach(std::move(field));
183 ROOT::Internal::CallConnectPageSourceOnField(fieldZero, *fPageSource);
184 return std::move(fieldZero.ReleaseSubfields()[0]);
185}
186
188ROOT::Experimental::RNTupleSingleProcessor::AddFieldToEntry(const std::string &fieldName, const std::string &typeName,
189 void *valuePtr,
190 const Internal::RNTupleProcessorProvenance &provenance)
191{
192 auto fieldIdx = fEntry->FindFieldIndex(fieldName, typeName);
193 if (!fieldIdx) {
194 // Strip the processor name prefix(es), if present.
195 std::string qualifiedFieldName = fieldName;
196 if (provenance.IsPresentInFieldName(qualifiedFieldName)) {
197 qualifiedFieldName = qualifiedFieldName.substr(provenance.Get().size() + 1);
198 }
199
200 auto field = CreateAndConnectField(qualifiedFieldName, typeName);
201
202 if (!field) {
203 throw RException(R__FAIL("cannot register field with name \"" + qualifiedFieldName +
204 "\" because it is not present in the on-disk information of the RNTuple(s) this "
205 "processor is created from"));
206 }
207
208 fieldIdx = fEntry->AddField(qualifiedFieldName, std::move(field), valuePtr, provenance);
209 }
210
211 return *fieldIdx;
212}
213
215{
216 if (entryNumber >= fNEntries || !fEntry)
217 return kInvalidNTupleIndex;
218
219 for (auto fieldIdx : fFieldIdxs) {
220 fEntry->ReadValue(fieldIdx, entryNumber);
221 }
222
223 fNEntriesProcessed++;
224 return entryNumber;
225}
226
228 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
229 const Internal::RNTupleProcessorProvenance & /* provenance */, bool updateFields)
230{
231 Initialize(fEntry);
232
233 fFieldIdxs = fieldIdxs;
234
235 if (updateFields) {
236 for (const auto &fieldIdx : fFieldIdxs) {
237 const auto &currField = fEntry->GetValue(fieldIdx).GetField();
238 auto newField = CreateAndConnectField(fEntry->GetQualifiedFieldName(fieldIdx), currField.GetTypeName());
239
240 fEntry->UpdateField(fieldIdx, std::move(newField));
241 }
242 }
243}
244
246{
247 if (fPageSource) {
248 fEntry->ResetFields(fFieldIdxs);
249 fPageSource.reset();
250 }
251}
252
254 ROOT::NTupleSize_t entryOffset)
255{
256 Connect(fFieldIdxs);
257 joinTable.Add(*fPageSource, Internal::RNTupleJoinTable::kDefaultPartitionKey, entryOffset);
258}
259
261{
262 static constexpr int width = 32;
263
264 std::string ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 4);
265 if (ntupleNameTrunc.size() < fNTupleSpec.fNTupleName.size())
266 ntupleNameTrunc = fNTupleSpec.fNTupleName.substr(0, width - 6) + "..";
267
268 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
269 output << std::setfill(' ') << "| " << ntupleNameTrunc << std::setw(width - 2 - ntupleNameTrunc.size()) << " |\n";
270
271 if (const std::string *storage = std::get_if<std::string>(&fNTupleSpec.fStorage)) {
272 std::string storageTrunc = storage->substr(0, width - 5);
273 if (storageTrunc.size() < storage->size())
274 storageTrunc = storage->substr(0, width - 8) + "...";
275
276 output << std::setfill(' ') << "| " << storageTrunc << std::setw(width - 2 - storageTrunc.size()) << " |\n";
277 } else {
278 output << "| " << std::setw(width - 2) << " |\n";
279 }
280
281 output << "+" << std::setfill('-') << std::setw(width - 1) << "+\n";
282}
283
284//------------------------------------------------------------------------------
285
287 std::vector<std::unique_ptr<RNTupleProcessor>> processors, const RNTupleProcessorOptions &options)
288 : RNTupleProcessor(options), fInnerProcessors(std::move(processors))
289{
290 if (fOptions.GetProcessorName().empty()) {
291 // `CreateChain` ensures there is at least one inner processor.
293 }
294
296}
297
299 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
300{
301 if (IsInitialized())
302 return;
303
304 if (!entry)
305 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
306 else
307 fEntry = std::move(entry);
308
309 fInnerProcessors[0]->Initialize(fEntry);
310}
311
313{
314 if (fNEntries == kInvalidNTupleIndex) {
315 fNEntries = 0;
316
317 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
318 if (fInnerNEntries[i] == kInvalidNTupleIndex) {
319 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
320 }
321
322 fNEntries += fInnerNEntries[i];
323 }
324 }
325
326 return fNEntries;
327}
328
330 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
331 const Internal::RNTupleProcessorProvenance &provenance, bool /* updateFields */)
332{
333 Initialize();
334 fFieldIdxs = fieldIdxs;
335 fProvenance = provenance;
336 ConnectInnerProcessor(fCurrentProcessorNumber);
337}
338
340{
341 for (const auto &innerProc : fInnerProcessors) {
342 innerProc->Disconnect();
343 }
344}
345
347{
348 if (fCurrentProcessorNumber != processorNumber) {
349 fInnerProcessors[fCurrentProcessorNumber]->Disconnect();
350 fCurrentProcessorNumber = processorNumber;
351 }
352
353 auto &innerProc = fInnerProcessors[processorNumber];
354 innerProc->Initialize(fEntry);
355 innerProc->Connect(fFieldIdxs, fProvenance, /*updateFields=*/true);
356}
357
359ROOT::Experimental::RNTupleChainProcessor::AddFieldToEntry(const std::string &fieldName, const std::string &typeName,
360 void *valuePtr,
361 const Internal::RNTupleProcessorProvenance &provenance)
362{
363 return fInnerProcessors[fCurrentProcessorNumber]->AddFieldToEntry(fieldName, typeName, valuePtr, provenance);
364}
365
367{
368 // If the requested entry number is lower than the current entry number, we have to again localise the correct local
369 // entry number starting from the first processor in the chain. Otherwise, we can continue looking from the inner
370 // processor that is currently connected, which is much faster when the chain consists of many inner processors.
371 if (fLastLoadedEntry != ROOT::kInvalidNTupleIndex && entryNumber < fLastLoadedEntry) {
372 fCurrentProcessorNumber = 0;
373 ConnectInnerProcessor(fCurrentProcessorNumber);
374 }
375
376 std::size_t currProcessorNumber = fCurrentProcessorNumber;
377 ROOT::NTupleSize_t entriesSeen = 0;
378 for (unsigned i = 0; i < currProcessorNumber; ++i) {
379 if (fInnerNEntries[i] == kInvalidNTupleIndex) {
380 fInnerNEntries[i] = fInnerProcessors[i]->GetNEntries();
381 }
382 entriesSeen += fInnerNEntries[i];
383 }
384 ROOT::NTupleSize_t localEntryNumber = entryNumber - entriesSeen;
385
386 // As long as the entry fails to load from the current processor, we decrement the local entry number with the number
387 // of entries in this processor and try with the next processor until we find the correct local entry number.
388 while (fInnerProcessors[currProcessorNumber]->LoadEntry(localEntryNumber) == kInvalidNTupleIndex) {
389 if (fInnerNEntries[currProcessorNumber] == kInvalidNTupleIndex) {
390 fInnerNEntries[currProcessorNumber] = fInnerProcessors[currProcessorNumber]->GetNEntries();
391 }
392
393 localEntryNumber -= fInnerNEntries[currProcessorNumber];
394
395 // The provided global entry number is larger than the number of available entries.
396 if (++currProcessorNumber >= fInnerProcessors.size())
397 return kInvalidNTupleIndex;
398
399 ConnectInnerProcessor(currProcessorNumber);
400 }
401
402 fCurrentProcessorNumber = currProcessorNumber;
403 fNEntriesProcessed++;
404 fLastLoadedEntry = entryNumber;
405 return entryNumber;
406}
407
409 ROOT::NTupleSize_t entryOffset)
410{
411 for (unsigned i = 0; i < fInnerProcessors.size(); ++i) {
412 const auto &innerProc = fInnerProcessors[i];
413 // TODO can this be done (more) lazily? I.e. only when a match cannot be found in the current inner proc?
414 innerProc->Initialize(fEntry);
415 innerProc->AddEntriesToJoinTable(joinTable, entryOffset);
416 entryOffset += innerProc->GetNEntries();
417 }
418}
419
421{
422 for (const auto &innerProc : fInnerProcessors) {
423 innerProc->PrintStructure(output);
424 }
425}
426
427//------------------------------------------------------------------------------
428
429ROOT::Experimental::RNTupleJoinProcessor::RNTupleJoinProcessor(std::unique_ptr<RNTupleProcessor> primaryProcessor,
430 std::unique_ptr<RNTupleProcessor> auxProcessor,
431 const std::vector<std::string> &joinFields,
432 const RNTupleProcessorOptions &options)
433 : RNTupleProcessor(options),
434 fPrimaryProcessor(std::move(primaryProcessor)),
435 fAuxiliaryProcessor(std::move(auxProcessor)),
436 fJoinFieldNames(joinFields)
437{
438 if (fOptions.GetProcessorName().empty()) {
439 fOptions.SetProcessorName(fPrimaryProcessor->fOptions.GetProcessorName());
440 }
441}
442
444 std::shared_ptr<ROOT::Experimental::Internal::RNTupleProcessorEntry> entry)
445{
446 if (IsInitialized())
447 return;
448
449 if (!entry)
450 fEntry = std::make_shared<Internal::RNTupleProcessorEntry>();
451 else
452 fEntry = std::move(entry);
453
454 fPrimaryProcessor->Initialize(fEntry);
455 fAuxiliaryProcessor->Initialize(fEntry);
456
457 if (!fJoinFieldNames.empty()) {
458 for (const auto &joinField : fJoinFieldNames) {
459 if (!fPrimaryProcessor->CanReadFieldFromDisk(joinField)) {
460 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in primary processor \"" +
461 fPrimaryProcessor->fOptions.GetProcessorName() + "\""));
462 }
463 if (!fAuxiliaryProcessor->CanReadFieldFromDisk(joinField)) {
464 throw RException(R__FAIL("could not find join field \"" + joinField + "\" in auxiliary processor \"" +
465 fAuxiliaryProcessor->fOptions.GetProcessorName() + "\""));
466 }
467
468 // We prepend the name of the primary processor in this case to prevent reading from the wrong join field in
469 // composed join operations.
470 auto fieldIdx = AddFieldToEntry(fOptions.GetProcessorName() + ".R_rntproc_join_" + joinField, "std::uint64_t",
471 nullptr, Internal::RNTupleProcessorProvenance(fOptions.GetProcessorName()));
472 fJoinFieldIdxs.insert(fieldIdx);
473 }
474
475 fJoinTable = Internal::RNTupleJoinTable::Create(fJoinFieldNames);
476 }
477}
478
480 const std::unordered_set<ROOT::Experimental::Internal::RNTupleProcessorEntry::FieldIndex_t> &fieldIdxs,
481 const Internal::RNTupleProcessorProvenance &provenance, bool updateFields)
482{
483 Initialize();
484
485 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->fOptions.GetProcessorName());
486 for (const auto &fieldIdx : fieldIdxs) {
487 const auto &fieldProvenance = fEntry->GetFieldProvenance(fieldIdx);
488 if (fieldProvenance.Contains(auxProvenance))
489 fAuxiliaryFieldIdxs.insert(fieldIdx);
490 else
491 fFieldIdxs.insert(fieldIdx);
492 }
493
494 fPrimaryProcessor->Connect(fFieldIdxs, provenance, updateFields);
495 fAuxiliaryProcessor->Connect(fAuxiliaryFieldIdxs, auxProvenance, updateFields);
496}
497
499{
500 fPrimaryProcessor->Disconnect();
501 fAuxiliaryProcessor->Disconnect();
502}
503
505ROOT::Experimental::RNTupleJoinProcessor::AddFieldToEntry(const std::string &fieldName, const std::string &typeName,
506 void *valuePtr,
507 const Internal::RNTupleProcessorProvenance &provenance)
508{
509 auto auxProvenance = provenance.Evolve(fAuxiliaryProcessor->fOptions.GetProcessorName());
510 if (auxProvenance.IsPresentInFieldName(fieldName)) {
511 // If the primaryProcessor has a field with the name of the auxProcessor (either as a "proper" field or because
512 // the primary processor itself is a join where its auxProcessor bears the same name as the current auxProcessor),
513 // there will be name conflicts, so error out.
514 if (fPrimaryProcessor->CanReadFieldFromDisk(fieldName)) {
515 throw RException(R__FAIL("ambiguous field name: \"" + fieldName +
516 "\" is present in the primary RNTupleProcessor \"" +
517 fPrimaryProcessor->fOptions.GetProcessorName() +
518 "\", but may also refer to a field in the auxiliary RNTupleProcessor named \"" +
519 fAuxiliaryProcessor->fOptions.GetProcessorName() +
520 "\". To avoid this ambiguity, rename the auxiliary RNTupleProcessor."));
521 }
522
523 auto fieldIdx = fAuxiliaryProcessor->AddFieldToEntry(fieldName, typeName, valuePtr, auxProvenance);
524 if (fieldIdx)
525 fAuxiliaryFieldIdxs.insert(fieldIdx);
526 return fieldIdx;
527 } else {
528 auto fieldIdx = fPrimaryProcessor->AddFieldToEntry(fieldName, typeName, valuePtr, provenance);
529 if (fieldIdx)
530 fFieldIdxs.insert(fieldIdx);
531 return fieldIdx;
532 }
533}
534
536{
537 for (const auto &fieldIdx : fAuxiliaryFieldIdxs) {
538 fEntry->SetFieldValidity(fieldIdx, isValid);
539 }
540}
541
543{
544 if (fPrimaryProcessor->LoadEntry(entryNumber) == kInvalidNTupleIndex) {
545 for (auto fieldIdx : fFieldIdxs) {
546 fEntry->SetFieldValidity(fieldIdx, false);
547 }
548 SetAuxiliaryFieldValidity(false);
549 return kInvalidNTupleIndex;
550 }
551
552 fNEntriesProcessed++;
553
554 if (!fJoinTable) {
555 // The auxiliary processor's fields are valid if the entry could be loaded.
556 fAuxiliaryProcessor->LoadEntry(entryNumber);
557 return entryNumber;
558 }
559
560 if (!fJoinTableIsBuilt) {
561 fAuxiliaryProcessor->AddEntriesToJoinTable(*fJoinTable);
562 fJoinTableIsBuilt = true;
563 }
564
565 // Collect the values of the join fields for this entry.
566 std::vector<ROOT::Experimental::Internal::RNTupleJoinTable::JoinValue_t> values;
567 values.reserve(fJoinFieldIdxs.size());
568 for (const auto &fieldIdx : fJoinFieldIdxs) {
569 auto val = fEntry->GetValue(fieldIdx).GetRef<ROOT::Experimental::Internal::RNTupleJoinTable::JoinValue_t>();
570 values.push_back(val);
571 }
572
573 // Find the entry index corresponding to the join field values for each auxiliary processor and load the
574 // corresponding entry.
575 const auto entryIdx = fJoinTable->GetEntryIndex(values);
576
577 if (entryIdx == kInvalidNTupleIndex) {
578 SetAuxiliaryFieldValidity(false);
579 } else {
580 SetAuxiliaryFieldValidity(true);
581 fAuxiliaryProcessor->LoadEntry(entryIdx);
582 }
583
584 return entryNumber;
585}
586
588{
589 if (fNEntries == kInvalidNTupleIndex)
590 fNEntries = fPrimaryProcessor->GetNEntries();
591 return fNEntries;
592}
593
595 ROOT::NTupleSize_t entryOffset)
596{
597 fPrimaryProcessor->AddEntriesToJoinTable(joinTable, entryOffset);
598}
599
601{
602 std::ostringstream primaryStructureStr;
603 fPrimaryProcessor->PrintStructure(primaryStructureStr);
604 const auto primaryStructure = ROOT::Split(primaryStructureStr.str(), "\n", /*skipEmpty=*/true);
605 const auto primaryStructureWidth = primaryStructure.front().size();
606
607 std::ostringstream auxStructureStr;
608 fAuxiliaryProcessor->PrintStructure(auxStructureStr);
609 const auto auxStructure = ROOT::Split(auxStructureStr.str(), "\n", /*skipEmpty=*/true);
610
611 const auto maxLength = std::max(primaryStructure.size(), auxStructure.size());
612 for (unsigned i = 0; i < maxLength; i++) {
613 if (i < primaryStructure.size())
614 output << primaryStructure[i];
615 else
616 output << std::setw(primaryStructureWidth) << "";
617
618 if (i < auxStructure.size())
619 output << " " << auxStructure[i];
620
621 output << "\n";
622 }
623}
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:322
Option_t Option_t width
Builds a join table on one or several fields of an RNTuple so it can be joined onto other RNTuples.
static std::unique_ptr< RNTupleJoinTable > Create(const std::vector< std::string > &joinFieldNames)
Create an RNTupleJoinTable from an existing RNTuple.
RNTupleJoinTable & Add(ROOT::Internal::RPageSource &pageSource, PartitionKey_t partitionKey=kDefaultPartitionKey, ROOT::NTupleSize_t entryOffset=0)
Add an entry mapping to the join table.
static constexpr PartitionKey_t kDefaultPartitionKey
std::string Get() const
Get the full processor provenance, in the form of "x.y.z".
bool IsPresentInFieldName(std::string_view fieldName) const
Check whether the provided field name contains this provenance.
RNTupleProcessorProvenance Evolve(const std::string &processorName) const
Add a new processor to the provenance.
Processor specialization for vertically combined (chained) RNTupleProcessors.
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset=0) final
Add the entry mappings for this processor to the provided join table.
void ConnectInnerProcessor(std::size_t processorNumber)
Update the entry to reflect any missing fields in the current inner processor.
Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(const std::string &fieldName, const std::string &typeName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
ROOT::NTupleSize_t GetNEntries() final
Get the total number of entries in this processor.
void Initialize(std::shared_ptr< Internal::RNTupleProcessorEntry > entry=nullptr) final
Initialize the processor by creating an (initially empty) fEntry, or setting an existing one.
std::vector< ROOT::NTupleSize_t > fInnerNEntries
void Connect(const std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > &fieldIdxs, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance(), bool updateFields=false) final
Connect the provided fields indices in the entry to their on-disk fields.
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided (global) entry number (i.e., considering all RNTuples in th...
void Disconnect() final
Disconnect the processor from associated physical storage.
std::vector< std::unique_ptr< RNTupleProcessor > > fInnerProcessors
Processor specialization for horizontally combined (joined) RNTupleProcessors.
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided entry number of the primary processor.
void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset=0) final
Add the entry mappings for this processor to the provided join table.
void Disconnect() final
Disconnect the processor from associated physical storage.
ROOT::NTupleSize_t GetNEntries() final
Get the total number of entries in this processor.
void SetAuxiliaryFieldValidity(bool validity)
Set the validity for all fields in the auxiliary processor at once.
void Connect(const std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > &fieldIdxs, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance(), bool updateFields=false) final
Connect the provided fields indices in the entry to their on-disk fields.
std::unique_ptr< RNTupleProcessor > fPrimaryProcessor
void Initialize(std::shared_ptr< Internal::RNTupleProcessorEntry > entry=nullptr) final
Initialize the processor by creating an (initially empty) fEntry, or setting an existing one.
Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(const std::string &fieldName, const std::string &typeName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
Specification of the name and location of an RNTuple, used for creating a new RNTupleProcessor.
std::variant< std::string, TDirectory * > fStorage
std::unique_ptr< ROOT::Internal::RPageSource > CreatePageSource() const
Interface for iterating over entries of vertically ("chained") and/or horizontally ("joined") combine...
static std::unique_ptr< RNTupleProcessor > CreateChain(std::vector< RNTupleOpenSpec > ntuples, const RNTupleProcessorOptions &opts=RNTupleProcessorOptions())
Create an RNTupleProcessor for a chain (i.e., a vertical combination) of RNTuples.
static std::unique_ptr< RNTupleProcessor > CreateJoin(RNTupleOpenSpec primaryNTuple, RNTupleOpenSpec auxNTuple, const std::vector< std::string > &joinFields, const RNTupleProcessorOptions &opts=RNTupleProcessorOptions())
Create an RNTupleProcessor for a join (i.e., a horizontal combination) of RNTuples.
static std::unique_ptr< RNTupleProcessor > Create(RNTupleOpenSpec ntuple, const RNTupleProcessorOptions &opts=RNTupleProcessorOptions())
Create an RNTupleProcessor for a single RNTuple.
Processor specialization for processing a single RNTuple.
void AddEntriesToJoinTable(Internal::RNTupleJoinTable &joinTable, ROOT::NTupleSize_t entryOffset=0) final
Add the entry mappings for this processor to the provided join table.
void Connect(const std::unordered_set< Internal::RNTupleProcessorEntry::FieldIndex_t > &fieldIdxs, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance(), bool updateFields=false) final
Connect the provided fields indices in the entry to their on-disk fields.
void Initialize(std::shared_ptr< Internal::RNTupleProcessorEntry > entry=nullptr) final
Initialize the processor by creating an (initially empty) fEntry, or setting an existing one.
void PrintStructureImpl(std::ostream &output) const final
Processor-specific implementation for printing its structure, called by PrintStructure().
void Disconnect() final
Disconnect the processor from associated physical storage.
bool CanReadFieldFromDisk(std::string_view fieldName) final
Check if a field exists on-disk and can be read by the processor.
ROOT::NTupleSize_t LoadEntry(ROOT::NTupleSize_t entryNumber) final
Load the entry identified by the provided (global) entry number (i.e., considering all RNTuples in th...
Internal::RNTupleProcessorEntry::FieldIndex_t AddFieldToEntry(const std::string &fieldName, const std::string &typeName, void *valuePtr=nullptr, const Internal::RNTupleProcessorProvenance &provenance=Internal::RNTupleProcessorProvenance()) final
Add a field to the entry.
std::unique_ptr< ROOT::RFieldBase > CreateAndConnectField(const std::string &qualifiedFieldName, const std::string &typeName)
Create a new field and connect it to the processor's page source.
static std::unique_ptr< RPageSourceFile > CreateFromAnchor(const RNTuple &anchor, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Used from the RNTuple class to build a datasource if the anchor is already available.
static std::unique_ptr< RPageSource > Create(std::string_view ntupleName, std::string_view location, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Guess the concrete derived page source from the file name (location)
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId)
Factory method to resurrect a field from the stored on-disk type information.
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:58
std::vector< std::unique_ptr< RFieldBase > > ReleaseSubfields()
Moves all subfields into the returned vector.
Definition RField.cxx:64
void Attach(std::unique_ptr< RFieldBase > child)
A public version of the Attach method that allows piece-wise construction of the zero field.
Definition RField.cxx:40
Representation of an RNTuple data set in a ROOT file.
Definition RNTuple.hxx:67
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:35
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
constexpr NTupleSize_t kInvalidNTupleIndex
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
constexpr DescriptorId_t kInvalidDescriptorId