Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-15 09:24:06

0001 /// \file ROOT/RNTupleMerger.hxx
0002 /// \ingroup NTuple
0003 /// \author Jakob Blomer <jblomer@cern.ch>, Max Orok <maxwellorok@gmail.com>, Alaettin Serhan Mete <amete@anl.gov>
0004 /// \date 2020-07-08
0005 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
0006 /// is welcome!
0007 
0008 /*************************************************************************
0009  * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers.               *
0010  * All rights reserved.                                                  *
0011  *                                                                       *
0012  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0013  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0014  *************************************************************************/
0015 
0016 #ifndef ROOT_RNTupleMerger
0017 #define ROOT_RNTupleMerger
0018 
0019 #include <ROOT/RError.hxx>
0020 #include <ROOT/RNTupleDescriptor.hxx>
0021 #include <ROOT/RNTupleTypes.hxx>
0022 #include <ROOT/RPageStorage.hxx>
0023 #include <ROOT/TTaskGroup.hxx>
0024 #include <Compression.h>
0025 
0026 #include <memory>
0027 #include <optional>
0028 
0029 namespace ROOT {
0030 
0031 class RNTuple;
0032 
0033 namespace Internal {
0034 class RPageAllocator;
0035 class RClusterPool;
0036 } // namespace Internal
0037 
0038 namespace Experimental::Internal {
0039 
0040 enum class ENTupleMergingMode {
0041    /// The merger will discard all columns that aren't present in the prototype model (i.e. the model of the first
0042    /// source); also all subsequent RNTuples must contain at least all the columns that are present in the prototype
0043    /// model
0044    kFilter,
0045    /// The merger will refuse to merge any 2 RNTuples whose schema doesn't match exactly
0046    kStrict,
0047    /// The merger will update the output model to include all columns from all sources. Entries corresponding to columns
0048    /// that are not present in a source will be set to the default value of the type.
0049    kUnion
0050 };
0051 
0052 inline const char *ToString(ENTupleMergingMode mode)
0053 {
0054    static const char *const kMergingModeStr[] = {"Filter", "Strict", "Union"};
0055    return kMergingModeStr[static_cast<int>(mode)];
0056 }
0057 
0058 enum class ENTupleMergeErrBehavior {
0059    /// The merger will abort merging as soon as an error is encountered
0060    kAbort,
0061    /// Upon errors, the merger will skip the current source and continue
0062    kSkip
0063 };
0064 
0065 enum class ENTupleMergeVersionBehavior {
0066    /// The merger will emit a warning when merging RNTuples with higher version than the latest supported by this
0067    /// ROOT version, but merging will work. Some optional features present in the source(s) may be missing from the
0068    /// merged RNTuple.
0069    kWarnOnHigherVersion,
0070    /// The merger will refuse to merge RNTuples with higher versions than the latest supported by this ROOT version.
0071    /// The merging process will abort as soon as one such source is encountered.
0072    kAbortOnHigherVersion
0073 };
0074 
0075 struct RColumnMergeInfo;
0076 struct RNTupleMergeData;
0077 struct RSealedPageMergeData;
0078 
0079 /// Set of merging options to pass to RNTupleMerger.
0080 /// If you're using the merger through TFileMerger you need to give it string-based options instead.
0081 /// Here is the mapping for the TFileMerger options:
0082 ///   - "rntuple.MergingMode=(Filter|Union|...)" -> sets fMergingMode
0083 ///   - "rntuple.ErrBehavior=(Abort|Skip|...)"   -> sets fErrBehavior
0084 ///   - "rntuple.VersionBehavior=(WarnOnHigherVersion|AbortOnHigherVersion|...)" -> sets fVersionBehavior
0085 ///   - "rntuple.ExtraVerbose"                   -> sets fExtraVerbose to true
0086 /// Rules about the string-based options:
0087 ///   1. there must be no space between the separators (i.e. `.` and `=`)
0088 ///   2. all string matching is case insensitive
0089 struct RNTupleMergeOptions {
0090    /// If fCompressionSettings is empty (the default), the merger will not change the
0091    /// compression of any of its sources (fast merging). Otherwise, all sources will be converted to the specified
0092    /// compression algorithm and level.
0093    std::optional<std::uint32_t> fCompressionSettings;
0094    /// Determines how the merging treats sources with different models (\see ENTupleMergingMode).
0095    ENTupleMergingMode fMergingMode = ENTupleMergingMode::kFilter;
0096    /// Determines how the Merge function behaves upon merging errors
0097    ENTupleMergeErrBehavior fErrBehavior = ENTupleMergeErrBehavior::kAbort;
0098    /// Determines how the Merge function behaves depending on the RNTuple sources' version.
0099    ENTupleMergeVersionBehavior fVersionBehavior = ENTupleMergeVersionBehavior::kWarnOnHigherVersion;
0100    /// If true, the merger will emit further diagnostics and information.
0101    bool fExtraVerbose = false;
0102 };
0103 
0104 // clang-format off
0105 /**
0106  * \class ROOT::Experimental::Internal::RNTupleMerger
0107  * \ingroup NTuple
0108  * \brief Given a set of RPageSources merge them into an RPagePersistentSink, optionally changing their compression.
0109  *        This can also be used to change the compression of a single RNTuple by just passing a single source.
0110  */
0111 // clang-format on
0112 class RNTupleMerger final {
0113    friend class ROOT::RNTuple;
0114 
0115    std::unique_ptr<ROOT::Internal::RPagePersistentSink> fDestination;
0116    std::unique_ptr<ROOT::Internal::RPageAllocator> fPageAlloc;
0117    std::optional<TTaskGroup> fTaskGroup;
0118    std::unique_ptr<ROOT::RNTupleModel> fModel;
0119 
0120    [[nodiscard]]
0121    ROOT::RResult<void> MergeCommonColumns(ROOT::Internal::RClusterPool &clusterPool,
0122                                           const ROOT::RClusterDescriptor &clusterDesc,
0123                                           std::span<const RColumnMergeInfo> commonColumns,
0124                                           const ROOT::Internal::RCluster::ColumnSet_t &commonColumnSet,
0125                                           std::size_t nCommonColumnsInCluster, RSealedPageMergeData &sealedPageData,
0126                                           const RNTupleMergeData &mergeData, ROOT::Internal::RPageAllocator &pageAlloc);
0127 
0128    [[nodiscard]]
0129    ROOT::RResult<void>
0130    MergeSourceClusters(ROOT::Internal::RPageSource &source, std::span<const RColumnMergeInfo> commonColumns,
0131                        std::span<const RColumnMergeInfo> extraDstColumns, RNTupleMergeData &mergeData);
0132 
0133    /// Creates a RNTupleMerger with the given destination.
0134    /// The model must be given if and only if `destination` has been initialized with that model
0135    /// (i.e. in case of incremental merging).
0136    RNTupleMerger(std::unique_ptr<ROOT::Internal::RPagePersistentSink> destination,
0137                  std::unique_ptr<ROOT::RNTupleModel> model);
0138 
0139 public:
0140    /// Creates a RNTupleMerger with the given destination.
0141    explicit RNTupleMerger(std::unique_ptr<ROOT::Internal::RPagePersistentSink> destination);
0142 
0143    /// Merge a given set of sources into the destination.
0144    /// Note that sources with an empty schema (i.e. created from a Model that had no fields added to it) are in
0145    /// general valid (depending on the merging mode) but add no entries to the destination.
0146    RResult<void> Merge(std::span<ROOT::Internal::RPageSource *> sources,
0147                        const RNTupleMergeOptions &mergeOpts = RNTupleMergeOptions());
0148 
0149 }; // end of class RNTupleMerger
0150 
0151 } // namespace Experimental::Internal
0152 } // namespace ROOT
0153 
0154 #endif