Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleDescriptor.cxx
Go to the documentation of this file.
1/// \file RNTupleDescriptor.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-04
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-2019, 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/RError.hxx>
17#include <ROOT/RField.hxx>
19#include <ROOT/RNTupleModel.hxx>
20#include <ROOT/RNTupleUtil.hxx>
21#include <ROOT/RStringView.hxx>
22
23#include <RZip.h>
24#include <TError.h>
25
26#include <algorithm>
27#include <cstdint>
28#include <cstring>
29#include <iostream>
30#include <utility>
31
32namespace {
33
34/// The machine-independent serialization of meta-data wraps the header and footer as well as sub structures in
35/// frames. The frame layout is
36///
37/// -----------------------------------------------------------
38/// | TYPE | DESCRIPTION |
39/// |----------------------------------------------------------
40/// | std::uint16_t | Version used to write the frame |
41/// | std::uint16_t | Minimum version for reading the frame |
42/// | std::uint32_t | Length of the frame incl. preamble |
43/// -----------------------------------------------------------
44///
45/// In addition, the header and footer store a 4 byte CRC32 checksum of the frame immediately after the frame.
46/// The footer also repeats the frame size just before the CRC32 checksum. That means, one can read the last 8 bytes
47/// to determine the footer length, and the first 8 bytes to determine the header length.
48///
49/// Within the frames, integers of different lengths are stored in a machine-independent representation. Strings and
50/// vectors store the number of items followed by the items. Time stamps are stored in number of seconds since the
51/// UNIX epoch.
52
53std::uint32_t SerializeInt64(std::int64_t val, void *buffer)
54{
55 if (buffer != nullptr) {
56 auto bytes = reinterpret_cast<unsigned char *>(buffer);
57 bytes[0] = (val & 0x00000000000000FF);
58 bytes[1] = (val & 0x000000000000FF00) >> 8;
59 bytes[2] = (val & 0x0000000000FF0000) >> 16;
60 bytes[3] = (val & 0x00000000FF000000) >> 24;
61 bytes[4] = (val & 0x000000FF00000000) >> 32;
62 bytes[5] = (val & 0x0000FF0000000000) >> 40;
63 bytes[6] = (val & 0x00FF000000000000) >> 48;
64 bytes[7] = (val & 0xFF00000000000000) >> 56;
65 }
66 return 8;
67}
68
69std::uint32_t SerializeUInt64(std::uint64_t val, void *buffer)
70{
71 return SerializeInt64(val, buffer);
72}
73
74std::uint32_t DeserializeInt64(const void *buffer, std::int64_t *val)
75{
76 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
77 *val = std::int64_t(bytes[0]) + (std::int64_t(bytes[1]) << 8) +
78 (std::int64_t(bytes[2]) << 16) + (std::int64_t(bytes[3]) << 24) +
79 (std::int64_t(bytes[4]) << 32) + (std::int64_t(bytes[5]) << 40) +
80 (std::int64_t(bytes[6]) << 48) + (std::int64_t(bytes[7]) << 56);
81 return 8;
82}
83
84std::uint32_t DeserializeUInt64(const void *buffer, std::uint64_t *val)
85{
86 return DeserializeInt64(buffer, reinterpret_cast<std::int64_t *>(val));
87}
88
89std::uint32_t SerializeInt32(std::int32_t val, void *buffer)
90{
91 if (buffer != nullptr) {
92 auto bytes = reinterpret_cast<unsigned char *>(buffer);
93 bytes[0] = (val & 0x000000FF);
94 bytes[1] = (val & 0x0000FF00) >> 8;
95 bytes[2] = (val & 0x00FF0000) >> 16;
96 bytes[3] = (val & 0xFF000000) >> 24;
97 }
98 return 4;
99}
100
101std::uint32_t SerializeUInt32(std::uint32_t val, void *buffer)
102{
103 return SerializeInt32(val, buffer);
104}
105
106std::uint32_t DeserializeInt32(const void *buffer, std::int32_t *val)
107{
108 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
109 *val = std::int32_t(bytes[0]) + (std::int32_t(bytes[1]) << 8) +
110 (std::int32_t(bytes[2]) << 16) + (std::int32_t(bytes[3]) << 24);
111 return 4;
112}
113
114std::uint32_t DeserializeUInt32(const void *buffer, std::uint32_t *val)
115{
116 return DeserializeInt32(buffer, reinterpret_cast<std::int32_t *>(val));
117}
118
119std::uint32_t SerializeInt16(std::int16_t val, void *buffer)
120{
121 if (buffer != nullptr) {
122 auto bytes = reinterpret_cast<unsigned char *>(buffer);
123 bytes[0] = (val & 0x00FF);
124 bytes[1] = (val & 0xFF00) >> 8;
125 }
126 return 2;
127}
128
129std::uint32_t SerializeUInt16(std::uint16_t val, void *buffer)
130{
131 return SerializeInt16(val, buffer);
132}
133
134std::uint32_t DeserializeInt16(const void *buffer, std::int16_t *val)
135{
136 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
137 *val = std::int16_t(bytes[0]) + (std::int16_t(bytes[1]) << 8);
138 return 2;
139}
140
141std::uint32_t DeserializeUInt16(const void *buffer, std::uint16_t *val)
142{
143 return DeserializeInt16(buffer, reinterpret_cast<std::int16_t *>(val));
144}
145
146std::uint32_t SerializeClusterSize(ROOT::Experimental::ClusterSize_t val, void *buffer)
147{
148 return SerializeUInt32(val, buffer);
149}
150
151std::uint32_t DeserializeClusterSize(const void *buffer, ROOT::Experimental::ClusterSize_t *val)
152{
153 std::uint32_t size;
154 auto nbytes = DeserializeUInt32(buffer, &size);
155 *val = size;
156 return nbytes;
157}
158
159std::uint32_t SerializeString(const std::string &val, void *buffer)
160{
161 if (buffer != nullptr) {
162 auto pos = reinterpret_cast<unsigned char *>(buffer);
163 pos += SerializeUInt32(val.length(), pos);
164 memcpy(pos, val.data(), val.length());
165 }
166 return SerializeUInt32(val.length(), nullptr) + val.length();
167}
168
169std::uint32_t DeserializeString(const void *buffer, std::string *val)
170{
171 auto base = reinterpret_cast<const unsigned char *>(buffer);
172 auto bytes = base;
173 std::uint32_t length;
174 bytes += DeserializeUInt32(buffer, &length);
175 val->resize(length);
176 memcpy(&(*val)[0], bytes, length);
177 return bytes + length - base;
178}
179
180std::uint32_t SerializeLocator(const ROOT::Experimental::RClusterDescriptor::RLocator &val, void *buffer)
181{
182 // In order to keep the meta-data small, we don't wrap the locator in a frame
183 if (buffer != nullptr) {
184 auto pos = reinterpret_cast<unsigned char *>(buffer);
185 pos += SerializeInt64(val.fPosition, pos);
186 pos += SerializeUInt32(val.fBytesOnStorage, pos);
187 pos += SerializeString(val.fUrl, pos);
188 }
189 return SerializeString(val.fUrl, nullptr) + 12;
190}
191
192std::uint32_t DeserializeLocator(const void *buffer, ROOT::Experimental::RClusterDescriptor::RLocator *val)
193{
194 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
195 bytes += DeserializeInt64(bytes, &val->fPosition);
196 bytes += DeserializeUInt32(bytes, &val->fBytesOnStorage);
197 bytes += DeserializeString(bytes, &val->fUrl);
198 return SerializeString(val->fUrl, nullptr) + 12;
199}
200
201std::uint32_t SerializeFrame(std::uint16_t protocolVersionCurrent, std::uint16_t protocolVersionMin, void *buffer,
202 void **ptrSize)
203{
204 if (buffer != nullptr) {
205 auto pos = reinterpret_cast<unsigned char *>(buffer);
206 pos += SerializeUInt16(protocolVersionCurrent, pos); // The protocol version used to write the structure
207 pos += SerializeUInt16(protocolVersionMin, pos); // The minimum protocol version required to read the data
208 *ptrSize = pos;
209 pos += SerializeUInt32(0, pos); // placeholder for the size of the frame
210 }
211 return 8;
212}
213
214std::uint32_t DeserializeFrame(std::uint16_t protocolVersion, const void *buffer, std::uint32_t *size)
215{
216 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
217 std::uint16_t protocolVersionAtWrite;
218 std::uint16_t protocolVersionMinRequired;
219 bytes += DeserializeUInt16(bytes, &protocolVersionAtWrite);
220 bytes += DeserializeUInt16(bytes, &protocolVersionMinRequired);
221 R__ASSERT(protocolVersionAtWrite >= protocolVersionMinRequired);
222 R__ASSERT(protocolVersion >= protocolVersionMinRequired);
223 bytes += DeserializeUInt32(bytes, size);
224 return 8;
225}
226
227std::uint32_t SerializeVersion(const ROOT::Experimental::RNTupleVersion &val, void *buffer)
228{
229 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
230 auto pos = base;
231 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
232
233 void *ptrSize = nullptr;
234 pos += SerializeFrame(0, 0, *where, &ptrSize);
235
236 pos += SerializeUInt32(val.GetVersionUse(), *where);
237 pos += SerializeUInt32(val.GetVersionMin(), *where);
238 pos += SerializeUInt64(val.GetFlags(), *where);
239
240 auto size = pos - base;
241 SerializeUInt32(size, ptrSize);
242 return size;
243}
244
245std::uint32_t DeserializeVersion(const void *buffer, ROOT::Experimental::RNTupleVersion *version)
246{
247 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
248 std::uint32_t frameSize;
249 bytes += DeserializeFrame(0, bytes, &frameSize);
250
251 std::uint32_t versionUse;
252 std::uint32_t versionMin;
253 std::uint64_t flags;
254 bytes += DeserializeUInt32(bytes, &versionUse);
255 bytes += DeserializeUInt32(bytes, &versionMin);
256 bytes += DeserializeUInt64(bytes, &flags);
257 *version = ROOT::Experimental::RNTupleVersion(versionUse, versionMin, flags);
258
259 return frameSize;
260}
261
262std::uint32_t SerializeUuid(const ROOT::Experimental::RNTupleUuid &val, void *buffer)
263{
264 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
265 auto pos = base;
266 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
267
268 void *ptrSize = nullptr;
269 pos += SerializeFrame(0, 0, *where, &ptrSize);
270
271 pos += SerializeString(val, *where);
272
273 auto size = pos - base;
274 SerializeUInt32(size, ptrSize);
275 return size;
276}
277
278std::uint32_t DeserializeUuid(const void *buffer, ROOT::Experimental::RNTupleUuid *uuid)
279{
280 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
281 std::uint32_t frameSize;
282 bytes += DeserializeFrame(0, bytes, &frameSize);
283
284 bytes += DeserializeString(bytes, uuid);
285
286 return frameSize;
287}
288
289std::uint32_t SerializeColumnModel(const ROOT::Experimental::RColumnModel &val, void *buffer)
290{
291 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
292 auto pos = base;
293 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
294
295 void *ptrSize = nullptr;
296 pos += SerializeFrame(0, 0, *where, &ptrSize);
297
298 pos += SerializeInt32(static_cast<int>(val.GetType()), *where);
299 pos += SerializeInt32(static_cast<int>(val.GetIsSorted()), *where);
300
301 auto size = pos - base;
302 SerializeUInt32(size, ptrSize);
303 return size;
304}
305
306std::uint32_t DeserializeColumnModel(const void *buffer, ROOT::Experimental::RColumnModel *columnModel)
307{
308 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
309 std::uint32_t frameSize;
310 bytes += DeserializeFrame(0, bytes, &frameSize);
311
312 std::int32_t type;
313 std::int32_t isSorted;
314 bytes += DeserializeInt32(bytes, &type);
315 bytes += DeserializeInt32(bytes, &isSorted);
316 *columnModel = ROOT::Experimental::RColumnModel(static_cast<ROOT::Experimental::EColumnType>(type), isSorted);
317
318 return frameSize;
319}
320
321std::uint32_t SerializeTimeStamp(const std::chrono::system_clock::time_point &val, void *buffer)
322{
323 return SerializeInt64(std::chrono::system_clock::to_time_t(val), buffer);
324}
325
326std::uint32_t DeserializeTimeStamp(const void *buffer, std::chrono::system_clock::time_point *timeStamp)
327{
328 std::int64_t secSinceUnixEpoch;
329 auto size = DeserializeInt64(buffer, &secSinceUnixEpoch);
330 *timeStamp = std::chrono::system_clock::from_time_t(secSinceUnixEpoch);
331 return size;
332}
333
334std::uint32_t SerializeColumnRange(const ROOT::Experimental::RClusterDescriptor::RColumnRange &val, void *buffer)
335{
336 // To keep the cluster footers small, we don't put a frame around individual column ranges.
337 if (buffer != nullptr) {
338 auto pos = reinterpret_cast<unsigned char *>(buffer);
339 // The column id is stored in SerializeFooter() for the column range and the page range altogether
340 pos += SerializeUInt64(val.fFirstElementIndex, pos);
341 pos += SerializeClusterSize(val.fNElements, pos);
342 pos += SerializeInt64(val.fCompressionSettings, pos);
343 }
344 return 20;
345}
346
347std::uint32_t DeserializeColumnRange(const void *buffer,
349{
350 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
351 // The column id is set elsewhere (see AddClustersFromFooter())
352 bytes += DeserializeUInt64(bytes, &columnRange->fFirstElementIndex);
353 bytes += DeserializeClusterSize(bytes, &columnRange->fNElements);
354 bytes += DeserializeInt64(bytes, &columnRange->fCompressionSettings);
355 return 20;
356}
357
358std::uint32_t SerializePageInfo(const ROOT::Experimental::RClusterDescriptor::RPageRange::RPageInfo &val, void *buffer)
359{
360 // To keep the cluster footers small, we don't put a frame around individual page infos.
361 if (buffer != nullptr) {
362 auto pos = reinterpret_cast<unsigned char *>(buffer);
363 // The column id is stored in SerializeFooter() for the column range and the page range altogether
364 pos += SerializeClusterSize(val.fNElements, pos);
365 pos += SerializeLocator(val.fLocator, pos);
366 }
367 return 4 + SerializeLocator(val.fLocator, nullptr);
368}
369
370std::uint32_t DeserializePageInfo(const void *buffer,
372{
373 auto base = reinterpret_cast<const unsigned char *>(buffer);
374 auto bytes = base;
375 // The column id is set elsewhere (see AddClustersFromFooter())
376 bytes += DeserializeClusterSize(bytes, &pageInfo->fNElements);
377 bytes += DeserializeLocator(bytes, &pageInfo->fLocator);
378 return bytes - base;
379}
380
381std::uint32_t SerializeCrc32(const unsigned char *data, std::uint32_t length, void *buffer)
382{
383 auto checksum = R__crc32(0, nullptr, 0);
384 if (buffer != nullptr) {
385 checksum = R__crc32(checksum, data, length);
386 SerializeUInt32(checksum, buffer);
387 }
388 return 4;
389}
390
391void VerifyCrc32(const unsigned char *data, std::uint32_t length)
392{
393 auto checksumReal = R__crc32(0, nullptr, 0);
394 checksumReal = R__crc32(checksumReal, data, length);
395 std::uint32_t checksumFound;
396 DeserializeUInt32(data + length, &checksumFound);
397 R__ASSERT(checksumFound == checksumReal);
398}
399
400std::uint32_t SerializeField(const ROOT::Experimental::RFieldDescriptor &val, void *buffer)
401{
402 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
403 auto pos = base;
404 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
405
406 void *ptrSize = nullptr;
409
410 pos += SerializeUInt64(val.GetId(), *where);
411 pos += SerializeVersion(val.GetFieldVersion(), *where);
412 pos += SerializeVersion(val.GetTypeVersion(), *where);
413 pos += SerializeString(val.GetFieldName(), *where);
414 pos += SerializeString(val.GetFieldDescription(), *where);
415 pos += SerializeString(val.GetTypeName(), *where);
416 pos += SerializeUInt64(val.GetNRepetitions(), *where);
417 pos += SerializeUInt32(static_cast<int>(val.GetStructure()), *where);
418 pos += SerializeUInt64(val.GetParentId(), *where);
419 pos += SerializeUInt32(val.GetLinkIds().size(), *where);
420 for (const auto& l : val.GetLinkIds())
421 pos += SerializeUInt64(l, *where);
422
423 auto size = pos - base;
424 SerializeUInt32(size, ptrSize);
425 return size;
426}
427
428std::uint32_t SerializeColumn(const ROOT::Experimental::RColumnDescriptor &val, void *buffer)
429{
430 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
431 auto pos = base;
432 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
433
434 void *ptrSize = nullptr;
437
438 pos += SerializeUInt64(val.GetId(), *where);
439 pos += SerializeVersion(val.GetVersion(), *where);
440 pos += SerializeColumnModel(val.GetModel(), *where);
441 pos += SerializeUInt64(val.GetFieldId(), *where);
442 pos += SerializeUInt32(val.GetIndex(), *where);
443
444 auto size = pos - base;
445 SerializeUInt32(size, ptrSize);
446 return size;
447}
448
449std::uint32_t SerializeClusterSummary(const ROOT::Experimental::RClusterDescriptor &val, void *buffer)
450{
451 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
452 auto pos = base;
453 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
454
455 void *ptrSize = nullptr;
458
459 pos += SerializeUInt64(val.GetId(), *where);
460 pos += SerializeVersion(val.GetVersion(), *where);
461 pos += SerializeUInt64(val.GetFirstEntryIndex(), *where);
462 pos += SerializeUInt64(val.GetNEntries(), *where);
463 pos += SerializeLocator(val.GetLocator(), *where);
464
465 auto size = pos - base;
466 SerializeUInt32(size, ptrSize);
467 return size;
468}
469
470} // anonymous namespace
471
472
473////////////////////////////////////////////////////////////////////////////////
474
475
477 return fFieldId == other.fFieldId &&
478 fFieldVersion == other.fFieldVersion &&
479 fTypeVersion == other.fTypeVersion &&
480 fFieldName == other.fFieldName &&
482 fTypeName == other.fTypeName &&
483 fNRepetitions == other.fNRepetitions &&
484 fStructure == other.fStructure &&
485 fParentId == other.fParentId &&
486 fLinkIds == other.fLinkIds;
487}
488
491 RFieldDescriptor clone;
492 clone.fFieldId = fFieldId;
493 clone.fFieldVersion = fFieldVersion;
494 clone.fTypeVersion = fTypeVersion;
495 clone.fFieldName = fFieldName;
496 clone.fFieldDescription = fFieldDescription;
497 clone.fTypeName = fTypeName;
498 clone.fNRepetitions = fNRepetitions;
499 clone.fStructure = fStructure;
500 clone.fParentId = fParentId;
501 clone.fLinkIds = fLinkIds;
502 return clone;
503}
504
505
506////////////////////////////////////////////////////////////////////////////////
507
508
510 return fColumnId == other.fColumnId &&
511 fVersion == other.fVersion &&
512 fModel == other.fModel &&
513 fFieldId == other.fFieldId &&
514 fIndex == other.fIndex;
515}
516
517
518////////////////////////////////////////////////////////////////////////////////
519
520
522 return fClusterId == other.fClusterId &&
523 fVersion == other.fVersion &&
524 fFirstEntryIndex == other.fFirstEntryIndex &&
525 fNEntries == other.fNEntries &&
526 fLocator == other.fLocator &&
527 fColumnRanges == other.fColumnRanges &&
528 fPageRanges == other.fPageRanges;
529}
530
531
532////////////////////////////////////////////////////////////////////////////////
533
534
536 return fName == other.fName &&
537 fDescription == other.fDescription &&
538 fAuthor == other.fAuthor &&
539 fCustodian == other.fCustodian &&
540 fTimeStampData == other.fTimeStampData &&
541 fTimeStampWritten == other.fTimeStampWritten &&
542 fVersion == other.fVersion &&
543 fOwnUuid == other.fOwnUuid &&
544 fGroupUuid == other.fGroupUuid &&
545 fFieldDescriptors == other.fFieldDescriptors &&
546 fColumnDescriptors == other.fColumnDescriptors &&
547 fClusterDescriptors == other.fClusterDescriptors;
548}
549
550
552{
553 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
554 auto pos = base;
555 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
556
557 void *ptrSize = nullptr;
558 pos += SerializeFrame(
560 pos += SerializeUInt64(0, *where); // reserved; can be at some point used, e.g., for compression flags
561
562 pos += SerializeString(fName, *where);
563 pos += SerializeString(fDescription, *where);
564 pos += SerializeString(fAuthor, *where);
565 pos += SerializeString(fCustodian, *where);
566 pos += SerializeTimeStamp(fTimeStampData, *where);
567 pos += SerializeTimeStamp(fTimeStampWritten, *where);
568 pos += SerializeVersion(fVersion, *where);
569 pos += SerializeUuid(fOwnUuid, *where);
570 pos += SerializeUuid(fGroupUuid, *where);
571 pos += SerializeUInt32(fFieldDescriptors.size(), *where);
572 for (const auto& f : fFieldDescriptors) {
573 pos += SerializeField(f.second, *where);
574 }
575 pos += SerializeUInt32(fColumnDescriptors.size(), *where);
576 for (const auto& c : fColumnDescriptors) {
577 pos += SerializeColumn(c.second, *where);
578 }
579
580 std::uint32_t size = pos - base;
581 SerializeUInt32(size, ptrSize);
582 size += SerializeCrc32(base, size, *where);
583
584 return size;
585}
586
588{
589 auto base = reinterpret_cast<unsigned char *>((buffer != nullptr) ? buffer : 0);
590 auto pos = base;
591 void** where = (buffer == nullptr) ? &buffer : reinterpret_cast<void**>(&pos);
592
593 void *ptrSize = nullptr;
594 pos += SerializeFrame(
596 pos += SerializeUInt64(0, *where); // reserved; can be at some point used, e.g., for compression flags
597
598 pos += SerializeUInt64(fClusterDescriptors.size(), *where);
599 for (const auto& cluster : fClusterDescriptors) {
600 pos += SerializeUuid(fOwnUuid, *where); // in order to verify that header and footer belong together
601 pos += SerializeClusterSummary(cluster.second, *where);
602
603 pos += SerializeUInt32(fColumnDescriptors.size(), *where);
604 for (const auto& column : fColumnDescriptors) {
605 auto columnId = column.first;
606 pos += SerializeUInt64(columnId, *where);
607
608 const auto &columnRange = cluster.second.GetColumnRange(columnId);
609 R__ASSERT(columnRange.fColumnId == columnId);
610 pos += SerializeColumnRange(columnRange, *where);
611
612 const auto &pageRange = cluster.second.GetPageRange(columnId);
613 R__ASSERT(pageRange.fColumnId == columnId);
614 auto nPages = pageRange.fPageInfos.size();
615 pos += SerializeUInt32(nPages, *where);
616 for (unsigned int i = 0; i < nPages; ++i) {
617 pos += SerializePageInfo(pageRange.fPageInfos[i], *where);
618 }
619 }
620 }
621
622 // The next 16 bytes make the ntuple's postscript
623 pos += SerializeUInt16(kFrameVersionCurrent, *where);
624 pos += SerializeUInt16(kFrameVersionMin, *where);
625 // Add the CRC32 bytes to the header and footer sizes
626 pos += SerializeUInt32(GetHeaderSize(), *where);
627 std::uint32_t size = pos - base + 4;
628 pos += SerializeUInt32(size + 4, *where);
629 size += SerializeCrc32(base, size, *where);
630
631 return size;
632}
633
634
636 const void *postscript, std::uint32_t &szHeader, std::uint32_t &szFooter)
637{
638 auto pos = reinterpret_cast<const unsigned char *>(postscript);
639 std::uint16_t dummy;
640 pos += DeserializeUInt16(pos, &dummy);
641 pos += DeserializeUInt16(pos, &dummy);
642 pos += DeserializeUInt32(pos, &szHeader);
643 pos += DeserializeUInt32(pos, &szFooter);
644}
645
646
648{
649 NTupleSize_t result = 0;
650 for (const auto &cd : fClusterDescriptors) {
651 result = std::max(result, cd.second.GetFirstEntryIndex() + cd.second.GetNEntries());
652 }
653 return result;
654}
655
657{
658 NTupleSize_t result = 0;
659 for (const auto &cd : fClusterDescriptors) {
660 auto columnRange = cd.second.GetColumnRange(columnId);
661 result = std::max(result, columnRange.fFirstElementIndex + columnRange.fNElements);
662 }
663 return result;
664}
665
666
669{
670 std::string leafName(fieldName);
671 auto posDot = leafName.find_last_of('.');
672 if (posDot != std::string::npos) {
673 auto parentName = leafName.substr(0, posDot);
674 leafName = leafName.substr(posDot + 1);
675 parentId = FindFieldId(parentName, parentId);
676 }
677 for (const auto &fd : fFieldDescriptors) {
678 if (fd.second.GetParentId() == parentId && fd.second.GetFieldName() == leafName)
679 return fd.second.GetId();
680 }
682}
683
684
686{
687 if (fieldId == kInvalidDescriptorId)
688 return "";
689
690 const auto &fieldDescriptor = fFieldDescriptors.at(fieldId);
691 auto prefix = GetQualifiedFieldName(fieldDescriptor.GetParentId());
692 if (prefix.empty())
693 return fieldDescriptor.GetFieldName();
694 return prefix + "." + fieldDescriptor.GetFieldName();
695}
696
697
700{
701 return FindFieldId("", kInvalidDescriptorId);
702}
703
704
707{
708 return FindFieldId(fieldName, GetFieldZeroId());
709}
710
711
714{
715 for (const auto &cd : fColumnDescriptors) {
716 if (cd.second.GetFieldId() == fieldId && cd.second.GetIndex() == columnIndex)
717 return cd.second.GetId();
718 }
720}
721
722
725{
726 // TODO(jblomer): binary search?
727 for (const auto &cd : fClusterDescriptors) {
728 auto columnRange = cd.second.GetColumnRange(columnId);
729 if (columnRange.Contains(index))
730 return cd.second.GetId();
731 }
733}
734
735
738{
739 const auto &clusterDesc = GetClusterDescriptor(clusterId);
740 auto firstEntryInNextCluster = clusterDesc.GetFirstEntryIndex() + clusterDesc.GetNEntries();
741 // TODO(jblomer): binary search?
742 for (const auto &cd : fClusterDescriptors) {
743 if (cd.second.GetFirstEntryIndex() == firstEntryInNextCluster)
744 return cd.second.GetId();
745 }
747}
748
749
752{
753 const auto &clusterDesc = GetClusterDescriptor(clusterId);
754 // TODO(jblomer): binary search?
755 for (const auto &cd : fClusterDescriptors) {
756 if (cd.second.GetFirstEntryIndex() + cd.second.GetNEntries() == clusterDesc.GetFirstEntryIndex())
757 return cd.second.GetId();
758 }
760}
761
762
763std::unique_ptr<ROOT::Experimental::RNTupleModel> ROOT::Experimental::RNTupleDescriptor::GenerateModel() const
764{
765 auto model = std::make_unique<RNTupleModel>();
766 for (const auto &topDesc : GetTopLevelFields()) {
767 auto field = Detail::RFieldBase::Create(topDesc.GetFieldName(), topDesc.GetTypeName());
768 model->AddField(field.Unwrap());
769 }
770 return model;
771}
772
773
774////////////////////////////////////////////////////////////////////////////////
775
776
779 // Reuse field name validity check
780 auto validName = Detail::RFieldBase::EnsureValidFieldName(fDescriptor.GetName());
781 if (!validName) {
782 return R__FORWARD_ERROR(validName);
783 }
784 // open-ended list of invariant checks
785 for (const auto& key_val: fDescriptor.fFieldDescriptors) {
786 const auto& id = key_val.first;
787 const auto& desc = key_val.second;
788 // parent not properly set
789 if (id != DescriptorId_t(0) && desc.GetParentId() == kInvalidDescriptorId) {
790 return R__FAIL("field with id '" + std::to_string(id) + "' has an invalid parent id");
791 }
792 }
793 return RResult<void>::Success();
794}
795
797{
798 RNTupleDescriptor result;
799 std::swap(result, fDescriptor);
800 return result;
801}
802
804{
805 auto pos = reinterpret_cast<unsigned char *>(headerBuffer);
806 auto base = pos;
807
808 std::uint32_t frameSize;
809 pos += DeserializeFrame(RNTupleDescriptor::kFrameVersionCurrent, base, &frameSize);
810 VerifyCrc32(base, frameSize);
811 std::uint64_t reserved;
812 pos += DeserializeUInt64(pos, &reserved);
813
814 pos += DeserializeString(pos, &fDescriptor.fName);
815 pos += DeserializeString(pos, &fDescriptor.fDescription);
816 pos += DeserializeString(pos, &fDescriptor.fAuthor);
817 pos += DeserializeString(pos, &fDescriptor.fCustodian);
818 pos += DeserializeTimeStamp(pos, &fDescriptor.fTimeStampData);
819 pos += DeserializeTimeStamp(pos, &fDescriptor.fTimeStampWritten);
820 pos += DeserializeVersion(pos, &fDescriptor.fVersion);
821 pos += DeserializeUuid(pos, &fDescriptor.fOwnUuid);
822 pos += DeserializeUuid(pos, &fDescriptor.fGroupUuid);
823
824 std::uint32_t nFields;
825 pos += DeserializeUInt32(pos, &nFields);
826 for (std::uint32_t i = 0; i < nFields; ++i) {
827 auto fieldBase = pos;
828 pos += DeserializeFrame(RFieldDescriptor::kFrameVersionCurrent, fieldBase, &frameSize);
829
831 pos += DeserializeUInt64(pos, &f.fFieldId);
832 pos += DeserializeVersion(pos, &f.fFieldVersion);
833 pos += DeserializeVersion(pos, &f.fTypeVersion);
834 pos += DeserializeString(pos, &f.fFieldName);
835 pos += DeserializeString(pos, &f.fFieldDescription);
836 pos += DeserializeString(pos, &f.fTypeName);
837 pos += DeserializeUInt64(pos, &f.fNRepetitions);
838 std::int32_t structure;
839 pos += DeserializeInt32(pos, &structure);
840 f.fStructure = static_cast<ENTupleStructure>(structure);
841 pos += DeserializeUInt64(pos, &f.fParentId);
842
843 std::uint32_t nLinks;
844 pos += DeserializeUInt32(pos, &nLinks);
845 f.fLinkIds.resize(nLinks);
846 for (std::uint32_t j = 0; j < nLinks; ++j) {
847 pos += DeserializeUInt64(pos, &f.fLinkIds[j]);
848 }
849
850 pos = fieldBase + frameSize;
851 fDescriptor.fFieldDescriptors.emplace(f.fFieldId, std::move(f));
852 }
853
854 std::uint32_t nColumns;
855 pos += DeserializeUInt32(pos, &nColumns);
856 for (std::uint32_t i = 0; i < nColumns; ++i) {
857 auto columnBase = pos;
858 pos += DeserializeFrame(RColumnDescriptor::kFrameVersionCurrent, columnBase, &frameSize);
859
861 pos += DeserializeUInt64(pos, &c.fColumnId);
862 pos += DeserializeVersion(pos, &c.fVersion);
863 pos += DeserializeColumnModel(pos, &c.fModel);
864 pos += DeserializeUInt64(pos, &c.fFieldId);
865 pos += DeserializeUInt32(pos, &c.fIndex);
866
867 pos = columnBase + frameSize;
868 fDescriptor.fColumnDescriptors.emplace(c.fColumnId, std::move(c));
869 }
870}
871
873 auto pos = reinterpret_cast<unsigned char *>(footerBuffer);
874 auto base = pos;
875
876 std::uint32_t frameSize;
877 pos += DeserializeFrame(RNTupleDescriptor::kFrameVersionCurrent, pos, &frameSize);
878 VerifyCrc32(base, frameSize);
879 std::uint64_t reserved;
880 pos += DeserializeUInt64(pos, &reserved);
881
882 std::uint64_t nClusters;
883 pos += DeserializeUInt64(pos, &nClusters);
884 for (std::uint64_t i = 0; i < nClusters; ++i) {
885 RNTupleUuid uuid;
886 pos += DeserializeUuid(pos, &uuid);
887 R__ASSERT(uuid == fDescriptor.fOwnUuid);
888 auto clusterBase = pos;
889 pos += DeserializeFrame(RClusterDescriptor::kFrameVersionCurrent, clusterBase, &frameSize);
890
891 std::uint64_t clusterId;
892 RNTupleVersion version;
893 std::uint64_t firstEntry;
894 std::uint64_t nEntries;
895 pos += DeserializeUInt64(pos, &clusterId);
896 pos += DeserializeVersion(pos, &version);
897 pos += DeserializeUInt64(pos, &firstEntry);
898 pos += DeserializeUInt64(pos, &nEntries);
899 AddCluster(clusterId, version, firstEntry, ROOT::Experimental::ClusterSize_t(nEntries));
901 pos += DeserializeLocator(pos, &locator);
902 SetClusterLocator(clusterId, locator);
903
904 pos = clusterBase + frameSize;
905
906 std::uint32_t nColumns;
907 pos += DeserializeUInt32(pos, &nColumns);
908 for (std::uint32_t j = 0; j < nColumns; ++j) {
909 uint64_t columnId;
910 pos += DeserializeUInt64(pos, &columnId);
911
913 columnRange.fColumnId = columnId;
914 pos += DeserializeColumnRange(pos, &columnRange);
915 AddClusterColumnRange(clusterId, columnRange);
916
918 pageRange.fColumnId = columnId;
919 uint32_t nPages;
920 pos += DeserializeUInt32(pos, &nPages);
921 for (unsigned int k = 0; k < nPages; ++k) {
923 pos += DeserializePageInfo(pos, &pageInfo);
924 pageRange.fPageInfos.emplace_back(pageInfo);
925 }
926 AddClusterPageRange(clusterId, std::move(pageRange));
927 }
928 }
929}
930
932 const std::string_view name, const std::string_view description, const std::string_view author,
933 const RNTupleVersion &version, const RNTupleUuid &uuid)
934{
935 fDescriptor.fName = std::string(name);
936 fDescriptor.fDescription = std::string(description);
937 fDescriptor.fAuthor = std::string(author);
938 fDescriptor.fVersion = version;
939 fDescriptor.fOwnUuid = uuid;
940 fDescriptor.fGroupUuid = uuid;
941}
942
944 const RFieldDescriptor& fieldDesc) : fField(fieldDesc.Clone())
945{
947 fField.fLinkIds = {};
948}
949
952 RDanglingFieldDescriptor fieldDesc;
953 fieldDesc.FieldVersion(field.GetFieldVersion())
955 .FieldName(field.GetName())
956 .TypeName(field.GetType())
957 .Structure(field.GetStructure())
959 return fieldDesc;
960}
961
964 if (fField.GetId() == kInvalidDescriptorId) {
965 return R__FAIL("invalid field id");
966 }
967 if (fField.GetStructure() == ENTupleStructure::kInvalid) {
968 return R__FAIL("invalid field structure");
969 }
970 // FieldZero is usually named "" and would be a false positive here
971 if (fField.GetId() != DescriptorId_t(0)) {
972 auto validName = Detail::RFieldBase::EnsureValidFieldName(fField.GetFieldName());
973 if (!validName) {
974 return R__FORWARD_ERROR(validName);
975 }
976 }
977 return fField.Clone();
978}
979
981 fDescriptor.fFieldDescriptors.emplace(fieldDesc.GetId(), fieldDesc.Clone());
982}
983
986{
987 if (linkId == DescriptorId_t(0)) {
988 return R__FAIL("cannot make FieldZero a child field");
989 }
990 if (fDescriptor.fFieldDescriptors.count(fieldId) == 0) {
991 return R__FAIL("field with id '" + std::to_string(fieldId) + "' doesn't exist in NTuple");
992 }
993 if (fDescriptor.fFieldDescriptors.count(linkId) == 0) {
994 return R__FAIL("child field with id '" + std::to_string(linkId) + "' doesn't exist in NTuple");
995 }
996 // fail if field already has a valid parent
997 auto parentId = fDescriptor.fFieldDescriptors.at(linkId).GetParentId();
998 if (parentId != kInvalidDescriptorId) {
999 return R__FAIL("field '" + std::to_string(linkId) + "' already has a parent ('" +
1000 std::to_string(parentId) + ")");
1001 }
1002 if (fieldId == linkId) {
1003 return R__FAIL("cannot make field '" + std::to_string(fieldId) + "' a child of itself");
1004 }
1005 fDescriptor.fFieldDescriptors.at(linkId).fParentId = fieldId;
1006 fDescriptor.fFieldDescriptors.at(fieldId).fLinkIds.push_back(linkId);
1007 return RResult<void>::Success();
1008}
1009
1011 DescriptorId_t columnId, DescriptorId_t fieldId, const RNTupleVersion &version, const RColumnModel &model,
1012 std::uint32_t index)
1013{
1015 c.fColumnId = columnId;
1016 c.fFieldId = fieldId;
1017 c.fVersion = version;
1018 c.fModel = model;
1019 c.fIndex = index;
1020 fDescriptor.fColumnDescriptors.emplace(columnId, std::move(c));
1021}
1022
1024 DescriptorId_t clusterId, RNTupleVersion version, NTupleSize_t firstEntryIndex, ClusterSize_t nEntries)
1025{
1027 c.fClusterId = clusterId;
1028 c.fVersion = version;
1029 c.fFirstEntryIndex = firstEntryIndex;
1030 c.fNEntries = nEntries;
1031 fDescriptor.fClusterDescriptors.emplace(clusterId, std::move(c));
1032}
1033
1036{
1037 fDescriptor.fClusterDescriptors[clusterId].fLocator = locator;
1038}
1039
1041 DescriptorId_t clusterId, const RClusterDescriptor::RColumnRange &columnRange)
1042{
1043 fDescriptor.fClusterDescriptors[clusterId].fColumnRanges[columnRange.fColumnId] = columnRange;
1044}
1045
1047 DescriptorId_t clusterId, RClusterDescriptor::RPageRange &&pageRange)
1048{
1049 fDescriptor.fClusterDescriptors[clusterId].fPageRanges.emplace(pageRange.fColumnId, std::move(pageRange));
1050}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:296
#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:292
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define R__ASSERT(e)
Definition TError.h:120
char name[80]
Definition TGX11.cxx:110
int type
Definition TGX11.cxx:121
typedef void((*Func_t)())
std::size_t GetNRepetitions() const
Definition RField.hxx:221
virtual RNTupleVersion GetTypeVersion() const
Indicates an evolution of the C++ type itself.
Definition RField.hxx:230
static RResult< void > EnsureValidFieldName(std::string_view fieldName)
Check whether a given string is a valid field name.
Definition RField.cxx:229
static RResult< std::unique_ptr< RFieldBase > > Create(const std::string &fieldName, const std::string &typeName)
Factory method to resurrect a field from the stored on-disk type information.
Definition RField.cxx:156
virtual RNTupleVersion GetFieldVersion() const
Indicates an evolution of the mapping scheme from C++ type to columns.
Definition RField.hxx:228
ENTupleStructure GetStructure() const
Definition RField.hxx:220
The available trivial, native content types of a column.
Meta-data for a set of ntuple clusters.
std::unordered_map< DescriptorId_t, RPageRange > fPageRanges
RNTupleVersion fVersion
Future versions of the cluster descriptor might add more meta-data, e.g. a semantic checksum.
RLocator fLocator
For pre-fetching / caching an entire contiguous cluster.
static constexpr std::uint16_t kFrameVersionMin
NTupleSize_t fFirstEntryIndex
Clusters can be swapped by adjusting the entry offsets.
std::unordered_map< DescriptorId_t, RColumnRange > fColumnRanges
bool operator==(const RClusterDescriptor &other) const
static constexpr std::uint16_t kFrameVersionCurrent
In order to handle changes to the serialization routine in future ntuple versions.
Meta-data stored for every column of an ntuple.
static constexpr std::uint16_t kFrameVersionCurrent
In order to handle changes to the serialization routine in future ntuple versions.
DescriptorId_t fFieldId
Every column belongs to one and only one field.
RColumnModel fModel
Contains the column type and whether it is sorted.
static constexpr std::uint16_t kFrameVersionMin
RNTupleVersion fVersion
Versions can change, e.g., when new column types are added.
std::uint32_t fIndex
A field can be serialized into several columns, which are numbered from zero to $n$.
bool operator==(const RColumnDescriptor &other) const
Holds the static meta-data of a column in a tree.
A helper class for piece-wise construction of an RFieldDescriptor.
RDanglingFieldDescriptor & TypeVersion(const RNTupleVersion &typeVersion)
RDanglingFieldDescriptor & FieldVersion(const RNTupleVersion &fieldVersion)
RDanglingFieldDescriptor & Structure(const ENTupleStructure &structure)
RResult< RFieldDescriptor > MakeDescriptor() const
Attempt to make a field descriptor.
static RDanglingFieldDescriptor FromField(const Detail::RFieldBase &field)
Make a new RDanglingFieldDescriptor based off a live NTuple field.
RDanglingFieldDescriptor & NRepetitions(std::uint64_t nRepetitions)
RDanglingFieldDescriptor & FieldName(const std::string &fieldName)
RDanglingFieldDescriptor & TypeName(const std::string &typeName)
RDanglingFieldDescriptor()=default
Make an empty dangling field descriptor.
Meta-data stored for every field of an ntuple.
std::vector< DescriptorId_t > fLinkIds
The pointers in the other direction from parent to children.
RNTupleVersion fFieldVersion
The version of the C++-type-to-column translation mechanics.
std::string fFieldDescription
Free text set by the user.
static constexpr std::uint16_t kFrameVersionMin
std::string fFieldName
The leaf name, not including parent fields.
const std::vector< DescriptorId_t > & GetLinkIds() const
DescriptorId_t fParentId
Establishes sub field relationships, such as classes and collections.
RNTupleVersion fTypeVersion
The version of the C++ type itself.
RFieldDescriptor Clone() const
Get a copy of the descriptor.
bool operator==(const RFieldDescriptor &other) const
ENTupleStructure fStructure
The structural information carried by this field in the data model tree.
std::string fTypeName
The C++ type that was used when writing the field.
std::uint64_t fNRepetitions
The number of elements per entry for fixed-size arrays.
static constexpr std::uint16_t kFrameVersionCurrent
In order to handle changes to the serialization routine in future ntuple versions.
RResult< void > EnsureValidDescriptor() const
Checks whether invariants hold:
void AddCluster(DescriptorId_t clusterId, RNTupleVersion version, NTupleSize_t firstEntryIndex, ClusterSize_t nEntries)
RResult< void > AddFieldLink(DescriptorId_t fieldId, DescriptorId_t linkId)
void AddColumn(DescriptorId_t columnId, DescriptorId_t fieldId, const RNTupleVersion &version, const RColumnModel &model, std::uint32_t index)
void SetClusterLocator(DescriptorId_t clusterId, RClusterDescriptor::RLocator locator)
void AddClusterColumnRange(DescriptorId_t clusterId, const RClusterDescriptor::RColumnRange &columnRange)
void SetNTuple(const std::string_view name, const std::string_view description, const std::string_view author, const RNTupleVersion &version, const RNTupleUuid &uuid)
void AddClusterPageRange(DescriptorId_t clusterId, RClusterDescriptor::RPageRange &&pageRange)
void AddField(const RFieldDescriptor &fieldDesc)
The on-storage meta-data of an ntuple.
std::unordered_map< DescriptorId_t, RClusterDescriptor > fClusterDescriptors
May contain only a subset of all the available clusters, e.g.
RNTupleUuid fGroupUuid
Column sets that are created as derived sets from existing NTuples share the same group id.
std::unique_ptr< RNTupleModel > GenerateModel() const
Re-create the C++ model from the stored meta-data.
std::chrono::system_clock::time_point fTimeStampWritten
The time stamp of writing the data to storage, which gets updated when re-written.
DescriptorId_t FindNextClusterId(DescriptorId_t clusterId) const
std::uint32_t SerializeHeader(void *buffer) const
We deliberately do not use ROOT's built-in serialization in order to allow for use of RNTuple's witho...
DescriptorId_t FindPrevClusterId(DescriptorId_t clusterId) const
DescriptorId_t GetFieldZeroId() const
Returns the logical parent of all top-level NTuple data fields.
std::unordered_map< DescriptorId_t, RColumnDescriptor > fColumnDescriptors
std::string fName
The ntuple name needs to be unique in a given storage location (file)
std::uint32_t SerializeFooter(void *buffer) const
Serializes cluster meta data. Returns the number of bytes and fills buffer if it is not nullptr.
std::string fAuthor
The origin of the data.
std::unordered_map< DescriptorId_t, RFieldDescriptor > fFieldDescriptors
static constexpr std::uint16_t kFrameVersionMin
RNTupleVersion fVersion
The version evolves with the ntuple summary meta-data.
bool operator==(const RNTupleDescriptor &other) const
std::string GetQualifiedFieldName(DescriptorId_t fieldId) const
Walks up the parents of the field ID and returns a field name of the form a.b.c.d In case of invalid ...
DescriptorId_t FindFieldId(std::string_view fieldName, DescriptorId_t parentId) const
std::string fCustodian
The current responsible for storing the data.
DescriptorId_t FindColumnId(DescriptorId_t fieldId, std::uint32_t columnIndex) const
NTupleSize_t GetNElements(DescriptorId_t columnId) const
static void LocateMetadata(const void *postscript, std::uint32_t &szHeader, std::uint32_t &szFooter)
Given kNBytesPostscript bytes, extract the header and footer lengths in bytes.
std::string fDescription
Free text from the user.
static constexpr std::uint16_t kFrameVersionCurrent
In order to handle changes to the serialization routine in future ntuple versions.
RNTupleUuid fOwnUuid
Every NTuple gets a unique identifier.
std::chrono::system_clock::time_point fTimeStampData
The time stamp of the ntuple data (immutable)
DescriptorId_t FindClusterId(DescriptorId_t columnId, NTupleSize_t index) const
For forward and backward compatibility, attach version information to the consitituents of the file f...
std::uint32_t GetVersionUse() const
std::uint32_t GetVersionMin() const
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:196
struct void * fTypeName
Definition cppyy.h:9
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
std::string RNTupleUuid
Every NTuple is identified by a UUID. TODO(jblomer): should this be a TUUID?
constexpr DescriptorId_t kInvalidDescriptorId
The window of element indexes of a particular column in a particular cluster.
std::int64_t fCompressionSettings
The usual format for ROOT compression settings (see Compression.h).
ClusterSize_t fNElements
A 32bit value for the number of column elements in the cluster.
Generic information about the physical location of data.
We do not need to store the element size / uncompressed page size because we know to which column the...
RLocator fLocator
The meaning of fLocator depends on the storage backend.
ClusterSize_t fNElements
The sum of the elements of all the pages must match the corresponding fNElements field in fColumnRang...
Records the parition of data into pages for a particular column in a particular cluster.
Wrap the 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...
auto * l
Definition textangle.C:4