Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleAttrWriting.cxx
Go to the documentation of this file.
1/// \file RNTupleAttrWriting.cxx
2/// \ingroup NTuple ROOT7
3/// \author Giacomo Parolini <giacomo.parolini@cern.ch>
4/// \date 2026-01-27
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
10#include <ROOT/RNTupleModel.hxx>
13#include <ROOT/StringUtils.hxx>
14
16
18{
20 if (!projFields.IsEmpty())
21 return R__FAIL("The Model used to create an AttributeSet cannot contain projected fields.");
22
23 for (const auto &field : model.GetConstFieldZero()) {
24 if (field.GetStructure() == ROOT::ENTupleStructure::kStreamer)
25 return R__FAIL(std::string("The Model used to create an AttributeSet cannot contain Streamer field '") +
26 field.GetQualifiedFieldName() + "'");
27 }
29}
30
31//
32// RNTupleAttrEntry
33//
35{
36 std::size_t bytesWritten = 0;
37 // Write the meta entry values
40
41 // Bind the user model's memory to the meta model's subfields
42 const auto &userFields =
44 assert(userFields.size() == fScopedEntry.fValues.size());
45 for (std::size_t i = 0; i < fScopedEntry.fValues.size(); ++i) {
46 std::shared_ptr<void> userPtr = fScopedEntry.fValues[i].GetPtr<void>();
47 auto value = userFields[i]->BindValue(userPtr);
48 bytesWritten += value.Append();
49 }
50 return bytesWritten;
51}
52
53//
54// RNTupleAttrSetWriter
55//
56std::unique_ptr<ROOT::Experimental::RNTupleAttrSetWriter>
58 std::unique_ptr<ROOT::Internal::RPageSink> sink,
59 std::unique_ptr<RNTupleModel> userModel)
60
61{
62 ValidateAttributeModel(*userModel).ThrowOnError();
63
64 // We create a "meta model" that's what we'll use to write data to storage. This meta model has 3 fields:
65 // the "meta fields" _rangeStart / _rangeLen and an untyped Record field which contains all the top-level fields
66 // from the user model as its children. This is done to "namespace" all user-defined attribute fields so that we
67 // are free to use whichever name we want for our meta fields.
68 // Note that the user model is preserved as-is to allow the user to create entries from it or use its default
69 // entry. When we actually write data to storage, we do some pointer trickery to correctly read the values from
70 // the user model and store them under the meta model's fields (see RNTupleAttrEntry::Append())
72 metaModel->SetDescription(userModel->GetDescription());
75 std::vector<std::unique_ptr<RFieldBase>> fields;
76 const auto subfields = userModel->GetConstFieldZero().GetConstSubfields();
77 fields.reserve(subfields.size());
78 for (const auto *field : subfields) {
79 fields.push_back(field->Clone(field->GetFieldName()));
80 }
81 auto userRootField = std::make_unique<ROOT::RRecordField>(kUserModelName, std::move(fields));
82 metaModel->AddField(std::move(userRootField));
83
84 metaModel->Freeze();
85 userModel->Freeze();
86
87 return std::unique_ptr<RNTupleAttrSetWriter>(
88 new RNTupleAttrSetWriter(mainFillContext, std::move(sink), std::move(metaModel), std::move(userModel),
89 std::move(rangeStartPtr), std::move(rangeLenPtr)));
90}
91
93 std::unique_ptr<ROOT::Internal::RPageSink> sink,
94 std::unique_ptr<RNTupleModel> metaModel,
95 std::unique_ptr<RNTupleModel> userModel,
96 std::shared_ptr<ROOT::NTupleSize_t> rangeStartPtr,
97 std::shared_ptr<ROOT::NTupleSize_t> rangeLenPtr)
98 : fFillContext(std::move(metaModel), std::move(sink)),
99 fMainFillContext(&mainFillContext),
100 fUserModel(std::move(userModel)),
101 fRangeStartPtr(std::move(rangeStartPtr)),
102 fRangeLenPtr(std::move(rangeLenPtr))
103{
104}
105
107{
108 const auto start = fMainFillContext->GetNEntries();
109 return RNTupleAttrPendingRange{start, fFillContext.GetModel().GetModelId()};
110}
111
113 REntry &entry)
114{
115 // NOTE: this has to happen before potentially throwing the exception, otherwise the pending range will log its
116 // "was not committed" warning in addition to it.
117 // Once the user passed the pending range to this function they already relinquished its ownership, thus we can
118 // very well consider it "committed" for error reporting purposes, even if it never ends up actually committed
119 // due to exception.
120 pendingRange.fWasCommitted = true;
121
122 if (pendingRange.GetModelId() != fFillContext.GetModel().GetModelId())
123 throw ROOT::RException(R__FAIL("Range passed to CommitRange() of AttributeSet '" + GetDescriptor().GetName() +
124 "' was not created by it or was already committed."));
125
126 // Get current entry number from the writer and use it as end of entry range
127 const auto end = fMainFillContext->GetNEntries();
128 auto &metaEntry = fFillContext.fModel->GetDefaultEntry();
129 R__ASSERT(end >= pendingRange.GetStart());
130 *fRangeStartPtr = pendingRange.GetStart();
131 *fRangeLenPtr = end - pendingRange.GetStart();
132 Internal::RNTupleAttrEntry pair{metaEntry, entry, *fFillContext.fModel};
133 fFillContext.FillImpl(pair);
134}
135
140
142{
143 fFillContext.FlushCluster();
144 fFillContext.fSink->CommitClusterGroup();
145 return fFillContext.fSink->CommitDataset();
146}
#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
static ROOT::RResult< void > ValidateAttributeModel(const ROOT::RNTupleModel &model)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#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 value
A not-yet-finalized Attribute Range used for writing.
Class used to write an RNTupleAttrSet in the context of an RNTupleWriter.
static std::unique_ptr< RNTupleAttrSetWriter > Create(const RNTupleFillContext &mainFillContext, std::unique_ptr< ROOT::Internal::RPageSink > sink, std::unique_ptr< RNTupleModel > userModel)
Creates an RNTupleAttrSetWriter associated to the RNTupleWriter owning mainFillContext and writing us...
ROOT::Internal::RNTupleLink Commit()
Commits the attributes written so far to disk and disables writing any new ones.
RNTupleAttrPendingRange BeginRange()
Begins an attribute range.
RNTupleAttrSetWriter(const RNTupleFillContext &mainFillContext, std::unique_ptr< ROOT::Internal::RPageSink > sink, std::unique_ptr< RNTupleModel > metaModel, std::unique_ptr< RNTupleModel > userModel, std::shared_ptr< ROOT::NTupleSize_t > rangeStartPtr, std::shared_ptr< ROOT::NTupleSize_t > rangeLenPtr)
void CommitRange(RNTupleAttrPendingRange range)
Ends an attribute range and associates the current values of the fields of the attribute model's defa...
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:51
std::vector< ROOT::RFieldBase::RValue > fValues
Corresponds to the fields of the linked model.
Definition REntry.hxx:63
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
std::vector< RFieldBase * > GetMutableSubfields()
A context for filling entries (data) into clusters of an RNTuple.
The RNTupleModel encapulates the schema of an RNTuple.
const ROOT::RFieldZero & GetConstFieldZero() const
Retrieves the field zero of this model, i.e. the root of the field hierarchy.
static std::unique_ptr< RNTupleModel > Create()
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:198
ROOT::RFieldZero & GetFieldZeroOfModel(RNTupleModel &model)
RProjectedFields & GetProjectedFieldsOfModel(RNTupleModel &model)
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
A pair of scoped + meta entry used by the RNTupleAttrSetWriter.