Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
RNTupleWriter.hxx
Go to the documentation of this file.
1/// \file ROOT/RNTupleWriter.hxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \date 2024-02-20
4
5/*************************************************************************
6 * Copyright (C) 1995-2024, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#ifndef ROOT_RNTupleWriter
14#define ROOT_RNTupleWriter
15
16#include <ROOT/RConfig.hxx> // for R__unlikely
17#include <ROOT/REntry.hxx>
18#include <ROOT/RError.hxx>
22#include <ROOT/RNTupleModel.hxx>
23#include <ROOT/RNTupleTypes.hxx>
24#include <ROOT/RPageStorage.hxx>
26
27#include <cstddef>
28#include <cstdint>
29#include <memory>
30#include <string_view>
31#include <utility>
32
33class TDirectory;
34
35namespace ROOT {
36
38
39namespace Experimental {
41class RFile;
42
43/// Creates an RNTupleWriter that writes into the given `file`, appending to it. The RNTuple is written under the
44/// path `ntuplePath`.
45/// `ntuplePath` may have the form `"path/to/ntuple"`, in which case the ntuple's name will be `"ntuple"` and it will
46/// be stored under the given `ntuplePath` in the RFile.
47/// Throws an exception if the model is null.
48/// NOTE: this is a temporary, experimental API that will be replaced by an overload of RNTupleWriter::Append in the
49/// future.
50std::unique_ptr<RNTupleWriter>
51RNTupleWriter_Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntuplePath,
52 ROOT::Experimental::RFile &file,
53 const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions());
54} // namespace Experimental
55
56namespace Internal {
57// Non-public factory method for an RNTuple writer that uses an already constructed page sink
58std::unique_ptr<RNTupleWriter>
59CreateRNTupleWriter(std::unique_ptr<ROOT::RNTupleModel> model, std::unique_ptr<Internal::RPageSink> sink);
60} // namespace Internal
61
62// clang-format off
63/**
64\class ROOT::RNTupleWriter
65\ingroup NTuple
66\brief An RNTuple that gets filled with entries (data) and writes them to storage
67
68RNTupleWriter is an interface for writing RNTuples to storage. It can be instantiated using the static functions
69Append() and Recreate(), providing an RNTupleModel that defines the schema of the data to be written.
70
71An RNTuple can be thought of as a table, whose columns are defined by its schema (i.e. by its associated RNTupleModel,
72whose Fields map to 0 or more columns).
73Writing into an RNTuple happens by filling *entries* into the RNTupleWriter, which make up the rows of the table.
74The simplest way to do so is by:
75
76- retrieving a (shared) pointer to each Field's value;
77- writing a value into each pointer;
78- calling `writer->Fill()` to commit the entry with all the current pointer values.
79
80~~~ {.cpp}
81#include <ROOT/RNTupleWriter.hxx>
82
83/// 1. Create the model.
84auto model = ROOT::RNTupleModel::Create();
85// Define the schema by adding Fields to the model.
86// MakeField returns a shared_ptr to the value to be written (in this case, a shared_ptr<int>)
87auto pFoo = model->MakeField<int>("foo");
88
89/// 2. Create writer from the model.
90auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "myNTuple", "some/file.root");
91
92/// 3. Write into it.
93for (int i = 0; i < 10; ++i) {
94 // Assign the value you want to each RNTuple Field (in this case there is only one Field "foo").
95 *pFoo = i;
96
97 // Fill() writes the entire entry to the RNTuple.
98 // After calling Fill() you can safely write another value into `pFoo` knowing that the previous one was
99 // already saved.
100 writer->Fill();
101}
102
103// On destruction, the writer will flush the written data to disk.
104~~~
105
106The caller has to make sure that the data that gets filled into an RNTuple is not modified for the time of the
107Fill() call. The Fill call serializes the C++ object into the column format and
108writes data into the corresponding column page buffers.
109
110The actual writing of the buffers to storage is deferred and can be triggered by FlushCluster() or by
111destructing the writer.
112
113On I/O errors, a ROOT::RException is thrown.
114
115*/
116// clang-format on
119 friend std::unique_ptr<RNTupleWriter>
120 Internal::CreateRNTupleWriter(std::unique_ptr<ROOT::RNTupleModel>, std::unique_ptr<Internal::RPageSink>);
121 friend std::unique_ptr<RNTupleWriter>
122 Experimental::RNTupleWriter_Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntuplePath,
124
125private:
128 /// All the Attribute Sets created from this Writer.
129 std::vector<std::shared_ptr<Experimental::RNTupleAttrSetWriter>> fAttributeSets;
130
132
133 RNTupleWriter(std::unique_ptr<ROOT::RNTupleModel> model, std::unique_ptr<Internal::RPageSink> sink);
134
137
138 // Helper function that is called from CommitCluster() when necessary
139 void CommitClusterGroup();
140
142
143 /// Create a writer, potentially wrapping the sink in a RPageSinkBuf.
144 static std::unique_ptr<RNTupleWriter> Create(std::unique_ptr<ROOT::RNTupleModel> model,
145 std::unique_ptr<Internal::RPageSink> sink,
146 const ROOT::RNTupleWriteOptions &options);
147
148public:
149 /// Creates an RNTupleWriter backed by `storage`, overwriting it if one with the same URI exists.
150 /// The format of the backing storage is determined by `storage`: in the simplest case it will be a local file, but
151 /// a different backend may be selected via the URI prefix.
152 ///
153 /// The RNTupleWriter will create an RNTuple with the schema determined by `model` (which must not be null) and
154 /// with name `ntupleName`. This same name can later be used to read back the RNTuple via RNTupleReader.
155 ///
156 /// \param model The RNTupleModel describing the schema of the RNTuple written by this writer
157 /// \param ntupleName The name of the RNTuple to be written
158 /// \param storage The URI where the RNTuple will be stored (usually just a file name or path)
159 /// \param options May be passed to customize the behavior of the RNTupleWriter (see also RNTupleWriteOptions).
160 ///
161 /// Throws a ROOT::RException if the model is null.
162 static std::unique_ptr<RNTupleWriter>
163 Recreate(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName, std::string_view storage,
165
166 /// Convenience function allowing to call Recreate() with an inline-defined model.
167 static std::unique_ptr<RNTupleWriter>
168 Recreate(std::initializer_list<std::pair<std::string_view, std::string_view>> fields, std::string_view ntupleName,
169 std::string_view storage, const ROOT::RNTupleWriteOptions &options = ROOT::RNTupleWriteOptions());
170
171 /// Creates an RNTupleWriter that writes into an existing TFile or TDirectory, without overwriting its content.
172 /// `fileOrDirectory` may be an empty TFile and its reference **must remain valid** for the lifetime of the
173 /// RNTupleWriter (which means the TDirectory object must not be moved, destroyed or replaced during that time).
174 /// \see Recreate()
175 static std::unique_ptr<RNTupleWriter> Append(std::unique_ptr<ROOT::RNTupleModel> model, std::string_view ntupleName,
176 TDirectory &fileOrDirectory,
178
179 RNTupleWriter(const RNTupleWriter &) = delete;
184
185 /// The simplest user interface if the default entry that comes with the ntuple model is used.
186 /// \return The number of uncompressed bytes written.
187 std::size_t Fill() { return fFillContext.Fill(fFillContext.fModel->GetDefaultEntry()); }
188 /// Multiple entries can have been instantiated from the ntuple model. This method will check the entry's model ID
189 /// to ensure it comes from the writer's own model or throw an exception otherwise.
190 /// \return The number of uncompressed bytes written.
191 std::size_t Fill(ROOT::REntry &entry) { return fFillContext.Fill(entry); }
192 /// Fill an entry into this ntuple, but don't commit the cluster. The calling code must pass an RNTupleFillStatus
193 /// and check RNTupleFillStatus::ShouldFlushCluster.
194 void FillNoFlush(ROOT::REntry &entry, RNTupleFillStatus &status) { fFillContext.FillNoFlush(entry, status); }
195
196 /// Fill an RRawPtrWriteEntry into this ntuple. This method will check the entry's model ID to ensure it comes from
197 /// the writer's own model or throw an exception otherwise.
198 /// \return The number of uncompressed bytes written.
199 std::size_t Fill(ROOT::Detail::RRawPtrWriteEntry &entry) { return fFillContext.Fill(entry); }
200 /// Fill an RRawPtrWriteEntry into this ntuple, but don't commit the cluster. The calling code must pass an
201 /// RNTupleFillStatus and check RNTupleFillStatus::ShouldFlushCluster.
203 {
204 fFillContext.FillNoFlush(entry, status);
205 }
206
207 /// Flush column data, preparing for CommitCluster or to reduce memory usage. This will trigger compression of pages,
208 /// but not actually write to storage (unless buffered writing is turned off).
209 void FlushColumns() { fFillContext.FlushColumns(); }
210 /// Flush so far filled entries to storage
211 void FlushCluster() { fFillContext.FlushCluster(); }
212 /// Ensure that the data from the so far seen Fill calls has been written to storage
213 void CommitCluster(bool commitClusterGroup = false)
214 {
215 fFillContext.FlushCluster();
216 if (commitClusterGroup)
218 }
219 /// Closes the underlying file (page sink) and expires the model. Automatically called on destruct.
220 /// Once the dataset is committed, calls to Fill(), [Commit|Flush]Cluster(), FlushColumns(), CreateEntry(),
221 /// and model updating fail.
222 void CommitDataset();
223
224 std::unique_ptr<ROOT::REntry> CreateEntry() const { return fFillContext.CreateEntry(); }
225 std::unique_ptr<ROOT::Detail::RRawPtrWriteEntry> CreateRawPtrWriteEntry() const
226 {
227 return fFillContext.CreateRawPtrWriteEntry();
228 }
229
230 /// Return the entry number that was last flushed in a cluster.
231 ROOT::NTupleSize_t GetLastFlushed() const { return fFillContext.GetLastFlushed(); }
232 /// Return the entry number that was last committed in a cluster.
233 ROOT::NTupleSize_t GetLastCommitted() const { return fFillContext.GetLastFlushed(); }
234 /// Return the entry number that was last committed in a cluster group.
236 /// Return the number of entries filled so far.
237 ROOT::NTupleSize_t GetNEntries() const { return fFillContext.GetNEntries(); }
238
239 void EnableMetrics() { fMetrics.Enable(); }
241
242 const ROOT::RNTupleModel &GetModel() const { return *fFillContext.fModel; }
243
244 /// Get a RNTupleModel::RUpdater that provides limited support for incremental updates to the underlying
245 /// model, e.g. addition of new fields.
246 ///
247 /// Note that a Model may not be extended with Streamer fields.
248 ///
249 /// **Example: add a new field after the model has been used to construct a `RNTupleWriter` object**
250 /// ~~~ {.cpp}
251 /// #include <ROOT/RNTuple.hxx>
252 ///
253 /// auto model = ROOT::RNTupleModel::Create();
254 /// auto fldFloat = model->MakeField<float>("fldFloat");
255 /// auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "myNTuple", "some/file.root");
256 /// auto updater = writer->CreateModelUpdater();
257 /// updater->BeginUpdate();
258 /// updater->AddField(std::make_unique<RField<float>>("pt"));
259 /// updater->CommitUpdate();
260 ///
261 /// // ...
262 /// ~~~
263 std::unique_ptr<ROOT::RNTupleModel::RUpdater> CreateModelUpdater()
264 {
265 return std::make_unique<ROOT::RNTupleModel::RUpdater>(*this);
266 }
267
268 /// Creates a new Attribute Set called `name` associated to this Writer and returns a non-owning pointer to it.
269 /// The lifetime of the Attribute Set ends at the same time as the Writer's.
270 /// If `options` are passed, they will be used for the attribute set writer; otherwise, they will be derived from
271 /// the main writer.
272 /// \warning Currently this is only supported for writers created via RNTupleWriter::Append(). This limitation
273 /// will be lifted in the future.
275 CreateAttributeSet(std::unique_ptr<RNTupleModel> model, std::string_view name,
276 const ROOT::RNTupleWriteOptions *options = nullptr);
277
278 /// Writes the given AttributeSet to the underlying storage and closes it. This method is only useful if you
279 /// want to close the AttributeSet early: otherwise it will automatically closed when the RNTupleWriter gets
280 /// destroyed.
282}; // class RNTupleWriter
283
284} // namespace ROOT
285
286#endif // ROOT_RNTupleWriter
char name[80]
Definition TGX11.cxx:148
A container of const raw pointers, corresponding to a row in the data set.
A collection of Counter objects with a name, a unit, and a description.
An interface to read from, or write to, a ROOT file, as well as performing other common operations.
Definition RFile.hxx:252
Non-owning handle to an RNTupleAttrSetWriter.
Class used to write an RNTupleAttrSet in the context of an RNTupleWriter.
Abstract interface to write data into an ntuple.
The REntry is a collection of values in an RNTuple corresponding to a complete row in the data set.
Definition REntry.hxx:54
A context for filling entries (data) into clusters of an RNTuple.
A status object after filling an entry.
A model is usually immutable after passing it to an RNTupleWriter.
The RNTupleModel encapulates the schema of an RNTuple.
Common user-tunable settings for storing RNTuples.
std::unique_ptr< ROOT::REntry > CreateEntry() const
static std::unique_ptr< RNTupleWriter > Create(std::unique_ptr< ROOT::RNTupleModel > model, std::unique_ptr< Internal::RPageSink > sink, const ROOT::RNTupleWriteOptions &options)
Create a writer, potentially wrapping the sink in a RPageSinkBuf.
RNTupleWriter(RNTupleWriter &&)=delete
static std::unique_ptr< RNTupleWriter > Recreate(std::unique_ptr< ROOT::RNTupleModel > model, std::string_view ntupleName, std::string_view storage, const ROOT::RNTupleWriteOptions &options=ROOT::RNTupleWriteOptions())
Creates an RNTupleWriter backed by storage, overwriting it if one with the same URI exists.
std::vector< std::shared_ptr< Experimental::RNTupleAttrSetWriter > > fAttributeSets
All the Attribute Sets created from this Writer.
RNTupleWriter(const RNTupleWriter &)=delete
std::unique_ptr< ROOT::Detail::RRawPtrWriteEntry > CreateRawPtrWriteEntry() const
Experimental::Detail::RNTupleMetrics fMetrics
RNTupleWriter & operator=(RNTupleWriter &&)=delete
const Experimental::Detail::RNTupleMetrics & GetMetrics() const
RNTupleFillContext fFillContext
void CloseAttributeSet(ROOT::Experimental::RNTupleAttrSetWriterHandle handle)
Writes the given AttributeSet to the underlying storage and closes it.
ROOT::RNTupleModel & GetUpdatableModel()
Internal::RPageSink & GetSink()
ROOT::Experimental::RNTupleAttrSetWriterHandle CreateAttributeSet(std::unique_ptr< RNTupleModel > model, std::string_view name, const ROOT::RNTupleWriteOptions *options=nullptr)
Creates a new Attribute Set called name associated to this Writer and returns a non-owning pointer to...
static std::unique_ptr< RNTupleWriter > Append(std::unique_ptr< ROOT::RNTupleModel > model, std::string_view ntupleName, TDirectory &fileOrDirectory, const ROOT::RNTupleWriteOptions &options=ROOT::RNTupleWriteOptions())
Creates an RNTupleWriter that writes into an existing TFile or TDirectory, without overwriting its co...
std::size_t Fill(ROOT::REntry &entry)
Multiple entries can have been instantiated from the ntuple model.
std::size_t Fill(ROOT::Detail::RRawPtrWriteEntry &entry)
Fill an RRawPtrWriteEntry into this ntuple.
void FillNoFlush(ROOT::REntry &entry, RNTupleFillStatus &status)
Fill an entry into this ntuple, but don't commit the cluster.
RNTupleWriter(std::unique_ptr< ROOT::RNTupleModel > model, std::unique_ptr< Internal::RPageSink > sink)
ROOT::NTupleSize_t GetLastCommitted() const
Return the entry number that was last committed in a cluster.
ROOT::NTupleSize_t GetLastCommittedClusterGroup() const
Return the entry number that was last committed in a cluster group.
void CommitDataset()
Closes the underlying file (page sink) and expires the model.
const ROOT::RNTupleModel & GetModel() const
ROOT::NTupleSize_t fLastCommittedClusterGroup
void FlushColumns()
Flush column data, preparing for CommitCluster or to reduce memory usage.
RNTupleWriter & operator=(const RNTupleWriter &)=delete
ROOT::NTupleSize_t GetLastFlushed() const
Return the entry number that was last flushed in a cluster.
void FillNoFlush(ROOT::Detail::RRawPtrWriteEntry &entry, RNTupleFillStatus &status)
Fill an RRawPtrWriteEntry into this ntuple, but don't commit the cluster.
std::unique_ptr< ROOT::RNTupleModel::RUpdater > CreateModelUpdater()
Get a RNTupleModel::RUpdater that provides limited support for incremental updates to the underlying ...
void FlushCluster()
Flush so far filled entries to storage.
ROOT::NTupleSize_t GetNEntries() const
Return the number of entries filled so far.
void CommitCluster(bool commitClusterGroup=false)
Ensure that the data from the so far seen Fill calls has been written to storage.
void CloseAttributeSetImpl(ROOT::Experimental::RNTupleAttrSetWriter &attrSet)
std::size_t Fill()
The simplest user interface if the default entry that comes with the ntuple model is used.
Describe directory structure in memory.
Definition TDirectory.h:45
Namespace for ROOT features in testing.
Definition TROOT.h:100
std::unique_ptr< RNTupleWriter > RNTupleWriter_Append(std::unique_ptr< ROOT::RNTupleModel > model, std::string_view ntuplePath, ROOT::Experimental::RFile &file, const ROOT::RNTupleWriteOptions &options=ROOT::RNTupleWriteOptions())
Creates an RNTupleWriter that writes into the given file, appending to it.
std::unique_ptr< RNTupleWriter > CreateRNTupleWriter(std::unique_ptr< ROOT::RNTupleModel > model, std::unique_ptr< Internal::RPageSink > sink)
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.