Skip to content

Commit 73035ae

Browse files
committed
[ntuple] Add RNTupleModelChangeset::AddColumnRepr
This is for now an internal-only functionality that will be used by the Merger to extend column representations as needed during merging. Note that we already support reading back extended column reprs, but there is currently no way to write them.
1 parent 6f8f0ba commit 73035ae

5 files changed

Lines changed: 54 additions & 1 deletion

File tree

tree/ntuple/inc/ROOT/RNTupleModel.hxx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,11 +402,18 @@ You will not normally use this directly; see `RNTupleModel::RUpdater` instead.
402402
*/
403403
// clang-format on
404404
struct RNTupleModelChangeset {
405+
struct RAddedColumnRepr {
406+
ROOT::RFieldBase *fField = nullptr;
407+
std::uint16_t fNumNewColumns = 0;
408+
};
409+
405410
RNTupleModel &fModel;
406411
/// Points to the fields in fModel that were added as part of an updater transaction
407412
std::vector<ROOT::RFieldBase *> fAddedFields;
408413
/// Points to the projected fields in fModel that were added as part of an updater transaction
409414
std::vector<ROOT::RFieldBase *> fAddedProjectedFields;
415+
/// Points to fields in fModel that had new column representations appended to them.
416+
std::vector<RAddedColumnRepr> fAddedColumnReprs;
410417

411418
RNTupleModelChangeset(RNTupleModel &model) : fModel(model) {}
412419
bool IsEmpty() const { return fAddedFields.empty() && fAddedProjectedFields.empty(); }
@@ -420,6 +427,9 @@ struct RNTupleModelChangeset {
420427
/// \see RNTupleModel::AddProjectedField()
421428
ROOT::RResult<void>
422429
AddProjectedField(std::unique_ptr<ROOT::RFieldBase> field, RNTupleModel::FieldMappingFunc_t mapping);
430+
431+
ROOT::RResult<void>
432+
AddColumnRepr(ROOT::RFieldBase *field, const ROOT::RFieldBase::RColumnRepresentations::Selection_t &reprs);
423433
};
424434

425435
} // namespace Internal

tree/ntuple/src/RFieldBase.cxx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,15 @@ ROOT::RFieldBase::RColumnRepresentations::Selection_t ROOT::RFieldBase::GetColum
830830

