|
26 | 26 | #include <ROOT/RPageStorage.hxx>
|
27 | 27 | #include <ROOT/RSpan.hxx>
|
28 | 28 |
|
| 29 | +#include <atomic> |
29 | 30 | #include <iostream>
|
30 | 31 | #include <iterator>
|
31 | 32 | #include <memory>
|
@@ -82,6 +83,8 @@ private:
|
82 | 83 | /// Retrieving descriptor data from an RNTupleReader is supposed to be for testing and information purposes,
|
83 | 84 | /// not on a hot code path.
|
84 | 85 | std::optional<ROOT::RNTupleDescriptor> fCachedDescriptor;
|
| 86 | + /// We know that the RNTupleReader is always reading a single RNTuple, so the number of entries is fixed. |
| 87 | + mutable std::atomic<ROOT::NTupleSize_t> fCachedNEntries = kInvalidNTupleIndex; |
85 | 88 | Experimental::Detail::RNTupleMetrics fMetrics;
|
86 | 89 | /// If not nullopt, these will be used when creating the model
|
87 | 90 | std::optional<ROOT::RNTupleDescriptor::RCreateModelOptions> fCreateModelOptions;
|
@@ -172,21 +175,20 @@ public:
|
172 | 175 | ~RNTupleReader();
|
173 | 176 |
|
174 | 177 | /// Returns the number of entries in this RNTuple.
|
175 |
| - /// \attention This method requires locking a mutex, therefore it can become relatively expensive to call repeatedly |
176 |
| - /// (even in the absence of contention). Unless necessary, you should not call this method in the condition of a |
177 |
| - /// `for` loop. Instead, either call it once and cache the result, use the faster `GetEntryRange()` or, equivalently, |
178 |
| - /// use the RNTupleReader directly as an iterator. |
179 |
| - /// |
| 178 | + /// Note that the recommended way to iterate the RNTuple is using |
180 | 179 | /// ~~~ {.cpp}
|
181 |
| - /// // BAD for performance: |
182 |
| - /// for (auto i = 0u; i < reader->GetNEntries(); ++i) { ... } |
183 |
| - /// |
184 |
| - /// // GOOD for performance (all equivalent): |
185 |
| - /// for (auto i = 0u, n = reader->GetNEntries(); i < n; ++i) { ... } |
| 180 | + /// // RECOMMENDED way to iterate an ntuple |
186 | 181 | /// for (auto i : reader->GetEntryRange()) { ... }
|
187 |
| - /// for (auto i : *reader) { ... } |
188 | 182 | /// ~~~
|
189 |
| - ROOT::NTupleSize_t GetNEntries() const { return fSource->GetNEntries(); } |
| 183 | + /// instead of |
| 184 | + /// ~~~ {.cpp} |
| 185 | + /// // DISCOURAGED way to iterate an ntuple |
| 186 | + /// for (auto i = 0u; i < reader->GetNEntries(); ++i) { ... } |
| 187 | + /// ~~~ |
| 188 | + /// The reason is that determining the number of entries is potentially an expensive operation. |
| 189 | + /// Currently in the RNTupleReader it is an atomic read (as of the 2nd call) |
| 190 | + /// but it may be more expensive in the future. |
| 191 | + ROOT::NTupleSize_t GetNEntries() const; |
190 | 192 | const ROOT::RNTupleModel &GetModel();
|
191 | 193 | std::unique_ptr<ROOT::REntry> CreateEntry();
|
192 | 194 |
|
|
0 commit comments