Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RNTupleAttrWriting.cxx
Go to the documentation of this file.
1/// \file RNTupleAttrWriting.cxx
2/// \author Giacomo Parolini <giacomo.parolini@cern.ch>
3/// \date 2026-01-27
4/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
5/// is welcome!
6
12#include <ROOT/StringUtils.hxx>
13
15
17{
18 const auto &projFields = ROOT::Internal::GetProjectedFieldsOfModel(model);
19 if (!projFields.IsEmpty())
20 return R__FAIL("The Model used to create an AttributeSet cannot contain projected fields.");
21
22 for (const auto &field : model.GetConstFieldZero()) {
23 if (field.GetStructure() == ROOT::ENTupleStructure::kStreamer)
24 return R__FAIL(std::string("The Model used to create an AttributeSet cannot contain Streamer field '") +
25 field.GetQualifiedFieldName() + "'");
26 }
28}
29
30//
31// RNTupleAttrEntry
32//
34{
35 std::size_t bytesWritten = 0;
36 // Write the meta entry values
37 bytesWritten += fMetaEntry.fValues[kMetaFieldIndex_RangeStart].Append();
38 bytesWritten += fMetaEntry.fValues[kMetaFieldIndex_RangeLen].Append();
39
40 // Bind the user model's memory to the meta model's subfields
41 const auto &userFields = ROOT::Internal::GetFieldZeroOfModel(fMetaModel)
43 ->GetMutableSubfields();
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{
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())
71 auto metaModel = RNTupleModel::Create();
72 metaModel->SetDescription(userModel->GetDescription());
73 auto rangeStartPtr = metaModel->MakeField<ROOT::NTupleSize_t>(kMetaFieldNames[kMetaFieldIndex_RangeStart]);
74 auto rangeLenPtr = metaModel->MakeField<ROOT::NTupleSize_t>(kMetaFieldNames[kMetaFieldIndex_RangeLen]);
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 =
82 std::make_unique<ROOT::RRecordField>(kMetaFieldNames[kMetaFieldIndex_UserData], std::move(fields));
83 metaModel->AddField(std::move(userRootField));
84
85 metaModel->Freeze();
86 userModel->Freeze();
87
88 return std::unique_ptr<RNTupleAttrSetWriter>(
89 new RNTupleAttrSetWriter(mainFillContext, std::move(sink), std::move(metaModel), std::move(userModel),
90 std::move(rangeStartPtr), std::move(rangeLenPtr)));
91}
92
94 std::unique_ptr<ROOT::Internal::RPageSink> sink,
95 std::unique_ptr<RNTupleModel> metaModel,
96 std::unique_ptr<RNTupleModel> userModel,
97 std::shared_ptr<ROOT::NTupleSize_t> rangeStartPtr,
98 std::shared_ptr<ROOT::NTupleSize_t> rangeLenPtr)
99 : fFillContext(std::move(metaModel), std::move(sink)),
100 fMainFillContext(&mainFillContext),
101 fUserModel(std::move(userModel)),
102 fRangeStartPtr(std::move(rangeStartPtr)),
103 fRangeLenPtr(std::move(rangeLenPtr))
104{
105}
106
112
114 REntry &entry)
115{
116 // NOTE: this has to happen before potentially throwing the exception, otherwise the pending range will log its
117 // "was not committed" warning in addition to it.
118 // Once the user passed the pending range to this function they already relinquished its ownership, thus we can
119 // very well consider it "committed" for error reporting purposes, even if it never ends up actually committed
120 // due to exception.
121 pendingRange.fWasCommitted = true;
122
123 if (pendingRange.GetModelId() != fFillContext.GetModel().GetModelId())
124 throw ROOT::RException(R__FAIL("Range passed to CommitRange() of AttributeSet '" + GetDescriptor().GetName() +
125 "' was not created by it or was already committed."));
126
127 // Get current entry number from the writer and use it as end of entry range
128 const auto end = fMainFillContext->GetNEntries();
129 auto &metaEntry = fFillContext.fModel->GetDefaultEntry();
130 R__ASSERT(end >= pendingRange.GetStart());
131 *fRangeStartPtr = pendingRange.GetStart();
132 *fRangeLenPtr = end - pendingRange.GetStart();
133 Internal::RNTupleAttrEntry pair{metaEntry, entry, *fFillContext.fModel};
134 fFillContext.FillImpl(pair);
135}
136
138{
139 CommitRange(std::move(pendingRange), fUserModel->GetDefaultEntry());
140}
141
143{
144 fFillContext.FlushCluster();
145 fFillContext.fSink->CommitClusterGroup();
146 return fFillContext.fSink->CommitDataset();
147}
#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
static ROOT::RResult< void > ValidateAttributeModel(const ROOT::RNTupleModel &model)
start
Definition Rotated.cxx:223
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
A not-yet-finalized Attribute Range used for writing.
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...
std::shared_ptr< ROOT::NTupleSize_t > fRangeLenPtr
std::unique_ptr< RNTupleModel > fUserModel
The model that the user provided on creation. Used to create user-visible entries.
const RNTupleFillContext * fMainFillContext
Fill context of the main RNTuple being written (i.e. the RNTuple whose attributes we are).
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)
std::shared_ptr< ROOT::NTupleSize_t > fRangeStartPtr
void CommitRange(RNTupleAttrPendingRange range)
Ends an attribute range and associates the current values of the fields of the attribute model's defa...
RNTupleFillContext fFillContext
Our own fill context.
const ROOT::RNTupleDescriptor & GetDescriptor() const
Returns the descriptor of the underlying attribute RNTuple.
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:54
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
std::vector< RFieldBase * > GetMutableSubfields()
A context for filling entries (data) into clusters of an RNTuple.
The RNTupleModel encapulates the schema of an RNTuple.
static std::unique_ptr< RNTupleModel > Create()
void ThrowOnError()
Short-hand method to throw an exception in the case of errors.
Definition RError.hxx:289
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:197
STL class.
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.