|
|
|||
File indexing completed on 2026-10-04 09:23:55
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/RNTupleTypes.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 Experimental { 0041 class RNTupleAttrSetWriterHandle; 0042 class RFile; 0043 0044 /// Creates an RNTupleWriter that writes into the given `file`, appending to it. The RNTuple is written under the 0045 /// path `ntuplePath`. 0046 /// `ntuplePath` may have the form `"path/to/ntuple"`, in which case the ntuple's name will be `"ntuple"` and it will 0047 /// be stored under the given `ntuplePath` in the RFile. 0048 /// Throws an exception if the model is null. 0049 /// NOTE: this is a temporary, experimental API that will be replaced by an overload of RNTupleWriter::Append in the 0050 /// future. 0051 std::unique_ptr<RNTupleWriter> 0052 RNTupleWriter_Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntuplePath, 0053 ROOT::Experimental::RFile &file, 0054 const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions()); 0055 } // namespace Experimental 0056 0057 namespace Internal { 0058 // Non-public factory method for an RNTuple writer that uses an already constructed page sink 0059 std::unique_ptr<RNTupleWriter> 0060 CreateRNTupleWriter(std::unique_ptr<ROOT::RNTupleModel> model, std::unique_ptr<Internal::RPageSink> sink); 0061 } // namespace Internal 0062 0063 // clang-format off 0064 /** 0065 \class ROOT::RNTupleWriter 0066 \ingroup NTuple 0067 \brief An RNTuple that gets filled with entries (data) and writes them to storage 0068 0069 RNTupleWriter is an interface for writing RNTuples to storage. It can be instantiated using the static functions 0070 Append() and Recreate(), providing an RNTupleModel that defines the schema of the data to be written. 0071 0072 An RNTuple can be thought of as a table, whose columns are defined by its schema (i.e. by its associated RNTupleModel, 0073 whose Fields map to 0 or more columns). 0074 Writing into an RNTuple happens by filling *entries* into the RNTupleWriter, which make up the rows of the table. 0075 The simplest way to do so is by: 0076 0077 - retrieving a (shared) pointer to each Field's value; 0078 - writing a value into each pointer; 0079 - calling `writer->Fill()` to commit the entry with all the current pointer values. 0080 0081 ~~~ {.cpp} 0082 #include <ROOT/RNTupleWriter.hxx> 0083 0084 /// 1. Create the model. 0085 auto model = ROOT::RNTupleModel::Create(); 0086 // Define the schema by adding Fields to the model. 0087 // MakeField returns a shared_ptr to the value to be written (in this case, a shared_ptr<int>) 0088 auto pFoo = model->MakeField<int>("foo"); 0089 0090 /// 2. Create writer from the model. 0091 auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "myNTuple", "some/file.root"); 0092 0093 /// 3. Write into it. 0094 for (int i = 0; i < 10; ++i) { 0095 // Assign the value you want to each RNTuple Field (in this case there is only one Field "foo"). 0096 *pFoo = i; 0097 0098 // Fill() writes the entire entry to the RNTuple. 0099 // After calling Fill() you can safely write another value into `pFoo` knowing that the previous one was 0100 // already saved. 0101 writer->Fill(); 0102 } 0103 0104 // On destruction, the writer will flush the written data to disk. 0105 ~~~ 0106 0107 The caller has to make sure that the data that gets filled into an RNTuple is not modified for the time of the 0108 Fill() call. The Fill call serializes the C++ object into the column format and 0109 writes data into the corresponding column page buffers. 0110 0111 The actual writing of the buffers to storage is deferred and can be triggered by FlushCluster() or by 0112 destructing the writer. 0113 0114 On I/O errors, a ROOT::RException is thrown. 0115 0116 */ 0117 // clang-format on 0118 class RNTupleWriter { 0119 friend ROOT::RNTupleModel::RUpdater; 0120 friend std::unique_ptr<RNTupleWriter> 0121 Internal::CreateRNTupleWriter(std::unique_ptr<ROOT::RNTupleModel>, std::unique_ptr<Internal::RPageSink>); 0122 friend std::unique_ptr<RNTupleWriter> 0123 Experimental::RNTupleWriter_Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntuplePath, 0124 ROOT::Experimental::RFile &file, const ROOT::RNTupleWriteOptions &options); 0125 0126 private: 0127 RNTupleFillContext fFillContext; 0128 Experimental::Detail::RNTupleMetrics fMetrics; 0129 /// All the Attribute Sets created from this Writer. 0130 std::vector<std::shared_ptr<Experimental::RNTupleAttrSetWriter>> fAttributeSets; 0131 0132 ROOT::NTupleSize_t fLastCommittedClusterGroup = 0; 0133 0134 RNTupleWriter(std::unique_ptr<ROOT::RNTupleModel> model, std::unique_ptr<Internal::RPageSink> sink); 0135 0136 ROOT::RNTupleModel &GetUpdatableModel(); 0137 Internal::RPageSink &GetSink() { return *fFillContext.fSink; } 0138 0139 // Helper function that is called from CommitCluster() when necessary 0140 void CommitClusterGroup(); 0141 0142 void CloseAttributeSetImpl(ROOT::Experimental::RNTupleAttrSetWriter &attrSet); 0143 0144 /// Create a writer, potentially wrapping the sink in a RPageSinkBuf. 0145 static std::unique_ptr<RNTupleWriter> Create(std::unique_ptr<ROOT::RNTupleModel> model, 0146 std::unique_ptr<Internal::RPageSink> sink, 0147 const ROOT::RNTupleWriteOptions &options); 0148 0149 public: 0150 /// Creates an RNTupleWriter backed by `storage`, overwriting it if one with the same URI exists. 0151 /// The format of the backing storage is determined by `storage`: in the simplest case it will be a local file, but 0152 /// a different backend may be selected via the URI prefix. 0153 /// 0154 /// The RNTupleWriter will create an RNTuple with the schema determined by `model` (which must not be null) and 0155 /// with name `ntupleName`. This same name can later be used to read back the RNTuple via RNTupleReader. 0156 /// 0157 /// \param model The RNTupleModel describing the schema of the RNTuple written by this writer 0158 /// \param ntupleName The name of the RNTuple to be written 0159 /// \param storage The URI where the RNTuple will be stored (usually just a file name or path) 0160 /// \param options May be passed to customize the behavior of the RNTupleWriter (see also RNTupleWriteOptions). 0161 /// 0162 /// Throws a ROOT::RException if the model is null. 0163 static std::unique_ptr<RNTupleWriter> 0164 Recreate(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName, std::string_view storage, 0165 const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions()); 0166 0167 /// Convenience function allowing to call Recreate() with an inline-defined model. 0168 static std::unique_ptr<RNTupleWriter> 0169 Recreate(std::initializer_list<std::pair<std::string_view, std::string_view>> fields, std::string_view ntupleName, 0170 std::string_view storage, const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions()); 0171 0172 /// Creates an RNTupleWriter that writes into an existing TFile or TDirectory, without overwriting its content. 0173 /// `fileOrDirectory` may be an empty TFile and its reference **must remain valid** for the lifetime of the 0174 /// RNTupleWriter (which means the TDirectory object must not be moved, destroyed or replaced during that time). 0175 /// \see Recreate() 0176 static std::unique_ptr<RNTupleWriter> Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName, 0177 TDirectory &fileOrDirectory, 0178 const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions()); 0179 0180 RNTupleWriter(const RNTupleWriter &) = delete; 0181 RNTupleWriter &operator=(const RNTupleWriter &) = delete; 0182 RNTupleWriter(RNTupleWriter &&) = delete; 0183 RNTupleWriter &operator=(RNTupleWriter &&) = delete; 0184 ~RNTupleWriter(); 0185 0186 /// The simplest user interface if the default entry that comes with the ntuple model is used. 0187 /// \return The number of uncompressed bytes written. 0188 std::size_t Fill() { return fFillContext.Fill(fFillContext.fModel->GetDefaultEntry()); } 0189 /// Multiple entries can have been instantiated from the ntuple model. This method will check the entry's model ID 0190 /// to ensure it comes from the writer's own model or throw an exception otherwise. 0191 /// \return The number of uncompressed bytes written. 0192 std::size_t Fill(ROOT::REntry &entry) { return fFillContext.Fill(entry); } 0193 /// Fill an entry into this ntuple, but don't commit the cluster. The calling code must pass an RNTupleFillStatus 0194 /// and check RNTupleFillStatus::ShouldFlushCluster. 0195 void FillNoFlush(ROOT::REntry &entry, RNTupleFillStatus &status) { fFillContext.FillNoFlush(entry, status); } 0196 0197 /// Fill an RRawPtrWriteEntry into this ntuple. This method will check the entry's model ID to ensure it comes from 0198 /// the writer's own model or throw an exception otherwise. 0199 /// \return The number of uncompressed bytes written. 0200 std::size_t Fill(ROOT::Detail::RRawPtrWriteEntry &entry) { return fFillContext.Fill(entry); } 0201 /// Fill an RRawPtrWriteEntry into this ntuple, but don't commit the cluster. The calling code must pass an 0202 /// RNTupleFillStatus and check RNTupleFillStatus::ShouldFlushCluster. 0203 void FillNoFlush(ROOT::Detail::RRawPtrWriteEntry &entry, RNTupleFillStatus &status) 0204 { 0205 fFillContext.FillNoFlush(entry, status); 0206 } 0207 0208 /// Flush column data, preparing for CommitCluster or to reduce memory usage. This will trigger compression of pages, 0209 /// but not actually write to storage (unless buffered writing is turned off). 0210 void FlushColumns() { fFillContext.FlushColumns(); } 0211 /// Flush so far filled entries to storage 0212 void FlushCluster() { fFillContext.FlushCluster(); } 0213 /// Ensure that the data from the so far seen Fill calls has been written to storage 0214 void CommitCluster(bool commitClusterGroup = false) 0215 { 0216 fFillContext.FlushCluster(); 0217 if (commitClusterGroup) 0218 CommitClusterGroup(); 0219 } 0220 /// Closes the underlying file (page sink) and expires the model. Automatically called on destruct. 0221 /// Once the dataset is committed, calls to Fill(), [Commit|Flush]Cluster(), FlushColumns(), CreateEntry(), 0222 /// and model updating fail. 0223 void CommitDataset(); 0224 0225 std::unique_ptr<ROOT::REntry> CreateEntry() const { return fFillContext.CreateEntry(); } 0226 std::unique_ptr<ROOT::Detail::RRawPtrWriteEntry> CreateRawPtrWriteEntry() const 0227 { 0228 return fFillContext.CreateRawPtrWriteEntry(); 0229 } 0230 0231 /// Return the entry number that was last flushed in a cluster. 0232 ROOT::NTupleSize_t GetLastFlushed() const { return fFillContext.GetLastFlushed(); } 0233 /// Return the entry number that was last committed in a cluster. 0234 ROOT::NTupleSize_t GetLastCommitted() const { return fFillContext.GetLastFlushed(); } 0235 /// Return the entry number that was last committed in a cluster group. 0236 ROOT::NTupleSize_t GetLastCommittedClusterGroup() const { return fLastCommittedClusterGroup; } 0237 /// Return the number of entries filled so far. 0238 ROOT::NTupleSize_t GetNEntries() const { return fFillContext.GetNEntries(); } 0239 0240 void EnableMetrics() { fMetrics.Enable(); } 0241 const Experimental::Detail::RNTupleMetrics &GetMetrics() const { return fMetrics; } 0242 0243 const ROOT::RNTupleModel &GetModel() const { return *fFillContext.fModel; } 0244 0245 /// Get a RNTupleModel::RUpdater that provides limited support for incremental updates to the underlying 0246 /// model, e.g. addition of new fields. 0247 /// 0248 /// Note that a Model may not be extended with Streamer fields. 0249 /// 0250 /// **Example: add a new field after the model has been used to construct a `RNTupleWriter` object** 0251 /// ~~~ {.cpp} 0252 /// #include <ROOT/RNTuple.hxx> 0253 /// 0254 /// auto model = ROOT::RNTupleModel::Create(); 0255 /// auto fldFloat = model->MakeField<float>("fldFloat"); 0256 /// auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "myNTuple", "some/file.root"); 0257 /// auto updater = writer->CreateModelUpdater(); 0258 /// updater->BeginUpdate(); 0259 /// updater->AddField(std::make_unique<RField<float>>("pt")); 0260 /// updater->CommitUpdate(); 0261 /// 0262 /// // ... 0263 /// ~~~ 0264 std::unique_ptr<ROOT::RNTupleModel::RUpdater> CreateModelUpdater() 0265 { 0266 return std::make_unique<ROOT::RNTupleModel::RUpdater>(*this); 0267 } 0268 0269 /// Creates a new Attribute Set called `name` associated to this Writer and returns a non-owning pointer to it. 0270 /// The lifetime of the Attribute Set ends at the same time as the Writer's. 0271 /// If `options` are passed, they will be used for the attribute set writer; otherwise, they will be derived from 0272 /// the main writer. 0273 /// \warning Currently this is only supported for writers created via RNTupleWriter::Append(). This limitation 0274 /// will be lifted in the future. 0275 ROOT::Experimental::RNTupleAttrSetWriterHandle 0276 CreateAttributeSet(std::unique_ptr<RNTupleModel> model, std::string_view name, 0277 const ROOT::RNTupleWriteOptions *options = nullptr); 0278 0279 /// Writes the given AttributeSet to the underlying storage and closes it. This method is only useful if you 0280 /// want to close the AttributeSet early: otherwise it will automatically closed when the RNTupleWriter gets 0281 /// destroyed. 0282 void CloseAttributeSet(ROOT::Experimental::RNTupleAttrSetWriterHandle handle); 0283 }; // class RNTupleWriter 0284 0285 } // namespace ROOT 0286 0287 #endif // ROOT_RNTupleWriter
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|