Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 09:08:34

0001 /// \file ROOT/RNTupleWriter.hxx
0002 /// \ingroup NTuple
0003 /// \author Jakob Blomer <jblomer@cern.ch>
0004 /// \date 2024-02-20
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_RNTupleWriter
0015 #define ROOT_RNTupleWriter
0016 
0017 #include <ROOT/RConfig.hxx> // for R__unlikely
0018 #include <ROOT/REntry.hxx>
0019 #include <ROOT/RError.hxx>
0020 #include <ROOT/RNTupleFillContext.hxx>
0021 #include <ROOT/RNTupleFillStatus.hxx>
0022 #include <ROOT/RNTupleMetrics.hxx>
0023 #include <ROOT/RNTupleModel.hxx>
0024 #include <ROOT/RNTupleUtil.hxx>
0025 #include <ROOT/RPageStorage.hxx>
0026 #include <ROOT/RRawPtrWriteEntry.hxx>
0027 
0028 #include <cstddef>
0029 #include <cstdint>
0030 #include <memory>
0031 #include <string_view>
0032 #include <utility>
0033 
0034 class TDirectory;
0035 
0036 namespace ROOT {
0037 
0038 class RNTupleWriteOptions;
0039 
0040 namespace Internal {
0041 // Non-public factory method for an RNTuple writer that uses an already constructed page sink
0042 std::unique_ptr<RNTupleWriter>
0043 CreateRNTupleWriter(std::unique_ptr<ROOT::RNTupleModel> model, std::unique_ptr<Internal::RPageSink> sink);
0044 } // namespace Internal
0045 
0046 // clang-format off
0047 /**
0048 \class ROOT::RNTupleWriter
0049 \ingroup NTuple
0050 \brief An RNTuple that gets filled with entries (data) and writes them to storage
0051 
0052 An output ntuple can be filled with entries. The caller has to make sure that the data that gets filled into an ntuple
0053 is not modified for the time of the Fill() call. The fill call serializes the C++ object into the column format and
0054 writes data into the corresponding column page buffers.  Writing of the buffers to storage is deferred and can be
0055 triggered by FlushCluster() or by destructing the writer.  On I/O errors, an exception is thrown.
0056 */
0057 // clang-format on
0058 class RNTupleWriter {
0059    friend ROOT::RNTupleModel::RUpdater;
0060    friend std::unique_ptr<RNTupleWriter>
0061       Internal::CreateRNTupleWriter(std::unique_ptr<ROOT::RNTupleModel>, std::unique_ptr<Internal::RPageSink>);
0062 
0063 private:
0064    /// The page sink's parallel page compression scheduler if IMT is on.
0065    /// Needs to be destructed after the page sink (in the fill context) is destructed and so declared before.
0066    std::unique_ptr<Internal::RPageStorage::RTaskScheduler> fZipTasks;
0067    Experimental::RNTupleFillContext fFillContext;
0068    Experimental::Detail::RNTupleMetrics fMetrics;
0069 
0070    ROOT::NTupleSize_t fLastCommittedClusterGroup = 0;
0071 
0072    RNTupleWriter(std::unique_ptr<ROOT::RNTupleModel> model, std::unique_ptr<Internal::RPageSink> sink);
0073 
0074    ROOT::RNTupleModel &GetUpdatableModel();
0075    Internal::RPageSink &GetSink() { return *fFillContext.fSink; }
0076 
0077    // Helper function that is called from CommitCluster() when necessary
0078    void CommitClusterGroup();
0079 
0080    /// Create a writer, potentially wrapping the sink in a RPageSinkBuf.
0081    static std::unique_ptr<RNTupleWriter> Create(std::unique_ptr<ROOT::RNTupleModel> model,
0082                                                 std::unique_ptr<Internal::RPageSink> sink,
0083                                                 const ROOT::RNTupleWriteOptions &options);
0084 
0085 public:
0086    /// Throws an exception if the model is null.
0087    static std::unique_ptr<RNTupleWriter>
0088    Recreate(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName, std::string_view storage,
0089             const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions());
0090    static std::unique_ptr<RNTupleWriter>
0091    Recreate(std::initializer_list<std::pair<std::string_view, std::string_view>> fields, std::string_view ntupleName,
0092             std::string_view storage, const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions());
0093    /// Throws an exception if the model is null.
0094    static std::unique_ptr<RNTupleWriter> Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName,
0095                                                 TDirectory &fileOrDirectory,
0096                                                 const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions());
0097    RNTupleWriter(const RNTupleWriter &) = delete;
0098    RNTupleWriter &operator=(const RNTupleWriter &) = delete;
0099    ~RNTupleWriter();
0100 
0101    /// The simplest user interface if the default entry that comes with the ntuple model is used.
0102    /// \return The number of uncompressed bytes written.
0103    std::size_t Fill() { return fFillContext.Fill(fFillContext.fModel->GetDefaultEntry()); }
0104    /// Multiple entries can have been instantiated from the ntuple model.  This method will check the entry's model ID
0105    /// to ensure it comes from the writer's own model or throw an exception otherwise.
0106    /// \return The number of uncompressed bytes written.
0107    std::size_t Fill(ROOT::REntry &entry) { return fFillContext.Fill(entry); }
0108    /// Fill an entry into this ntuple, but don't commit the cluster. The calling code must pass an RNTupleFillStatus
0109    /// and check RNTupleFillStatus::ShouldFlushCluster.
0110    void FillNoFlush(ROOT::REntry &entry, RNTupleFillStatus &status) { fFillContext.FillNoFlush(entry, status); }
0111 
0112    /// Fill an RRawPtrWriteEntry into this ntuple.  This method will check the entry's model ID to ensure it comes from
0113    /// the writer's own model or throw an exception otherwise.
0114    /// \return The number of uncompressed bytes written.
0115    std::size_t Fill(Experimental::Detail::RRawPtrWriteEntry &entry) { return fFillContext.Fill(entry); }
0116    /// Fill an RRawPtrWriteEntry into this ntuple, but don't commit the cluster. The calling code must pass an
0117    /// RNTupleFillStatus and check RNTupleFillStatus::ShouldFlushCluster.
0118    void FillNoFlush(Experimental::Detail::RRawPtrWriteEntry &entry, RNTupleFillStatus &status)
0119    {
0120       fFillContext.FillNoFlush(entry, status);
0121    }
0122 
0123    /// Flush column data, preparing for CommitCluster or to reduce memory usage. This will trigger compression of pages,
0124    /// but not actually write to storage (unless buffered writing is turned off).
0125    void FlushColumns() { fFillContext.FlushColumns(); }
0126    /// Flush so far filled entries to storage
0127    void FlushCluster() { fFillContext.FlushCluster(); }
0128    /// Ensure that the data from the so far seen Fill calls has been written to storage
0129    void CommitCluster(bool commitClusterGroup = false)
0130    {
0131       fFillContext.FlushCluster();
0132       if (commitClusterGroup)
0133          CommitClusterGroup();
0134    }
0135    /// Closes the underlying file (page sink) and expires the model. Automatically called on destruct.
0136    /// Once the dataset is committed, calls to Fill(), [Commit|Flush]Cluster(), FlushColumns(), CreateEntry(),
0137    /// and model updating fail.
0138    void CommitDataset();
0139 
0140    std::unique_ptr<ROOT::REntry> CreateEntry() const { return fFillContext.CreateEntry(); }
0141    std::unique_ptr<Experimental::Detail::RRawPtrWriteEntry> CreateRawPtrWriteEntry() const
0142    {
0143       return fFillContext.CreateRawPtrWriteEntry();
0144    }
0145 
0146    /// Return the entry number that was last flushed in a cluster.
0147    ROOT::NTupleSize_t GetLastFlushed() const { return fFillContext.GetLastFlushed(); }
0148    /// Return the entry number that was last committed in a cluster.
0149    ROOT::NTupleSize_t GetLastCommitted() const { return fFillContext.GetLastFlushed(); }
0150    /// Return the entry number that was last committed in a cluster group.
0151    ROOT::NTupleSize_t GetLastCommittedClusterGroup() const { return fLastCommittedClusterGroup; }
0152    /// Return the number of entries filled so far.
0153    ROOT::NTupleSize_t GetNEntries() const { return fFillContext.GetNEntries(); }
0154 
0155    void EnableMetrics() { fMetrics.Enable(); }
0156    const Experimental::Detail::RNTupleMetrics &GetMetrics() const { return fMetrics; }
0157 
0158    const ROOT::RNTupleModel &GetModel() const { return *fFillContext.fModel; }
0159 
0160    /// Get a RNTupleModel::RUpdater that provides limited support for incremental updates to the underlying
0161    /// model, e.g. addition of new fields.
0162    ///
0163    /// **Example: add a new field after the model has been used to construct a `RNTupleWriter` object**
0164    /// ~~~ {.cpp}
0165    /// #include <ROOT/RNTuple.hxx>
0166    ///
0167    /// auto model = ROOT::RNTupleModel::Create();
0168    /// auto fldFloat = model->MakeField<float>("fldFloat");
0169    /// auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "myNTuple", "some/file.root");
0170    /// auto updater = writer->CreateModelUpdater();
0171    /// updater->BeginUpdate();
0172    /// updater->AddField(std::make_unique<RField<float>>("pt"));
0173    /// updater->CommitUpdate();
0174    ///
0175    /// // ...
0176    /// ~~~
0177    std::unique_ptr<ROOT::RNTupleModel::RUpdater> CreateModelUpdater()
0178    {
0179       return std::make_unique<ROOT::RNTupleModel::RUpdater>(*this);
0180    }
0181 }; // class RNTupleWriter
0182 
0183 } // namespace ROOT
0184 
0185 #endif // ROOT_RNTupleWriter