Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RPageStorageFile.cxx
Go to the documentation of this file.
1/// \file RPageStorageFile.cxx
2/// \ingroup NTuple
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2019-11-25
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#include <ROOT/RCluster.hxx>
15#include <ROOT/RLogger.hxx>
17#include <ROOT/RNTupleModel.hxx>
19#include <ROOT/RNTupleZip.hxx>
20#include <ROOT/RPage.hxx>
22#include <ROOT/RPagePool.hxx>
24#include <ROOT/RRawFile.hxx>
26#include <ROOT/RNTupleTypes.hxx>
27#include <ROOT/RNTupleUtils.hxx>
28
29#include <RVersion.h>
30#include <TDirectory.h>
31#include <TError.h>
33
34#include <algorithm>
35#include <cstdio>
36#include <cstdlib>
37#include <cstring>
38#include <iterator>
39#include <limits>
40#include <utility>
41
42#include <functional>
43#include <mutex>
44
59
61 : RPagePersistentSink(ntupleName, options)
62{
63 EnableDefaultMetrics("RPageSinkFile");
64 fFeatures.fCanMergePages = true;
65}
66
67ROOT::Internal::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, std::string_view path,
68 const ROOT::RNTupleWriteOptions &options)
69 : RPageSinkFile(ntupleName, options)
70{
72}
73
74ROOT::Internal::RPageSinkFile::RPageSinkFile(std::string_view ntupleName, TDirectory &fileOrDirectory,
75 const ROOT::RNTupleWriteOptions &options)
76 : RPageSinkFile(ntupleName, options)
77{
78 fWriter = RNTupleFileWriter::Append(ntupleName, fileOrDirectory, options.GetMaxKeySize(), /*hidden=*/false);
79}
80
82 std::string_view ntupleDir, const ROOT::RNTupleWriteOptions &options)
83 : RPageSinkFile(ntupleName, options)
84{
85 fWriter = RNTupleFileWriter::Append(ntupleName, file, ntupleDir, options.GetMaxKeySize());
86}
87
88ROOT::Internal::RPageSinkFile::RPageSinkFile(std::unique_ptr<ROOT::Internal::RNTupleFileWriter> writer,
89 const ROOT::RNTupleWriteOptions &options)
91{
92 fWriter = std::move(writer);
93}
94
96
97void ROOT::Internal::RPageSinkFile::InitImpl(unsigned char *serializedHeader, std::uint32_t length)
98{
99 auto zipBuffer = MakeUninitArray<unsigned char>(length);
100 auto szZipHeader =
101 RNTupleCompressor::Zip(serializedHeader, length, GetWriteOptions().GetCompression(), zipBuffer.get());
102 fWriter->WriteNTupleHeader(zipBuffer.get(), szZipHeader, length);
103}
104
106 ROOT::NTupleSize_t firstEntry)
107{
108 RPagePersistentSink::UpdateSchema(changeset, firstEntry);
109
110 auto fnAddStreamerInfo = [this](const ROOT::RFieldBase *field) {
111 const TClass *cl = nullptr;
112 if (auto classField = dynamic_cast<const RClassField *>(field)) {
113 cl = classField->GetClass();
114 } else if (auto streamerField = dynamic_cast<const RStreamerField *>(field)) {
115 cl = streamerField->GetClass();
116 } else if (auto soaField = dynamic_cast<const ROOT::Experimental::RSoAField *>(field)) {
117 cl = soaField->GetSoAClass();
118 }
119 if (!cl)
120 return;
121
122 auto streamerInfo = cl->GetStreamerInfo(field->GetTypeVersion());
123 if (!streamerInfo) {
124 throw RException(R__FAIL(std::string("cannot get streamerInfo for ") + cl->GetName() + " [" +
125 std::to_string(field->GetTypeVersion()) + "]"));
126 }
127 fInfosOfClassFields[streamerInfo->GetNumber()] = streamerInfo;
128 };
129
130 for (const auto field : changeset.fAddedFields) {
131 fnAddStreamerInfo(field);
132 for (const auto &subField : *field) {
133 fnAddStreamerInfo(&subField);
134 }
135 }
136}
137
140{
141 std::uint64_t offsetData;
142 {
143 RNTupleAtomicTimer timer(fCounters->fTimeWallWrite, fCounters->fTimeCpuWrite);
144 offsetData = fWriter->WriteBlob(sealedPage.GetBuffer(), sealedPage.GetBufferSize(), bytesPacked);
145 }
146
148 result.SetPosition(offsetData);
149 result.SetNBytesOnStorage(sealedPage.GetDataSize());
150 fCounters->fNPageCommitted.Inc();
151 fCounters->fSzWritePayload.Add(sealedPage.GetBufferSize());
152 fNBytesCurrentCluster += sealedPage.GetBufferSize();
153 return result;
154}
155
158{
159 auto element = columnHandle.fColumn->GetElement();
160 RPageStorage::RSealedPage sealedPage;
161 {
162 RNTupleAtomicTimer timer(fCounters->fTimeWallZip, fCounters->fTimeCpuZip);
163 sealedPage = SealPage(page, *element);
164 }
165
166 fCounters->fSzZip.Add(page.GetNBytes());
167 return WriteSealedPage(sealedPage, element->GetPackedSize(page.GetNElements()));
168}
169
171 const RPageStorage::RSealedPage &sealedPage)
172{
173 const auto nBits = fDescriptorBuilder.GetDescriptor().GetColumnDescriptor(physicalColumnId).GetBitsOnStorage();
174 const auto bytesPacked = (nBits * sealedPage.GetNElements() + 7) / 8;
175 return WriteSealedPage(sealedPage, bytesPacked);
176}
177
178void ROOT::Internal::RPageSinkFile::CommitBatchOfPages(CommitBatch &batch, std::vector<RNTupleLocator> &locators)
179{
180 RNTupleAtomicTimer timer(fCounters->fTimeWallWrite, fCounters->fTimeCpuWrite);
181
182 std::uint64_t offset = fWriter->ReserveBlob(batch.fSize, batch.fBytesPacked);
183
184 locators.reserve(locators.size() + batch.fSealedPages.size());
185
186 for (const auto *pagePtr : batch.fSealedPages) {
187 fWriter->WriteIntoReservedBlob(pagePtr->GetBuffer(), pagePtr->GetBufferSize(), offset);
188 RNTupleLocator locator;
189 locator.SetPosition(offset);
190 locator.SetNBytesOnStorage(pagePtr->GetDataSize());
191 locators.push_back(locator);
192 offset += pagePtr->GetBufferSize();
193 }
194
195 fCounters->fNPageCommitted.Add(batch.fSealedPages.size());
196 fCounters->fSzWritePayload.Add(batch.fSize);
198
199 batch.fSize = 0;
200 batch.fBytesPacked = 0;
201 batch.fSealedPages.clear();
202}
203
204std::vector<ROOT::RNTupleLocator>
205ROOT::Internal::RPageSinkFile::CommitSealedPageVImpl(std::span<RPageStorage::RSealedPageGroup> ranges,
206 const std::vector<bool> &mask)
207{
208 const std::uint64_t maxKeySize = fOptions->GetMaxKeySize();
209
210 CommitBatch batch{};
211 std::vector<RNTupleLocator> locators;
212
213 std::size_t iPage = 0;
214 for (auto rangeIt = ranges.begin(); rangeIt != ranges.end(); ++rangeIt) {
215 auto &range = *rangeIt;
216 if (range.fFirst == range.fLast) {
217 // Skip empty ranges, they might not have a physical column ID!
218 continue;
219 }
220
221 const auto bitsOnStorage =
222 fDescriptorBuilder.GetDescriptor().GetColumnDescriptor(range.fPhysicalColumnId).GetBitsOnStorage();
223
224 for (auto sealedPageIt = range.fFirst; sealedPageIt != range.fLast; ++sealedPageIt, ++iPage) {
225 if (!mask[iPage])
226 continue;
227
228 const auto bytesPacked = (bitsOnStorage * sealedPageIt->GetNElements() + 7) / 8;
229
230 if (batch.fSize > 0 && batch.fSize + sealedPageIt->GetBufferSize() > maxKeySize) {
231 /**
232 * Adding this page would exceed maxKeySize. Since we always want to write into a single key
233 * with vectorized writes, we commit the current set of pages before proceeding.
234 * NOTE: we do this *before* checking if sealedPageIt->GetBufferSize() > maxKeySize to guarantee that
235 * we always flush the current batch before doing an individual WriteBlob. This way we
236 * preserve the assumption that a CommitBatch always contain a sequential set of pages.
237 */
238 CommitBatchOfPages(batch, locators);
239 }
240
241 if (sealedPageIt->GetBufferSize() > maxKeySize) {
242 // This page alone is bigger than maxKeySize: save it by itself, since it will need to be
243 // split into multiple keys.
244
245 // Since this check implies the previous check on batchSize + newSize > maxSize, we should
246 // already have committed the current batch before writing this page.
247 assert(batch.fSize == 0);
248
249 std::uint64_t offset =
250 fWriter->WriteBlob(sealedPageIt->GetBuffer(), sealedPageIt->GetBufferSize(), bytesPacked);
251 RNTupleLocator locator;
252 locator.SetPosition(offset);
253 locator.SetNBytesOnStorage(sealedPageIt->GetDataSize());
254 locators.push_back(locator);
255
256 fCounters->fNPageCommitted.Inc();
257 fCounters->fSzWritePayload.Add(sealedPageIt->GetBufferSize());
258 fNBytesCurrentCluster += sealedPageIt->GetBufferSize();
259
260 } else {
261 batch.fSealedPages.emplace_back(&(*sealedPageIt));
262 batch.fSize += sealedPageIt->GetBufferSize();
263 batch.fBytesPacked += bytesPacked;
264 }
265 }
266 }
267
268 if (batch.fSize > 0) {
269 CommitBatchOfPages(batch, locators);
270 }
271
272 return locators;
273}
274
281
283ROOT::Internal::RPageSinkFile::CommitClusterGroupImpl(unsigned char *serializedPageList, std::uint32_t length)
284{
285 auto bufPageListZip = MakeUninitArray<unsigned char>(length);
286 auto szPageListZip =
287 RNTupleCompressor::Zip(serializedPageList, length, GetWriteOptions().GetCompression(), bufPageListZip.get());
288
290 result.SetNBytesOnStorage(szPageListZip);
291 result.SetPosition(fWriter->WriteBlob(bufPageListZip.get(), szPageListZip, length));
292 return result;
293}
294
296ROOT::Internal::RPageSinkFile::CommitDatasetImpl(unsigned char *serializedFooter, std::uint32_t length)
297{
298 // Add the streamer info records from streamer fields: because of runtime polymorphism we may need to add additional
299 // types not covered by the type names of the class fields
300 for (const auto &extraTypeInfo : fDescriptorBuilder.GetDescriptor().GetExtraTypeInfoIterable()) {
301 if (extraTypeInfo.GetContentId() != EExtraTypeInfoIds::kStreamerInfo)
302 continue;
303 // Ideally, we would avoid deserializing the streamer info records of the streamer fields that we just serialized.
304 // However, this happens only once at the end of writing and only when streamer fields are used, so the
305 // preference here is for code simplicity.
306 fInfosOfClassFields.merge(RNTupleSerializer::DeserializeStreamerInfos(extraTypeInfo.GetContent()).Unwrap());
307 }
308 fWriter->UpdateStreamerInfos(fInfosOfClassFields);
309
310 auto bufFooterZip = MakeUninitArray<unsigned char>(length);
311 auto szFooterZip =
312 RNTupleCompressor::Zip(serializedFooter, length, GetWriteOptions().GetCompression(), bufFooterZip.get());
313 fWriter->WriteNTupleFooter(bufFooterZip.get(), szFooterZip, length);
314 return fWriter->Commit(GetWriteOptions().GetCompression());
315}
316
317std::unique_ptr<ROOT::Internal::RPageSink>
319{
320 auto writer = fWriter->CloneAsHidden(name);
321 auto cloned = std::unique_ptr<RPageSinkFile>(new RPageSinkFile(std::move(writer), opts));
322 return cloned;
323}
324
325////////////////////////////////////////////////////////////////////////////////
326
328 : RPageSource(ntupleName, opts)
329{
330 EnableDefaultMetrics("RPageSourceFile");
331 fFileCounters = std::make_unique<RFileCounters>(RFileCounters{
332 *fMetrics.MakeCounter<RNTupleAtomicCounter *>("szSkip", "B",
333 "cumulative seek distance (excluding header/footer reads)"),
334 *fMetrics.MakeCounter<RNTupleCalcPerf *>(
335 "szFile", "B", "total file size", fMetrics,
336 [this](const RNTupleMetrics &) -> std::pair<bool, double> {
337 if (fFileSize > 0)
338 return {true, static_cast<double>(fFileSize)};
339 return {false, -1.};
340 }),
341 *fMetrics.MakeCounter<RNTupleCalcPerf *>(
342 "randomness", "",
343 "ratio of seek distance to bytes read (excluding file structure reads)", fMetrics,
344 [](const RNTupleMetrics &metrics) -> std::pair<bool, double> {
345 if (const auto szSkip = metrics.GetLocalCounter("szSkip")) {
346 if (const auto szReadPayload = metrics.GetLocalCounter("szReadPayload")) {
347 if (const auto szReadOverhead = metrics.GetLocalCounter("szReadOverhead")) {
348 auto totalRead = szReadPayload->GetValueAsInt() + szReadOverhead->GetValueAsInt();
349 if (totalRead > 0) {
350 return {true, (1. * szSkip->GetValueAsInt()) / totalRead};
351 }
352 }
353 }
354 }
355 return {false, -1.};
356 }),
357 *fMetrics.MakeCounter<RNTupleCalcPerf *>(
358 "sparseness", "",
359 "ratio of bytes read to total file size (excluding file structure reads)", fMetrics,
360 [this](const RNTupleMetrics &metrics) -> std::pair<bool, double> {
361 if (fFileSize > 0) {
362 if (const auto szReadPayload = metrics.GetLocalCounter("szReadPayload")) {
363 if (const auto szReadOverhead = metrics.GetLocalCounter("szReadOverhead")) {
364 auto totalRead = szReadPayload->GetValueAsInt() + szReadOverhead->GetValueAsInt();
365 return {true, (1. * totalRead) / fFileSize};
366 }
367 }
368 }
369 return {false, -1.};
370 })});
371}
372
374 std::unique_ptr<ROOT::Internal::RRawFile> file,
375 const ROOT::RNTupleReadOptions &options)
376 : RPageSourceFile(ntupleName, options)
377{
378 fFile = std::move(file);
381}
382
383ROOT::Internal::RPageSourceFile::RPageSourceFile(std::string_view ntupleName, std::string_view path,
384 const ROOT::RNTupleReadOptions &options)
385 : RPageSourceFile(ntupleName, ROOT::Internal::RRawFile::Create(path), options)
386{
387}
388
389std::unique_ptr<ROOT::Internal::RPageSourceFile>
391{
392 if (!anchor.fFile)
393 throw RException(R__FAIL("This RNTuple object was not streamed from a ROOT file (TFile or descendant)"));
394
395 std::unique_ptr<ROOT::Internal::RRawFile> rawFile;
396 // For local TFiles, TDavixFile, TCurlFile, and TNetXNGFile, we want to open a new RRawFile to take advantage of the
397 // faster reading. We check the exact class name to avoid classes inheriting in ROOT (for example TMemFile) or in
398 // experiment frameworks.
399 std::string className = anchor.fFile->IsA()->GetName();
400 auto url = anchor.fFile->GetEndpointUrl();
401 auto protocol = std::string(url->GetProtocol());
402 if (className == "TFile") {
403 rawFile = ROOT::Internal::RRawFile::Create(url->GetFile());
404 } else if (className == "TDavixFile" || className == "TCurlFile" || className == "TNetXNGFile") {
405 rawFile = ROOT::Internal::RRawFile::Create(url->GetUrl());
406 } else {
407 rawFile.reset(new ROOT::Internal::RRawFileTFile(anchor.fFile));
408 }
409
410 auto pageSource = std::make_unique<RPageSourceFile>("", std::move(rawFile), options);
411 pageSource->fAnchor = anchor;
412 // NOTE: fNTupleName gets set only upon Attach().
413 return pageSource;
414}
415
420
421std::unique_ptr<ROOT::Internal::RPageSource>
423 const ROOT::RNTupleReadOptions &options)
424{
425 assert(anchorLink.fLocator.GetType() == RNTupleLocator::kTypeFile);
426
427 const auto anchorPos = anchorLink.fLocator.GetPosition<std::uint64_t>();
428 auto anchor =
429 fReader.GetNTupleProperAtOffset(anchorPos, anchorLink.fLocator.GetNBytesOnStorage(), anchorLink.fLength).Unwrap();
430 auto pageSource = std::make_unique<RPageSourceFile>("", fFile->Clone(), options);
431 pageSource->fAnchor = anchor;
432 // NOTE: fNTupleName gets set only upon Attach().
433 return pageSource;
434}
435
437{
438 // If we constructed the page source with (ntuple name, path), we need to find the anchor first.
439 // Otherwise, the page source was created by OpenFromAnchor()
440 if (!fAnchor) {
441 fAnchor = fReader.GetNTuple(fNTupleName).Unwrap();
442 }
443 fReader.SetMaxKeySize(fAnchor->GetMaxKeySize());
444
445 fDescriptorBuilder.SetVersion(fAnchor->GetVersionEpoch(), fAnchor->GetVersionMajor(), fAnchor->GetVersionMinor(),
446 fAnchor->GetVersionPatch());
447 fDescriptorBuilder.SetOnDiskHeaderSize(fAnchor->GetNBytesHeader());
448 fDescriptorBuilder.AddToOnDiskFooterSize(fAnchor->GetNBytesFooter());
449
450 // Reserve enough space for the compressed and the uncompressed header/footer (see AttachImpl)
451 const auto bufSize = fAnchor->GetNBytesHeader() + fAnchor->GetNBytesFooter() +
452 std::max(fAnchor->GetLenHeader(), fAnchor->GetLenFooter());
454 fStructureBuffer.fPtrHeader = fStructureBuffer.fBuffer.get();
455 fStructureBuffer.fPtrFooter = fStructureBuffer.fBuffer.get() + fAnchor->GetNBytesHeader();
456
457 auto readvLimits = fFile->GetReadVLimits();
458 // Never try to vectorize reads to a split key
459 readvLimits.fMaxSingleSize = std::min<size_t>(readvLimits.fMaxSingleSize, fAnchor->GetMaxKeySize());
460
461 if ((readvLimits.fMaxReqs < 2) ||
462 (std::max(fAnchor->GetNBytesHeader(), fAnchor->GetNBytesFooter()) > readvLimits.fMaxSingleSize) ||
463 (fAnchor->GetNBytesHeader() + fAnchor->GetNBytesFooter() > readvLimits.fMaxTotalSize)) {
464 RNTupleAtomicTimer timer(fCounters->fTimeWallRead, fCounters->fTimeCpuRead);
465 fReader.ReadBuffer(fStructureBuffer.fPtrHeader, fAnchor->GetNBytesHeader(), fAnchor->GetSeekHeader());
466 fReader.ReadBuffer(fStructureBuffer.fPtrFooter, fAnchor->GetNBytesFooter(), fAnchor->GetSeekFooter());
467 fCounters->fNRead.Add(2);
468 } else {
469 RNTupleAtomicTimer timer(fCounters->fTimeWallRead, fCounters->fTimeCpuRead);
470 R__ASSERT(fAnchor->GetNBytesHeader() < std::numeric_limits<std::size_t>::max());
471 R__ASSERT(fAnchor->GetNBytesFooter() < std::numeric_limits<std::size_t>::max());
472 ROOT::Internal::RRawFile::RIOVec readRequests[2] = {{fStructureBuffer.fPtrHeader, fAnchor->GetSeekHeader(),
473 static_cast<std::size_t>(fAnchor->GetNBytesHeader()), 0},
474 {fStructureBuffer.fPtrFooter, fAnchor->GetSeekFooter(),
475 static_cast<std::size_t>(fAnchor->GetNBytesFooter()), 0}};
476 fFile->ReadV(readRequests, 2);
477 fCounters->fNReadV.Inc();
478 }
479}
480
482{
483 auto unzipBuf = reinterpret_cast<unsigned char *>(fStructureBuffer.fPtrFooter) + fAnchor->GetNBytesFooter();
484
485 RNTupleDecompressor::Unzip(fStructureBuffer.fPtrHeader, fAnchor->GetNBytesHeader(), fAnchor->GetLenHeader(),
486 unzipBuf);
488
489 RNTupleDecompressor::Unzip(fStructureBuffer.fPtrFooter, fAnchor->GetNBytesFooter(), fAnchor->GetLenFooter(),
490 unzipBuf);
492
493 auto desc = fDescriptorBuilder.MoveDescriptor();
494
495 // fNTupleName is empty if and only if we created this source via CreateFromAnchor. If that's the case, this is the
496 // earliest we can set the name.
497 if (fNTupleName.empty())
498 fNTupleName = desc.GetName();
499
500 std::vector<unsigned char> buffer;
501 for (const auto &cgDesc : desc.GetClusterGroupIterable()) {
502 buffer.resize(std::max<size_t>(buffer.size(),
503 cgDesc.GetPageListLength() + cgDesc.GetPageListLocator().GetNBytesOnStorage()));
504 auto *zipBuffer = buffer.data() + cgDesc.GetPageListLength();
505 fReader.ReadBuffer(zipBuffer, cgDesc.GetPageListLocator().GetNBytesOnStorage(),
506 cgDesc.GetPageListLocator().GetPosition<std::uint64_t>());
507 RNTupleDecompressor::Unzip(zipBuffer, cgDesc.GetPageListLocator().GetNBytesOnStorage(),
508 cgDesc.GetPageListLength(), buffer.data());
509
510 RNTupleSerializer::DeserializePageList(buffer.data(), cgDesc.GetPageListLength(), cgDesc.GetId(), desc, mode);
511 }
512
513 // For the page reads, we rely on the I/O scheduler to define the read requests
514 fFile->SetBuffering(false);
515
516 // Set file size once after buffering is turned off
517 fFileSize = fFile->GetSize();
518
519 return desc;
520}
521
523 RNTupleLocalIndex localIndex, RSealedPage &sealedPage)
524{
525 const auto clusterId = localIndex.GetClusterId();
526
528 {
529 auto descriptorGuard = GetSharedDescriptorGuard();
530 const auto &clusterDescriptor = descriptorGuard->GetClusterDescriptor(clusterId);
531 pageInfo = clusterDescriptor.GetPageRange(physicalColumnId).Find(localIndex.GetIndexInCluster());
532 }
533
534 sealedPage.SetBufferSize(pageInfo.GetLocator().GetNBytesOnStorage() + pageInfo.HasChecksum() * kNBytesPageChecksum);
535 sealedPage.SetNElements(pageInfo.GetNElements());
536 sealedPage.SetHasChecksum(pageInfo.HasChecksum());
537 if (!sealedPage.GetBuffer())
538 return;
540 fReader.ReadBuffer(const_cast<void *>(sealedPage.GetBuffer()), sealedPage.GetBufferSize(),
541 pageInfo.GetLocator().GetPosition<std::uint64_t>());
542 } else {
543 assert(!pageInfo.HasChecksum());
544 memcpy(const_cast<void *>(sealedPage.GetBuffer()), ROOT::Internal::RPage::GetPageZeroBuffer(),
545 sealedPage.GetBufferSize());
546 }
547
549}
550
552 const RClusterInfo &clusterInfo,
553 ROOT::NTupleSize_t idxInCluster)
554{
555 const auto columnId = columnHandle.fPhysicalId;
556 const auto clusterId = clusterInfo.fClusterId;
557 const auto pageInfo = clusterInfo.fPageInfo;
558
559 const auto element = columnHandle.fColumn->GetElement();
560 const auto elementSize = element->GetSize();
561 const auto elementInMemoryType = element->GetIdentifier().fInMemoryType;
562
563 if (pageInfo.GetLocator().GetType() == RNTupleLocator::kTypePageZero) {
564 auto pageZero = fPageAllocator->NewPage(elementSize, pageInfo.GetNElements());
565 pageZero.GrowUnchecked(pageInfo.GetNElements());
566 memset(pageZero.GetBuffer(), 0, pageZero.GetNBytes());
567 pageZero.SetWindow(clusterInfo.fColumnOffset + pageInfo.GetFirstElementIndex(),
568 ROOT::Internal::RPage::RClusterInfo(clusterId, clusterInfo.fColumnOffset));
569 return fPagePool.RegisterPage(std::move(pageZero), RPagePool::RKey{columnId, elementInMemoryType});
570 }
571
572 RSealedPage sealedPage;
573 sealedPage.SetNElements(pageInfo.GetNElements());
574 sealedPage.SetHasChecksum(pageInfo.HasChecksum());
575 sealedPage.SetBufferSize(pageInfo.GetLocator().GetNBytesOnStorage() + pageInfo.HasChecksum() * kNBytesPageChecksum);
576 std::unique_ptr<unsigned char[]> directReadBuffer; // only used if cluster pool is turned off
577
579 directReadBuffer = MakeUninitArray<unsigned char>(sealedPage.GetBufferSize());
580 {
581 RNTupleAtomicTimer timer(fCounters->fTimeWallRead, fCounters->fTimeCpuRead);
582 const auto offset = pageInfo.GetLocator().GetPosition<std::uint64_t>();
583 // Track seek distance (excluding file structure reads)
585 if (fLastOffset != 0) {
586 const auto distance = static_cast<std::uint64_t>(std::abs(
587 static_cast<std::int64_t>(offset) - static_cast<std::int64_t>(fLastOffset)));
588 fFileCounters->fSzSkip.Add(distance);
589 }
590 fReader.ReadBuffer(directReadBuffer.get(), sealedPage.GetBufferSize(), offset);
591 fLastOffset = offset + sealedPage.GetBufferSize();
592 }
593 fCounters->fNPageRead.Inc();
594 fCounters->fNRead.Inc();
595 fCounters->fSzReadPayload.Add(sealedPage.GetBufferSize());
596 sealedPage.SetBuffer(directReadBuffer.get());
597 } else {
598 if (!fCurrentCluster || (fCurrentCluster->GetId() != clusterId) || !fCurrentCluster->ContainsColumn(columnId))
599 fCurrentCluster = fClusterPool.GetCluster(clusterId, fActivePhysicalColumns.ToColumnSet());
600 R__ASSERT(fCurrentCluster->ContainsColumn(columnId));
601
602 auto cachedPageRef =
603 fPagePool.GetPage(RPagePool::RKey{columnId, elementInMemoryType}, RNTupleLocalIndex(clusterId, idxInCluster));
604 if (!cachedPageRef.Get().IsNull())
605 return cachedPageRef;
606
607 ROnDiskPage::Key key(columnId, pageInfo.GetPageNumber());
608 auto onDiskPage = fCurrentCluster->GetOnDiskPage(key);
609 R__ASSERT(onDiskPage && (sealedPage.GetBufferSize() == onDiskPage->GetSize()));
610 sealedPage.SetBuffer(onDiskPage->GetAddress());
611 }
612
613 ROOT::Internal::RPage newPage;
614 {
615 RNTupleAtomicTimer timer(fCounters->fTimeWallUnzip, fCounters->fTimeCpuUnzip);
616 newPage = UnsealPage(sealedPage, *element).Unwrap();
617 fCounters->fSzUnzip.Add(elementSize * pageInfo.GetNElements());
618 }
619
620 newPage.SetWindow(clusterInfo.fColumnOffset + pageInfo.GetFirstElementIndex(),
621 ROOT::Internal::RPage::RClusterInfo(clusterId, clusterInfo.fColumnOffset));
622 fCounters->fNPageUnsealed.Inc();
623 return fPagePool.RegisterPage(std::move(newPage), RPagePool::RKey{columnId, elementInMemoryType});
624}
625
626std::unique_ptr<ROOT::Internal::RPageSource> ROOT::Internal::RPageSourceFile::CloneImpl() const
627{
628 auto clone = new RPageSourceFile(fNTupleName, fOptions);
629 clone->fFile = fFile->Clone();
630 clone->fReader = ROOT::Internal::RMiniFileReader(clone->fFile.get());
631 return std::unique_ptr<RPageSourceFile>(clone);
632}
633
634std::unique_ptr<ROOT::Internal::RCluster>
636 std::vector<ROOT::Internal::RRawFile::RIOVec> &readRequests)
637{
638 struct ROnDiskPageLocator {
639 ROOT::DescriptorId_t fColumnId = 0;
640 ROOT::NTupleSize_t fPageNo = 0;
641 std::uint64_t fOffset = 0;
642 std::uint64_t fSize = 0;
643 std::size_t fBufPos = 0;
644 };
645
646 std::vector<ROnDiskPageLocator> onDiskPages;
647 auto activeSize = 0;
648 auto pageZeroMap = std::make_unique<ROnDiskPageMap>();
650 clusterKey, *pageZeroMap,
651 [&](ROOT::DescriptorId_t physicalColumnId, ROOT::NTupleSize_t pageNo,
652 const ROOT::RClusterDescriptor::RPageInfo &pageInfo) {
653 const auto &pageLocator = pageInfo.GetLocator();
654 if (pageLocator.GetType() == RNTupleLocator::kTypeUnknown)
655 throw RException(R__FAIL("tried to read a page with an unknown locator"));
656 const auto nBytes = pageLocator.GetNBytesOnStorage() + pageInfo.HasChecksum() * kNBytesPageChecksum;
657 activeSize += nBytes;
658 onDiskPages.push_back({physicalColumnId, pageNo, pageLocator.GetPosition<std::uint64_t>(), nBytes, 0});
659 });
660
661 // Linearize the page requests by file offset
662 std::sort(onDiskPages.begin(), onDiskPages.end(),
663 [](const ROnDiskPageLocator &a, const ROnDiskPageLocator &b) { return a.fOffset < b.fOffset; });
664
665 // In order to coalesce close-by pages, we collect the sizes of the gaps between pages on disk. We then order
666 // the gaps by size, sum them up and find a cutoff for the largest gap that we tolerate when coalescing pages.
667 // The size of the cutoff is given by the fraction of extra bytes we are willing to read in order to reduce
668 // the number of read requests. We thus schedule the lowest number of requests given a tolerable fraction
669 // of extra bytes.
670 // TODO(jblomer): Eventually we may want to select the parameter at runtime according to link latency and speed,
671 // memory consumption, device block size.
672 float maxOverhead = 0.25 * float(activeSize);
673 std::vector<std::size_t> gaps;
674 if (onDiskPages.size())
675 gaps.reserve(onDiskPages.size() - 1);
676 for (unsigned i = 1; i < onDiskPages.size(); ++i) {
677 std::int64_t gap =
678 static_cast<int64_t>(onDiskPages[i].fOffset) - (onDiskPages[i - 1].fSize + onDiskPages[i - 1].fOffset);
679 gaps.emplace_back(std::max(gap, std::int64_t(0)));
680 // If the pages overlap, substract the overlapped bytes from `activeSize`
681 activeSize += std::min(gap, std::int64_t(0));
682 }
683 std::sort(gaps.begin(), gaps.end());
684 std::size_t gapCut = 0;
685 std::size_t currentGap = 0;
686 float szExtra = 0.0;
687 for (auto g : gaps) {
688 if (g != currentGap) {
689 gapCut = currentGap;
690 currentGap = g;
691 }
692 szExtra += g;
693 if (szExtra > maxOverhead)
694 break;
695 }
696
697 // In a first step, we coalesce the read requests and calculate the cluster buffer size.
698 // In a second step, we'll fix-up the memory destinations for the read calls given the
699 // address of the allocated buffer. We must not touch, however, the read requests from previous
700 // calls to PrepareSingleCluster()
701 const auto currentReadRequestIdx = readRequests.size();
702
704 // To simplify the first loop iteration, pretend an empty request starting at the first page's fOffset.
705 if (!onDiskPages.empty())
706 req.fOffset = onDiskPages[0].fOffset;
707 std::size_t szPayload = 0;
708 std::size_t szOverhead = 0;
709 const std::uint64_t maxKeySize = fReader.GetMaxKeySize();
710 for (auto &s : onDiskPages) {
711 R__ASSERT(s.fSize > 0);
712 const std::int64_t readUpTo = req.fOffset + req.fSize;
713 // Note: byte ranges of pages may overlap
714 const std::uint64_t overhead = std::max(static_cast<std::int64_t>(s.fOffset) - readUpTo, std::int64_t(0));
715 const std::uint64_t extent = std::max(static_cast<std::int64_t>(s.fOffset + s.fSize) - readUpTo, std::int64_t(0));
716 if (req.fSize + extent < maxKeySize && overhead <= gapCut) {
717 szPayload += (extent - overhead);
718 szOverhead += overhead;
719 s.fBufPos = reinterpret_cast<intptr_t>(req.fBuffer) + s.fOffset - req.fOffset;
720 req.fSize += extent;
721 continue;
722 }
723
724 // close the current request and open new one
725 if (req.fSize > 0)
726 readRequests.emplace_back(req);
727
728 req.fBuffer = reinterpret_cast<unsigned char *>(req.fBuffer) + req.fSize;
729 s.fBufPos = reinterpret_cast<intptr_t>(req.fBuffer);
730
731 szPayload += s.fSize;
732 req.fOffset = s.fOffset;
733 req.fSize = s.fSize;
734 }
735 readRequests.emplace_back(req);
736 fCounters->fSzReadPayload.Add(szPayload);
737 fCounters->fSzReadOverhead.Add(szOverhead);
738
739 // Register the on disk pages in a page map
740 auto buffer = new unsigned char[reinterpret_cast<intptr_t>(req.fBuffer) + req.fSize];
741 auto pageMap = std::make_unique<ROOT::Internal::ROnDiskPageMapHeap>(std::unique_ptr<unsigned char[]>(buffer));
742 for (const auto &s : onDiskPages) {
743 ROnDiskPage::Key key(s.fColumnId, s.fPageNo);
744 pageMap->Register(key, ROnDiskPage(buffer + s.fBufPos, s.fSize));
745 }
746 fCounters->fNPageRead.Add(onDiskPages.size());
747 for (auto i = currentReadRequestIdx; i < readRequests.size(); ++i) {
748 readRequests[i].fBuffer = buffer + reinterpret_cast<intptr_t>(readRequests[i].fBuffer);
749 }
750
751 auto cluster = std::make_unique<RCluster>(clusterKey.fClusterId);
752 cluster->Adopt(std::move(pageMap));
753 cluster->Adopt(std::move(pageZeroMap));
754 for (auto colId : clusterKey.fPhysicalColumnSet)
755 cluster->SetColumnAvailable(colId);
756 return cluster;
757}
758
759std::vector<std::unique_ptr<ROOT::Internal::RCluster>>
760ROOT::Internal::RPageSourceFile::LoadClusters(std::span<RCluster::RKey> clusterKeys)
761{
762 fCounters->fNClusterLoaded.Add(clusterKeys.size());
763
764 std::vector<std::unique_ptr<ROOT::Internal::RCluster>> clusters;
765 std::vector<ROOT::Internal::RRawFile::RIOVec> readRequests;
766
767 clusters.reserve(clusterKeys.size());
768 for (auto key : clusterKeys) {
769 clusters.emplace_back(PrepareSingleCluster(key, readRequests));
770 }
771
772 auto nReqs = readRequests.size();
773 auto readvLimits = fFile->GetReadVLimits();
774 // We never want to do vectorized reads of split blobs, so we limit our single size to maxKeySize.
775 readvLimits.fMaxSingleSize = std::min<size_t>(readvLimits.fMaxSingleSize, fReader.GetMaxKeySize());
776
777 int iReq = 0;
778 while (nReqs > 0) {
779 auto nBatch = std::min(nReqs, readvLimits.fMaxReqs);
780
781 if (readvLimits.HasSizeLimit()) {
782 std::uint64_t totalSize = 0;
783 for (std::size_t i = 0; i < nBatch; ++i) {
784 if (readRequests[iReq + i].fSize > readvLimits.fMaxSingleSize) {
785 nBatch = i;
786 break;
787 }
788
789 totalSize += readRequests[iReq + i].fSize;
790 if (totalSize > readvLimits.fMaxTotalSize) {
791 nBatch = i;
792 break;
793 }
794 }
795 }
796
797 // Track seek distance for each read request (excluding file structure reads)
799 for (std::size_t i = 0; i < nBatch; ++i) {
800 const auto offset = readRequests[iReq + i].fOffset;
801 if (fLastOffset != 0) {
802 const auto distance = static_cast<std::uint64_t>(std::abs(
803 static_cast<std::int64_t>(offset) - static_cast<std::int64_t>(fLastOffset)));
804 fFileCounters->fSzSkip.Add(distance);
805 }
806 fLastOffset = offset + readRequests[iReq + i].fSize;
807 }
808
809 if (nBatch <= 1) {
810 nBatch = 1;
811 RNTupleAtomicTimer timer(fCounters->fTimeWallRead, fCounters->fTimeCpuRead);
812 fReader.ReadBuffer(readRequests[iReq].fBuffer, readRequests[iReq].fSize, readRequests[iReq].fOffset);
813 } else {
814 RNTupleAtomicTimer timer(fCounters->fTimeWallRead, fCounters->fTimeCpuRead);
815 fFile->ReadV(&readRequests[iReq], nBatch);
816 }
817 fCounters->fNReadV.Inc();
818 fCounters->fNRead.Add(nBatch);
819
820 iReq += nBatch;
821 nReqs -= nBatch;
822 }
823
824 return clusters;
825}
826
828{
829 fReader.LoadStreamerInfo();
830}
fBuffer
#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:300
#define b(i)
Definition RSha256.hxx:100
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char mode
char name[80]
Definition TGX11.cxx:148
A thread-safe integral performance counter.
A metric element that computes its floating point value from other counters.
A collection of Counter objects with a name, a unit, and a description.
An interface to read from, or write to, a ROOT file, as well as performing other common operations.
Definition RFile.hxx:252
The SoA field provides I/O for an in-memory SoA layout linked to an on-disk collection of the underly...
Definition RFieldSoA.hxx:55
Managed a set of clusters containing compressed and packed pages.
An in-memory subset of the packed and compressed pages of a cluster.
Definition RCluster.hxx:148
ROOT::Internal::RColumnElementBase * GetElement() const
Definition RColumn.hxx:339
Read RNTuple data blocks from a TFile container, provided by a RRawFile.
Definition RMiniFile.hxx:61
Helper class to compress data blocks in the ROOT compression frame format.
static std::size_t Zip(const void *from, std::size_t nbytes, int compression, void *to)
Returns the size of the compressed data, written into the provided output buffer.
Helper class to uncompress data blocks in the ROOT compression frame format.
static void Unzip(const void *from, size_t nbytes, size_t dataLen, void *to)
The nbytes parameter provides the size ls of the from buffer.
Write RNTuple data blocks in a TFile or a bare file container.
static std::unique_ptr< RNTupleFileWriter > Append(std::string_view ntupleName, TDirectory &fileOrDirectory, std::uint64_t maxKeySize, bool isHidden)
The directory parameter can also be a TFile object (TFile inherits from TDirectory).
static std::unique_ptr< RNTupleFileWriter > Recreate(std::string_view ntupleName, std::string_view path, EContainerFormat containerFormat, const ROOT::RNTupleWriteOptions &options)
Create or truncate the local file given by path with the new empty RNTuple identified by ntupleName.
A helper class for serializing and deserialization of the RNTuple binary format.
static RResult< void > DeserializePageList(const void *buffer, std::uint64_t bufSize, ROOT::DescriptorId_t clusterGroupId, RNTupleDescriptor &desc, EDescriptorDeserializeMode mode)
static RResult< void > DeserializeFooter(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RNTupleDescriptorBuilder &descBuilder)
static RResult< StreamerInfoMap_t > DeserializeStreamerInfos(const std::string &extraTypeInfoContent)
static RResult< void > DeserializeHeader(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RNTupleDescriptorBuilder &descBuilder)
A memory region that contains packed and compressed pages.
Definition RCluster.hxx:99
A page as being stored on disk, that is packed and compressed.
Definition RCluster.hxx:41
void UpdateSchema(const ROOT::Internal::RNTupleModelChangeset &changeset, ROOT::NTupleSize_t firstEntry) override
Incorporate incremental changes to the model into the ntuple descriptor.
ROOT::Internal::RNTupleDescriptorBuilder fDescriptorBuilder
RPagePersistentSink(std::string_view ntupleName, const ROOT::RNTupleWriteOptions &options)
std::unique_ptr< RCounters > fCounters
void EnableDefaultMetrics(const std::string &prefix)
Enables the default set of metrics provided by RPageSink.
A thread-safe cache of pages loaded from the page source.
Definition RPagePool.hxx:47
Reference to a page stored in the page pool.
std::uint64_t fNBytesCurrentCluster
Number of bytes committed to storage in the current cluster.
void CommitBatchOfPages(CommitBatch &batch, std::vector< RNTupleLocator > &locators)
Subroutine of CommitSealedPageVImpl, used to perform a vector write of the (multi-)range of pages con...
RPageSinkFile(std::string_view ntupleName, const ROOT::RNTupleWriteOptions &options)
std::unique_ptr< RPageSink > CloneAsHidden(std::string_view name, const ROOT::RNTupleWriteOptions &opts) const override
Creates a new sink with the same underlying storage as this but writing to a different RNTuple named ...
std::uint64_t StageClusterImpl() final
Returns the number of bytes written to storage (excluding metadata)
void InitImpl(unsigned char *serializedHeader, std::uint32_t length) final
RNTupleLocator CommitPageImpl(ColumnHandle_t columnHandle, const RPage &page) override
RNTupleLocator WriteSealedPage(const RPageStorage::RSealedPage &sealedPage, std::size_t bytesPacked)
We pass bytesPacked so that TFile::ls() reports a reasonable value for the compression ratio of the c...
RNTupleLocator CommitClusterGroupImpl(unsigned char *serializedPageList, std::uint32_t length) final
Returns the locator of the page list envelope of the given buffer that contains the serialized page l...
RNTupleLocator CommitSealedPageImpl(ROOT::DescriptorId_t physicalColumnId, const RPageStorage::RSealedPage &sealedPage) final
RNTupleLink CommitDatasetImpl() final
std::unique_ptr< ROOT::Internal::RNTupleFileWriter > fWriter
void UpdateSchema(const ROOT::Internal::RNTupleModelChangeset &changeset, ROOT::NTupleSize_t firstEntry) final
Incorporate incremental changes to the model into the ntuple descriptor.
std::vector< RNTupleLocator > CommitSealedPageVImpl(std::span< RPageStorage::RSealedPageGroup > ranges, const std::vector< bool > &mask) final
Vector commit of preprocessed pages.
ROOT::Internal::RNTupleSerializer::StreamerInfoMap_t fInfosOfClassFields
On UpdateSchema(), the new class fields register the corresponding streamer info here so that the str...
std::unique_ptr< ROOT::RNTupleWriteOptions > fOptions
const ROOT::RNTupleWriteOptions & GetWriteOptions() const
Returns the sink's write options.
RSealedPage SealPage(const ROOT::Internal::RPage &page, const ROOT::Internal::RColumnElementBase &element)
Helper for streaming a page.
std::int64_t fFileSize
Total file size, set once in AttachImpl()
RNTupleDescriptorBuilder fDescriptorBuilder
The descriptor is created from the header and footer either in AttachImpl or in CreateFromAnchor.
std::unique_ptr< ROOT::Internal::RCluster > PrepareSingleCluster(const ROOT::Internal::RCluster::RKey &clusterKey, std::vector< RRawFile::RIOVec > &readRequests)
Helper function for LoadClusters: it prepares the memory buffer (page map) and the read requests for ...
std::uint64_t fLastOffset
Tracks the last read offset for seek distance calculation.
ROOT::Internal::RCluster * fCurrentCluster
The last cluster from which a page got loaded. Points into fClusterPool->fPool.
std::unique_ptr< RPageSource > OpenWithDifferentAnchor(const ROOT::Internal::RNTupleLink &anchorLink, const ROOT::RNTupleReadOptions &options={}) final
Creates a new PageSource using the same underlying file as this but referring to a different RNTuple,...
RPageRef LoadPageImpl(ColumnHandle_t columnHandle, const RClusterInfo &clusterInfo, ROOT::NTupleSize_t idxInCluster) final
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.
ROOT::RNTupleDescriptor AttachImpl(RNTupleSerializer::EDescriptorDeserializeMode mode) final
LoadStructureImpl() has been called before AttachImpl() is called
std::vector< std::unique_ptr< ROOT::Internal::RCluster > > LoadClusters(std::span< ROOT::Internal::RCluster::RKey > clusterKeys) final
Populates all the pages of the given cluster ids and columns; it is possible that some columns do not...
std::unique_ptr< RFileCounters > fFileCounters
RPageSourceFile(std::string_view ntupleName, const ROOT::RNTupleReadOptions &options)
std::unique_ptr< RPageSource > CloneImpl() const final
The cloned page source creates a new raw file and reader and opens its own file descriptor to the dat...
void LoadStreamerInfo() final
Forces the loading of ROOT StreamerInfo from the underlying file. This currently only has an effect f...
RStructureBuffer fStructureBuffer
Populated by LoadStructureImpl(), reset at the end of Attach()
std::unique_ptr< RRawFile > fFile
An RRawFile is used to request the necessary byte ranges from a local or a remote file.
std::optional< RNTuple > fAnchor
Either provided by CreateFromAnchor, or read from the ROOT file given the ntuple name.
ROOT::Internal::RMiniFileReader fReader
Takes the fFile to read ntuple blobs from it.
void LoadSealedPage(ROOT::DescriptorId_t physicalColumnId, RNTupleLocalIndex localIndex, RSealedPage &sealedPage) final
Read the packed and compressed bytes of a page into the memory buffer provided by sealedPage....
ROOT::Internal::RClusterPool fClusterPool
The cluster pool asynchronously preloads the next few clusters. Note that derived classes should call...
ROOT::RNTupleReadOptions fOptions
const RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor. Multiple threads can take the lock concurrently....
void PrepareLoadCluster(const ROOT::Internal::RCluster::RKey &clusterKey, ROOT::Internal::ROnDiskPageMap &pageZeroMap, std::function< void(ROOT::DescriptorId_t, ROOT::NTupleSize_t, const ROOT::RClusterDescriptor::RPageInfo &)> perPageFunc)
Prepare a page range read for the column set in clusterKey. Specifically, pages referencing the kType...
void EnableDefaultMetrics(const std::string &prefix)
Enables the default set of metrics provided by RPageSource. prefix will be used as the prefix for the...
std::unique_ptr< RCounters > fCounters
ROOT::Internal::RPagePool fPagePool
Pages that are unzipped with IMT are staged into the page pool.
RPageSource(std::string_view ntupleName, const ROOT::RNTupleReadOptions &fOptions)
RActivePhysicalColumns fActivePhysicalColumns
The active columns are implicitly defined by the model fields or views.
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)
static RResult< ROOT::Internal::RPage > UnsealPage(const RSealedPage &sealedPage, const ROOT::Internal::RColumnElementBase &element, ROOT::Internal::RPageAllocator &pageAlloc)
Helper for unstreaming a page. This is commonly used in derived, concrete page sources....
std::unique_ptr< ROOT::Internal::RPageAllocator > fPageAllocator
For the time being, we will use the heap allocator for all sources and sinks. This may change in the ...
static constexpr std::size_t kNBytesPageChecksum
The page checksum is a 64bit xxhash3.
RColumnHandle ColumnHandle_t
The column handle identifies a column with the current open page storage.
ROOT::Experimental::Detail::RNTupleMetrics fMetrics
const std::string & GetNTupleName() const
Returns the NTuple name.
Stores information about the cluster in which this page resides.
Definition RPage.hxx:53
A page is a slice of a column that is mapped into memory.
Definition RPage.hxx:44
std::uint32_t GetNElements() const
Definition RPage.hxx:121
std::size_t GetNBytes() const
The space taken by column elements in the buffer.
Definition RPage.hxx:112
static const void * GetPageZeroBuffer()
Return a pointer to the page zero buffer used if there is no on-disk data for a particular deferred c...
Definition RPage.cxx:23
void SetWindow(const ROOT::NTupleSize_t rangeFirst, const RClusterInfo &clusterInfo)
Seek the page to a certain position of the column.
Definition RPage.hxx:158
The RRawFileTFile wraps an open TFile, but does not take ownership.
The RRawFile provides read-only access to local and remote files.
Definition RRawFile.hxx:43
static std::unique_ptr< RRawFile > Create(std::string_view url, ROptions options=ROptions())
Factory method that returns a suitable concrete implementation according to the transport in the url.
Definition RRawFile.cxx:64
The field for a class with dictionary.
Definition RField.hxx:136
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
A field translates read and write calls from/to underlying columns to/from tree values.
The on-storage metadata of an RNTuple.
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
ROOT::NTupleSize_t GetIndexInCluster() const
ROOT::DescriptorId_t GetClusterId() const
Generic information about the physical location of data.
std::uint64_t GetNBytesOnStorage() const
ELocatorType GetType() const
For non-disk locators, the value for the Type field.
T GetPosition() const
Note that for GetPosition() / SetPosition(), the locator type must correspond (kTypeFile,...
void SetPosition(std::uint64_t position)
void SetNBytesOnStorage(std::uint64_t nBytesOnStorage)
Common user-tunable settings for reading RNTuples.
Common user-tunable settings for storing RNTuples.
std::uint64_t GetMaxKeySize() const
TFile * fFile
! The file from which the ntuple was streamed, registered in the custom streamer
Definition RNTuple.hxx:123
void ThrowOnError()
Short-hand method to throw an exception in the case of errors.
Definition RError.hxx:290
The field for a class using ROOT standard streaming.
Definition RField.hxx:236
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4657
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
Describe directory structure in memory.
Definition TDirectory.h:45
virtual const TUrl * GetEndpointUrl() const
Definition TFile.h:323
TClass * IsA() const override
Definition TFile.h:436
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
RNTupleTimer< RNTupleAtomicCounter, RNTupleTickCounter< RNTupleAtomicCounter > > RNTupleAtomicTimer
std::unique_ptr< T[]> MakeUninitArray(std::size_t size)
Make an array of default-initialized elements.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
The identifiers that specifies the content of a (partial) cluster.
Definition RCluster.hxx:152
ROOT::DescriptorId_t fClusterId
Definition RCluster.hxx:153
The incremental changes to a RNTupleModel
std::vector< ROOT::RFieldBase * > fAddedFields
Points to the fields in fModel that were added as part of an updater transaction.
On-disk pages within a page source are identified by the column and page number.
Definition RCluster.hxx:51
size_t fSize
Total size in bytes of the batch.
std::vector< const RSealedPage * > fSealedPages
The list of pages to commit.
size_t fBytesPacked
Total uncompressed size of the elements in the page batch.
File-specific I/O performance counters.
Summarizes cluster-level information that are necessary to load a certain page. Used by LoadPageImpl(...
std::uint64_t fColumnOffset
The first element number of the page's column in the given cluster.
ROOT::RClusterDescriptor::RPageInfoExtended fPageInfo
Location of the page on disk.
A sealed page contains the bytes of a page as written to storage (packed & compressed).
RResult< void > VerifyChecksumIfEnabled() const
void SetNElements(std::uint32_t nElements)
void SetBufferSize(std::size_t bufferSize)
Used for vector reads from multiple offsets into multiple buffers.
Definition RRawFile.hxx:61
std::size_t fSize
The number of desired bytes.
Definition RRawFile.hxx:67
void * fBuffer
The destination for reading.
Definition RRawFile.hxx:63
std::uint64_t fOffset
The file offset.
Definition RRawFile.hxx:65
Information about a single page in the context of a cluster's page range.
const RNTupleLocator & GetLocator() const