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