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