Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tree/ntuple/inc/ROOT/REntry.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class RNTupleAttrSetReader;

namespace Internal {
struct RNTupleAttrEntry;
class RNTupleMergeStrategySlow;
}
} // namespace Experimental

Expand All @@ -56,6 +57,7 @@ class REntry {
friend class RNTupleModel;
friend class RNTupleReader;
friend class Experimental::RNTupleAttrSetReader;
friend class Experimental::Internal::RNTupleMergeStrategySlow;
friend struct Experimental::Internal::RNTupleAttrEntry;

private:
Expand Down
4 changes: 4 additions & 0 deletions tree/ntuple/inc/ROOT/RFieldBase.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ void CallConnectPageSourceOnField(RFieldBase &, ROOT::Internal::RPageSource &);
ROOT::RResult<std::unique_ptr<ROOT::RFieldBase>>
CallFieldBaseCreate(const std::string &fieldName, const std::string &typeName, const ROOT::RCreateFieldOptions &options,
const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId);
void CallSetArtificialOnField(RFieldBase &);

} // namespace Internal

namespace Experimental::Internal {
struct RNTupleAttrEntry;
class RNTupleMerger;
}

// clang-format off
Expand All @@ -90,6 +92,7 @@ class RFieldBase {
friend class RFieldZero; // to reset fParent pointer in ReleaseSubfields()
friend class ROOT::Detail::RRawPtrWriteEntry; // to call Append()
friend class ROOT::Experimental::RNTupleAttrSetReader; // for field->Read() in LoadEntry()
friend class ROOT::Experimental::Internal::RNTupleMerger;
friend struct ROOT::Internal::RFieldCallbackInjector; // used for unit tests
friend struct ROOT::Internal::RFieldRepresentationModifier; // used for unit tests
friend void Internal::CallFlushColumnsOnField(RFieldBase &);
Expand All @@ -100,6 +103,7 @@ class RFieldBase {
Internal::CallFieldBaseCreate(const std::string &fieldName, const std::string &typeName,
const ROOT::RCreateFieldOptions &options, const ROOT::RNTupleDescriptor *desc,
ROOT::DescriptorId_t fieldId);
friend void Internal::CallSetArtificialOnField(RFieldBase &);

using ReadCallback_t = std::function<void(void *)>;

Expand Down
55 changes: 55 additions & 0 deletions tree/ntuple/inc/ROOT/RNTupleMerger.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

namespace ROOT {

class REntry;
class RNTuple;

namespace Internal {
Expand All @@ -35,6 +36,10 @@ class RPageSource;

namespace Experimental::Internal {

class RNTupleMergeStrategySlow;
struct RNTupleSlowMergeData;
struct RDescriptorsComparison;

enum class ENTupleMergingMode {
/// The merger will discard all columns that aren't present in the prototype model (i.e. the model of the first
/// source); also all subsequent RNTuples must contain at least all the columns that are present in the prototype
Expand Down Expand Up @@ -95,6 +100,56 @@ struct RNTupleMergeOptions {
bool fExtraVerbose = false;
};

/// Information regarding the current slow merge process that gets passed to the SlowMergeActions
struct RNTupleSlowMergeContext {
ROOT::NTupleSize_t fSourceEntryIndex = 0;
ROOT::NTupleSize_t fDestinationEntryIndex = 0;
};

enum class ENTupleSlowMergeResult {
// Don't emit this entry
kDrop,
// Emit this entry, then continue
kEmit,
// Emit this entry, then call the function again
kEmitMulti,
};

// clang-format off
/**
* \class ROOT::Experimental::Internal::RNTupleSlowMergeActions
* \ingroup NTuple
* \brief Container for callbacks that are invoked during the "slow merge" process.
* This allows customizing how the merging happens entry-by-entry, enabling things like dropping individual
* entries from the destination RNTuple, modifying their values on the fly or creating new entries artificially.
*/
// clang-format on
class RNTupleSlowMergeActions {
public:
RNTupleSlowMergeActions() = default;
virtual ~RNTupleSlowMergeActions() = default;

RNTupleSlowMergeActions(const RNTupleSlowMergeActions &) = delete;
RNTupleSlowMergeActions &operator=(const RNTupleSlowMergeActions &) = delete;
RNTupleSlowMergeActions(RNTupleSlowMergeActions &&) = default;
RNTupleSlowMergeActions &operator=(RNTupleSlowMergeActions &&) = default;

/// Invoked every time an entry is merged from a source RNTuple to the destination RNTuple.
virtual ENTupleSlowMergeResult OnFill(ROOT::REntry &, const RNTupleSlowMergeContext &)
{
return ENTupleSlowMergeResult::kEmit;
}

/// Invoked at the end of the merge process, right before committing the dataset.
/// This allows appending more entries at the end of the merge.
virtual ENTupleSlowMergeResult BeforeCommit(ROOT::REntry &, const RNTupleSlowMergeContext &)
{
return ENTupleSlowMergeResult::kDrop;
}
};

// using RNTupleSlowMergeFn_t = std::function<RNTupleSlowMergeResult(ROOT::REntry &, const RNTupleSlowMergeContext &)>;

// clang-format off
/**
* \class ROOT::Experimental::Internal::RNTupleMerger
Expand Down
5 changes: 4 additions & 1 deletion tree/ntuple/src/RFieldBase.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ void ROOT::Internal::CallConnectPageSourceOnField(RFieldBase &field, ROOT::Inter
{
field.ConnectPageSource(source);
}
void ROOT::Internal::CallSetArtificialOnField(RFieldBase &field)
{
field.SetArtificial();
}

ROOT::RResult<std::unique_ptr<ROOT::RFieldBase>>
ROOT::Internal::CallFieldBaseCreate(const std::string &fieldName, const std::string &typeName,
Expand Down Expand Up @@ -605,7 +609,6 @@ std::unique_ptr<ROOT::RFieldBase> ROOT::RFieldBase::Clone(std::string_view newNa
{
auto clone = CloneImpl(newName);
clone->fTypeAlias = fTypeAlias;
clone->fOnDiskId = fOnDiskId;
clone->fDescription = fDescription;
// We can just copy the references because fColumnRepresentatives point into a static structure
clone->fColumnRepresentatives = fColumnRepresentatives;
Expand Down
Loading
Loading