831831
void ROOT::RFieldBase::SetColumnRepresentatives(const RColumnRepresentations::Selection_t &representatives)
832832
{
833-
if (fState != EState::kUnconnected)
833+
const auto isNewSelectionASuperset = [&]() {
834+
if (representatives.size() < fColumnRepresentatives.size())
835+
return false;
836+
for (auto i = 0u; i < fColumnRepresentatives.size(); ++i)
837+
if (representatives[i] != fColumnRepresentatives[i].get())
838+
return false;
839+
return true;
840+
};
841+
if (fState != EState::kUnconnected && !(fState == EState::kConnectedToSink && isNewSelectionASuperset()))
834842
throw RException(R__FAIL("cannot set column representative once field is connected"));
835843
const auto &validTypes = GetColumnRepresentations().GetSerializationTypes();
836844
fColumnRepresentatives.clear();

tree/ntuple/src/RNTupleModel.cxx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,27 @@ ROOT::RNTupleModel::RUpdater::AddProjectedField(std::unique_ptr<ROOT::RFieldBase
287287
return R__FORWARD_RESULT(fOpenChangeset.AddProjectedField(std::move(field), std::move(mapping)));
288288
}
289289

290+
ROOT::RResult<void> ROOT::Internal::RNTupleModelChangeset::AddColumnRepr(
291+
ROOT::RFieldBase *field, const ROOT::RFieldBase::RColumnRepresentations::Selection_t &newReprs)
292+
{
293+
auto reprs = field->GetColumnRepresentatives();
294+
const auto nPrev = reprs.size();
295+
for (auto newRepr : newReprs)
296+
// NOTE: we don't need to check for duplicates because SetColumnRepresentatives will do that for us.
297+
reprs.push_back(newRepr);
298+
299+
field->SetColumnRepresentatives(reprs);
300+
const auto nNew = field->GetColumnRepresentatives().size();
301+
assert(reprs.size() > 0 && reprs[0].size() <= 2);
302+
const auto cardinality = static_cast<std::uint16_t>(reprs[0].size());
303+
assert(nNew >= nPrev);
304+
std::uint16_t nAdded = (nNew - nPrev) * cardinality;
305+
if (nAdded > 0)
306+
fAddedColumnReprs.push_back(RAddedColumnRepr{field, nAdded});
307+
308+
return RResult<void>::Success();
309+
}
310+
290311
void ROOT::RNTupleModel::EnsureValidFieldName(std::string_view fieldName)
291312
{
292313
RResult<void> nameValid = ROOT::Internal::EnsureValidNameForRNTuple(fieldName, "Field");

tree/ntuple/src/RPageSinkBuf.cxx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,20 @@ void ROOT::Internal::RPageSinkBuf::UpdateSchema(const ROOT::Internal::RNTupleMod
125125
GetProjectedFieldsOfModel(*fInnerModel).Add(std::move(cloned), fieldMap);
126126
return p;
127127
};
128+
auto cloneAddColumnRepr = [&](const RNTupleModelChangeset::RAddedColumnRepr &repr) {
129+
auto &innerField = fInnerModel->GetMutableField(repr.fField->GetFieldName());
130+
innerField.SetColumnRepresentatives(repr.fField->GetColumnRepresentatives());
131+
ROOT::Internal::CallConnectExtendedColumnsToPageSinkOnField(innerField, *this, firstEntry);
132+
return repr;
133+
};
128134
RNTupleModelChangeset innerChangeset{*fInnerModel};
129135
fInnerModel->Unfreeze();
130136
std::transform(changeset.fAddedFields.cbegin(), changeset.fAddedFields.cend(),
131137
std::back_inserter(innerChangeset.fAddedFields), cloneAddField);
132138
std::transform(changeset.fAddedProjectedFields.cbegin(), changeset.fAddedProjectedFields.cend(),
133139
std::back_inserter(innerChangeset.fAddedProjectedFields), cloneAddProjectedField);
140+
std::transform(changeset.fAddedColumnReprs.cbegin(), changeset.fAddedColumnReprs.cend(),
141+
std::back_inserter(innerChangeset.fAddedColumnReprs), cloneAddColumnRepr);
134142
fInnerModel->Freeze();
135143
fInnerSink->UpdateSchema(innerChangeset, firstEntry);
136144
}

tree/ntuple/src/RPageStorage.cxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,9 @@ void ROOT::Internal::RPagePersistentSink::UpdateSchema(const ROOT::Internal::RNT
868868
for (const auto &descendant : *f)
869869
nNewPhysicalColumns += getNColumns(descendant);
870870
}
871+
for (auto added : changeset.fAddedColumnReprs) {
872+
nNewPhysicalColumns += added.fNumNewColumns;
873+
}
871874
fDescriptorBuilder.ShiftAliasColumns(nNewPhysicalColumns);
872875
}
873876

@@ -913,6 +916,9 @@ void ROOT::Internal::RPagePersistentSink::UpdateSchema(const ROOT::Internal::RNT
913916
for (auto &descendant : *f)
914917
addProjectedField(descendant);
915918
}
919+
for (const auto& [f, _] : changeset.fAddedColumnReprs) {
920+
ROOT::Internal::CallConnectExtendedColumnsToPageSinkOnField(*f, *this, firstEntry);
921+
}
916922

917923
const auto nColumns = descriptor.GetNPhysicalColumns();
918924
fOpenColumnRanges.reserve(fOpenColumnRanges.size() + (nColumns - nColumnsBeforeUpdate));

0 commit comments

Comments
 (0)