Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RMiniFile.cxx
Go to the documentation of this file.
1/// \file RMiniFile.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2019-12-22
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 "Rtypes.h"
17#include <ROOT/RConfig.hxx>
18#include <ROOT/RError.hxx>
19
20#include "ROOT/RMiniFile.hxx"
21
22#include <ROOT/RRawFile.hxx>
23#include <ROOT/RNTupleZip.hxx>
24
25#include <Byteswap.h>
26#include <TError.h>
27#include <TFile.h>
28#include <TKey.h>
29
30#include <xxhash.h>
31
32#include <algorithm>
33#include <cerrno>
34#include <cstdio>
35#include <cstring>
36#include <memory>
37#include <string>
38#include <chrono>
39
40#ifndef R__LITTLE_ENDIAN
41#ifdef R__BYTESWAP
42// `R__BYTESWAP` is defined in RConfig.hxx for little-endian architectures; undefined otherwise
43#define R__LITTLE_ENDIAN 1
44#else
45#define R__LITTLE_ENDIAN 0
46#endif
47#endif /* R__LITTLE_ENDIAN */
48
49namespace {
50
51// The following types are used to read and write the TFile binary format
52
53/// Big-endian 16-bit unsigned integer
54class RUInt16BE {
55private:
56 std::uint16_t fValBE = 0;
57 static std::uint16_t Swap(std::uint16_t val)
58 {
59#if R__LITTLE_ENDIAN == 1
60 return RByteSwap<sizeof(val)>::bswap(val);
61#else
62 return val;
63#endif
64 }
65
66public:
67 RUInt16BE() = default;
68 explicit RUInt16BE(const std::uint16_t val) : fValBE(Swap(val)) {}
69 operator std::uint16_t() const { return Swap(fValBE); }
70 RUInt16BE &operator=(const std::uint16_t val)
71 {
72 fValBE = Swap(val);
73 return *this;
74 }
75};
76
77/// Big-endian 32-bit unsigned integer
78class RUInt32BE {
79private:
80 std::uint32_t fValBE = 0;
81 static std::uint32_t Swap(std::uint32_t val)
82 {
83#if R__LITTLE_ENDIAN == 1
84 return RByteSwap<sizeof(val)>::bswap(val);
85#else
86 return val;
87#endif
88 }
89
90public:
91 RUInt32BE() = default;
92 explicit RUInt32BE(const std::uint32_t val) : fValBE(Swap(val)) {}
93 operator std::uint32_t() const { return Swap(fValBE); }
94 RUInt32BE &operator=(const std::uint32_t val)
95 {
96 fValBE = Swap(val);
97 return *this;
98 }
99};
100
101/// Big-endian 32-bit signed integer
102class RInt32BE {
103private:
104 std::int32_t fValBE = 0;
105 static std::int32_t Swap(std::int32_t val)
106 {
107#if R__LITTLE_ENDIAN == 1
108 return RByteSwap<sizeof(val)>::bswap(val);
109#else
110 return val;
111#endif
112 }
113
114public:
115 RInt32BE() = default;
116 explicit RInt32BE(const std::int32_t val) : fValBE(Swap(val)) {}
117 operator std::int32_t() const { return Swap(fValBE); }
118 RInt32BE &operator=(const std::int32_t val)
119 {
120 fValBE = Swap(val);
121 return *this;
122 }
123};
124
125/// Big-endian 64-bit unsigned integer
126class RUInt64BE {
127private:
128 std::uint64_t fValBE = 0;
129 static std::uint64_t Swap(std::uint64_t val)
130 {
131#if R__LITTLE_ENDIAN == 1
132 return RByteSwap<sizeof(val)>::bswap(val);
133#else
134 return val;
135#endif
136 }
137
138public:
139 RUInt64BE() = default;
140 explicit RUInt64BE(const std::uint64_t val) : fValBE(Swap(val)) {}
141 operator std::uint64_t() const { return Swap(fValBE); }
142 RUInt64BE &operator=(const std::uint64_t val)
143 {
144 fValBE = Swap(val);
145 return *this;
146 }
147};
148
149constexpr std::int32_t ChecksumRNTupleClass()
150{
151 const char ident[] = "ROOT::Experimental::RNTuple"
152 "fVersionEpoch"
153 "unsigned short"
154 "fVersionMajor"
155 "unsigned short"
156 "fVersionMinor"
157 "unsigned short"
158 "fVersionPatch"
159 "unsigned short"
160 "fSeekHeader"
161 "unsigned long"
162 "fNBytesHeader"
163 "unsigned long"
164 "fLenHeader"
165 "unsigned long"
166 "fSeekFooter"
167 "unsigned long"
168 "fNBytesFooter"
169 "unsigned long"
170 "fLenFooter"
171 "unsigned long";
172 std::int32_t id = 0;
173 for (unsigned i = 0; i < (sizeof(ident) - 1); i++)
174 id = static_cast<std::int32_t>(static_cast<std::int64_t>(id) * 3 + ident[i]);
175 return id;
176}
177
178#pragma pack(push, 1)
179/// A name (type, identifies, ...) in the TFile binary format
180struct RTFString {
181 unsigned char fLName{0};
182 char fData[255];
183 RTFString() = default;
184 RTFString(const std::string &str)
185 {
186 // The length of strings with 255 characters and longer are encoded with a 32-bit integer following the first
187 // byte. This is currently not handled.
188 R__ASSERT(str.length() < 255);
189 fLName = str.length();
190 memcpy(fData, str.data(), fLName);
191 }
192 std::size_t GetSize() const
193 {
194 // A length of 255 is special and means that the first byte is followed by a 32-bit integer with the actual
195 // length.
196 R__ASSERT(fLName != 255);
197 return 1 + fLName;
198 }
199};
200
201/// The timestamp format used in TFile; the default constructor initializes with the current time
202struct RTFDatetime {
203 RUInt32BE fDatetime;
204 RTFDatetime()
205 {
206 auto now = std::chrono::system_clock::now();
207 auto tt = std::chrono::system_clock::to_time_t(now);
208 auto tm = *localtime(&tt);
209 fDatetime = (tm.tm_year + 1900 - 1995) << 26 | (tm.tm_mon + 1) << 22 | tm.tm_mday << 17 | tm.tm_hour << 12 |
210 tm.tm_min << 6 | tm.tm_sec;
211 }
212 explicit RTFDatetime(RUInt32BE val) : fDatetime(val) {}
213};
214
215/// The key part of a TFile record excluding the class, object, and title names
216struct RTFKey {
217 RInt32BE fNbytes{0};
218 RUInt16BE fVersion{4};
219 RUInt32BE fObjLen{0};
220 RTFDatetime fDatetime;
221 RUInt16BE fKeyLen{0};
222 RUInt16BE fCycle{1};
223 union {
224 struct {
225 RUInt32BE fSeekKey{0};
226 RUInt32BE fSeekPdir{0};
227 } fInfoShort;
228 struct {
229 RUInt64BE fSeekKey{0};
230 RUInt64BE fSeekPdir{0};
231 } fInfoLong;
232 };
233
234 std::uint32_t fKeyHeaderSize{18 + sizeof(fInfoShort)}; // not part of serialization
235
236 RTFKey() : fInfoShort() {}
237 RTFKey(std::uint64_t seekKey, std::uint64_t seekPdir, const RTFString &clName, const RTFString &objName,
238 const RTFString &titleName, std::size_t szObjInMem, std::size_t szObjOnDisk = 0)
239 {
240 R__ASSERT(szObjInMem < std::numeric_limits<std::int32_t>::max());
241 R__ASSERT(szObjOnDisk < std::numeric_limits<std::int32_t>::max());
242 fObjLen = szObjInMem;
243 if ((seekKey > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) ||
244 (seekPdir > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max()))) {
245 fKeyHeaderSize = 18 + sizeof(fInfoLong);
246 fKeyLen = fKeyHeaderSize + clName.GetSize() + objName.GetSize() + titleName.GetSize();
247 fInfoLong.fSeekKey = seekKey;
248 fInfoLong.fSeekPdir = seekPdir;
249 fVersion = fVersion + 1000;
250 } else {
251 fKeyHeaderSize = 18 + sizeof(fInfoShort);
252 fKeyLen = fKeyHeaderSize + clName.GetSize() + objName.GetSize() + titleName.GetSize();
253 fInfoShort.fSeekKey = seekKey;
254 fInfoShort.fSeekPdir = seekPdir;
255 }
256 fNbytes = fKeyLen + ((szObjOnDisk == 0) ? szObjInMem : szObjOnDisk);
257 }
258
259 void MakeBigKey()
260 {
261 if (fVersion >= 1000)
262 return;
263 std::uint32_t seekKey = fInfoShort.fSeekKey;
264 std::uint32_t seekPdir = fInfoShort.fSeekPdir;
265 fInfoLong.fSeekKey = seekKey;
266 fInfoLong.fSeekPdir = seekPdir;
267 fKeyHeaderSize = fKeyHeaderSize + sizeof(fInfoLong) - sizeof(fInfoShort);
268 fKeyLen = fKeyLen + sizeof(fInfoLong) - sizeof(fInfoShort);
269 fNbytes = fNbytes + sizeof(fInfoLong) - sizeof(fInfoShort);
270 fVersion = fVersion + 1000;
271 }
272
273 std::uint32_t GetSize() const
274 {
275 // Negative size indicates a gap in the file
276 if (fNbytes < 0)
277 return -fNbytes;
278 return fNbytes;
279 }
280
281 std::uint32_t GetHeaderSize() const
282 {
283 if (fVersion >= 1000)
284 return 18 + sizeof(fInfoLong);
285 return 18 + sizeof(fInfoShort);
286 }
287
288 std::uint64_t GetSeekKey() const
289 {
290 if (fVersion >= 1000)
291 return fInfoLong.fSeekKey;
292 return fInfoShort.fSeekKey;
293 }
294};
295
296/// The TFile global header
297struct RTFHeader {
298 char fMagic[4]{'r', 'o', 'o', 't'};
299 RUInt32BE fVersion{(ROOT_VERSION_CODE >> 16) * 10000 + ((ROOT_VERSION_CODE & 0xFF00) >> 8) * 100 +
300 (ROOT_VERSION_CODE & 0xFF)};
301 RUInt32BE fBEGIN{100};
302 union {
303 struct {
304 RUInt32BE fEND{0};
305 RUInt32BE fSeekFree{0};
306 RUInt32BE fNbytesFree{0};
307 RUInt32BE fNfree{1};
308 RUInt32BE fNbytesName{0};
309 unsigned char fUnits{4};
310 RUInt32BE fCompress{0};
311 RUInt32BE fSeekInfo{0};
312 RUInt32BE fNbytesInfo{0};
313 } fInfoShort;
314 struct {
315 RUInt64BE fEND{0};
316 RUInt64BE fSeekFree{0};
317 RUInt32BE fNbytesFree{0};
318 RUInt32BE fNfree{1};
319 RUInt32BE fNbytesName{0};
320 unsigned char fUnits{8};
321 RUInt32BE fCompress{0};
322 RUInt64BE fSeekInfo{0};
323 RUInt32BE fNbytesInfo{0};
324 } fInfoLong;
325 };
326
327 RTFHeader() : fInfoShort() {}
328 RTFHeader(int compression) : fInfoShort() { fInfoShort.fCompress = compression; }
329
330 void SetBigFile()
331 {
332 if (fVersion >= 1000000)
333 return;
334
335 // clang-format off
336 std::uint32_t end = fInfoShort.fEND;
337 std::uint32_t seekFree = fInfoShort.fSeekFree;
338 std::uint32_t nbytesFree = fInfoShort.fNbytesFree;
339 std::uint32_t nFree = fInfoShort.fNfree;
340 std::uint32_t nbytesName = fInfoShort.fNbytesName;
341 std::uint32_t compress = fInfoShort.fCompress;
342 std::uint32_t seekInfo = fInfoShort.fSeekInfo;
343 std::uint32_t nbytesInfo = fInfoShort.fNbytesInfo;
344 fInfoLong.fEND = end;
345 fInfoLong.fSeekFree = seekFree;
346 fInfoLong.fNbytesFree = nbytesFree;
347 fInfoLong.fNfree = nFree;
348 fInfoLong.fNbytesName = nbytesName;
349 fInfoLong.fUnits = 8;
350 fInfoLong.fCompress = compress;
351 fInfoLong.fSeekInfo = seekInfo;
352 fInfoLong.fNbytesInfo = nbytesInfo;
353 fVersion = fVersion + 1000000;
354 // clang-format on
355 }
356
357 bool IsBigFile(std::uint64_t offset = 0) const
358 {
359 return (fVersion >= 1000000) || (offset > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max()));
360 }
361
362 std::uint32_t GetSize() const
363 {
364 std::uint32_t sizeHead = 4 + sizeof(fVersion) + sizeof(fBEGIN);
365 if (IsBigFile())
366 return sizeHead + sizeof(fInfoLong);
367 return sizeHead + sizeof(fInfoShort);
368 }
369
370 std::uint64_t GetEnd() const
371 {
372 if (IsBigFile())
373 return fInfoLong.fEND;
374 return fInfoShort.fEND;
375 }
376
377 void SetEnd(std::uint64_t value)
378 {
379 if (IsBigFile(value)) {
380 SetBigFile();
381 fInfoLong.fEND = value;
382 } else {
383 fInfoShort.fEND = value;
384 }
385 }
386
387 std::uint64_t GetSeekFree() const
388 {
389 if (IsBigFile())
390 return fInfoLong.fSeekFree;
391 return fInfoShort.fSeekFree;
392 }
393
394 void SetSeekFree(std::uint64_t value)
395 {
396 if (IsBigFile(value)) {
397 SetBigFile();
398 fInfoLong.fSeekFree = value;
399 } else {
400 fInfoShort.fSeekFree = value;
401 }
402 }
403
404 void SetNbytesFree(std::uint32_t value)
405 {
406 if (IsBigFile()) {
407 fInfoLong.fNbytesFree = value;
408 } else {
409 fInfoShort.fNbytesFree = value;
410 }
411 }
412
413 void SetNbytesName(std::uint32_t value)
414 {
415 if (IsBigFile()) {
416 fInfoLong.fNbytesName = value;
417 } else {
418 fInfoShort.fNbytesName = value;
419 }
420 }
421
422 std::uint64_t GetSeekInfo() const
423 {
424 if (IsBigFile())
425 return fInfoLong.fSeekInfo;
426 return fInfoShort.fSeekInfo;
427 }
428
429 void SetSeekInfo(std::uint64_t value)
430 {
431 if (IsBigFile(value)) {
432 SetBigFile();
433 fInfoLong.fSeekInfo = value;
434 } else {
435 fInfoShort.fSeekInfo = value;
436 }
437 }
438
439 void SetNbytesInfo(std::uint32_t value)
440 {
441 if (IsBigFile()) {
442 fInfoLong.fNbytesInfo = value;
443 } else {
444 fInfoShort.fNbytesInfo = value;
445 }
446 }
447
448 void SetCompression(std::uint32_t value)
449 {
450 if (IsBigFile()) {
451 fInfoLong.fCompress = value;
452 } else {
453 fInfoShort.fCompress = value;
454 }
455 }
456};
457
458/// A reference to an unused byte-range in a TFile
459struct RTFFreeEntry {
460 RUInt16BE fVersion{1};
461 union {
462 struct {
463 RUInt32BE fFirst{0};
464 RUInt32BE fLast{0};
465 } fInfoShort;
466 struct {
467 RUInt64BE fFirst{0};
468 RUInt64BE fLast{0};
469 } fInfoLong;
470 };
471
472 RTFFreeEntry() : fInfoShort() {}
473 void Set(std::uint64_t first, std::uint64_t last)
474 {
475 if (last > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) {
476 fVersion = fVersion + 1000;
477 fInfoLong.fFirst = first;
478 fInfoLong.fLast = last;
479 } else {
480 fInfoShort.fFirst = first;
481 fInfoShort.fLast = last;
482 }
483 }
484 std::uint32_t GetSize() { return (fVersion >= 1000) ? 18 : 10; }
485};
486
487/// Streamer info for TObject
488struct RTFObject {
489 RUInt16BE fVersion{1};
490 RUInt32BE fUniqueID{0}; // unused
491 RUInt32BE fBits;
492 explicit RTFObject(std::uint32_t bits) : fBits(bits) {}
493};
494
495/// Streamer info for data member RNTuple::fVersionEpoch
496struct RTFStreamerElementVersionEpoch {
497 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementVersionEpoch) - sizeof(RUInt32BE))};
498 RUInt16BE fVersion{4};
499
500 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
501 RUInt16BE fVersionNamed{1};
502 RTFObject fObjectNamed{0x02000000 | 0x01000000};
503 char fLName = 13;
504 char fName[13]{'f', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'E', 'p', 'o', 'c', 'h'};
505 char fLTitle = 0;
506
507 RUInt32BE fType{12};
508 RUInt32BE fSize{2};
509 RUInt32BE fArrLength{0};
510 RUInt32BE fArrDim{0};
511 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
512 char fLTypeName = 14;
513 char fTypeName[14]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 's', 'h', 'o', 'r', 't'};
514};
515
516/// Streamer info for data member RNTuple::fVersionMajor
517struct RTFStreamerElementVersionMajor {
518 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementVersionMajor) - sizeof(RUInt32BE))};
519 RUInt16BE fVersion{4};
520
521 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
522 RUInt16BE fVersionNamed{1};
523 RTFObject fObjectNamed{0x02000000 | 0x01000000};
524 char fLName = 13;
525 char fName[13]{'f', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'M', 'a', 'j', 'o', 'r'};
526 char fLTitle = 0;
527
528 RUInt32BE fType{12};
529 RUInt32BE fSize{2};
530 RUInt32BE fArrLength{0};
531 RUInt32BE fArrDim{0};
532 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
533 char fLTypeName = 14;
534 char fTypeName[14]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 's', 'h', 'o', 'r', 't'};
535};
536
537/// Streamer info for data member RNTuple::fVersionMajor
538struct RTFStreamerElementVersionMinor {
539 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementVersionMinor) - sizeof(RUInt32BE))};
540 RUInt16BE fVersion{4};
541
542 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
543 RUInt16BE fVersionNamed{1};
544 RTFObject fObjectNamed{0x02000000 | 0x01000000};
545 char fLName = 13;
546 char fName[13]{'f', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'M', 'i', 'n', 'o', 'r'};
547 char fLTitle = 0;
548
549 RUInt32BE fType{12};
550 RUInt32BE fSize{2};
551 RUInt32BE fArrLength{0};
552 RUInt32BE fArrDim{0};
553 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
554 char fLTypeName = 14;
555 char fTypeName[14]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 's', 'h', 'o', 'r', 't'};
556};
557
558/// Streamer info for data member RNTuple::fVersionPatch
559struct RTFStreamerElementVersionPatch {
560 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementVersionPatch) - sizeof(RUInt32BE))};
561 RUInt16BE fVersion{4};
562
563 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
564 RUInt16BE fVersionNamed{1};
565 RTFObject fObjectNamed{0x02000000 | 0x01000000};
566 char fLName = 13;
567 char fName[13]{'f', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'P', 'a', 't', 'c', 'h'};
568 char fLTitle = 0;
569
570 RUInt32BE fType{12};
571 RUInt32BE fSize{2};
572 RUInt32BE fArrLength{0};
573 RUInt32BE fArrDim{0};
574 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
575 char fLTypeName = 14;
576 char fTypeName[14]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 's', 'h', 'o', 'r', 't'};
577};
578
579/// Streamer info for data member RNTuple::fSeekHeader
580struct RTFStreamerElementSeekHeader {
581 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementSeekHeader) - sizeof(RUInt32BE))};
582 RUInt16BE fVersion{4};
583
584 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 13)};
585 RUInt16BE fVersionNamed{1};
586 RTFObject fObjectNamed{0x02000000 | 0x01000000};
587 char fLName = 11;
588 char fName[11]{'f', 'S', 'e', 'e', 'k', 'H', 'e', 'a', 'd', 'e', 'r'};
589 char fLTitle = 0;
590
591 RUInt32BE fType{14};
592 RUInt32BE fSize{8};
593 RUInt32BE fArrLength{0};
594 RUInt32BE fArrDim{0};
595 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
596 char fLTypeName = 13;
597 char fTypeName[13]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g'};
598};
599
600/// Streamer info for data member RNTuple::fNbytesHeader
601struct RTFStreamerElementNBytesHeader {
602 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementNBytesHeader) - sizeof(RUInt32BE))};
603 RUInt16BE fVersion{4};
604
605 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
606 RUInt16BE fVersionNamed{1};
607 RTFObject fObjectNamed{0x02000000 | 0x01000000};
608 char fLName = 13;
609 char fName[13]{'f', 'N', 'B', 'y', 't', 'e', 's', 'H', 'e', 'a', 'd', 'e', 'r'};
610 char fLTitle = 0;
611
612 RUInt32BE fType{14};
613 RUInt32BE fSize{8};
614 RUInt32BE fArrLength{0};
615 RUInt32BE fArrDim{0};
616 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
617 char fLTypeName = 13;
618 char fTypeName[13]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g'};
619};
620
621/// Streamer info for data member RNTuple::fLenHeader
622struct RTFStreamerElementLenHeader {
623 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementLenHeader) - sizeof(RUInt32BE))};
624 RUInt16BE fVersion{4};
625
626 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 12)};
627 RUInt16BE fVersionNamed{1};
628 RTFObject fObjectNamed{0x02000000 | 0x01000000};
629 char fLName = 10;
630 char fName[10]{'f', 'L', 'e', 'n', 'H', 'e', 'a', 'd', 'e', 'r'};
631 char fLTitle = 0;
632
633 RUInt32BE fType{14};
634 RUInt32BE fSize{8};
635 RUInt32BE fArrLength{0};
636 RUInt32BE fArrDim{0};
637 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
638 char fLTypeName = 13;
639 char fTypeName[13]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g'};
640};
641
642/// Streamer info for data member RNTuple::fSeekFooter
643struct RTFStreamerElementSeekFooter {
644 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementSeekFooter) - sizeof(RUInt32BE))};
645 RUInt16BE fVersion{4};
646
647 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 13)};
648 RUInt16BE fVersionNamed{1};
649 RTFObject fObjectNamed{0x02000000 | 0x01000000};
650 char fLName = 11;
651 char fName[11]{'f', 'S', 'e', 'e', 'k', 'F', 'o', 'o', 't', 'e', 'r'};
652 char fLTitle = 0;
653
654 RUInt32BE fType{14};
655 RUInt32BE fSize{8};
656 RUInt32BE fArrLength{0};
657 RUInt32BE fArrDim{0};
658 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
659 char fLTypeName = 13;
660 char fTypeName[13]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g'};
661};
662
663/// Streamer info for data member RNTuple::fNbytesFooter
664struct RTFStreamerElementNBytesFooter {
665 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementNBytesFooter) - sizeof(RUInt32BE))};
666 RUInt16BE fVersion{4};
667
668 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
669 RUInt16BE fVersionNamed{1};
670 RTFObject fObjectNamed{0x02000000 | 0x01000000};
671 char fLName = 13;
672 char fName[13]{'f', 'N', 'B', 'y', 't', 'e', 's', 'F', 'o', 'o', 't', 'e', 'r'};
673 char fLTitle = 0;
674
675 RUInt32BE fType{14};
676 RUInt32BE fSize{8};
677 RUInt32BE fArrLength{0};
678 RUInt32BE fArrDim{0};
679 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
680 char fLTypeName = 13;
681 char fTypeName[13]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g'};
682};
683
684/// Streamer info for data member RNTuple::fLenFooter
685struct RTFStreamerElementLenFooter {
686 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementLenFooter) - sizeof(RUInt32BE))};
687 RUInt16BE fVersion{4};
688
689 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 12)};
690 RUInt16BE fVersionNamed{1};
691 RTFObject fObjectNamed{0x02000000 | 0x01000000};
692 char fLName = 10;
693 char fName[10]{'f', 'L', 'e', 'n', 'F', 'o', 'o', 't', 'e', 'r'};
694 char fLTitle = 0;
695
696 RUInt32BE fType{14};
697 RUInt32BE fSize{8};
698 RUInt32BE fArrLength{0};
699 RUInt32BE fArrDim{0};
700 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
701 char fLTypeName = 13;
702 char fTypeName[13]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g'};
703};
704
705struct RTFStreamerElementMaxKeySize {
706 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementMaxKeySize) - sizeof(RUInt32BE))};
707 RUInt16BE fVersion{4};
708
709 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 13)};
710 RUInt16BE fVersionNamed{1};
711 RTFObject fObjectNamed{0x02000000 | 0x01000000};
712 char fLName = 11;
713 char fName[11]{'f', 'M', 'a', 'x', 'K', 'e', 'y', 'S', 'i', 'z', 'e'};
714 char fLTitle = 0;
715
716 RUInt32BE fType{14};
717 RUInt32BE fSize{8};
718 RUInt32BE fArrLength{0};
719 RUInt32BE fArrDim{0};
720 char fMaxIndex[20]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
721 char fLTypeName = 13;
722 char fTypeName[13]{'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g'};
723};
724
725/// Streamer info frame for data member RNTuple::fVersionEpoch
726struct RTFStreamerVersionEpoch {
727 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerVersionEpoch) - sizeof(RUInt32BE))};
728 RUInt32BE fNewClassTag{0xffffffff};
729 char fClassName[19]{'T', 'S', 't', 'r', 'e', 'a', 'm', 'e', 'r', 'B', 'a', 's', 'i', 'c', 'T', 'y', 'p', 'e', '\0'};
730 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerVersionEpoch) - 2 * sizeof(RUInt32BE) -
731 19 /* strlen(fClassName) + 1 */ - sizeof(RUInt32BE))};
732 RUInt16BE fVersion{2};
733 RTFStreamerElementVersionEpoch fStreamerElementVersionEpoch;
734};
735
736/// Streamer info frame for data member RNTuple::fVersionMajor
737struct RTFStreamerVersionMajor {
738 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerVersionMajor) - sizeof(RUInt32BE))};
739 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
740 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerVersionMajor) - 3 * sizeof(RUInt32BE))};
741 RUInt16BE fVersion{2};
742 RTFStreamerElementVersionMajor fStreamerElementVersionMajor;
743};
744
745/// Streamer info frame for data member RNTuple::fVersionMinor
746struct RTFStreamerVersionMinor {
747 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerVersionMinor) - sizeof(RUInt32BE))};
748 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
749 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerVersionMinor) - 3 * sizeof(RUInt32BE))};
750 RUInt16BE fVersion{2};
751 RTFStreamerElementVersionMinor fStreamerElementVersionMinor;
752};
753
754/// Streamer info frame for data member RNTuple::fVersionPatch
755struct RTFStreamerVersionPatch {
756 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerVersionPatch) - sizeof(RUInt32BE))};
757 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
758 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerVersionPatch) - 3 * sizeof(RUInt32BE))};
759 RUInt16BE fVersion{2};
760 RTFStreamerElementVersionPatch fStreamerElementVersionPatch;
761};
762
763/// Streamer info frame for data member RNTuple::fSeekHeader
764struct RTFStreamerSeekHeader {
765 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerSeekHeader) - sizeof(RUInt32BE))};
766 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
767 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerSeekHeader) - 3 * sizeof(RUInt32BE))};
768 RUInt16BE fVersion{2};
769 RTFStreamerElementSeekHeader fStreamerElementSeekHeader;
770};
771
772/// Streamer info frame for data member RNTuple::fNbytesHeader
773struct RTFStreamerNBytesHeader {
774 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerNBytesHeader) - sizeof(RUInt32BE))};
775 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
776 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerNBytesHeader) - 3 * sizeof(RUInt32BE))};
777 RUInt16BE fVersion{2};
778 RTFStreamerElementNBytesHeader fStreamerElementNBytesHeader;
779};
780
781/// Streamer info frame for data member RNTuple::fLenHeader
782struct RTFStreamerLenHeader {
783 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerLenHeader) - sizeof(RUInt32BE))};
784 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
785 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerLenHeader) - 3 * sizeof(RUInt32BE))};
786 RUInt16BE fVersion{2};
787 RTFStreamerElementLenHeader fStreamerElementLenHeader;
788};
789
790/// Streamer info frame for data member RNTuple::fSeekFooter
791struct RTFStreamerSeekFooter {
792 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerSeekFooter) - sizeof(RUInt32BE))};
793 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
794 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerSeekFooter) - 3 * sizeof(RUInt32BE))};
795 RUInt16BE fVersion{2};
796 RTFStreamerElementSeekFooter fStreamerElementSeekFooter;
797};
798
799/// Streamer info frame for data member RNTuple::fNBytesFooter
800struct RTFStreamerNBytesFooter {
801 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerNBytesFooter) - sizeof(RUInt32BE))};
802 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
803 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerNBytesFooter) - 3 * sizeof(RUInt32BE))};
804 RUInt16BE fVersion{2};
805 RTFStreamerElementNBytesFooter fStreamerElementNBytesFooter;
806};
807
808/// Streamer info frame for data member RNTuple::fLenFooter
809struct RTFStreamerLenFooter {
810 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerLenFooter) - sizeof(RUInt32BE))};
811 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
812 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerLenFooter) - 3 * sizeof(RUInt32BE))};
813 RUInt16BE fVersion{2};
814 RTFStreamerElementLenFooter fStreamerElementLenFooter;
815};
816
817/// Streamer info frame for data member RNTuple::fLenFooter
818struct RTFStreamerMaxKeySize {
819 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerMaxKeySize) - sizeof(RUInt32BE))};
820 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
821 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerMaxKeySize) - 3 * sizeof(RUInt32BE))};
822 RUInt16BE fVersion{2};
823 RTFStreamerElementMaxKeySize fStreamerElementMaxKeySize;
824};
825
826/// Streamer info for class RNTuple
827struct RTFStreamerInfoObject {
828 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerInfoObject) - sizeof(fByteCount))};
829 RUInt32BE fNewClassTag{0xffffffff};
830 char fClassName[14]{'T', 'S', 't', 'r', 'e', 'a', 'm', 'e', 'r', 'I', 'n', 'f', 'o', '\0'};
831 RUInt32BE fByteCountRemaining{0x40000000 |
832 (sizeof(RTFStreamerInfoObject) - 2 * sizeof(RUInt32BE) - 14 - sizeof(RUInt32BE))};
833 RUInt16BE fVersion{9};
834
835 RUInt32BE fByteCountNamed{
836 0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 29 /* strlen("ROOT::Experimental::RNTuple") + 2 */)};
837 RUInt16BE fVersionNamed{1};
838 RTFObject fObjectNamed{0x02000000 | 0x01000000 | 0x00010000};
839 char fLName = 27;
840 char fName[27]{'R', 'O', 'O', 'T', ':', ':', 'E', 'x', 'p', 'e', 'r', 'i', 'm', 'e',
841 'n', 't', 'a', 'l', ':', ':', 'R', 'N', 'T', 'u', 'p', 'l', 'e'};
842 char fLTitle = 0;
843
844 RInt32BE fChecksum{ChecksumRNTupleClass()};
845 /// NOTE: this needs to be kept in sync with the RNTuple version in RNTuple.hxx
846 RUInt32BE fVersionRNTuple{6};
847
848 RUInt32BE fByteCountObjArr{0x40000000 |
849 (sizeof(RUInt32BE) + 10 /* strlen(TObjArray) + 1 */ + sizeof(RUInt32BE) +
850 sizeof(RUInt16BE) + sizeof(RTFObject) + 1 + 2 * sizeof(RUInt32BE) + sizeof(fStreamers))};
851 RUInt32BE fNewClassTagObjArray{0xffffffff};
852 char fClassNameObjArray[10]{'T', 'O', 'b', 'j', 'A', 'r', 'r', 'a', 'y', '\0'};
853 RUInt32BE fByteCountObjArrRemaining{
854 0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 1 + 2 * sizeof(RUInt32BE) + sizeof(fStreamers))};
855 RUInt16BE fVersionObjArr{3};
856 RTFObject fObjectObjArr{0x02000000};
857 char fNameObjArr{0};
858
859 RUInt32BE fNObjects{11};
860 RUInt32BE fLowerBound{0};
861
862 struct {
863 RTFStreamerVersionEpoch fStreamerVersionEpoch;
864 RTFStreamerVersionMajor fStreamerVersionMajor;
865 RTFStreamerVersionMinor fStreamerVersionMinor;
866 RTFStreamerVersionPatch fStreamerVersionPatch;
867 RTFStreamerSeekHeader fStreamerSeekHeader;
868 RTFStreamerNBytesHeader fStreamerNBytesHeader;
869 RTFStreamerLenHeader fStreamerLenHeader;
870 RTFStreamerSeekFooter fStreamerSeekFooter;
871 RTFStreamerNBytesFooter fStreamerNBytesFooter;
872 RTFStreamerLenFooter fStreamerLenFooter;
873 RTFStreamerMaxKeySize fStreamerMaxKeySize;
874 } fStreamers;
875};
876
877/// The list of streamer info objects, for a new ntuple contains only the RNTuple class
878struct RTFStreamerInfoList {
879 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerInfoList) - sizeof(fByteCount))};
880 RUInt16BE fVersion{5};
881 RTFObject fObject{0x02000000};
882 char fName{0};
883 RUInt32BE fNObjects{1};
884 RTFStreamerInfoObject fStreamerInfo;
885 char fEnd{0};
886
887 std::uint32_t GetSize() const { return sizeof(RTFStreamerInfoList); }
888};
889
890/// The header of the directory key index
891struct RTFKeyList {
892 RUInt32BE fNKeys;
893 std::uint32_t GetSize() const { return sizeof(RTFKeyList); }
894 explicit RTFKeyList(std::uint32_t nKeys) : fNKeys(nKeys) {}
895};
896
897/// A streamed TFile object
898struct RTFFile {
899 RUInt16BE fClassVersion{5};
900 RTFDatetime fDateC;
901 RTFDatetime fDateM;
902 RUInt32BE fNBytesKeys{0};
903 RUInt32BE fNBytesName{0};
904 // The version of the key has to tell whether offsets are 32bit or 64bit long
905 union {
906 struct {
907 RUInt32BE fSeekDir{100};
908 RUInt32BE fSeekParent{0};
909 RUInt32BE fSeekKeys{0};
910 } fInfoShort;
911 struct {
912 RUInt64BE fSeekDir{100};
913 RUInt64BE fSeekParent{0};
914 RUInt64BE fSeekKeys{0};
915 } fInfoLong;
916 };
917
918 RTFFile() : fInfoShort() {}
919
920 // In case of a short TFile record (<2G), 3 padding ints are written after the UUID
921 std::uint32_t GetSize() const
922 {
923 if (fClassVersion >= 1000)
924 return sizeof(RTFFile);
925 return 18 + sizeof(fInfoShort);
926 }
927
928 std::uint64_t GetSeekKeys() const
929 {
930 if (fClassVersion >= 1000)
931 return fInfoLong.fSeekKeys;
932 return fInfoShort.fSeekKeys;
933 }
934
935 void SetSeekKeys(std::uint64_t seekKeys)
936 {
937 if (seekKeys > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) {
938 std::uint32_t seekDir = fInfoShort.fSeekDir;
939 std::uint32_t seekParent = fInfoShort.fSeekParent;
940 fInfoLong.fSeekDir = seekDir;
941 fInfoLong.fSeekParent = seekParent;
942 fInfoLong.fSeekKeys = seekKeys;
943 fClassVersion = fClassVersion + 1000;
944 } else {
945 fInfoShort.fSeekKeys = seekKeys;
946 }
947 }
948};
949
950/// A zero UUID stored at the end of the TFile record
951struct RTFUUID {
952 RUInt16BE fVersionClass{1};
953 unsigned char fUUID[16] = {0};
954
955 RTFUUID() = default;
956 std::uint32_t GetSize() const { return sizeof(RTFUUID); }
957};
958
959/// A streamed RNTuple class
960///
961/// NOTE: this must be kept in sync with RNTuple.hxx.
962/// Aside ensuring consistency between the two classes' members, you need to make sure
963/// that fVersionClass matches the class version of RNTuple.
964struct RTFNTuple {
965 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFNTuple) - sizeof(fByteCount))};
966 RUInt16BE fVersionClass{6};
967 RUInt16BE fVersionEpoch{0};
968 RUInt16BE fVersionMajor{0};
969 RUInt16BE fVersionMinor{0};
970 RUInt16BE fVersionPatch{0};
971 RUInt64BE fSeekHeader{0};
972 RUInt64BE fNBytesHeader{0};
973 RUInt64BE fLenHeader{0};
974 RUInt64BE fSeekFooter{0};
975 RUInt64BE fNBytesFooter{0};
976 RUInt64BE fLenFooter{0};
977 RUInt64BE fMaxKeySize{0};
978
979 static constexpr std::uint32_t GetSizePlusChecksum() { return sizeof(RTFNTuple) + sizeof(std::uint64_t); }
980
981 RTFNTuple() = default;
982 explicit RTFNTuple(const ROOT::Experimental::RNTuple &inMemoryAnchor)
983 {
984 fVersionEpoch = inMemoryAnchor.GetVersionEpoch();
985 fVersionMajor = inMemoryAnchor.GetVersionMajor();
986 fVersionMinor = inMemoryAnchor.GetVersionMinor();
987 fVersionPatch = inMemoryAnchor.GetVersionPatch();
988 fSeekHeader = inMemoryAnchor.GetSeekHeader();
989 fNBytesHeader = inMemoryAnchor.GetNBytesHeader();
990 fLenHeader = inMemoryAnchor.GetLenHeader();
991 fSeekFooter = inMemoryAnchor.GetSeekFooter();
992 fNBytesFooter = inMemoryAnchor.GetNBytesFooter();
993 fLenFooter = inMemoryAnchor.GetLenFooter();
994 fMaxKeySize = inMemoryAnchor.GetMaxKeySize();
995 }
996 std::uint32_t GetSize() const { return sizeof(RTFNTuple); }
997 // The byte count and class version members are not checksummed
998 std::uint32_t GetOffsetCkData() { return sizeof(fByteCount) + sizeof(fVersionClass); }
999 std::uint32_t GetSizeCkData() { return GetSize() - GetOffsetCkData(); }
1000 unsigned char *GetPtrCkData() { return reinterpret_cast<unsigned char *>(this) + GetOffsetCkData(); }
1001};
1002
1003/// The bare file global header
1004struct RBareFileHeader {
1005 char fMagic[7]{'r', 'n', 't', 'u', 'p', 'l', 'e'};
1006 RUInt32BE fRootVersion{(ROOT_VERSION_CODE >> 16) * 10000 + ((ROOT_VERSION_CODE & 0xFF00) >> 8) * 100 +
1007 (ROOT_VERSION_CODE & 0xFF)};
1008 RUInt32BE fFormatVersion{1};
1009 RUInt32BE fCompress{0};
1010 RTFNTuple fNTuple;
1011 // followed by the ntuple name
1012};
1013#pragma pack(pop)
1014
1015/// The artifical class name shown for opaque RNTuple keys (see TBasket)
1016constexpr char const *kBlobClassName = "RBlob";
1017/// The class name of the RNTuple anchor
1018constexpr char const *kNTupleClassName = "ROOT::Experimental::RNTuple";
1019
1020} // anonymous namespace
1021
1022namespace ROOT {
1023namespace Experimental {
1024namespace Internal {
1025/// If a TFile container is written by a C stream (simple file), on dataset commit, the file header
1026/// and the TFile record need to be updated
1028 RTFHeader fHeader;
1030 std::uint64_t fSeekNTuple{0}; // Remember the offset for the keys list
1031 std::uint64_t fSeekFileRecord{0};
1032};
1033
1034/// The RKeyBlob writes an invisible key into a TFile. That is, a key that is not indexed in the list of keys,
1035/// like a TBasket.
1036/// NOTE: out of anonymous namespace because otherwise ClassDefInline fails to compile
1037/// on some platforms.
1038class RKeyBlob : public TKey {
1039public:
1040 RKeyBlob() = default;
1041
1042 explicit RKeyBlob(TFile *file) : TKey(file)
1043 {
1044 fClassName = kBlobClassName;
1045 fVersion += 1000;
1046 fKeylen = Sizeof();
1047 }
1048
1049 /// Register a new key for a data record of size nbytes
1050 void Reserve(size_t nbytes, std::uint64_t *seekKey)
1051 {
1052 Create(nbytes);
1053 *seekKey = fSeekKey;
1054 }
1055
1057};
1058
1059} // namespace Internal
1060} // namespace Experimental
1061} // namespace ROOT
1062
1064
1066 std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch,
1067 std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter,
1068 std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize)
1069{
1070 RNTuple ntuple;
1071 ntuple.fVersionEpoch = versionEpoch;
1072 ntuple.fVersionMajor = versionMajor;
1073 ntuple.fVersionMinor = versionMinor;
1074 ntuple.fVersionPatch = versionPatch;
1075 ntuple.fSeekHeader = seekHeader;
1076 ntuple.fNBytesHeader = nbytesHeader;
1077 ntuple.fLenHeader = lenHeader;
1078 ntuple.fSeekFooter = seekFooter;
1079 ntuple.fNBytesFooter = nbytesFooter;
1080 ntuple.fLenFooter = lenFooter;
1081 ntuple.fMaxKeySize = maxKeySize;
1082 return ntuple;
1083}
1084
1087{
1088 char ident[4];
1089 ReadBuffer(ident, 4, 0);
1090 if (std::string(ident, 4) == "root")
1091 return GetNTupleProper(ntupleName);
1092 fIsBare = true;
1093 return GetNTupleBare(ntupleName);
1094}
1095
1098{
1099 RTFHeader fileHeader;
1100 ReadBuffer(&fileHeader, sizeof(fileHeader), 0);
1101
1102 RTFKey key;
1103 RTFString name;
1104 ReadBuffer(&key, sizeof(key), fileHeader.fBEGIN);
1105 // Skip over the entire key length, including the class name, object name, and title stored in it.
1106 std::uint64_t offset = fileHeader.fBEGIN + key.fKeyLen;
1107 // Skip over the name and title of the TNamed preceding the TFile entry.
1108 ReadBuffer(&name, 1, offset);
1109 offset += name.GetSize();
1110 ReadBuffer(&name, 1, offset);
1111 offset += name.GetSize();
1112 RTFFile file;
1113 ReadBuffer(&file, sizeof(file), offset);
1114
1115 RUInt32BE nKeys;
1116 offset = file.GetSeekKeys();
1117 ReadBuffer(&key, sizeof(key), offset);
1118 offset += key.fKeyLen;
1119 ReadBuffer(&nKeys, sizeof(nKeys), offset);
1120 offset += sizeof(nKeys);
1121 bool found = false;
1122 for (unsigned int i = 0; i < nKeys; ++i) {
1123 ReadBuffer(&key, sizeof(key), offset);
1124 auto offsetNextKey = offset + key.fKeyLen;
1125
1126 offset += key.GetHeaderSize();
1127 ReadBuffer(&name, 1, offset);
1128 ReadBuffer(&name, name.GetSize(), offset);
1129 if (std::string_view(name.fData, name.fLName) != kNTupleClassName) {
1130 offset = offsetNextKey;
1131 continue;
1132 }
1133 offset += name.GetSize();
1134 ReadBuffer(&name, 1, offset);
1135 ReadBuffer(&name, name.GetSize(), offset);
1136 if (std::string_view(name.fData, name.fLName) == ntupleName) {
1137 found = true;
1138 break;
1139 }
1140 offset = offsetNextKey;
1141 }
1142 if (!found) {
1143 return R__FAIL("no RNTuple named '" + std::string(ntupleName) + "' in file '" + fRawFile->GetUrl() + "'");
1144 }
1145
1146 offset = key.GetSeekKey() + key.fKeyLen;
1147
1148 if (key.fObjLen < sizeof(RTFNTuple)) {
1149 return R__FAIL("invalid anchor size: " + std::to_string(key.fObjLen) + " < " + std::to_string(sizeof(RTFNTuple)));
1150 }
1151 // The object length can be larger than the size of RTFNTuple if it comes from a future RNTuple class version.
1152 auto bufAnchor = std::make_unique<unsigned char[]>(key.fObjLen);
1153 RTFNTuple *ntuple = new (bufAnchor.get()) RTFNTuple;
1154
1155 auto objNbytes = key.GetSize() - key.fKeyLen;
1156 ReadBuffer(ntuple, objNbytes, offset);
1157 if (objNbytes != key.fObjLen) {
1158 RNTupleDecompressor decompressor;
1159 decompressor.Unzip(bufAnchor.get(), objNbytes, key.fObjLen);
1160 }
1161
1162 if (ntuple->fVersionClass < 4) {
1163 return R__FAIL("invalid anchor, unsupported pre-release of RNTuple");
1164 }
1165
1166 // We require that future class versions only append members and store the checksum in the last 8 bytes
1167 // Checksum calculation: strip byte count, class version, fChecksum member
1168 RUInt64BE *ckOnDisk = reinterpret_cast<RUInt64BE *>(bufAnchor.get() + key.fObjLen - sizeof(uint64_t));
1169 auto lenCkData = key.fObjLen - ntuple->GetOffsetCkData() - sizeof(uint64_t);
1170 auto ckCalc = XXH3_64bits(ntuple->GetPtrCkData(), lenCkData);
1171 if (ckCalc != (uint64_t)(*ckOnDisk)) {
1172 return R__FAIL("RNTuple anchor checksum mismatch");
1173 }
1174
1175 return CreateAnchor(ntuple->fVersionEpoch, ntuple->fVersionMajor, ntuple->fVersionMinor, ntuple->fVersionPatch,
1176 ntuple->fSeekHeader, ntuple->fNBytesHeader, ntuple->fLenHeader, ntuple->fSeekFooter,
1177 ntuple->fNBytesFooter, ntuple->fLenFooter, ntuple->fMaxKeySize);
1178}
1179
1182{
1183 RBareFileHeader fileHeader;
1184 ReadBuffer(&fileHeader, sizeof(fileHeader), 0);
1185 RTFString name;
1186 auto offset = sizeof(fileHeader);
1187 ReadBuffer(&name, 1, offset);
1188 ReadBuffer(&name, name.GetSize(), offset);
1189 std::string_view foundName(name.fData, name.fLName);
1190 if (foundName != ntupleName) {
1191 return R__FAIL("expected RNTuple named '" + std::string(ntupleName) + "' but instead found '" +
1192 std::string(foundName) + "' in file '" + fRawFile->GetUrl() + "'");
1193 }
1194 offset += name.GetSize();
1195
1196 RTFNTuple ntuple;
1197 ReadBuffer(&ntuple, sizeof(ntuple), offset);
1198 std::uint64_t onDiskChecksum;
1199 ReadBuffer(&onDiskChecksum, sizeof(onDiskChecksum), offset + sizeof(ntuple));
1200 auto checksum = XXH3_64bits(ntuple.GetPtrCkData(), ntuple.GetSizeCkData());
1201 if (checksum != static_cast<uint64_t>(onDiskChecksum))
1202 return R__FAIL("RNTuple bare file: anchor checksum mismatch");
1203 return CreateAnchor(ntuple.fVersionEpoch, ntuple.fVersionMajor, ntuple.fVersionMinor, ntuple.fVersionPatch,
1204 ntuple.fSeekHeader, ntuple.fNBytesHeader, ntuple.fLenHeader, ntuple.fSeekFooter,
1205 ntuple.fNBytesFooter, ntuple.fLenFooter, ntuple.fMaxKeySize);
1206}
1207
1208void ROOT::Experimental::Internal::RMiniFileReader::ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset)
1209{
1210 auto nread = fRawFile->ReadAt(buffer, nbytes, offset);
1211 R__ASSERT(nread == nbytes);
1212}
1213
1214////////////////////////////////////////////////////////////////////////////////
1215
1217{
1218 if (fFile)
1219 fclose(fFile);
1220}
1221
1223 std::int64_t offset)
1224{
1225 R__ASSERT(fFile);
1226 size_t retval;
1227 if ((offset >= 0) && (static_cast<std::uint64_t>(offset) != fFilePos)) {
1228#ifdef R__SEEK64
1229 retval = fseeko64(fFile, offset, SEEK_SET);
1230#else
1231 retval = fseek(fFile, offset, SEEK_SET);
1232#endif
1233 if (retval)
1234 throw RException(R__FAIL(std::string("Seek failed: ") + strerror(errno)));
1235 fFilePos = offset;
1236 }
1237 retval = fwrite(buffer, 1, nbytes, fFile);
1238 if (retval != nbytes)
1239 throw RException(R__FAIL(std::string("write failed: ") + strerror(errno)));
1240 fFilePos += nbytes;
1241}
1242
1244 const void *buffer, std::size_t nbytes, std::size_t len, std::int64_t offset, std::uint64_t directoryOffset,
1245 const std::string &className, const std::string &objectName, const std::string &title)
1246{
1247 if (offset > 0)
1248 fKeyOffset = offset;
1249 RTFString strClass{className};
1250 RTFString strObject{objectName};
1251 RTFString strTitle{title};
1252
1253 RTFKey key(fKeyOffset, directoryOffset, strClass, strObject, strTitle, len, nbytes);
1254 Write(&key, key.fKeyHeaderSize, fKeyOffset);
1255 Write(&strClass, strClass.GetSize());
1256 Write(&strObject, strObject.GetSize());
1257 Write(&strTitle, strTitle.GetSize());
1258 auto offsetData = fFilePos;
1259 // The next key starts after the data.
1260 fKeyOffset = offsetData + nbytes;
1261 if (buffer)
1262 Write(buffer, nbytes);
1263
1264 return offsetData;
1265}
1266
1267////////////////////////////////////////////////////////////////////////////////
1268
1270 std::int64_t offset)
1271{
1272 R__ASSERT(fFile);
1273 fFile->Seek(offset);
1274 bool rv = fFile->WriteBuffer((char *)(buffer), nbytes);
1275 if (rv)
1276 throw RException(R__FAIL("WriteBuffer failed."));
1277}
1278
1279std::uint64_t
1281{
1282 std::uint64_t offsetKey;
1283 RKeyBlob keyBlob(fFile);
1284 // Since it is unknown beforehand if offsetKey is beyond the 2GB limit or not,
1285 // RKeyBlob will always reserve space for a big key (version >= 1000)
1286 keyBlob.Reserve(nbytes, &offsetKey);
1287
1288 auto offset = offsetKey;
1289 RTFString strClass{kBlobClassName};
1290 RTFString strObject;
1291 RTFString strTitle;
1292 RTFKey keyHeader(offset, offset, strClass, strObject, strTitle, len, nbytes);
1293 // Follow the fact that RKeyBlob is a big key unconditionally (see above)
1294 keyHeader.MakeBigKey();
1295
1296 Write(&keyHeader, keyHeader.fKeyHeaderSize, offset);
1297 offset += keyHeader.fKeyHeaderSize;
1298 Write(&strClass, strClass.GetSize(), offset);
1299 offset += strClass.GetSize();
1300 Write(&strObject, strObject.GetSize(), offset);
1301 offset += strObject.GetSize();
1302 Write(&strTitle, strTitle.GetSize(), offset);
1303 offset += strTitle.GetSize();
1304 auto offsetData = offset;
1305 if (buffer)
1306 Write(buffer, nbytes, offset);
1307
1308 return offsetData;
1309}
1310
1311////////////////////////////////////////////////////////////////////////////////
1312
1314{
1315 fFileSimple.fControlBlock = std::make_unique<ROOT::Experimental::Internal::RTFileControlBlock>();
1316}
1317
1319
1320std::unique_ptr<ROOT::Experimental::Internal::RNTupleFileWriter>
1321ROOT::Experimental::Internal::RNTupleFileWriter::Recreate(std::string_view ntupleName, std::string_view path,
1322 int defaultCompression, EContainerFormat containerFormat)
1323{
1324 std::string fileName(path);
1325 size_t idxDirSep = fileName.find_last_of("\\/");
1326 if (idxDirSep != std::string::npos) {
1327 fileName.erase(0, idxDirSep + 1);
1328 }
1329#ifdef R__SEEK64
1330 FILE *fileStream = fopen64(std::string(path.data(), path.size()).c_str(), "wb");
1331#else
1332 FILE *fileStream = fopen(std::string(path.data(), path.size()).c_str(), "wb");
1333#endif
1334 R__ASSERT(fileStream);
1335
1336 auto writer = std::unique_ptr<RNTupleFileWriter>(new RNTupleFileWriter(ntupleName));
1337 writer->fFileSimple.fFile = fileStream;
1338 writer->fFileName = fileName;
1339
1340 switch (containerFormat) {
1341 case EContainerFormat::kTFile: writer->WriteTFileSkeleton(defaultCompression); break;
1342 case EContainerFormat::kBare:
1343 writer->fIsBare = true;
1344 writer->WriteBareFileSkeleton(defaultCompression);
1345 break;
1346 default: R__ASSERT(false && "Internal error: unhandled container format");
1347 }
1348
1349 return writer;
1350}
1351
1352std::unique_ptr<ROOT::Experimental::Internal::RNTupleFileWriter>
1354{
1355 auto writer = std::unique_ptr<RNTupleFileWriter>(new RNTupleFileWriter(ntupleName));
1356 writer->fFileProper.fFile = &file;
1357 return writer;
1358}
1359
1361{
1362 if (fFileProper) {
1363 // Easy case, the ROOT file header and the RNTuple streaming is taken care of by TFile
1364 fFileProper.fFile->WriteObject(&fNTupleAnchor, fNTupleName.c_str());
1365 fFileProper.fFile->Write();
1366 return;
1367 }
1368
1369 // Writing by C file stream: prepare the container format header and stream the RNTuple anchor object
1370 R__ASSERT(fFileSimple);
1371
1372 if (fIsBare) {
1373 RTFNTuple ntupleOnDisk(fNTupleAnchor);
1374 fFileSimple.Write(&ntupleOnDisk, ntupleOnDisk.GetSize(), fFileSimple.fControlBlock->fSeekNTuple);
1375 // Append the checksum
1376 std::uint64_t checksum = XXH3_64bits(ntupleOnDisk.GetPtrCkData(), ntupleOnDisk.GetSizeCkData());
1377 fFileSimple.Write(&checksum, sizeof(checksum));
1378 fflush(fFileSimple.fFile);
1379 return;
1380 }
1381
1382 WriteTFileNTupleKey();
1383 WriteTFileKeysList();
1384 WriteTFileStreamerInfo();
1385 WriteTFileFreeList();
1386
1387 // Update header and TFile record
1388 fFileSimple.Write(&fFileSimple.fControlBlock->fHeader, fFileSimple.fControlBlock->fHeader.GetSize(), 0);
1389 fFileSimple.Write(&fFileSimple.fControlBlock->fFileRecord, fFileSimple.fControlBlock->fFileRecord.GetSize(),
1390 fFileSimple.fControlBlock->fSeekFileRecord);
1391 fflush(fFileSimple.fFile);
1392}
1393
1394std::uint64_t ROOT::Experimental::Internal::RNTupleFileWriter::WriteBlob(const void *data, size_t nbytes, size_t len)
1395{
1396 std::uint64_t offset;
1397 if (fFileSimple) {
1398 if (fIsBare) {
1399 offset = fFileSimple.fKeyOffset;
1400 fFileSimple.Write(data, nbytes);
1401 fFileSimple.fKeyOffset += nbytes;
1402 } else {
1403 offset = fFileSimple.WriteKey(data, nbytes, len, -1, 100, kBlobClassName);
1404 }
1405 } else {
1406 offset = fFileProper.WriteKey(data, nbytes, len);
1407 }
1408 return offset;
1409}
1410
1412{
1413 std::uint64_t offset;
1414 if (fFileSimple) {
1415 if (fIsBare) {
1416 offset = fFileSimple.fKeyOffset;
1417 fFileSimple.fKeyOffset += nbytes;
1418 } else {
1419 offset = fFileSimple.WriteKey(/*buffer=*/nullptr, nbytes, len, -1, 100, kBlobClassName);
1420 }
1421 } else {
1422 offset = fFileProper.WriteKey(/*buffer=*/nullptr, nbytes, len);
1423 }
1424 return offset;
1425}
1426
1428 std::int64_t offset)
1429{
1430 if (fFileSimple) {
1431 fFileSimple.Write(buffer, nbytes, offset);
1432 } else {
1433 fFileProper.Write(buffer, nbytes, offset);
1434 }
1435}
1436
1437std::uint64_t
1439{
1440 auto offset = WriteBlob(data, nbytes, lenHeader);
1441 fNTupleAnchor.fLenHeader = lenHeader;
1442 fNTupleAnchor.fNBytesHeader = nbytes;
1443 fNTupleAnchor.fSeekHeader = offset;
1444 return offset;
1445}
1446
1447std::uint64_t
1449{
1450 auto offset = WriteBlob(data, nbytes, lenFooter);
1451 fNTupleAnchor.fLenFooter = lenFooter;
1452 fNTupleAnchor.fNBytesFooter = nbytes;
1453 fNTupleAnchor.fSeekFooter = offset;
1454 return offset;
1455}
1456
1458{
1459 RBareFileHeader bareHeader;
1460 bareHeader.fCompress = defaultCompression;
1461 fFileSimple.Write(&bareHeader, sizeof(bareHeader), 0);
1462 RTFString ntupleName{fNTupleName};
1463 fFileSimple.Write(&ntupleName, ntupleName.GetSize());
1464
1465 // Write zero-initialized ntuple to reserve the space; will be overwritten on commit
1466 RTFNTuple ntupleOnDisk;
1467 fFileSimple.fControlBlock->fSeekNTuple = fFileSimple.fFilePos;
1468 fFileSimple.Write(&ntupleOnDisk, ntupleOnDisk.GetSize());
1469 std::uint64_t checksum = 0;
1470 fFileSimple.Write(&checksum, sizeof(checksum));
1471 fFileSimple.fKeyOffset = fFileSimple.fFilePos;
1472}
1473
1475{
1476 RTFString strTList{"TList"};
1477 RTFString strStreamerInfo{"StreamerInfo"};
1478 RTFString strStreamerTitle{"Doubly linked list"};
1479
1480 fFileSimple.fControlBlock->fHeader.SetSeekInfo(fFileSimple.fKeyOffset);
1481 RTFKey keyStreamerInfo(fFileSimple.fControlBlock->fHeader.GetSeekInfo(), 100, strTList, strStreamerInfo,
1482 strStreamerTitle, 0);
1483 RTFStreamerInfoList streamerInfo;
1484 auto classTagOffset = keyStreamerInfo.fKeyLen + offsetof(struct RTFStreamerInfoList, fStreamerInfo) +
1485 offsetof(struct RTFStreamerInfoObject, fStreamers) +
1486 offsetof(struct RTFStreamerVersionEpoch, fNewClassTag) + 2;
1487 streamerInfo.fStreamerInfo.fStreamers.fStreamerVersionMajor.fClassTag = 0x80000000 | classTagOffset;
1488 streamerInfo.fStreamerInfo.fStreamers.fStreamerVersionMinor.fClassTag = 0x80000000 | classTagOffset;
1489 streamerInfo.fStreamerInfo.fStreamers.fStreamerVersionPatch.fClassTag = 0x80000000 | classTagOffset;
1490 streamerInfo.fStreamerInfo.fStreamers.fStreamerSeekHeader.fClassTag = 0x80000000 | classTagOffset;
1491 streamerInfo.fStreamerInfo.fStreamers.fStreamerNBytesHeader.fClassTag = 0x80000000 | classTagOffset;
1492 streamerInfo.fStreamerInfo.fStreamers.fStreamerLenHeader.fClassTag = 0x80000000 | classTagOffset;
1493 streamerInfo.fStreamerInfo.fStreamers.fStreamerSeekFooter.fClassTag = 0x80000000 | classTagOffset;
1494 streamerInfo.fStreamerInfo.fStreamers.fStreamerNBytesFooter.fClassTag = 0x80000000 | classTagOffset;
1495 streamerInfo.fStreamerInfo.fStreamers.fStreamerLenFooter.fClassTag = 0x80000000 | classTagOffset;
1496 streamerInfo.fStreamerInfo.fStreamers.fStreamerMaxKeySize.fClassTag = 0x80000000 | classTagOffset;
1497 RNTupleCompressor compressor;
1498 auto szStreamerInfo = compressor.Zip(&streamerInfo, streamerInfo.GetSize(), 1);
1499 fFileSimple.WriteKey(compressor.GetZipBuffer(), szStreamerInfo, streamerInfo.GetSize(),
1500 fFileSimple.fControlBlock->fHeader.GetSeekInfo(), 100, "TList", "StreamerInfo",
1501 "Doubly linked list");
1502 fFileSimple.fControlBlock->fHeader.SetNbytesInfo(fFileSimple.fFilePos -
1503 fFileSimple.fControlBlock->fHeader.GetSeekInfo());
1504}
1505
1507{
1508 RTFString strEmpty;
1509 RTFString strRNTupleClass{"ROOT::Experimental::RNTuple"};
1510 RTFString strRNTupleName{fNTupleName};
1511 RTFString strFileName{fFileName};
1512
1513 RTFKey keyRNTuple(fFileSimple.fControlBlock->fSeekNTuple, 100, strRNTupleClass, strRNTupleName, strEmpty,
1514 RTFNTuple::GetSizePlusChecksum());
1515
1516 fFileSimple.fControlBlock->fFileRecord.SetSeekKeys(fFileSimple.fKeyOffset);
1517 RTFKeyList keyList{1};
1518 RTFKey keyKeyList(fFileSimple.fControlBlock->fFileRecord.GetSeekKeys(), 100, strEmpty, strFileName, strEmpty,
1519 keyList.GetSize() + keyRNTuple.fKeyLen);
1520 fFileSimple.Write(&keyKeyList, keyKeyList.fKeyHeaderSize, fFileSimple.fControlBlock->fFileRecord.GetSeekKeys());
1521 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1522 fFileSimple.Write(&strFileName, strFileName.GetSize());
1523 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1524 fFileSimple.Write(&keyList, keyList.GetSize());
1525 fFileSimple.Write(&keyRNTuple, keyRNTuple.fKeyHeaderSize);
1526 // Write class name, object name, and title for this key.
1527 fFileSimple.Write(&strRNTupleClass, strRNTupleClass.GetSize());
1528 fFileSimple.Write(&strRNTupleName, strRNTupleName.GetSize());
1529 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1530 fFileSimple.fControlBlock->fFileRecord.fNBytesKeys =
1531 fFileSimple.fFilePos - fFileSimple.fControlBlock->fFileRecord.GetSeekKeys();
1532 fFileSimple.fKeyOffset = fFileSimple.fFilePos;
1533}
1534
1536{
1537 fFileSimple.fControlBlock->fHeader.SetSeekFree(fFileSimple.fKeyOffset);
1538 RTFString strEmpty;
1539 RTFString strFileName{fFileName};
1540 RTFFreeEntry freeEntry;
1541 RTFKey keyFreeList(fFileSimple.fControlBlock->fHeader.GetSeekFree(), 100, strEmpty, strFileName, strEmpty,
1542 freeEntry.GetSize());
1543 std::uint64_t firstFree = fFileSimple.fControlBlock->fHeader.GetSeekFree() + keyFreeList.GetSize();
1544 freeEntry.Set(firstFree, std::max(2000000000ULL, ((firstFree / 1000000000ULL) + 1) * 1000000000ULL));
1545 fFileSimple.WriteKey(&freeEntry, freeEntry.GetSize(), freeEntry.GetSize(),
1546 fFileSimple.fControlBlock->fHeader.GetSeekFree(), 100, "", fFileName, "");
1547 fFileSimple.fControlBlock->fHeader.SetNbytesFree(fFileSimple.fFilePos -
1548 fFileSimple.fControlBlock->fHeader.GetSeekFree());
1549 fFileSimple.fControlBlock->fHeader.SetEnd(fFileSimple.fFilePos);
1550}
1551
1553{
1554 RTFString strRNTupleClass{"ROOT::Experimental::RNTuple"};
1555 RTFString strRNTupleName{fNTupleName};
1556 RTFString strEmpty;
1557
1558 RTFNTuple ntupleOnDisk(fNTupleAnchor);
1559 RUInt64BE checksum{XXH3_64bits(ntupleOnDisk.GetPtrCkData(), ntupleOnDisk.GetSizeCkData())};
1560 fFileSimple.fControlBlock->fSeekNTuple = fFileSimple.fKeyOffset;
1561
1562 char keyBuf[RTFNTuple::GetSizePlusChecksum()];
1563
1564 // concatenate the RNTuple anchor with its checksum
1565 memcpy(keyBuf, &ntupleOnDisk, sizeof(RTFNTuple));
1566 memcpy(keyBuf + sizeof(RTFNTuple), &checksum, sizeof(checksum));
1567
1568 fFileSimple.WriteKey(keyBuf, sizeof(keyBuf), sizeof(keyBuf), fFileSimple.fControlBlock->fSeekNTuple, 100,
1569 "ROOT::Experimental::RNTuple", fNTupleName, "");
1570}
1571
1573{
1574 RTFString strTFile{"TFile"};
1575 RTFString strFileName{fFileName};
1576 RTFString strEmpty;
1577
1578 fFileSimple.fControlBlock->fHeader = RTFHeader(defaultCompression);
1579
1580 RTFUUID uuid;
1581
1582 // First record of the file: the TFile object at offset 100
1583 RTFKey keyRoot(100, 0, strTFile, strFileName, strEmpty,
1584 sizeof(RTFFile) + strFileName.GetSize() + strEmpty.GetSize() + uuid.GetSize());
1585 std::uint32_t nbytesName = keyRoot.fKeyLen + strFileName.GetSize() + 1;
1586 fFileSimple.fControlBlock->fFileRecord.fNBytesName = nbytesName;
1587 fFileSimple.fControlBlock->fHeader.SetNbytesName(nbytesName);
1588
1589 fFileSimple.Write(&keyRoot, keyRoot.fKeyHeaderSize, 100);
1590 // Write class name, object name, and title for the TFile key.
1591 fFileSimple.Write(&strTFile, strTFile.GetSize());
1592 fFileSimple.Write(&strFileName, strFileName.GetSize());
1593 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1594 // Write the name and title of the TNamed preceding the TFile entry.
1595 fFileSimple.Write(&strFileName, strFileName.GetSize());
1596 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1597 // Will be overwritten on commit
1598 fFileSimple.fControlBlock->fSeekFileRecord = fFileSimple.fFilePos;
1599 fFileSimple.Write(&fFileSimple.fControlBlock->fFileRecord, fFileSimple.fControlBlock->fFileRecord.GetSize());
1600 fFileSimple.Write(&uuid, uuid.GetSize());
1601
1602 // Padding bytes to allow the TFile record to grow for a big file
1603 RUInt32BE padding{0};
1604 for (int i = 0; i < 3; ++i)
1605 fFileSimple.Write(&padding, sizeof(padding));
1606 fFileSimple.fKeyOffset = fFileSimple.fFilePos;
1607}
dim_t fSize
#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 ROOT_VERSION_CODE
Definition RVersion.hxx:24
#define ClassDefInlineOverride(name, id)
Definition Rtypes.h:353
#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 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 data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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 unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
char name[80]
Definition TGX11.cxx:110
Binding & operator=(OUT(*fun)(void))
void ReadBuffer(char *&buffer) override
T1 fFirst
Definition X11Events.mm:86
The RKeyBlob writes an invisible key into a TFile.
void Reserve(size_t nbytes, std::uint64_t *seekKey)
Register a new key for a data record of size nbytes.
RResult< RNTuple > GetNTuple(std::string_view ntupleName)
Extracts header and footer location for the RNTuple identified by ntupleName.
RResult< RNTuple > GetNTupleProper(std::string_view ntupleName)
Used when the file turns out to be a TFile container.
RNTuple CreateAnchor(std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch, std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter, std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize)
RResult< RNTuple > GetNTupleBare(std::string_view ntupleName)
Used when the file container turns out to be a bare file.
void ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset)
Reads a given byte range from the file into the provided memory buffer.
Helper class to compress data blocks in the ROOT compression frame format.
size_t Zip(const void *from, size_t nbytes, int compression, Writer_t fnWriter)
Returns the size of the compressed data.
Helper class to uncompress data blocks in the ROOT compression frame format.
void Unzip(const void *from, size_t nbytes, size_t dataLen, void *to)
The nbytes parameter provides the size ls of the from buffer.
Write RNTuple data blocks in a TFile or a bare file container.
Definition RMiniFile.hxx:92
std::uint64_t WriteBlob(const void *data, size_t nbytes, size_t len)
Writes a new record as an RBlob key into the file.
std::uint64_t WriteNTupleFooter(const void *data, size_t nbytes, size_t lenFooter)
Writes the compressed footer and registeres its location; lenFooter is the size of the uncompressed f...
void WriteTFileKeysList()
Write the TList with the RNTuple key.
void Commit()
Writes the RNTuple key to the file so that the header and footer keys can be found.
std::uint64_t ReserveBlob(size_t nbytes, size_t len)
Reserves a new record as an RBlob key in the file.
RFileSimple fFileSimple
For simple use cases, survives without libRIO dependency.
static std::unique_ptr< RNTupleFileWriter > Append(std::string_view ntupleName, TFile &file)
Add a new RNTuple identified by ntupleName to the existing TFile.
void WriteTFileNTupleKey()
The only key that will be visible in file->ls()
void WriteTFileFreeList()
Last record in the file.
EContainerFormat
For testing purposes, RNTuple data can be written into a bare file container instead of a ROOT file.
static std::unique_ptr< RNTupleFileWriter > Recreate(std::string_view ntupleName, std::string_view path, int defaultCompression, EContainerFormat containerFormat)
Create or truncate the local file given by path with the new empty RNTuple identified by ntupleName.
void WriteTFileSkeleton(int defaultCompression)
For a TFile container written by a C file stream, write the header and TFile object.
void WriteBareFileSkeleton(int defaultCompression)
For a bare file, which is necessarily written by a C file stream, write file header.
void WriteTFileStreamerInfo()
Write the compressed streamer info record with the description of the RNTuple class.
std::uint64_t WriteNTupleHeader(const void *data, size_t nbytes, size_t lenHeader)
Writes the compressed header and registeres its location; lenHeader is the size of the uncompressed h...
void WriteIntoReservedBlob(const void *buffer, size_t nbytes, std::int64_t offset)
Write into a reserved record; the caller is responsible for making sure that the written byte range i...
Base class for all ROOT issued exceptions.
Definition RError.hxx:78
Representation of an RNTuple data set in a ROOT file.
Definition RNTuple.hxx:61
std::uint16_t fVersionMajor
Changing the major version indicates forward incompatible changes; such changes should correspond to ...
Definition RNTuple.hxx:79
std::uint64_t fSeekFooter
The file offset of the footer excluding the TKey part.
Definition RNTuple.hxx:91
std::uint64_t GetLenFooter() const
Definition RNTuple.hxx:116
std::uint64_t fMaxKeySize
The maximum size for a TKey payload. Payloads bigger than this size will be chained as multiple blobs...
Definition RNTuple.hxx:97
std::uint64_t GetNBytesHeader() const
Definition RNTuple.hxx:111
std::uint64_t GetLenHeader() const
Definition RNTuple.hxx:112
std::uint16_t fVersionMinor
Changing the minor version indicates new optional fields added to the RNTuple meta-data.
Definition RNTuple.hxx:81
std::uint16_t fVersionEpoch
Version of the RNTuple binary format that the writer supports (see specification).
Definition RNTuple.hxx:75
std::uint16_t GetVersionEpoch() const
Definition RNTuple.hxx:105
std::uint64_t fNBytesFooter
The size of the compressed ntuple footer.
Definition RNTuple.hxx:93
std::uint64_t fLenFooter
The size of the uncompressed ntuple footer.
Definition RNTuple.hxx:95
std::uint64_t GetNBytesFooter() const
Definition RNTuple.hxx:115
std::uint64_t GetMaxKeySize() const
Definition RNTuple.hxx:117
std::uint64_t GetSeekHeader() const
Definition RNTuple.hxx:110
std::uint64_t fLenHeader
The size of the uncompressed ntuple header.
Definition RNTuple.hxx:89
std::uint64_t fNBytesHeader
The size of the compressed ntuple header.
Definition RNTuple.hxx:87
std::uint16_t GetVersionMinor() const
Definition RNTuple.hxx:107
std::uint16_t fVersionPatch
Changing the patch version indicates new backported features from newer binary format versions.
Definition RNTuple.hxx:83
std::uint16_t GetVersionMajor() const
Definition RNTuple.hxx:106
std::uint16_t GetVersionPatch() const
Definition RNTuple.hxx:108
std::uint64_t GetSeekFooter() const
Definition RNTuple.hxx:114
std::uint64_t fSeekHeader
The file offset of the header excluding the TKey part.
Definition RNTuple.hxx:85
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
The RRawFile provides read-only access to local and remote files.
Definition RRawFile.hxx:43
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:53
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
Int_t Sizeof() const override
Return the size in bytes of the key header structure.
Definition TKey.cxx:1342
Int_t fVersion
Key version identifier.
Definition TKey.h:39
Short_t fKeylen
Number of bytes for the key itself.
Definition TKey.h:43
Long64_t fSeekKey
Location of object on file.
Definition TKey.h:45
virtual void Create(Int_t nbytes, TFile *f=nullptr)
Create a TKey object of specified size.
Definition TKey.cxx:460
TString fClassName
Object Class name.
Definition TKey.h:47
struct void * fTypeName
Definition cppyy.h:9
#define Swap(a, b)
Definition geom.c:201
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Helper templated class for swapping bytes; specializations for N={2,4,8} are provided below.
Definition Byteswap.h:124
void Write(const void *buffer, size_t nbytes, std::int64_t offset)
Low-level writing using a TFile.
std::uint64_t WriteKey(const void *buffer, size_t nbytes, size_t len)
Writes an RBlob opaque key with the provided buffer as data record and returns the offset of the reco...
std::unique_ptr< ROOT::Experimental::Internal::RTFileControlBlock > fControlBlock
Keeps track of TFile control structures, which need to be updated on committing the data set.
void Write(const void *buffer, size_t nbytes, std::int64_t offset=-1)
Writes bytes in the open stream, either at fFilePos or at the given offset.
std::uint64_t WriteKey(const void *buffer, std::size_t nbytes, std::size_t len, std::int64_t offset=-1, std::uint64_t directoryOffset=100, const std::string &className="", const std::string &objectName="", const std::string &title="")
Writes a TKey including the data record, given by buffer, into fFile; returns the file offset to the ...
If a TFile container is written by a C stream (simple file), on dataset commit, the file header and t...
auto * tt
Definition textangle.C:16