72 std::unique_ptr<RFieldBase::RValue>
fValue;
99 auto iReal =
fField->begin();
100 for (; iReal !=
fField->end(); ++iProto, ++iReal) {
113 std::string msg =
"RNTupleDS: invalid type \"" +
fField->GetTypeName() +
"\" for column \"" +
116 throw std::runtime_error(msg);
126 fValue = std::make_unique<RFieldBase::RValue>(
fField->CreateValue());
132 if (
fValue && keepValue) {
146 return fValue->GetPtr<
void>().get();
193 fieldInfos.emplace_back(fieldId, nRepetitions);
200 bool representableAsRVec =
201 convertToRVec && (fieldDesc.GetTypeName().substr(0, 19) ==
"ROOT::VecOps::RVec<" ||
202 fieldDesc.GetTypeName().substr(0, 12) ==
"std::vector<" || fieldDesc.GetTypeName() ==
"");
204 AddField(desc, colName,
f.GetId(), fieldInfos, representableAsRVec);
210 }
else if (nRepetitions > 0) {
213 AddField(desc, colName,
f.GetId(), fieldInfos);
218 auto innerName = colName.empty() ?
f.GetFieldName() : (std::string(colName) +
"." +
f.GetFieldName());
220 AddField(desc, innerName,
f.GetId(), fieldInfos);
227 if (!fieldOrException)
229 auto valueField = fieldOrException.Unwrap();
232 if (cardinalityField->As32Bit()) {
234 std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint32_t>>(fieldDesc.GetFieldName());
235 }
else if (cardinalityField->As64Bit()) {
237 std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint64_t>>(fieldDesc.GetFieldName());
239 R__ASSERT(
false &&
"cardinality field stored with an unexpected integer type");
242 valueField->SetOnDiskId(fieldId);
243 for (
auto &
f : *valueField) {
244 f.SetOnDiskId(desc.
FindFieldId(
f.GetFieldName(),
f.GetParent()->GetOnDiskId()));
246 std::unique_ptr<ROOT::RFieldBase> cardinalityField;
248 if (!fieldInfos.empty()) {
249 const auto &info = fieldInfos.back();
251 if (info.fNRepetitions > 0) {
252 cardinalityField = std::make_unique<ROOT::Internal::RDF::RArraySizeField>(
name, info.fNRepetitions);
254 cardinalityField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::size_t>>(
name);
256 cardinalityField->SetOnDiskId(info.fFieldId);
259 for (
auto i = fieldInfos.rbegin(); i != fieldInfos.rend(); ++i) {
260 const auto &fieldInfo = *i;
262 const auto valueFieldName = valueField->GetFieldName();
264 if (fieldInfo.fNRepetitions > 0) {
267 std::make_unique<ROOT::RArrayAsRVecField>(valueFieldName, valueField->Clone(
"_0"), fieldInfo.fNRepetitions);
272 valueField = std::make_unique<ROOT::RRVecField>(valueFieldName, valueField->Clone(
"_0"));
279 valueField->SetOnDiskId(fieldInfo.fFieldId);
283 if (i != fieldInfos.rbegin()) {
284 const auto cardinalityFieldName = cardinalityField->GetFieldName();
285 if (fieldInfo.fNRepetitions > 0) {
287 cardinalityField = std::make_unique<ROOT::RArrayAsRVecField>(
288 cardinalityFieldName, cardinalityField->Clone(
"_0"), fieldInfo.fNRepetitions);
291 cardinalityField = std::make_unique<ROOT::RRVecField>(cardinalityFieldName, cardinalityField->Clone(
"_0"));
294 cardinalityField->SetOnDiskId(fieldInfo.fFieldId);
298 if (cardinalityField) {
299 fColumnNames.emplace_back(
"R_rdf_sizeof_" + std::string(colName));
300 fColumnTypes.emplace_back(cardinalityField->GetTypeName());
304 fieldInfos.emplace_back(fieldId, nRepetitions);
312 pageSource->Attach();
313 fPrincipalDescriptor = pageSource->GetSharedDescriptorGuard()->Clone();
316 fStagingArea.emplace_back(std::move(pageSource));
318 AddField(fPrincipalDescriptor,
"", fPrincipalDescriptor.GetFieldZeroId(),
319 std::vector<ROOT::RDF::RNTupleDS::RFieldInfo>());
321 auto topLevelFields = fPrincipalDescriptor.GetTopLevelFields();
322 const auto nTopLevelFields = std::distance(topLevelFields.begin(), topLevelFields.end());
323 fTopLevelFieldNames.reserve(nTopLevelFields);
324 for (
const auto &field : topLevelFields)
325 fTopLevelFieldNames.push_back(field.GetFieldName());
336 static std::once_flag flag;
337 std::call_once(flag, []() {
338 if (
auto env =
gSystem->
Getenv(
"ROOT_RNTUPLE_CLUSTERBUNCHSIZE"); env !=
nullptr && strlen(env) > 0) {
339 std::string envStr{env};
340 auto envNum{std::stoul(envStr)};
341 envNum = envNum == 0 ? 1 : envNum;
348std::unique_ptr<ROOT::Internal::RPageSource> CreatePageSource(std::string_view ntupleName, std::string_view fileName)
355 :
RNTupleDS(CreatePageSource(ntupleName, fileName))
358 fFileNames = std::vector<std::string>{std::string{fileName}};
362 :
RNTupleDS(CreatePageSource(ntupleName, fileNames[0]))
370 const std::pair<ULong64_t, ULong64_t> &range)
387 std::distance(fColumnNames.begin(), std::find(fColumnNames.begin(), fColumnNames.end(), fieldName));
392 return fProtoFields[
index].get();
401 if (requestedType != fColumnTypes[
index]) {
402 auto &altProtoFields = fAlternativeProtoFields[
index];
405 if (
auto altProtoField = std::find_if(altProtoFields.begin(), altProtoFields.end(),
406 [&requestedType](
const std::unique_ptr<ROOT::RFieldBase> &fld) {
407 return fld->GetTypeName() == requestedType;
409 altProtoField != altProtoFields.end()) {
410 return altProtoField->get();
414 std::unique_ptr<RFieldBase> newAltProtoField;
415 const std::string strName = std::string(fieldName);
417 if (requestedType ==
"bool") {
418 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<bool>>(strName);
419 }
else if (requestedType ==
"char") {
420 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<char>>(strName);
421 }
else if (requestedType ==
"std::int8_t") {
422 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int8_t>>(strName);
423 }
else if (requestedType ==
"std::uint8_t") {
424 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint8_t>>(strName);
425 }
else if (requestedType ==
"std::int16_t") {
426 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int16_t>>(strName);
427 }
else if (requestedType ==
"std::uint16_t") {
428 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint16_t>>(strName);
429 }
else if (requestedType ==
"std::int32_t") {
430 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int32_t>>(strName);
431 }
else if (requestedType ==
"std::uint32_t") {
432 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint32_t>>(strName);
433 }
else if (requestedType ==
"std::int64_t") {
434 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::int64_t>>(strName);
435 }
else if (requestedType ==
"std::uint64_t") {
436 newAltProtoField = std::make_unique<ROOT::Internal::RDF::RRDFCardinalityField<std::uint64_t>>(strName);
438 throw std::runtime_error(
"RNTupleDS: Could not create field with type \"" + requestedType +
439 "\" for column \"" + std::string(fieldName) +
"\"");
443 if (!newAltProtoFieldOrException) {
444 throw std::runtime_error(
"RNTupleDS: Could not create field with type \"" + requestedType +
445 "\" for column \"" + std::string(fieldName) +
"\"");
447 newAltProtoField = newAltProtoFieldOrException.Unwrap();
449 newAltProtoField->SetOnDiskId(fProtoFields[
index]->GetOnDiskId());
450 auto *newField = newAltProtoField.get();
451 altProtoFields.emplace_back(std::move(newAltProtoField));
456 return fProtoFields[
index].get();
459std::unique_ptr<ROOT::Detail::RDF::RColumnReaderBase>
463 assert(field !=
nullptr);
467 fFieldId2QualifiedName[field->
GetOnDiskId()] = fPrincipalDescriptor.GetQualifiedFieldName(field->
GetOnDiskId());
468 for (
const auto &s : *field) {
469 fFieldId2QualifiedName[s.GetOnDiskId()] = fPrincipalDescriptor.GetQualifiedFieldName(s.GetOnDiskId());
472 auto reader = std::make_unique<ROOT::Internal::RDF::RNTupleColumnReader>(
this, field);
473 fActiveColumnReaders[slot].emplace_back(reader.get());
481 std::unique_lock lock(fMutexStaging);
482 fCvStaging.wait(lock, [
this] {
return fIsReadyForStaging || fStagingThreadShouldTerminate; });
483 if (fStagingThreadShouldTerminate)
486 assert(!fHasNextSources);
488 fHasNextSources =
true;
489 fIsReadyForStaging =
false;
492 fCvStaging.notify_one();
498 const auto nFiles = fFileNames.empty() ? 1 : fFileNames.size();
500 for (
auto i = fNextFileIndex; (i < nFiles) && ((i - fNextFileIndex) < fNSlots); ++i) {
502 if (fStagingThreadShouldTerminate)
505 if (fStagingArea[i]) {
509 fStagingArea[i] = CreatePageSource(fNTupleName, fFileNames[i]);
510 fStagingArea[i]->LoadStructure();
517 assert(fNextRanges.empty());
519 auto nFiles = fFileNames.empty() ? 1 : fFileNames.size();
520 auto nRemainingFiles = nFiles - fNextFileIndex;
522 if (nRemainingFiles == 0)
527 if ((nRemainingFiles >= fNSlots) || (fGlobalEntryRange.has_value())) {
528 while ((fNextRanges.size() < fNSlots) && (fNextFileIndex < nFiles)) {
531 std::swap(fStagingArea[fNextFileIndex], range.
fSource);
536 range.
fSource = CreatePageSource(fNTupleName, fFileNames[fNextFileIndex]);
538 range.
fFileName = fFileNames[fNextFileIndex];
541 auto nEntries = range.
fSource->GetNEntries();
546 fNextRanges.emplace_back(std::move(range));
555 std::vector<std::pair<ULong64_t, ULong64_t>> ranges;
562 for (
auto r : fActiveColumnReaders[0]) {
563 r->Disconnect(
true );
568 if (fCurrentRanges.empty() || fSeenEntriesNoGlobalRange > 0) {
572 std::unique_lock lock(fMutexStaging);
573 fCvStaging.wait(lock, [
this] {
return fHasNextSources; });
576 if (fNextRanges.empty()) {
581 assert(fNextRanges.size() <= fNSlots);
583 fCurrentRanges.clear();
584 std::swap(fCurrentRanges, fNextRanges);
589 std::lock_guard
_(fMutexStaging);
590 fIsReadyForStaging =
true;
591 fHasNextSources =
false;
593 fCvStaging.notify_one();
600 fFirstEntry2RangeIdx.clear();
601 fOriginalRanges.clear();
605 for (std::size_t i = 0; i < fCurrentRanges.size(); ++i) {
609 if (fCurrentRanges[i].fFirstEntry == 0) {
611 fSeenEntriesNoGlobalRange += nEntriesPerSource;
612 nEntriesPerSource = 0;
615 auto start = fCurrentRanges[i].fFirstEntry + fSeenEntriesNoGlobalRange;
616 auto end = fCurrentRanges[i].fLastEntry + fSeenEntriesNoGlobalRange;
618 nEntriesPerSource += end - start;
620 if (fGlobalEntryRange.has_value()) {
638 if (fGlobalEntryRange->first >= start && fGlobalEntryRange->second <= end) {
639 fOriginalRanges.emplace_back(start, end);
640 fFirstEntry2RangeIdx[fGlobalEntryRange->first] = i;
641 ranges.emplace_back(fGlobalEntryRange->first, fGlobalEntryRange->second);
646 else if (fGlobalEntryRange->second > end && fGlobalEntryRange->first < end) {
647 fOriginalRanges.emplace_back(start, end);
648 fFirstEntry2RangeIdx[fGlobalEntryRange->first] = i;
649 ranges.emplace_back(fGlobalEntryRange->first, end);
650 std::optional<std::pair<ULong64_t, ULong64_t>> newvalues({end, fGlobalEntryRange->second});
651 fGlobalEntryRange.swap(newvalues);
654 else if (fGlobalEntryRange->second < start) {
659 else if (fGlobalEntryRange->first >= end) {
660 fOriginalRanges.emplace_back(start, end);
661 fFirstEntry2RangeIdx[start] = i;
662 ranges.emplace_back(start, start);
667 fFirstEntry2RangeIdx[start] = i;
668 fOriginalRanges.emplace_back(start, end);
669 ranges.emplace_back(start, end);
673 fSeenEntriesNoGlobalRange += nEntriesPerSource;
675 if (fCurrentRanges[0].fSource) {
676 for (
auto r : fActiveColumnReaders[0]) {
677 r->Connect(*fCurrentRanges[0].fSource, fOriginalRanges[0].first);
690 const auto &entryRangeDS = fActiveRangesPerSlot.at(slot * ROOT::Internal::RDF::CacheLineStep<REntryRangeDS>());
691 assert(entryRangeDS.fSource !=
nullptr);
693 for (
auto r : fActiveColumnReaders[slot]) {
694 r->Connect(*entryRangeDS.fSource, columnReaderOffset);
704 for (
auto r : fActiveColumnReaders[slot]) {
705 r->Disconnect(
true );
711 auto colNamePos = std::find(fColumnNames.begin(), fColumnNames.end(), colName);
713 if (colNamePos == fColumnNames.end()) {
714 auto msg = std::string(
"RNTupleDS: There is no column with name \"") + std::string(colName) +
"\"";
715 throw std::runtime_error(msg);
718 const auto index = std::distance(fColumnNames.begin(), colNamePos);
719 return fColumnTypes[
index];
724 return std::find(fColumnNames.begin(), fColumnNames.end(), colName) != fColumnNames.end();
729 fSeenEntriesNoGlobalRange = 0;
731 fIsReadyForStaging = fHasNextSources = fStagingThreadShouldTerminate =
false;
734 fThreadStaging = std::thread(&RNTupleDS::ExecStaging,
this);
735 assert(fNextRanges.empty());
737 if (fCurrentRanges.empty() || (fFileNames.size() > fNSlots)) {
740 std::lock_guard
_(fMutexStaging);
741 fIsReadyForStaging =
true;
743 fCvStaging.notify_one();
747 fNextFileIndex = std::max(fFileNames.size(), std::size_t(1));
753 for (
unsigned int i = 0; i < fNSlots; ++i) {
754 for (
auto r : fActiveColumnReaders[i]) {
755 r->Disconnect(
false );
759 std::lock_guard
_(fMutexStaging);
760 fStagingThreadShouldTerminate =
true;
762 fCvStaging.notify_one();
765 fThreadStaging.join();
768 if (fFileNames.size() > fNSlots) {
769 fCurrentRanges.clear();
771 fStagingArea.clear();
772 fStagingArea.resize(fFileNames.size());
778 assert(fNSlots == 0);
781 fActiveColumnReaders.resize(fNSlots);
782 fActiveRangesPerSlot.resize(fNSlots * ROOT::Internal::RDF::CacheLineStep<REntryRangeDS>());
787 return ROOT::RDataFrame(std::make_unique<ROOT::RDF::RNTupleDS>(ntupleName, fileName));
792 return ROOT::RDataFrame(std::make_unique<ROOT::RDF::RNTupleDS>(ntupleName, fileNames));
796 unsigned int slot,
const std::unordered_map<std::string, ROOT::RDF::Experimental::RSample *> &sampleMap)
const
805 : fActiveRangesPerSlot.at(slot * ROOT::Internal::RDF::CacheLineStep<REntryRangeDS>());
808 if (!entryRangeDS.fSource)
811 const auto &ntupleName = entryRangeDS.fSource->GetNTupleName();
812 const auto &ntuplePath = entryRangeDS.fFileName;
813 const auto ntupleID = std::string(ntuplePath) +
'/' + ntupleName;
815 if (sampleMap.empty())
817 std::make_pair(entryRangeDS.fFirstEntry - entryRangeDS.fEntryOffset,
818 entryRangeDS.fLastEntry - entryRangeDS.fEntryOffset),
819 nullptr, fPrincipalDescriptor.GetNEntries());
821 if (sampleMap.find(ntupleID) == sampleMap.end())
822 throw std::runtime_error(
"Full sample identifier '" + ntupleID +
"' cannot be found in the available samples.");
825 std::make_pair(entryRangeDS.fFirstEntry - entryRangeDS.fEntryOffset,
826 entryRangeDS.fLastEntry - entryRangeDS.fEntryOffset),
827 sampleMap.at(ntupleID), fPrincipalDescriptor.GetNEntries());
832 const std::pair<ULong64_t, ULong64_t> &range)
834 std::unique_ptr<ROOT::RDF::RNTupleDS> ds{
new ROOT::RDF::RNTupleDS(ntupleName, fileNames, range)};
844 source->LoadAllPageLists();
845 auto descGuard = source->GetSharedDescriptorGuard();
863 std::span<const ROOT::Internal::RNTupleClusterBoundaries> fClusters;
864 std::size_t fClusterIdxBegin;
865 std::size_t fClusterIdxEnd;
868 RSplittableRangeOfClusterBoundaries(std::span<const ROOT::Internal::RNTupleClusterBoundaries> clusters,
869 std::size_t clusterIdxBegin, std::size_t clusterIdxEnd)
870 : fClusters(clusters), fClusterIdxBegin(clusterIdxBegin), fClusterIdxEnd(clusterIdxEnd)
872 assert(fClusterIdxEnd > fClusterIdxBegin);
875 std::unique_ptr<ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl> SplitWork() final
878 auto clusterIdxMid = fClusterIdxBegin + (fClusterIdxEnd - fClusterIdxBegin) / 2;
879 auto newClusterIdxBegin = clusterIdxMid;
880 auto newClusterIdxEnd = fClusterIdxEnd;
881 fClusterIdxEnd = clusterIdxMid;
883 return std::make_unique<RSplittableRangeOfClusterBoundaries>(fClusters, newClusterIdxBegin, newClusterIdxEnd);
886 bool IsDivisible() const final
889 return fClusterIdxEnd - fClusterIdxBegin > 2;
892 bool Empty() const final
899 std::uint64_t GetCurrentBeginEntry()
const {
return fClusters[fClusterIdxBegin].fFirstEntry; }
901 std::uint64_t GetCurrentEndEntry()
const {
return fClusters[fClusterIdxEnd - 1].fLastEntryPlusOne; }
903 bool IsProcessingFirstCluster()
const {
return fClusterIdxBegin == 0; }
911 std::shared_ptr<ROOT::Internal::RPageSource> pageSource,
912 std::uint64_t beginEntry, std::uint64_t endEntry,
917 entryRangeDS.
fSource = std::move(pageSource);
921 fActiveRangesPerSlot.at(slot * ROOT::Internal::RDF::CacheLineStep<REntryRangeDS>()) = std::move(entryRangeDS);
938 std::atomic<ULong64_t> &processedEntries,
ULong64_t columnReaderOffset)
941 const auto &slot = slotRAII.fSlot;
943 const auto &range =
static_cast<const RSplittableRangeOfClusterBoundaries &
>(rangeImpl);
944 const auto &beginEntry = range.GetCurrentBeginEntry();
945 const auto &endEntry = range.GetCurrentEndEntry();
948 auto localPageSource = [&]() -> std::shared_ptr<ROOT::Internal::RPageSource> {
951 if (range.IsProcessingFirstCluster())
954 auto newPageSource = pageSource->Clone();
955 newPageSource->Attach();
956 return newPageSource;
960 localPageSource->SetEntryRange({beginEntry, endEntry - beginEntry});
962 processedEntries.fetch_add(endEntry - beginEntry);
966 InsertActiveEntryRange(slot, fileName, std::move(localPageSource), beginEntry, endEntry, columnReaderOffset);
968 lm.
RNTupleThreadTask({beginEntry + columnReaderOffset, endEntry + columnReaderOffset}, slot, columnReaderOffset);
971 fActiveRangesPerSlot.at(slot * ROOT::Internal::RDF::CacheLineStep<REntryRangeDS>()) = {};
993 ROOT::TThreadExecutor &pool, std::unique_ptr<ROOT::Internal::RPageSource> pageSource, std::string_view fileName,
994 std::span<const ROOT::Internal::RNTupleClusterBoundaries> clusterBoundaries, std::uint64_t nEntries,
996 std::atomic<ULong64_t> &globalEntries)
999 const auto columnReaderOffset{globalEntries.fetch_add(nEntries)};
1003 std::shared_ptr<ROOT::Internal::RPageSource> sharedPageSource{std::move(pageSource)};
1005 auto parallelForBody = [
this, &sharedPageSource, &lm, &fileName, &slotStack, &processedEntries,
1007 this->ParallelForBody(sharedPageSource, rangeImpl, lm, fileName, slotStack, processedEntries, columnReaderOffset);
1011 pool, std::make_unique<RSplittableRangeOfClusterBoundaries>(clusterBoundaries, 0, clusterBoundaries.size()),
1020 std::vector<std::uint64_t> fileEntries(fFileNames.size());
1021 auto getEntries = [](std::string_view ntupleName, std::string_view fileName) {
1024 const auto descGuard = source->GetSharedDescriptorGuard();
1025 return descGuard->GetNEntries();
1027 pool.
Foreach([&fileEntries,
this,
1028 getEntries](std::size_t idx) { fileEntries[idx] = getEntries(fNTupleName, fFileNames[idx]); },
1034 std::vector<std::uint64_t> ret;
1035 ret.reserve(fFileNames.size());
1036 for (
auto nEntries : fileEntries) {
1051 std::size_t fileIdx,
const std::vector<std::uint64_t> &globalFileOffsets,
ROOT::TThreadExecutor &pool,
1053 std::atomic<ULong64_t> &globalEntries)
1055 const auto &fileName = fFileNames[fileIdx];
1056 auto source = CreatePageSource(fNTupleName, fileName);
1059 source->LoadAllPageLists();
1061 const std::uint64_t globalFileOffset = globalFileOffsets[fileIdx];
1063 const auto globalBegin = fGlobalEntryRange.value().first;
1064 const auto globalEnd = fGlobalEntryRange.value().second;
1066 const auto clustersAndEntries =
1067 [&]() -> std::pair<std::vector<ROOT::Internal::RNTupleClusterBoundaries>,
ROOT::NTupleSize_t> {
1068 const auto descGuard = source->GetSharedDescriptorGuard();
1069 const auto nEntries = descGuard->GetNEntries();
1073 if (nEntries == 0 || (globalFileOffset + nEntries) < globalBegin || globalFileOffset > globalEnd)
1080 if ((globalBegin >= globalFileOffset) || (globalEnd < (globalFileOffset + nEntries))) {
1081 std::vector<ROOT::Internal::RNTupleClusterBoundaries> adjustedClusters;
1082 for (
const auto &cluster : clustersInFile) {
1083 const std::uint64_t localBegin = globalBegin < globalFileOffset ? 0 : globalBegin - globalFileOffset;
1084 const std::uint64_t localEnd =
1085 globalEnd > globalFileOffset + nEntries ? globalFileOffset + nEntries : globalEnd - globalFileOffset;
1086 const auto currentBegin = std::max(cluster.fFirstEntry, localBegin);
1087 const auto currentEnd = std::min(cluster.fLastEntryPlusOne, localEnd);
1090 if (currentBegin < currentEnd)
1093 return std::make_pair(adjustedClusters, nEntries);
1096 return std::make_pair(clustersInFile, nEntries);
1101 const auto &clusters = clustersAndEntries.first;
1102 ScheduleTaskForPageSource(pool, std::move(source), fileName, clusters, nEntries, lm, slotStack, processedEntries,
1114 std::atomic<ULong64_t> &processedEntries,
1115 std::atomic<ULong64_t> &globalEntries)
1118 const auto &fileName = fFileNames[fileIdx];
1119 auto source = CreatePageSource(fNTupleName, fFileNames[fileIdx]);
1122 source->LoadAllPageLists();
1123 const auto clustersAndEntries = [&]() {
1124 const auto descGuard = source->GetSharedDescriptorGuard();
1130 const auto &clusters = clustersAndEntries.first;
1131 ScheduleTaskForPageSource(pool, std::move(source), fileName, clusters, nEntries, lm, slotStack, processedEntries,
1149 std::atomic<ULong64_t> processedEntries(0ull);
1150 std::atomic<ULong64_t> globalEntries(0ull);
1152 if (fGlobalEntryRange.has_value()) {
1153 const auto globalFileOffsets = ComputeGlobalEntryOffsets(pool);
1155 [&](std::size_t fileIdx) {
1156 ScheduleTasksForFileWithGlobalOffset(fileIdx, globalFileOffsets, pool, lm, slotStack, processedEntries,
1162 [&](std::size_t fileIdx) {
1163 ScheduleTasksForFile(fileIdx, pool, lm, slotStack, processedEntries, globalEntries);
1168 if (fGlobalEntryRange.has_value()) {
1169 const auto [begin, end] = fGlobalEntryRange.value();
1170 ULong64_t finalProcessedEntries = processedEntries.load();
1178 if ((end - begin) > finalProcessedEntries) {
1180 "RDataFrame stopped processing after %lld entries, whereas an entry range (begin=%lld,end=%lld) was "
1181 "requested. Consider adjusting the end value of the entry range to a maximum of %lld.",
1182 finalProcessedEntries, begin, end, begin + finalProcessedEntries);
long long Long64_t
Portable signed long integer 8 bytes.
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
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 r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
R__EXTERN TSystem * gSystem
The head node of a RDF computation graph.
void RNTupleThreadTask(const std::pair< ULong64_t, ULong64_t > &entryRange, unsigned int slot, std::uint64_t columnReaderOffset)
The task run by every thread on the input entry range, for the RNTuple data source.
Abstract implementation of the oneAPI Range requirements.
Every RDF column is represented by exactly one RNTuple field.
void * GetImpl(Long64_t entry) final
void Connect(RPageSource &source, Long64_t entryOffset)
Connect the field and its subfields to the page source.
RNTupleColumnReader(RNTupleDS *ds, RFieldBase *protoField)
std::unique_ptr< RFieldBase::RValue > fValue
The memory location used to read from fField.
std::unique_ptr< RFieldBase > fField
The field backing the RDF column.
Long64_t fEntryOffset
For chains, the logical entry and the physical entry in any particular file can be different.
std::shared_ptr< void > fValuePtr
Used to reuse the object created by fValue when reconnecting sources.
RNTupleDS * fDataSource
The data source that owns this column reader.
~RNTupleColumnReader() override=default
RFieldBase * fProtoField
The prototype field from which fField is cloned.
Long64_t fLastEntry
Last entry number that was read.
void Disconnect(bool keepValue)
Base for an artificial field that transforms an RNTuple column containing the offset of collections i...
static void SetClusterBunchSize(RNTupleReadOptions &options, unsigned int val)
Abstract interface to read data from an ntuple.
RSharedDescriptorGuard GetSharedDescriptorGuard() const
Takes the read lock for the descriptor.
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)
A thread-safe list of N indexes (0 to size - 1).
An artificial field that transforms an RNTuple column that contains the offset of collections into co...
std::vector< void * > Record_t
friend void ROOT::Internal::RDF::ProcessMT(RDataSource &, ROOT::Detail::RDF::RLoopManager &)
std::optional< std::pair< ULong64_t, ULong64_t > > fGlobalEntryRange
The RDataSource implementation for RNTuple.
void AddField(const ROOT::RNTupleDescriptor &desc, std::string_view colName, ROOT::DescriptorId_t fieldId, std::vector< RFieldInfo > fieldInfos, bool convertToRVec=true)
Provides the RDF column "colName" given the field identified by fieldID.
std::vector< std::pair< ULong64_t, ULong64_t > > GetEntryRanges() final
Return ranges of entries to distribute to tasks.
void ScheduleTaskForPageSource(ROOT::TThreadExecutor &pool, std::unique_ptr< ROOT::Internal::RPageSource > pageSource, std::string_view fileName, std::span< const ROOT::Internal::RNTupleClusterBoundaries > clusterBoundaries, std::uint64_t nEntries, ROOT::Detail::RDF::RLoopManager &lm, ROOT::Internal::RSlotStack &slotStack, std::atomic< ULong64_t > &processedEntries, std::atomic< ULong64_t > &globalEntries)
Call parallel_for to schedule a splittable task for a page source.
void InsertActiveEntryRange(unsigned int slot, std::string_view fileName, std::shared_ptr< ROOT::Internal::RPageSource > pageSource, std::uint64_t beginEntry, std::uint64_t endEntry, std::uint64_t offset)
void ExecStaging()
The main function of the fThreadStaging background thread.
void ScheduleTasksForFile(std::size_t fileIdx, ROOT::TThreadExecutor &pool, ROOT::Detail::RDF::RLoopManager &lm, ROOT::Internal::RSlotStack &slotStack, std::atomic< ULong64_t > &processedEntries, std::atomic< ULong64_t > &globalEntries)
Launch the task(s) for the input file index.
std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > GetColumnReaders(unsigned int, std::string_view, const std::type_info &) final
If the other GetColumnReaders overload returns an empty vector, this overload will be called instead.
std::vector< std::unique_ptr< ROOT::RFieldBase > > fProtoFields
We prepare a prototype field for every column.
void SetNSlots(unsigned int nSlots) final
Inform RDataSource of the number of processing slots (i.e.
ROOT::RFieldBase * GetFieldWithTypeChecks(std::string_view fieldName, const std::type_info &tid)
std::vector< std::string > fFileNames
void InitSlot(unsigned int slot, ULong64_t firstEntry) final
Convenience method called at the start of the data processing associated to a slot.
RNTupleDS(std::unique_ptr< ROOT::Internal::RPageSource > pageSource)
void ParallelForBody(std::shared_ptr< ROOT::Internal::RPageSource > pageSource, const ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl &rangeImpl, ROOT::Detail::RDF::RLoopManager &lm, std::string_view fileName, ROOT::Internal::RSlotStack &slotStack, std::atomic< ULong64_t > &processedEntries, ULong64_t columnReaderOffset)
Apply the computation graph to an input range.
std::string GetTypeName(std::string_view colName) const final
Type of a column as a string, e.g.
std::unordered_map< ROOT::DescriptorId_t, std::string > fFieldId2QualifiedName
Connects the IDs of active proto fields and their subfields to their fully qualified name (a....
std::string fNTupleName
The data source may be constructed with an ntuple name and a list of files.
void ScheduleTasksForFileWithGlobalOffset(std::size_t fileIdx, const std::vector< std::uint64_t > &globalFileOffsets, ROOT::TThreadExecutor &pool, ROOT::Detail::RDF::RLoopManager &lm, ROOT::Internal::RSlotStack &slotStack, std::atomic< ULong64_t > &processedEntries, std::atomic< ULong64_t > &globalEntries)
Launch the task(s) for the input file index, taking into account dataset global entry offsets.
void PrepareNextRanges()
Populates fNextRanges with the next set of entry ranges.
void StageNextSources()
Starting from fNextFileIndex, opens the next fNSlots files.
std::vector< std::uint64_t > ComputeGlobalEntryOffsets(ROOT::TThreadExecutor &pool) const
Computes global entry offsets for the dataset.
void Finalize() final
Convenience method called after concluding an event-loop.
std::vector< std::shared_ptr< ROOT::Internal::RPageSource > > fStagingArea
The staging area is relevant for chains of files, i.e.
std::vector< std::string > fColumnTypes
void Initialize() final
Convenience method called before starting an event-loop.
std::vector< std::string > fColumnNames
bool HasColumn(std::string_view colName) const final
Checks if the dataset has a certain column.
Record_t GetColumnReadersImpl(std::string_view name, const std::type_info &) final
type-erased vector of pointers to pointers to column values - one per slot
void FinalizeSlot(unsigned int slot) final
Convenience method called at the end of the data processing associated to a slot.
This type represents a sample identifier, to be used in conjunction with RDataFrame features such as ...
ROOT's RDataFrame offers a modern, high-level interface for analysis of data stored in TTree ,...
Base class for all ROOT issued exceptions.
A field translates read and write calls from/to underlying columns to/from tree values.
RConstSchemaIterator cbegin() const
const std::string & GetFieldName() const
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.
ROOT::DescriptorId_t GetOnDiskId() const
std::unique_ptr< RFieldBase > Clone(std::string_view newName) const
Copies the field and its subfields using a possibly new name and a new, unconnected set of columns.
std::uint64_t GetNRepetitions() const
const std::string & GetFieldName() const
const std::string & GetTypeName() const
The container field for an ntuple model, which itself has no physical representation.
std::vector< std::unique_ptr< RFieldBase > > ReleaseSubfields()
Moves all subfields into the returned vector.
void Attach(std::unique_ptr< RFieldBase > child)
A public version of the Attach method that allows piece-wise construction of the zero field.
The on-storage metadata of an RNTuple.
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
ROOT::DescriptorId_t FindFieldId(std::string_view fieldName, ROOT::DescriptorId_t parentId) const
Common user-tunable settings for reading RNTuples.
A pseudo container class which is a generator of indices.
This class provides a simple interface to execute the same task multiple times in parallel threads,...
void Foreach(F func, unsigned nTimes, unsigned nChunks=0)
Execute a function without arguments several times in parallel, dividing the execution in nChunks.
virtual const char * Getenv(const char *env)
Get environment variable.
void ParallelFor(ROOT::TThreadExecutor &pool, std::unique_ptr< RAbstractTBBRangeImpl > rangeImpl, const std::function< void(const RAbstractTBBRangeImpl &)> &body)
std::string TypeID2TypeName(const std::type_info &id)
Returns the name of a type starting from its type_info An empty string is returned in case of failure...
ROOT::RDataFrame FromRNTuple(std::string_view ntupleName, const std::vector< std::string > &fileNames, const std::pair< ULong64_t, ULong64_t > &range)
Internal overload of the function that allows passing a range of entries.
std::pair< std::vector< ROOT::Internal::RNTupleClusterBoundaries >, ROOT::NTupleSize_t > GetClustersAndEntries(std::string_view ntupleName, std::string_view location)
Retrieves the cluster boundaries and the number of entries for the input RNTuple.
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &)
std::vector< ROOT::Internal::RNTupleClusterBoundaries > GetClusterBoundaries(const RNTupleDescriptor &desc)
Return the cluster boundaries for each cluster in this RNTuple.
std::string GetRenormalizedTypeName(const std::string &metaNormalizedName)
Given a type name normalized by ROOT meta, renormalize it for RNTuple. E.g., insert std::prefix.
RDataFrame FromRNTuple(std::string_view ntupleName, std::string_view fileName)
std::vector< std::string > ColumnNames_t
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
constexpr NTupleSize_t kInvalidNTupleIndex
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Tag to let data sources use the native data type when creating a column reader.
A RAII object to pop and push slot numbers from a RSlotStack object.
Page source information consumed while running the computation graph.
std::string_view fFileName
Offset of both first and last entries w.r.t. the page source.
ULong64_t fLastEntry
End entry index in fSource, e.g. the number of entries in the range is fLastEntry - fFirstEntry.
ULong64_t fFirstEntry
First entry index in fSource.
std::shared_ptr< ROOT::Internal::RPageSource > fSource
The page source. It can be shared between this object and other multithreaded tasks.