Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RPageStorageDaos.cxx
Go to the documentation of this file.
1/// \file RPageStorageDaos.cxx
2/// \ingroup NTuple ROOT7
3/// \author Javier Lopez-Gomez <j.lopez@cern.ch>
4/// \date 2020-11-03
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#include <ROOT/RCluster.hxx>
17#include <ROOT/RClusterPool.hxx>
18#include <ROOT/RLogger.hxx>
20#include <ROOT/RNTupleModel.hxx>
23#include <ROOT/RNTupleUtil.hxx>
24#include <ROOT/RNTupleZip.hxx>
25#include <ROOT/RPage.hxx>
27#include <ROOT/RPagePool.hxx>
28#include <ROOT/RDaos.hxx>
30
31#include <RVersion.h>
32#include <TError.h>
33
34#include <algorithm>
35#include <cstdio>
36#include <cstdlib>
37#include <cstring>
38#include <limits>
39#include <utility>
40#include <regex>
41#include <cassert>
42
43namespace {
48
49/// \brief RNTuple page-DAOS mappings
50enum EDaosMapping { kOidPerCluster, kOidPerPage };
51
52struct RDaosKey {
53 daos_obj_id_t fOid;
54 DistributionKey_t fDkey;
55 AttributeKey_t fAkey;
56};
57
58/// \brief Pre-defined keys for object store. `kDistributionKeyDefault` is the distribution key for metadata and
59/// pagelist values; optionally it can be used for ntuple pages (if under the `kOidPerPage` mapping strategy).
60/// `kAttributeKeyDefault` is the attribute key for ntuple pages under `kOidPerPage`.
61/// `kAttributeKey{Anchor,Header,Footer}` are the respective attribute keys for anchor/header/footer metadata elements.
62static constexpr DistributionKey_t kDistributionKeyDefault = 0x5a3c69f0cafe4a11;
63static constexpr AttributeKey_t kAttributeKeyDefault = 0x4243544b53444229;
64static constexpr AttributeKey_t kAttributeKeyAnchor = 0x4243544b5344422a;
65static constexpr AttributeKey_t kAttributeKeyHeader = 0x4243544b5344422b;
66static constexpr AttributeKey_t kAttributeKeyFooter = 0x4243544b5344422c;
67
68/// \brief Pre-defined 64 LSb of the OIDs for ntuple metadata (holds anchor/header/footer) and clusters' pagelists.
69static constexpr decltype(daos_obj_id_t::lo) kOidLowMetadata = -1;
70static constexpr decltype(daos_obj_id_t::lo) kOidLowPageList = -2;
71
72static constexpr daos_oclass_id_t kCidMetadata = OC_SX;
73
74static constexpr EDaosMapping kDefaultDaosMapping = kOidPerCluster;
75
76template <EDaosMapping mapping>
77RDaosKey GetPageDaosKey(ROOT::Experimental::Internal::ntuple_index_t ntplId, long unsigned clusterId,
78 long unsigned columnId, long unsigned pageCount)
79{
80 if constexpr (mapping == kOidPerCluster) {
81 return RDaosKey{daos_obj_id_t{static_cast<decltype(daos_obj_id_t::lo)>(clusterId),
82 static_cast<decltype(daos_obj_id_t::hi)>(ntplId)},
83 static_cast<DistributionKey_t>(columnId), static_cast<AttributeKey_t>(pageCount)};
84 } else if constexpr (mapping == kOidPerPage) {
85 return RDaosKey{daos_obj_id_t{static_cast<decltype(daos_obj_id_t::lo)>(pageCount),
86 static_cast<decltype(daos_obj_id_t::hi)>(ntplId)},
87 kDistributionKeyDefault, kAttributeKeyDefault};
88 }
89}
90
91struct RDaosURI {
92 /// \brief Label of the DAOS pool
93 std::string fPoolLabel;
94 /// \brief Label of the container for this RNTuple
95 std::string fContainerLabel;
96};
97
98/**
99 \brief Parse a DAOS RNTuple URI of the form 'daos://pool_id/container_id'.
100*/
101RDaosURI ParseDaosURI(std::string_view uri)
102{
103 std::regex re("daos://([^/]+)/(.+)");
104 std::cmatch m;
105 if (!std::regex_match(uri.data(), m, re))
106 throw ROOT::Experimental::RException(R__FAIL("Invalid DAOS pool URI."));
107 return {m[1], m[2]};
108}
109
110/// \brief Unpacks a 64-bit RNTuple page locator address for object stores into a pair of 32-bit values:
111/// the attribute key under which the cage is stored and the offset within that cage to access the page.
112std::pair<uint32_t, uint32_t> DecodeDaosPagePosition(const ROOT::Experimental::RNTupleLocatorObject64 &address)
113{
114 auto position = static_cast<uint32_t>(address.fLocation & 0xFFFFFFFF);
115 auto offset = static_cast<uint32_t>(address.fLocation >> 32);
116 return {position, offset};
117}
118
119/// \brief Packs an attribute key together with an offset within its contents into a single 64-bit address.
120/// The offset is kept in the MSb half and defaults to zero, which is the case when caging is disabled.
121ROOT::Experimental::RNTupleLocatorObject64 EncodeDaosPagePosition(uint64_t position, uint64_t offset = 0)
122{
123 uint64_t address = (position & 0xFFFFFFFF) | (offset << 32);
125}
126
127/// \brief Helper structure concentrating the functionality required to locate an ntuple within a DAOS container.
128/// It includes a hashing function that converts the RNTuple's name into a 32-bit identifier; this value is used to
129/// index the subspace for the ntuple among all objects in the container. A zero-value hash value is reserved for
130/// storing any future metadata related to container-wide management; a zero-index ntuple is thus disallowed and
131/// remapped to "1". Once the index is computed, `InitNTupleDescriptorBuilder()` can be called to return a
132/// partially-filled builder with the ntuple's anchor, header and footer, lacking only pagelists. Upon that call,
133/// a copy of the anchor is stored in `fAnchor`.
134struct RDaosContainerNTupleLocator {
135 std::string fName{};
136 ntuple_index_t fIndex{};
137 std::optional<ROOT::Experimental::Internal::RDaosNTupleAnchor> fAnchor;
138 static const ntuple_index_t kReservedIndex = 0;
139
140 RDaosContainerNTupleLocator() = default;
141 explicit RDaosContainerNTupleLocator(const std::string &ntupleName) : fName(ntupleName), fIndex(Hash(ntupleName)){};
142
143 bool IsValid() { return fAnchor.has_value() && fAnchor->fNBytesHeader; }
144 [[nodiscard]] ntuple_index_t GetIndex() const { return fIndex; };
145 static ntuple_index_t Hash(const std::string &ntupleName)
146 {
147 // Convert string to numeric representation via `std::hash`.
148 uint64_t h = std::hash<std::string>{}(ntupleName);
149 // Fold the hash into 32-bit using `boost::hash_combine()` algorithm and magic number.
150 auto seed = static_cast<uint32_t>(h >> 32);
151 seed ^= static_cast<uint32_t>(h & 0xffffffff) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
152 auto hash = static_cast<ntuple_index_t>(seed);
153 return (hash == kReservedIndex) ? kReservedIndex + 1 : hash;
154 }
155
156 int InitNTupleDescriptorBuilder(ROOT::Experimental::Internal::RDaosContainer &cont,
158 {
159 std::unique_ptr<unsigned char[]> buffer, zipBuffer;
160 auto &anchor = fAnchor.emplace();
161 int err;
162
164 daos_obj_id_t oidMetadata{kOidLowMetadata, static_cast<decltype(daos_obj_id_t::hi)>(this->GetIndex())};
165
166 buffer = MakeUninitArray<unsigned char>(anchorSize);
167 if ((err = cont.ReadSingleAkey(buffer.get(), anchorSize, oidMetadata, kDistributionKeyDefault,
168 kAttributeKeyAnchor, kCidMetadata))) {
169 return err;
170 }
171
172 anchor.Deserialize(buffer.get(), anchorSize).Unwrap();
173 if (anchor.fVersionEpoch != ROOT::RNTuple::kVersionEpoch) {
175 R__FAIL("unsupported RNTuple epoch version: " + std::to_string(anchor.fVersionEpoch)));
176 }
177
178 builder.SetOnDiskHeaderSize(anchor.fNBytesHeader);
179 buffer = MakeUninitArray<unsigned char>(anchor.fLenHeader);
180 zipBuffer = MakeUninitArray<unsigned char>(anchor.fNBytesHeader);
181 if ((err = cont.ReadSingleAkey(zipBuffer.get(), anchor.fNBytesHeader, oidMetadata, kDistributionKeyDefault,
182 kAttributeKeyHeader, kCidMetadata)))
183 return err;
184 ROOT::Experimental::Internal::RNTupleDecompressor::Unzip(zipBuffer.get(), anchor.fNBytesHeader, anchor.fLenHeader,
185 buffer.get());
186 ROOT::Experimental::Internal::RNTupleSerializer::DeserializeHeader(buffer.get(), anchor.fLenHeader, builder);
187
188 builder.AddToOnDiskFooterSize(anchor.fNBytesFooter);
189 buffer = MakeUninitArray<unsigned char>(anchor.fLenFooter);
190 zipBuffer = MakeUninitArray<unsigned char>(anchor.fNBytesFooter);
191 if ((err = cont.ReadSingleAkey(zipBuffer.get(), anchor.fNBytesFooter, oidMetadata, kDistributionKeyDefault,
192 kAttributeKeyFooter, kCidMetadata)))
193 return err;
194 ROOT::Experimental::Internal::RNTupleDecompressor::Unzip(zipBuffer.get(), anchor.fNBytesFooter, anchor.fLenFooter,
195 buffer.get());
196 ROOT::Experimental::Internal::RNTupleSerializer::DeserializeFooter(buffer.get(), anchor.fLenFooter, builder);
197
198 return 0;
199 }
200
201 static std::pair<RDaosContainerNTupleLocator, ROOT::Experimental::Internal::RNTupleDescriptorBuilder>
202 LocateNTuple(ROOT::Experimental::Internal::RDaosContainer &cont, const std::string &ntupleName)
203 {
204 auto result = std::make_pair(RDaosContainerNTupleLocator(ntupleName),
206
207 auto &loc = result.first;
208 auto &builder = result.second;
209
210 if (int err = loc.InitNTupleDescriptorBuilder(cont, builder); !err) {
211 if (ntupleName.empty() || ntupleName != builder.GetDescriptor().GetName()) {
212 // Hash already taken by a differently-named ntuple.
214 R__FAIL("LocateNTuple: ntuple name '" + ntupleName + "' unavailable in this container."));
215 }
216 }
217 return result;
218 }
219};
220
221} // anonymous namespace
222
223////////////////////////////////////////////////////////////////////////////////
224
226{
228 if (buffer != nullptr) {
229 auto bytes = reinterpret_cast<unsigned char *>(buffer);
240 }
241 return RNTupleSerializer::SerializeString(fObjClass, nullptr) + 32;
242}
243
245ROOT::Experimental::Internal::RDaosNTupleAnchor::Deserialize(const void *buffer, std::uint32_t bufSize)
246{
247 if (bufSize < 32)
248 return R__FAIL("DAOS anchor too short");
249
251 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
253 if (fVersionAnchor != RDaosNTupleAnchor().fVersionAnchor) {
254 return R__FAIL("unsupported DAOS anchor version: " + std::to_string(fVersionAnchor));
255 }
256
265 auto result = RNTupleSerializer::DeserializeString(bytes, bufSize - 32, fObjClass);
266 if (!result)
267 return R__FORWARD_ERROR(result);
268 return result.Unwrap() + 32;
269}
270
272{
274}
275
276////////////////////////////////////////////////////////////////////////////////
277
278ROOT::Experimental::Internal::RPageSinkDaos::RPageSinkDaos(std::string_view ntupleName, std::string_view uri,
279 const RNTupleWriteOptions &options)
280 : RPagePersistentSink(ntupleName, options), fURI(uri)
281{
282 static std::once_flag once;
283 std::call_once(once, []() {
284 R__LOG_WARNING(NTupleLog()) << "The DAOS backend is experimental and still under development. "
285 << "Do not store real data with this version of RNTuple!";
286 });
287 fCompressor = std::make_unique<RNTupleCompressor>();
288 EnableDefaultMetrics("RPageSinkDaos");
289}
290
292
293void ROOT::Experimental::Internal::RPageSinkDaos::InitImpl(unsigned char *serializedHeader, std::uint32_t length)
294{
295 auto opts = dynamic_cast<RNTupleWriteOptionsDaos *>(fOptions.get());
296 fNTupleAnchor.fObjClass = opts ? opts->GetObjectClass() : RNTupleWriteOptionsDaos().GetObjectClass();
297 auto oclass = RDaosObject::ObjClassId(fNTupleAnchor.fObjClass);
298 if (oclass.IsUnknown())
299 throw ROOT::Experimental::RException(R__FAIL("Unknown object class " + fNTupleAnchor.fObjClass));
300
301 size_t cageSz = opts ? opts->GetMaxCageSize() : RNTupleWriteOptionsDaos().GetMaxCageSize();
302 size_t pageSz = opts ? opts->GetMaxUnzippedPageSize() : RNTupleWriteOptionsDaos().GetMaxUnzippedPageSize();
303 fCageSizeLimit = std::max(cageSz, pageSz);
304
305 auto args = ParseDaosURI(fURI);
306 auto pool = std::make_shared<RDaosPool>(args.fPoolLabel);
307
308 fDaosContainer = std::make_unique<RDaosContainer>(pool, args.fContainerLabel, /*create =*/true);
309 fDaosContainer->SetDefaultObjectClass(oclass);
310
311 auto [locator, _] = RDaosContainerNTupleLocator::LocateNTuple(*fDaosContainer, fNTupleName);
312 fNTupleIndex = locator.GetIndex();
313
314 auto zipBuffer = MakeUninitArray<unsigned char>(length);
315 auto szZipHeader = fCompressor->Zip(serializedHeader, length, GetWriteOptions().GetCompression(),
316 RNTupleCompressor::MakeMemCopyWriter(zipBuffer.get()));
317 WriteNTupleHeader(zipBuffer.get(), szZipHeader, length);
318}
319
322{
323 auto element = columnHandle.fColumn->GetElement();
324 RPageStorage::RSealedPage sealedPage;
325 {
326 Detail::RNTupleAtomicTimer timer(fCounters->fTimeWallZip, fCounters->fTimeCpuZip);
327 sealedPage = SealPage(page, *element);
328 }
329
330 fCounters->fSzZip.Add(page.GetNBytes());
331 return CommitSealedPageImpl(columnHandle.fPhysicalId, sealedPage);
332}
333
336 const RPageStorage::RSealedPage &sealedPage)
337{
338 auto offsetData = fPageId.fetch_add(1);
339 DescriptorId_t clusterId = fDescriptorBuilder.GetDescriptor().GetNActiveClusters();
340
341 {
342 Detail::RNTupleAtomicTimer timer(fCounters->fTimeWallWrite, fCounters->fTimeCpuWrite);
343 RDaosKey daosKey = GetPageDaosKey<kDefaultDaosMapping>(fNTupleIndex, clusterId, physicalColumnId, offsetData);
344 fDaosContainer->WriteSingleAkey(sealedPage.GetBuffer(), sealedPage.GetBufferSize(), daosKey.fOid, daosKey.fDkey,
345 daosKey.fAkey);
346 }
347
349 result.fPosition = EncodeDaosPagePosition(offsetData);
350 result.fBytesOnStorage = sealedPage.GetDataSize();
352 fCounters->fNPageCommitted.Inc();
353 fCounters->fSzWritePayload.Add(sealedPage.GetBufferSize());
354 fNBytesCurrentCluster += sealedPage.GetBufferSize();
355 return result;
356}
357
358std::vector<ROOT::Experimental::RNTupleLocator>
359ROOT::Experimental::Internal::RPageSinkDaos::CommitSealedPageVImpl(std::span<RPageStorage::RSealedPageGroup> ranges,
360 const std::vector<bool> &mask)
361{
363 std::vector<ROOT::Experimental::RNTupleLocator> locators;
364 auto nPages = mask.size();
365 locators.reserve(nPages);
366
367 const uint32_t maxCageSz = fCageSizeLimit;
368 const bool useCaging = fCageSizeLimit > 0;
369 const std::uint8_t locatorFlags = useCaging ? EDaosLocatorFlags::kCagedPage : 0;
370
371 DescriptorId_t clusterId = fDescriptorBuilder.GetDescriptor().GetNActiveClusters();
372 int64_t payloadSz = 0;
373 std::size_t positionOffset;
374 uint32_t positionIndex;
375
376 /// Aggregate batch of requests by object ID and distribution key, determined by the ntuple-DAOS mapping
377 for (auto &range : ranges) {
378 positionOffset = 0;
379 /// Under caging, the atomic page counter is fetch-incremented for every column range to get the position of its
380 /// first cage and indicate the next one, also ensuring subsequent pages of different columns do not end up caged
381 /// together. This increment is not necessary in the absence of caging, as each page is trivially caged.
382 positionIndex = useCaging ? fPageId.fetch_add(1) : fPageId.load();
383
384 for (auto sealedPageIt = range.fFirst; sealedPageIt != range.fLast; ++sealedPageIt) {
385 const RPageStorage::RSealedPage &s = *sealedPageIt;
386
387 if (positionOffset + s.GetBufferSize() > maxCageSz) {
388 positionOffset = 0;
389 positionIndex = fPageId.fetch_add(1);
390 }
391
392 d_iov_t pageIov;
393 d_iov_set(&pageIov, const_cast<void *>(s.GetBuffer()), s.GetBufferSize());
394
395 RDaosKey daosKey =
396 GetPageDaosKey<kDefaultDaosMapping>(fNTupleIndex, clusterId, range.fPhysicalColumnId, positionIndex);
397 auto odPair = RDaosContainer::ROidDkeyPair{daosKey.fOid, daosKey.fDkey};
398 auto [it, ret] = writeRequests.emplace(odPair, RDaosContainer::RWOperation(odPair));
399 it->second.Insert(daosKey.fAkey, pageIov);
400
401 RNTupleLocator locator;
402 locator.fPosition = EncodeDaosPagePosition(positionIndex, positionOffset);
403 locator.fBytesOnStorage = s.GetDataSize();
405 locator.fReserved = locatorFlags;
406 locators.push_back(locator);
407
408 positionOffset += s.GetBufferSize();
409 payloadSz += s.GetBufferSize();
410 }
411 }
412 fNBytesCurrentCluster += payloadSz;
413
414 {
415 Detail::RNTupleAtomicTimer timer(fCounters->fTimeWallWrite, fCounters->fTimeCpuWrite);
416 if (int err = fDaosContainer->WriteV(writeRequests))
417 throw ROOT::Experimental::RException(R__FAIL("WriteV: error" + std::string(d_errstr(err))));
418 }
419
420 fCounters->fNPageCommitted.Add(nPages);
421 fCounters->fSzWritePayload.Add(payloadSz);
422
423 return locators;
424}
425
427{
428 return std::exchange(fNBytesCurrentCluster, 0);
429}
430
433 std::uint32_t length)
434{
435 auto bufPageListZip = MakeUninitArray<unsigned char>(length);
436 auto szPageListZip = fCompressor->Zip(serializedPageList, length, GetWriteOptions().GetCompression(),
437 RNTupleCompressor::MakeMemCopyWriter(bufPageListZip.get()));
438
439 auto offsetData = fClusterGroupId.fetch_add(1);
440 fDaosContainer->WriteSingleAkey(
441 bufPageListZip.get(), szPageListZip,
442 daos_obj_id_t{kOidLowPageList, static_cast<decltype(daos_obj_id_t::hi)>(fNTupleIndex)}, kDistributionKeyDefault,
443 offsetData, kCidMetadata);
445 result.fPosition = RNTupleLocatorObject64{offsetData};
446 result.fBytesOnStorage = szPageListZip;
448 fCounters->fSzWritePayload.Add(static_cast<int64_t>(szPageListZip));
449 return result;
450}
451
453 std::uint32_t length)
454{
455 auto bufFooterZip = MakeUninitArray<unsigned char>(length);
456 auto szFooterZip = fCompressor->Zip(serializedFooter, length, GetWriteOptions().GetCompression(),
457 RNTupleCompressor::MakeMemCopyWriter(bufFooterZip.get()));
458 WriteNTupleFooter(bufFooterZip.get(), szFooterZip, length);
459 WriteNTupleAnchor();
460}
461
462void ROOT::Experimental::Internal::RPageSinkDaos::WriteNTupleHeader(const void *data, size_t nbytes, size_t lenHeader)
463{
464 fDaosContainer->WriteSingleAkey(
465 data, nbytes, daos_obj_id_t{kOidLowMetadata, static_cast<decltype(daos_obj_id_t::hi)>(fNTupleIndex)},
466 kDistributionKeyDefault, kAttributeKeyHeader, kCidMetadata);
467 fNTupleAnchor.fLenHeader = lenHeader;
468 fNTupleAnchor.fNBytesHeader = nbytes;
469}
470
471void ROOT::Experimental::Internal::RPageSinkDaos::WriteNTupleFooter(const void *data, size_t nbytes, size_t lenFooter)
472{
473 fDaosContainer->WriteSingleAkey(
474 data, nbytes, daos_obj_id_t{kOidLowMetadata, static_cast<decltype(daos_obj_id_t::hi)>(fNTupleIndex)},
475 kDistributionKeyDefault, kAttributeKeyFooter, kCidMetadata);
476 fNTupleAnchor.fLenFooter = lenFooter;
477 fNTupleAnchor.fNBytesFooter = nbytes;
478}
479
481{
482 const auto ntplSize = RDaosNTupleAnchor::GetSize();
483 auto buffer = MakeUninitArray<unsigned char>(ntplSize);
484 fNTupleAnchor.Serialize(buffer.get());
485 fDaosContainer->WriteSingleAkey(
486 buffer.get(), ntplSize, daos_obj_id_t{kOidLowMetadata, static_cast<decltype(daos_obj_id_t::hi)>(fNTupleIndex)},
487 kDistributionKeyDefault, kAttributeKeyAnchor, kCidMetadata);
488}
489
490////////////////////////////////////////////////////////////////////////////////
491
492ROOT::Experimental::Internal::RPageSourceDaos::RPageSourceDaos(std::string_view ntupleName, std::string_view uri,
493 const RNTupleReadOptions &options)
494 : RPageSource(ntupleName, options),
495 fURI(uri),
496 fClusterPool(std::make_unique<RClusterPool>(*this, options.GetClusterBunchSize()))
497{
498 EnableDefaultMetrics("RPageSourceDaos");
499
500 auto args = ParseDaosURI(uri);
501 auto pool = std::make_shared<RDaosPool>(args.fPoolLabel);
502 fDaosContainer = std::make_unique<RDaosContainer>(pool, args.fContainerLabel);
503}
504
506
508{
510 std::unique_ptr<unsigned char[]> buffer, zipBuffer;
511
512 auto [locator, descBuilder] = RDaosContainerNTupleLocator::LocateNTuple(*fDaosContainer, fNTupleName);
513 if (!locator.IsValid())
515 R__FAIL("Attach: requested ntuple '" + fNTupleName + "' is not present in DAOS container."));
516
517 auto oclass = RDaosObject::ObjClassId(locator.fAnchor->fObjClass);
518 if (oclass.IsUnknown())
519 throw ROOT::Experimental::RException(R__FAIL("Attach: unknown object class " + locator.fAnchor->fObjClass));
520
521 fDaosContainer->SetDefaultObjectClass(oclass);
522 fNTupleIndex = locator.GetIndex();
523 daos_obj_id_t oidPageList{kOidLowPageList, static_cast<decltype(daos_obj_id_t::hi)>(fNTupleIndex)};
524
525 auto desc = descBuilder.MoveDescriptor();
526
527 for (const auto &cgDesc : desc.GetClusterGroupIterable()) {
528 buffer = MakeUninitArray<unsigned char>(cgDesc.GetPageListLength());
529 zipBuffer = MakeUninitArray<unsigned char>(cgDesc.GetPageListLocator().fBytesOnStorage);
530 fDaosContainer->ReadSingleAkey(
531 zipBuffer.get(), cgDesc.GetPageListLocator().fBytesOnStorage, oidPageList, kDistributionKeyDefault,
532 cgDesc.GetPageListLocator().GetPosition<RNTupleLocatorObject64>().fLocation, kCidMetadata);
533 RNTupleDecompressor::Unzip(zipBuffer.get(), cgDesc.GetPageListLocator().fBytesOnStorage,
534 cgDesc.GetPageListLength(), buffer.get());
535
536 RNTupleSerializer::DeserializePageList(buffer.get(), cgDesc.GetPageListLength(), cgDesc.GetId(), desc);
537 }
538
539 return desc;
540}
541
543{
544 return fDaosContainer->GetDefaultObjectClass().ToString();
545}
546
548 RClusterIndex clusterIndex, RSealedPage &sealedPage)
549{
550 const auto clusterId = clusterIndex.GetClusterId();
551
553 {
554 auto descriptorGuard = GetSharedDescriptorGuard();
555 const auto &clusterDescriptor = descriptorGuard->GetClusterDescriptor(clusterId);
556 pageInfo = clusterDescriptor.GetPageRange(physicalColumnId).Find(clusterIndex.GetIndex());
557 }
558
559 sealedPage.SetBufferSize(pageInfo.fLocator.fBytesOnStorage + pageInfo.fHasChecksum * kNBytesPageChecksum);
560 sealedPage.SetNElements(pageInfo.fNElements);
561 sealedPage.SetHasChecksum(pageInfo.fHasChecksum);
562 if (!sealedPage.GetBuffer())
563 return;
564
566 assert(!pageInfo.fHasChecksum);
567 memcpy(const_cast<void *>(sealedPage.GetBuffer()), RPage::GetPageZeroBuffer(), sealedPage.GetBufferSize());
568 return;
569 }
570
572 // Suboptimal but hard to do differently: we load the full cage up to and including the requested page.
573 // In practice, individual LoadSealedPage calls are rare and usually full clusters are buffered.
574 // The support for extracting individual pages from a cage makes testing easier, however.
575 const auto [position, offset] = DecodeDaosPagePosition(pageInfo.fLocator.GetPosition<RNTupleLocatorObject64>());
576 RDaosKey daosKey = GetPageDaosKey<kDefaultDaosMapping>(fNTupleIndex, clusterId, physicalColumnId, position);
577 const auto bufSize = offset + sealedPage.GetBufferSize();
578 auto cageHeadBuffer = MakeUninitArray<unsigned char>(bufSize);
579 fDaosContainer->ReadSingleAkey(cageHeadBuffer.get(), bufSize, daosKey.fOid, daosKey.fDkey, daosKey.fAkey);
580 memcpy(const_cast<void *>(sealedPage.GetBuffer()), cageHeadBuffer.get() + offset, sealedPage.GetBufferSize());
581 } else {
582 RDaosKey daosKey = GetPageDaosKey<kDefaultDaosMapping>(
583 fNTupleIndex, clusterId, physicalColumnId, pageInfo.fLocator.GetPosition<RNTupleLocatorObject64>().fLocation);
584 fDaosContainer->ReadSingleAkey(const_cast<void *>(sealedPage.GetBuffer()), sealedPage.GetBufferSize(),
585 daosKey.fOid, daosKey.fDkey, daosKey.fAkey);
586 }
587
589}
590
593 const RClusterInfo &clusterInfo,
594 ClusterSize_t::ValueType idxInCluster)
595{
596 const auto columnId = columnHandle.fPhysicalId;
597 const auto clusterId = clusterInfo.fClusterId;
598 const auto &pageInfo = clusterInfo.fPageInfo;
599
600 const auto element = columnHandle.fColumn->GetElement();
601 const auto elementSize = element->GetSize();
602 const auto elementInMemoryType = element->GetIdentifier().fInMemoryType;
603
604 if (pageInfo.fLocator.fType == RNTupleLocator::kTypePageZero) {
605 auto pageZero = fPageAllocator->NewPage(elementSize, pageInfo.fNElements);
606 pageZero.GrowUnchecked(pageInfo.fNElements);
607 memset(pageZero.GetBuffer(), 0, pageZero.GetNBytes());
608 pageZero.SetWindow(clusterInfo.fColumnOffset + pageInfo.fFirstInPage,
609 RPage::RClusterInfo(clusterId, clusterInfo.fColumnOffset));
610 return fPagePool.RegisterPage(std::move(pageZero), RPagePool::RKey{columnId, elementInMemoryType});
611 }
612
613 RSealedPage sealedPage;
614 sealedPage.SetNElements(pageInfo.fNElements);
615 sealedPage.SetHasChecksum(pageInfo.fHasChecksum);
616 sealedPage.SetBufferSize(pageInfo.fLocator.fBytesOnStorage + pageInfo.fHasChecksum * kNBytesPageChecksum);
617 std::unique_ptr<unsigned char[]> directReadBuffer; // only used if cluster pool is turned off
618
619 if (fOptions.GetClusterCache() == RNTupleReadOptions::EClusterCache::kOff) {
620 if (pageInfo.fLocator.fReserved & EDaosLocatorFlags::kCagedPage) {
622 R__FAIL("accessing caged pages is only supported in conjunction with cluster cache"));
623 }
624
625 directReadBuffer = MakeUninitArray<unsigned char>(sealedPage.GetBufferSize());
626 RDaosKey daosKey = GetPageDaosKey<kDefaultDaosMapping>(
627 fNTupleIndex, clusterId, columnId, pageInfo.fLocator.GetPosition<RNTupleLocatorObject64>().fLocation);
628 fDaosContainer->ReadSingleAkey(directReadBuffer.get(), sealedPage.GetBufferSize(), daosKey.fOid, daosKey.fDkey,
629 daosKey.fAkey);
630 fCounters->fNPageRead.Inc();
631 fCounters->fNRead.Inc();
632 fCounters->fSzReadPayload.Add(sealedPage.GetBufferSize());
633 sealedPage.SetBuffer(directReadBuffer.get());
634 } else {
635 if (!fCurrentCluster || (fCurrentCluster->GetId() != clusterId) || !fCurrentCluster->ContainsColumn(columnId))
636 fCurrentCluster = fClusterPool->GetCluster(clusterId, fActivePhysicalColumns.ToColumnSet());
637 R__ASSERT(fCurrentCluster->ContainsColumn(columnId));
638
639 auto cachedPageRef =
640 fPagePool.GetPage(RPagePool::RKey{columnId, elementInMemoryType}, RClusterIndex(clusterId, idxInCluster));
641 if (!cachedPageRef.Get().IsNull())
642 return cachedPageRef;
643
644 ROnDiskPage::Key key(columnId, pageInfo.fPageNo);
645 auto onDiskPage = fCurrentCluster->GetOnDiskPage(key);
646 R__ASSERT(onDiskPage && (sealedPage.GetBufferSize() == onDiskPage->GetSize()));
647 sealedPage.SetBuffer(onDiskPage->GetAddress());
648 }
649
650 RPage newPage;
651 {
652 Detail::RNTupleAtomicTimer timer(fCounters->fTimeWallUnzip, fCounters->fTimeCpuUnzip);
653 newPage = UnsealPage(sealedPage, *element).Unwrap();
654 fCounters->fSzUnzip.Add(elementSize * pageInfo.fNElements);
655 }
656
657 newPage.SetWindow(clusterInfo.fColumnOffset + pageInfo.fFirstInPage,
658 RPage::RClusterInfo(clusterId, clusterInfo.fColumnOffset));
659 fCounters->fNPageUnsealed.Inc();
660 return fPagePool.RegisterPage(std::move(newPage), RPagePool::RKey{columnId, elementInMemoryType});
661}
662
663std::unique_ptr<ROOT::Experimental::Internal::RPageSource>
665{
666 auto clone = new RPageSourceDaos(fNTupleName, fURI, fOptions);
667 return std::unique_ptr<RPageSourceDaos>(clone);
668}
669
670std::vector<std::unique_ptr<ROOT::Experimental::Internal::RCluster>>
672{
673 struct RDaosSealedPageLocator {
674 DescriptorId_t fClusterId = 0;
675 DescriptorId_t fColumnId = 0;
676 NTupleSize_t fPageNo = 0;
677 std::uint64_t fPosition = 0;
678 std::uint64_t fCageOffset = 0;
679 std::uint64_t fDataSize = 0; // page payload
680 std::uint64_t fBufferSize = 0; // page payload + checksum (if available)
681 };
682
683 // Prepares read requests for a single cluster; `readRequests` is modified by this function. Requests are coalesced
684 // by OID and distribution key.
685 // TODO(jalopezg): this may be a private member function; that, however, requires additional changes given that
686 // `RDaosContainer::MultiObjectRWOperation_t` cannot be forward-declared
687 auto fnPrepareSingleCluster = [&](const RCluster::RKey &clusterKey,
689 auto clusterId = clusterKey.fClusterId;
690 // Group page locators by their position in the object store; with caging enabled, this facilitates the
691 // processing of cages' requests together into a single IOV to be loaded.
692 std::unordered_map<std::uint32_t, std::vector<RDaosSealedPageLocator>> onDiskPages;
693
694 unsigned clusterBufSz = 0, nPages = 0;
695 auto pageZeroMap = std::make_unique<ROnDiskPageMap>();
696 PrepareLoadCluster(
697 clusterKey, *pageZeroMap,
698 [&](DescriptorId_t physicalColumnId, NTupleSize_t pageNo,
700 const auto &pageLocator = pageInfo.fLocator;
701 uint32_t position, offset;
702 std::tie(position, offset) = DecodeDaosPagePosition(pageLocator.GetPosition<RNTupleLocatorObject64>());
703 auto [itLoc, _] = onDiskPages.emplace(position, std::vector<RDaosSealedPageLocator>());
704 auto pageBufferSize = pageLocator.fBytesOnStorage + pageInfo.fHasChecksum * kNBytesPageChecksum;
705
706 itLoc->second.push_back(
707 {clusterId, physicalColumnId, pageNo, position, offset, pageLocator.fBytesOnStorage, pageBufferSize});
708 ++nPages;
709 clusterBufSz += pageBufferSize;
710 });
711
712 auto clusterBuffer = new unsigned char[clusterBufSz];
713 auto pageMap = std::make_unique<ROnDiskPageMapHeap>(std::unique_ptr<unsigned char[]>(clusterBuffer));
714
715 auto cageBuffer = clusterBuffer;
716 // Fill the cluster page map and the read requests for the RDaosContainer::ReadV() call
717 for (auto &[cageIndex, pageVec] : onDiskPages) {
718 auto columnId = pageVec[0].fColumnId; // All pages in a cage belong to the same column
719 std::size_t cageSz = 0;
720
721 for (auto &s : pageVec) {
722 assert(columnId == s.fColumnId);
723 assert(cageIndex == s.fPosition);
724 // Register the on disk pages in a page map
725 ROnDiskPage::Key key(s.fColumnId, s.fPageNo);
726 pageMap->Register(key, ROnDiskPage(cageBuffer + s.fCageOffset, s.fBufferSize));
727 cageSz += s.fBufferSize;
728 }
729
730 // Prepare new read request batched up by object ID and distribution key
731 d_iov_t iov;
732 d_iov_set(&iov, cageBuffer, cageSz);
733
734 RDaosKey daosKey = GetPageDaosKey<kDefaultDaosMapping>(fNTupleIndex, clusterId, columnId, cageIndex);
735 auto odPair = RDaosContainer::ROidDkeyPair{daosKey.fOid, daosKey.fDkey};
736 auto [itReq, ret] = readRequests.emplace(odPair, RDaosContainer::RWOperation(odPair));
737 itReq->second.Insert(daosKey.fAkey, iov);
738
739 cageBuffer += cageSz;
740 }
741 fCounters->fNPageRead.Add(nPages);
742 fCounters->fSzReadPayload.Add(clusterBufSz);
743
744 auto cluster = std::make_unique<RCluster>(clusterId);
745 cluster->Adopt(std::move(pageMap));
746 cluster->Adopt(std::move(pageZeroMap));
747 for (auto colId : clusterKey.fPhysicalColumnSet)
748 cluster->SetColumnAvailable(colId);
749 return cluster;
750 };
751
752 fCounters->fNClusterLoaded.Add(clusterKeys.size());
753
754 std::vector<std::unique_ptr<ROOT::Experimental::Internal::RCluster>> clusters;
756 for (auto key : clusterKeys) {
757 clusters.emplace_back(fnPrepareSingleCluster(key, readRequests));
758 }
759
760 {
761 Detail::RNTupleAtomicTimer timer(fCounters->fTimeWallRead, fCounters->fTimeCpuRead);
762 if (int err = fDaosContainer->ReadV(readRequests))
763 throw ROOT::Experimental::RException(R__FAIL("ReadV: error" + std::string(d_errstr(err))));
764 }
765 fCounters->fNReadV.Inc();
766 fCounters->fNRead.Add(readRequests.size());
767
768 return clusters;
769}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:294
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:290
#define R__LOG_WARNING(...)
Definition RLogger.hxx:363
#define h(i)
Definition RSha256.hxx:106
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t bytes
UInt_t Hash(const TString &s)
Definition TString.h:494
#define _(A, B)
Definition cfortran.h:108
Record wall time and CPU time between construction and destruction.
Managed a set of clusters containing compressed and packed pages.
RColumnElementBase * GetElement() const
Definition RColumn.hxx:331
A RDaosContainer provides read/write access to objects in a given container.
Definition RDaos.hxx:157
RDaosObject::DistributionKey_t DistributionKey_t
Definition RDaos.hxx:160
std::unordered_map< ROidDkeyPair, RWOperation, ROidDkeyPair::Hash > MultiObjectRWOperation_t
Definition RDaos.hxx:231
int ReadSingleAkey(void *buffer, std::size_t length, daos_obj_id_t oid, DistributionKey_t dkey, AttributeKey_t akey, ObjClassId_t cid)
Read data from a single object attribute key to the given buffer.
Definition RDaos.cxx:211
RDaosObject::AttributeKey_t AttributeKey_t
Definition RDaos.hxx:161
static Writer_t MakeMemCopyWriter(unsigned char *dest)
static void Unzip(const void *from, size_t nbytes, size_t dataLen, void *to)
The nbytes parameter provides the size ls of the from buffer.
A helper class for piece-wise construction of an RNTupleDescriptor.
void AddToOnDiskFooterSize(std::uint64_t size)
The real footer size also include the page list envelopes.
A helper class for serializing and deserialization of the RNTuple binary format.
static std::uint32_t DeserializeUInt16(const void *buffer, std::uint16_t &val)
static RResult< void > DeserializeHeader(const void *buffer, std::uint64_t bufSize, RNTupleDescriptorBuilder &descBuilder)
static RResult< void > DeserializeFooter(const void *buffer, std::uint64_t bufSize, RNTupleDescriptorBuilder &descBuilder)
static std::uint32_t SerializeString(const std::string &val, void *buffer)
static std::uint32_t DeserializeUInt32(const void *buffer, std::uint32_t &val)
static std::uint32_t SerializeUInt64(std::uint64_t val, void *buffer)
static RResult< void > DeserializePageList(const void *buffer, std::uint64_t bufSize, DescriptorId_t clusterGroupId, RNTupleDescriptor &desc)
static std::uint32_t DeserializeUInt64(const void *buffer, std::uint64_t &val)
static RResult< std::uint32_t > DeserializeString(const void *buffer, std::uint64_t bufSize, std::string &val)
static std::uint32_t SerializeUInt16(std::uint16_t val, void *buffer)
static std::uint32_t SerializeUInt32(std::uint32_t val, void *buffer)
A page as being stored on disk, that is packed and compressed.
Definition RCluster.hxx:42
Base class for a sink with a physical storage backend.
void EnableDefaultMetrics(const std::string &prefix)
Enables the default set of metrics provided by RPageSink.
Reference to a page stored in the page pool.
RNTupleLocator CommitClusterGroupImpl(unsigned char *serializedPageList, std::uint32_t length) final
Returns the locator of the page list envelope of the given buffer that contains the serialized page l...
RPageSinkDaos(std::string_view ntupleName, std::string_view uri, const RNTupleWriteOptions &options)
void WriteNTupleFooter(const void *data, size_t nbytes, size_t lenFooter)
std::uint64_t StageClusterImpl() final
Returns the number of bytes written to storage (excluding metadata)
void WriteNTupleHeader(const void *data, size_t nbytes, size_t lenHeader)
void InitImpl(unsigned char *serializedHeader, std::uint32_t length) final
RNTupleLocator CommitPageImpl(ColumnHandle_t columnHandle, const RPage &page) final
RNTupleLocator CommitSealedPageImpl(DescriptorId_t physicalColumnId, const RPageStorage::RSealedPage &sealedPage) final
std::vector< RNTupleLocator > CommitSealedPageVImpl(std::span< RPageStorage::RSealedPageGroup > ranges, const std::vector< bool > &mask) final
Vector commit of preprocessed pages.
std::unique_ptr< RNTupleCompressor > fCompressor
Helper to zip pages and header/footer; includes a 16MB (kMAXZIPBUF) zip buffer.
Storage provider that reads ntuple pages from a DAOS container.
std::string GetObjectClass() const
Return the object class used for user data OIDs in this ntuple.
RPageRef LoadPageImpl(ColumnHandle_t columnHandle, const RClusterInfo &clusterInfo, ClusterSize_t::ValueType idxInCluster) final
std::vector< std::unique_ptr< RCluster > > LoadClusters(std::span< RCluster::RKey > clusterKeys) final
Populates all the pages of the given cluster ids and columns; it is possible that some columns do not...
RPageSourceDaos(std::string_view ntupleName, std::string_view uri, const RNTupleReadOptions &options)
void LoadSealedPage(DescriptorId_t physicalColumnId, RClusterIndex clusterIndex, RSealedPage &sealedPage) final
Read the packed and compressed bytes of a page into the memory buffer provided by sealedPage.
RNTupleDescriptor AttachImpl() final
LoadStructureImpl() has been called before AttachImpl() is called
std::unique_ptr< RDaosContainer > fDaosContainer
A container that stores object data (header/footer, pages, etc.)
std::unique_ptr< RPageSource > CloneImpl() const final
The cloned page source creates a new connection to the pool/container.
Abstract interface to read data from an ntuple.
void EnableDefaultMetrics(const std::string &prefix)
Enables the default set of metrics provided by RPageSource.
Stores information about the cluster in which this page resides.
Definition RPage.hxx:56
A page is a slice of a column that is mapped into memory.
Definition RPage.hxx:47
std::size_t GetNBytes() const
The space taken by column elements in the buffer.
Definition RPage.hxx:115
void SetWindow(const NTupleSize_t rangeFirst, const RClusterInfo &clusterInfo)
Seek the page to a certain position of the column.
Definition RPage.hxx:162
static const void * GetPageZeroBuffer()
Return a pointer to the page zero buffer used if there is no on-disk data for a particular deferred c...
Definition RPage.cxx:25
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
DescriptorId_t GetClusterId() const
ClusterSize_t::ValueType GetIndex() const
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
The on-storage meta-data of an ntuple.
Common user-tunable settings for reading ntuples.
DAOS-specific user-tunable settings for storing ntuples.
Common user-tunable settings for storing ntuples.
void ThrowOnError()
Short-hand method to throw an exception in the case of errors.
Definition RError.hxx:281
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:194
static constexpr std::uint16_t kVersionEpoch
Definition RNTuple.hxx:79
const char * d_errstr(int rc)
static void d_iov_set(d_iov_t *iov, void *buf, size_t size)
Definition daos.h:50
uint16_t daos_oclass_id_t
Definition daos.h:135
@ OC_SX
Definition daos.h:129
std::unique_ptr< T[]> MakeUninitArray(std::size_t size)
Make an array of default-initialized elements.
RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
The identifiers that specifies the content of a (partial) cluster.
Definition RCluster.hxx:156
A pair of <object ID, distribution key> that can be used to issue a fetch/update request for multiple...
Definition RDaos.hxx:166
Describes a read/write operation on multiple attribute keys under the same object ID and distribution...
Definition RDaos.hxx:190
Entry point for an RNTuple in a DAOS container.
std::uint32_t fNBytesFooter
The size of the compressed ntuple footer.
RResult< std::uint32_t > Deserialize(const void *buffer, std::uint32_t bufSize)
std::uint64_t fVersionAnchor
Allows for evolving the struct in future versions.
std::string fObjClass
The object class for user data OIDs, e.g. SX
std::uint16_t fVersionEpoch
Version of the binary format supported by the writer.
std::uint32_t fLenHeader
The size of the uncompressed ntuple header.
std::uint32_t fLenFooter
The size of the uncompressed ntuple footer.
std::uint32_t fNBytesHeader
The size of the compressed ntuple header.
static constexpr std::size_t kOCNameMaxLength
This limit is currently not defined in any header and any call to daos_oclass_id2name() within DAOS u...
Definition RDaos.hxx:108
On-disk pages within a page source are identified by the column and page number.
Definition RCluster.hxx:52
Summarizes cluster-level information that are necessary to load a certain page.
std::uint64_t fColumnOffset
The first element number of the page's column in the given cluster.
RClusterDescriptor::RPageRange::RPageInfoExtended fPageInfo
Location of the page on disk.
A sealed page contains the bytes of a page as written to storage (packed & compressed).
We do not need to store the element size / uncompressed page size because we know to which column the...
std::uint32_t fNElements
The sum of the elements of all the pages must match the corresponding fNElements field in fColumnRang...
bool fHasChecksum
If true, the 8 bytes following the serialized page are an xxhash of the on-disk page data.
RNTupleLocator fLocator
The meaning of fLocator depends on the storage backend.
RNTupleLocator payload that is common for object stores using 64bit location information.
Generic information about the physical location of data.
std::uint8_t fReserved
Reserved for use by concrete storage backends.
ELocatorType fType
For non-disk locators, the value for the Type field.
std::variant< std::uint64_t, RNTupleLocatorObject64 > fPosition
Simple on-disk locators consisting of a 64-bit offset use variant type uint64_t; extended locators ha...
iovec for memory buffer
Definition daos.h:37
uint64_t hi
Definition daos.h:147
uint64_t lo
Definition daos.h:146
TMarker m
Definition textangle.C:8