Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RNTupleReader.cxx
Go to the documentation of this file.
1/// \file RNTupleReader.cxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2024-02-20
4
5/*************************************************************************
6 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
14
15#include <ROOT/RField.hxx>
19#include <ROOT/RNTuple.hxx>
20#include <ROOT/RNTupleModel.hxx>
22
23#include <TROOT.h>
24
25#include <cassert>
26
28{
29 const auto descGuard = fPtrControlBlock->fPageSource->GetSharedDescriptorGuard();
30 const auto clusterId = Internal::CallFindClusterIdOn(descGuard.GetRef(), entryNumber);
31 if (clusterId == kInvalidDescriptorId)
32 throw RException(R__FAIL(std::string("entry number ") + std::to_string(entryNumber) + " out of range"));
33
34 auto [itr, _] = fPtrControlBlock->fActiveClusters.try_emplace(clusterId, 0);
35 if (itr->second++ == 0)
36 fPtrControlBlock->fPageSource->PinCluster(clusterId);
37}
38
40{
41 const auto descGuard = fPtrControlBlock->fPageSource->GetSharedDescriptorGuard();
42 const auto clusterId = Internal::CallFindClusterIdOn(descGuard.GetRef(), entryNumber);
43
44 if (clusterId == kInvalidDescriptorId)
45 throw RException(R__FAIL(std::string("entry number ") + std::to_string(entryNumber) + " out of range"));
46
47 auto itr = fPtrControlBlock->fActiveClusters.find(clusterId);
48 assert(itr != fPtrControlBlock->fActiveClusters.end());
49
50 if (--(itr->second) == 0) {
51 fPtrControlBlock->fActiveClusters.erase(itr);
52 fPtrControlBlock->fPageSource->UnpinCluster(clusterId);
53 }
54}
55
57{
58 if (entryNumber == fEntryNumber || entryNumber == kInvalidNTupleIndex)
59 return;
60
61 const std::lock_guard<std::mutex> _(fPtrControlBlock->fLock);
62 if (fPtrControlBlock->fPageSource) {
63 ActivateEntry(entryNumber);
66 }
67 fEntryNumber = entryNumber;
68}
69
71{
73 return;
74
75 const std::lock_guard<std::mutex> _(fPtrControlBlock->fLock);
76 if (fPtrControlBlock->fPageSource) {
78 }
80}
81
87
89{
90 std::swap(fEntryNumber, other.fEntryNumber);
91 std::swap(fPtrControlBlock, other.fPtrControlBlock);
92 assert(other.fEntryNumber == kInvalidNTupleIndex);
93 assert(!other.fPtrControlBlock);
94}
95
98{
99 if (this == &other)
100 return *this;
101 if (other.fPtrControlBlock.get() != fPtrControlBlock.get()) {
102 Reset();
104 }
106 return *this;
107}
108
110{
111 std::swap(fEntryNumber, other.fEntryNumber);
112 std::swap(fPtrControlBlock, other.fPtrControlBlock);
113 return *this;
114}
115
116void ROOT::RNTupleReader::ConnectModel(ROOT::RNTupleModel &model, bool allowFieldSubstitutions)
117{
118 auto &fieldZero = ROOT::Internal::GetFieldZeroOfModel(model);
119 ROOT::Internal::SetAllowFieldSubstitutions(fieldZero, allowFieldSubstitutions);
120 // We must not use the descriptor guard to prevent recursive locking in field.ConnectPageSource
121 ROOT::DescriptorId_t fieldZeroId = fSource->GetSharedDescriptorGuard()->GetFieldZeroId();
122 fieldZero.SetOnDiskId(fieldZeroId);
123 // Iterate only over fieldZero's direct subfields; their descendants are recursively handled in
124 // RFieldBase::ConnectPageSource
125 for (auto &field : fieldZero.GetMutableSubfields()) {
126 // If the model has been created from the descriptor, the on-disk IDs are already set.
127 // User-provided models instead need to find their corresponding IDs in the descriptor.
128 if (field->GetOnDiskId() == ROOT::kInvalidDescriptorId) {
129 field->SetOnDiskId(fSource->GetSharedDescriptorGuard()->FindFieldId(field->GetFieldName(), fieldZeroId));
130 }
132 }
134}
135
137{
138#ifdef R__USE_IMT
139 if (IsImplicitMTEnabled() &&
140 fSource->GetReadOptions().GetUseImplicitMT() == ROOT::RNTupleReadOptions::EImplicitMT::kDefault) {
141 fUnzipTasks = std::make_unique<Experimental::Internal::RNTupleImtTaskScheduler>();
142 fSource->SetTaskScheduler(fUnzipTasks.get());
143 }
144#endif
145 fMetrics.ObserveMetrics(fSource->GetMetrics());
146 if (enableMetrics)
148 fSource->Attach();
149 fNEntries = fSource->GetNEntries();
150 fActiveEntriesControlBlock = std::make_shared<RActiveEntriesControlBlock>(fSource.get());
151}
152
153ROOT::RNTupleReader::RNTupleReader(std::unique_ptr<ROOT::RNTupleModel> model,
154 std::unique_ptr<ROOT::Internal::RPageSource> source,
155 const ROOT::RNTupleReadOptions &options)
156 : fSource(std::move(source)), fModel(std::move(model)), fMetrics("RNTupleReader")
157{
158 // TODO(jblomer): properly support projected fields
159 auto &projectedFields = ROOT::Internal::GetProjectedFieldsOfModel(*fModel);
160 if (!projectedFields.IsEmpty()) {
161 throw RException(R__FAIL("model has projected fields, which is incompatible with providing a read model"));
162 }
163 fModel->Freeze();
165 ConnectModel(*fModel, false /* allowFieldSubstitutions */);
166}
167
168ROOT::RNTupleReader::RNTupleReader(std::unique_ptr<ROOT::Internal::RPageSource> source,
169 const ROOT::RNTupleReadOptions &options)
170 : fSource(std::move(source)), fModel(nullptr), fMetrics("RNTupleReader")
171{
173}
174
176{
177 const std::lock_guard<std::mutex> _(fActiveEntriesControlBlock->fLock);
178 fActiveEntriesControlBlock->fPageSource = nullptr;
179}
180
181std::unique_ptr<ROOT::RNTupleReader> ROOT::RNTupleReader::Open(std::unique_ptr<ROOT::RNTupleModel> model,
182 std::string_view ntupleName, std::string_view storage,
183 const ROOT::RNTupleReadOptions &options)
184{
185 return std::unique_ptr<RNTupleReader>(
186 new RNTupleReader(std::move(model), Internal::RPageSource::Create(ntupleName, storage, options), options));
187}
188
189std::unique_ptr<ROOT::RNTupleReader> ROOT::RNTupleReader::Open(std::string_view ntupleName, std::string_view storage,
190 const ROOT::RNTupleReadOptions &options)
191{
192 return std::unique_ptr<RNTupleReader>(
193 new RNTupleReader(Internal::RPageSource::Create(ntupleName, storage, options), options));
194}
195
196std::unique_ptr<ROOT::RNTupleReader>
198{
199 return std::unique_ptr<RNTupleReader>(
200 new RNTupleReader(Internal::RPageSourceFile::CreateFromAnchor(ntuple, options), options));
201}
202
203std::unique_ptr<ROOT::RNTupleReader> ROOT::RNTupleReader::Open(std::unique_ptr<ROOT::RNTupleModel> model,
204 const ROOT::RNTuple &ntuple,
205 const ROOT::RNTupleReadOptions &options)
206{
207 return std::unique_ptr<RNTupleReader>(
208 new RNTupleReader(std::move(model), Internal::RPageSourceFile::CreateFromAnchor(ntuple, options), options));
209}
210
211std::unique_ptr<ROOT::RNTupleReader>
213 std::string_view ntupleName, std::string_view storage,
214 const ROOT::RNTupleReadOptions &options)
215{
216 auto reader = std::unique_ptr<RNTupleReader>(
217 new RNTupleReader(Internal::RPageSource::Create(ntupleName, storage, options), options));
218 reader->fCreateModelOptions = createModelOpts;
219 return reader;
220}
221
222std::unique_ptr<ROOT::RNTupleReader>
224 const ROOT::RNTuple &ntuple, const ROOT::RNTupleReadOptions &options)
225{
226 auto reader = std::unique_ptr<RNTupleReader>(
227 new RNTupleReader(Internal::RPageSourceFile::CreateFromAnchor(ntuple, options), options));
228 reader->fCreateModelOptions = createModelOpts;
229 return reader;
230}
231
233{
234 if (!fModel) {
235 fModel = fSource->GetSharedDescriptorGuard()->CreateModel(
237 ConnectModel(*fModel, true /* allowFieldSubstitutions */);
238 }
239 return *fModel;
240}
241
242std::unique_ptr<ROOT::REntry> ROOT::RNTupleReader::CreateEntry()
243{
244 return GetModel().CreateEntry();
245}
246
247void ROOT::RNTupleReader::PrintInfo(const ENTupleInfo what, std::ostream &output) const
248{
249 using namespace ROOT::Internal;
250
251 switch (what) {
253 std::string name;
254 std::unique_ptr<ROOT::RNTupleModel> fullModel;
255 {
256 auto descriptorGuard = fSource->GetSharedDescriptorGuard();
257 name = descriptorGuard->GetName();
259 opts.SetCreateBare(true);
260 // When printing the schema we always try to reconstruct the whole thing even when we are missing the
261 // dictionaries.
262 opts.SetEmulateUnknownTypes(true);
263 fullModel = descriptorGuard->CreateModel(opts);
264 }
265
266 // FitString defined in RFieldVisitor.cxx
267 output << "RNTuple : " << name << "\n";
268 output << "Entries : " << GetNEntries() << "\n\n";
269
270 // Traverses through all fields to gather information needed for printing.
271 RPrepareVisitor prepVisitor;
272 // Traverses through all fields to do the actual printing.
273 RPrintSchemaVisitor printVisitor(output);
274
275 // Note that we do not need to connect the model, we are only looking at its tree of fields
276 fullModel->GetConstFieldZero().AcceptVisitor(prepVisitor);
277
278 printVisitor.SetDeepestLevel(prepVisitor.GetDeepestLevel());
279 printVisitor.SetNumFields(prepVisitor.GetNumFields());
280
281 fullModel->GetConstFieldZero().AcceptVisitor(printVisitor);
282 output << std::flush;
283 break;
284 }
285 case ENTupleInfo::kStorageDetails: fSource->GetSharedDescriptorGuard()->PrintInfo(output); break;
286 case ENTupleInfo::kMetrics: fMetrics.Print(output); break;
287 default:
288 // Unhandled case, internal error
289 R__ASSERT(false);
290 }
291}
292
294{
295 if (!fDisplayReader) {
297 opts.SetEmulateUnknownTypes(true);
298 auto fullModel = fSource->GetSharedDescriptorGuard()->CreateModel(opts);
299 fDisplayReader = std::unique_ptr<RNTupleReader>(
300 new RNTupleReader(std::move(fullModel), fSource->Clone(), ROOT::RNTupleReadOptions{}));
301 }
302 return fDisplayReader.get();
303}
304
305void ROOT::RNTupleReader::Show(ROOT::NTupleSize_t index, std::ostream &output)
306{
307 auto reader = GetDisplayReader();
308 const auto &entry = reader->GetModel().GetDefaultEntry();
309
310 reader->LoadEntry(index);
311 output << "{";
312 for (auto iValue = entry.begin(); iValue != entry.end();) {
313 output << std::endl;
314 ROOT::Internal::RPrintValueVisitor visitor(*iValue, output, 1 /* level */);
315 iValue->GetField().AcceptVisitor(visitor);
316
317 if (++iValue == entry.end()) {
318 output << std::endl;
319 break;
320 } else {
321 output << ",";
322 }
323 }
324 output << "}" << std::endl;
325}
326
328{
329 auto descriptorGuard = fSource->GetSharedDescriptorGuard();
330 if (!fCachedDescriptor || fCachedDescriptor->GetGeneration() != descriptorGuard->GetGeneration())
331 fCachedDescriptor = descriptorGuard->Clone();
332 return *fCachedDescriptor;
333}
334
336{
337 auto fieldId = fSource->GetSharedDescriptorGuard()->FindFieldId(fieldName);
338 if (fieldId == ROOT::kInvalidDescriptorId) {
339 throw RException(R__FAIL("no field named '" + std::string(fieldName) + "' in RNTuple '" +
340 fSource->GetSharedDescriptorGuard()->GetName() + "'"));
341 }
342 return fieldId;
343}
344
345std::unique_ptr<ROOT::Experimental::RNTupleAttrSetReader>
346ROOT::RNTupleReader::OpenAttributeSet(std::string_view attrSetName, const ROOT::RNTupleReadOptions &readOpts)
347{
348 auto attrSets = GetDescriptor().GetAttrSetIterable();
349 const auto it =
350 std::find_if(attrSets.begin(), attrSets.end(), [&](const auto &d) { return d.GetName() == attrSetName; });
351 if (it == attrSets.end())
352 throw ROOT::RException(R__FAIL(std::string("No such attribute set: ") + std::string(attrSetName)));
353
354 auto attrSource = fSource->OpenWithDifferentAnchor({it->GetAnchorLocator(), it->GetAnchorLength()}, readOpts);
355 auto newReader = std::unique_ptr<RNTupleReader>(new RNTupleReader(std::move(attrSource), readOpts));
356 R__ASSERT(newReader);
357 auto attrSetReader = std::unique_ptr<ROOT::Experimental::RNTupleAttrSetReader>(
358 new ROOT::Experimental::RNTupleAttrSetReader(std::move(newReader), it->GetSchemaVersionMajor()));
359 return attrSetReader;
360}
#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:299
#define d(i)
Definition RSha256.hxx:102
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
char name[80]
Definition TGX11.cxx:148
#define _(A, B)
Definition cfortran.h:108
Class used to read a RNTupleAttrSet in the context of a RNTupleReader.
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).
Visitor used for a pre-processing run to collect information needed by another visitor class.
unsigned int GetDeepestLevel() const
unsigned int GetNumFields() const
Contains settings for printing and prints a summary of an RField instance.
Renders a JSON value corresponding to the field.
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
The on-storage metadata of an RNTuple.
The RNTupleModel encapulates the schema of an RNTuple.
Common user-tunable settings for reading RNTuples.
An active entry token is a pledge for the data of a certain entry number not to be evicted from the p...
std::shared_ptr< RActiveEntriesControlBlock > fPtrControlBlock
RActiveEntryToken & operator=(const RActiveEntryToken &other)
void ActivateEntry(NTupleSize_t entryNumber)
void Reset()
Release the entry number, i.e.
RActiveEntryToken(std::shared_ptr< RActiveEntriesControlBlock > ptrControlBlock)
void DeactivateEntry(NTupleSize_t entryNumber)
void SetEntryNumber(NTupleSize_t entryNumber)
Set or replace the entry number.
Reads RNTuple data from storage.
std::unique_ptr< RNTupleReader > fDisplayReader
We use a dedicated on-demand reader for Show().
std::unique_ptr< ROOT::REntry > CreateEntry()
static std::unique_ptr< RNTupleReader > Open(std::string_view ntupleName, std::string_view storage, const ROOT::RNTupleReadOptions &options=ROOT::RNTupleReadOptions())
Open an RNTuple for reading.
void InitPageSource(bool enableMetrics)
std::unique_ptr< Internal::RPageStorage::RTaskScheduler > fUnzipTasks
Set as the page source's scheduler for parallel page decompression if implicit multi-threading (IMT) ...
ROOT::NTupleSize_t fNEntries
We know that the RNTupleReader is always reading a single RNTuple, so the number of entries is fixed.
std::unique_ptr< ROOT::RNTupleModel > fModel
Needs to be destructed before fSource.
const ROOT::RNTupleDescriptor & GetDescriptor()
Returns a cached copy of the page source descriptor.
std::optional< ROOT::RNTupleDescriptor::RCreateModelOptions > fCreateModelOptions
If not nullopt, these will be used when creating the model.
void PrintInfo(const ENTupleInfo what=ENTupleInfo::kSummary, std::ostream &output=std::cout) const
Prints a detailed summary of the RNTuple, including a list of fields.
std::unique_ptr< Internal::RPageSource > fSource
RNTupleReader(std::unique_ptr< ROOT::RNTupleModel > model, std::unique_ptr< Internal::RPageSource > source, const ROOT::RNTupleReadOptions &options)
const ROOT::RNTupleModel & GetModel()
std::unique_ptr< Experimental::RNTupleAttrSetReader > OpenAttributeSet(std::string_view attrSetName, const ROOT::RNTupleReadOptions &options={})
Looks for an attribute set with the given name and creates an RNTupleAttrSetReader for it,...
std::optional< ROOT::RNTupleDescriptor > fCachedDescriptor
The RNTuple descriptor in the page source is protected by a read-write lock.
std::shared_ptr< RActiveEntriesControlBlock > fActiveEntriesControlBlock
Initialized when the page source is connected.
void ConnectModel(ROOT::RNTupleModel &model, bool allowFieldSubstitutions)
ROOT::NTupleSize_t GetNEntries() const
Returns the number of entries in this RNTuple.
ROOT::DescriptorId_t RetrieveFieldId(std::string_view fieldName) const
void Show(ROOT::NTupleSize_t index, std::ostream &output=std::cout)
Shows the values of the i-th entry/row, starting with 0 for the first entry.
RNTupleReader * GetDisplayReader()
Experimental::Detail::RNTupleMetrics fMetrics
void EnableMetrics()
Enable performance measurements (decompression time, bytes read from storage, etc....
Representation of an RNTuple data set in a ROOT file.
Definition RNTuple.hxx:67
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:35
ROOT::RFieldZero & GetFieldZeroOfModel(RNTupleModel &model)
ROOT::DescriptorId_t CallFindClusterIdOn(const ROOT::RNTupleDescriptor &desc, ROOT::NTupleSize_t entryIdx)
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
RProjectedFields & GetProjectedFieldsOfModel(RNTupleModel &model)
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:669
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
constexpr NTupleSize_t kInvalidNTupleIndex
ENTupleInfo
Listing of the different options that can be printed by RNTupleReader::GetInfo().
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
constexpr DescriptorId_t kInvalidDescriptorId
static const char * what
Definition stlLoader.cc:5