Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-31 09:45:46

0001 /// \file ROOT/RNTupleParallelWriter.hxx
0002 /// \ingroup NTuple
0003 /// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
0004 /// \date 2024-02-01
0005 
0006 /*************************************************************************
0007  * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers.               *
0008  * All rights reserved.                                                  *
0009  *                                                                       *
0010  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0011  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0012  *************************************************************************/
0013 
0014 #ifndef ROOT_RNTupleParallelWriter
0015 #define ROOT_RNTupleParallelWriter
0016 
0017 #include <ROOT/RNTupleMetrics.hxx>
0018 #include <ROOT/RNTupleWriteOptions.hxx>
0019 
0020 #include <memory>
0021 #include <mutex>
0022 #include <string_view>
0023 #include <vector>
0024 
0025 class TDirectory;
0026 
0027 namespace ROOT {
0028 
0029 class RNTupleModel;
0030 
0031 namespace Internal {
0032 class RPageSink;
0033 } // namespace Internal
0034 
0035 class RNTupleFillContext;
0036 
0037 /**
0038 \class ROOT::RNTupleParallelWriter
0039 \ingroup NTuple
0040 \brief A writer to fill an RNTuple from multiple contexts
0041 
0042 Compared to the sequential RNTupleWriter, a parallel writer enables the creation of multiple RNTupleFillContext (see
0043 CreateFillContext()).  Each fill context prepares independent clusters that are appended to the common RNTuple with
0044 internal synchronization.  Before destruction, all fill contexts must have flushed their data and been destroyed (or
0045 data could be lost!).
0046 
0047 For user convenience, CreateFillContext() is thread-safe and may be called from multiple threads in parallel at any
0048 time, also after some data has already been written.  Internally, the original model is cloned and ownership is passed
0049 to a newly created RNTupleFillContext.  For that reason, it is recommended to use RNTupleModel::CreateBare when creating
0050 the model for parallel writing and avoid the allocation of a useless default REntry per context.
0051 
0052 Note that the sequence of independently prepared clusters is indeterminate and therefore entries are only partially
0053 ordered:  Entries from one context are totally ordered as they were filled.  However, there is no orderering with other
0054 contexts and the entries may be appended to the RNTuple either before or after other entries written in parallel into
0055 other contexts.  In addition, two consecutive entries in one fill context can end up separated in the final RNTuple, if
0056 they happen to fall onto a cluster boundary and other contexts append more entries before the next cluster is full.
0057 
0058 At the moment, the parallel writer does not (yet) support incremental updates of the underlying model. Please refer to
0059 RNTupleWriter::CreateModelUpdater if required for your use case.
0060 */
0061 class RNTupleParallelWriter {
0062 private:
0063    /// A global mutex to protect the internal data structures of this object.
0064    std::mutex fMutex;
0065    /// A mutex to synchronize the final page sink.
0066    std::mutex fSinkMutex;
0067    /// The final RPageSink that represents the synchronization point.
0068    std::unique_ptr<ROOT::Internal::RPageSink> fSink;
0069    /// The original RNTupleModel connected to fSink; needs to be destructed before it.
0070    std::unique_ptr<ROOT::RNTupleModel> fModel;
0071    Experimental::Detail::RNTupleMetrics fMetrics;
0072    /// List of all created helpers. They must be destroyed before this RNTupleParallelWriter is destructed.
0073    std::vector<std::weak_ptr<RNTupleFillContext>> fFillContexts;
0074 
0075    RNTupleParallelWriter(std::unique_ptr<ROOT::RNTupleModel> model, std::unique_ptr<ROOT::Internal::RPageSink> sink);
0076    RNTupleParallelWriter(const RNTupleParallelWriter &) = delete;
0077    RNTupleParallelWriter &operator=(const RNTupleParallelWriter &) = delete;
0078    RNTupleParallelWriter(RNTupleParallelWriter &&) = delete;
0079    RNTupleParallelWriter &operator=(RNTupleParallelWriter &&) = delete;
0080 
0081 public:
0082    /// Recreate a new file and return a writer to write an RNTuple.
0083    static std::unique_ptr<RNTupleParallelWriter>
0084    Recreate(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName, std::string_view storage,
0085             const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions());
0086    /// Append an RNTuple to the existing file.
0087    ///
0088    /// While the writer synchronizes between multiple fill contexts created from the same writer, there is no
0089    /// synchronization with other writers or other clients that write into the same file. The caller must ensure that
0090    /// the underlying file is not be accessed while data is filled into any created context. To improve performance, it
0091    /// is allowed to use special methods that are guaranteed to not interact with the underlying file, such as
0092    /// RNTupleFillContext::FillNoFlush().
0093    static std::unique_ptr<RNTupleParallelWriter>
0094    Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName, TDirectory &fileOrDirectory,
0095           const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions());
0096 
0097    ~RNTupleParallelWriter();
0098 
0099    /// Create a new RNTupleFillContext that can be used to fill entries and prepare clusters in parallel. This method is
0100    /// thread-safe and may be called from multiple threads in parallel at any time, also after some data has already
0101    /// been written.
0102    ///
0103    /// Note that all fill contexts must be destroyed before CommitDataset() is called.
0104    std::shared_ptr<RNTupleFillContext> CreateFillContext();
0105 
0106    /// Automatically called by the destructor
0107    void CommitDataset();
0108 
0109    void EnableMetrics() { fMetrics.Enable(); }
0110    const Experimental::Detail::RNTupleMetrics &GetMetrics() const { return fMetrics; }
0111 };
0112 
0113 } // namespace ROOT
0114 
0115 #endif