Logo ROOT  
Reference Guide
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/RMiniFile.hxx"
17
18#include <ROOT/RRawFile.hxx>
19#include <ROOT/RNTupleZip.hxx>
20
21#include <TError.h>
22#include <TFile.h>
23#include <TKey.h>
24
25#include <algorithm>
26#include <cstdio>
27#include <cstring>
28#include <iostream>
29#include <string>
30#include <utility>
31#include <chrono>
32
33namespace {
34
35// The following types are used to read and write the TFile binary format
36
37/// Big-endian 16-bit unsigned integer
38class RUInt16BE {
39private:
40 std::uint16_t fValBE = 0;
41 static std::uint16_t Swap(std::uint16_t val) {
42 return (val & 0x00FF) << 8 | (val & 0xFF00) >> 8;
43 }
44public:
45 RUInt16BE() = default;
46 explicit RUInt16BE(const std::uint16_t val) : fValBE(Swap(val)) {}
47 operator std::uint16_t() const {
48 return Swap(fValBE);
49 }
50 RUInt16BE& operator =(const std::uint16_t val) {
51 fValBE = Swap(val);
52 return *this;
53 }
54};
55
56/// Big-endian 32-bit unsigned integer
57class RUInt32BE {
58private:
59 std::uint32_t fValBE = 0;
60 static std::uint32_t Swap(std::uint32_t val) {
61 auto x = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
62 return (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
63 }
64public:
65 RUInt32BE() = default;
66 explicit RUInt32BE(const std::uint32_t val) : fValBE(Swap(val)) {}
67 operator std::uint32_t() const {
68 return Swap(fValBE);
69 }
70 RUInt32BE& operator =(const std::uint32_t val) {
71 fValBE = Swap(val);
72 return *this;
73 }
74};
75
76/// Big-endian 32-bit signed integer
77class RInt32BE {
78private:
79 std::int32_t fValBE = 0;
80 static std::int32_t Swap(std::int32_t val) {
81 auto x = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
82 return (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
83 }
84public:
85 RInt32BE() = default;
86 explicit RInt32BE(const std::int32_t val) : fValBE(Swap(val)) {}
87 operator std::int32_t() const {
88 return Swap(fValBE);
89 }
90 RInt32BE& operator =(const std::int32_t val) {
91 fValBE = Swap(val);
92 return *this;
93 }
94};
95
96/// Big-endian 64-bit unsigned integer
97class RUInt64BE {
98private:
99 std::uint64_t fValBE = 0;
100 static std::uint64_t Swap(std::uint64_t val) {
101 auto x = (val & 0x00000000FFFFFFFF) << 32 | (val & 0xFFFFFFFF00000000) >> 32;
102 x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
103 return (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
104 }
105public:
106 RUInt64BE() = default;
107 explicit RUInt64BE(const std::uint64_t val) : fValBE(Swap(val)) {}
108 operator std::uint64_t() const {
109 return Swap(fValBE);
110 }
111 RUInt64BE& operator =(const std::uint64_t val) {
112 fValBE = Swap(val);
113 return *this;
114 }
115};
116
117/// Composition of class RNTuple as being interpreted by TFile
118constexpr std::int32_t ChecksumRNTupleClass() {
119 const char ident[] = "ROOT::Experimental::RNTuple"
120 "fVersion"
121 "unsigned int"
122 "fSize"
123 "unsigned int"
124 "fSeekHeader"
125 "unsigned long"
126 "fNBytesHeader"
127 "unsigned int"
128 "fLenHeader"
129 "unsigned int"
130 "fSeekFooter"
131 "unsigned long"
132 "fNBytesFooter"
133 "unsigned int"
134 "fLenFooter"
135 "unsigned int"
136 "fReserved"
137 "unsigned long";
138 std::int32_t id = 0;
139 for (unsigned i = 0; i < (sizeof(ident) - 1); i++)
140 id = static_cast<std::int32_t>(static_cast<std::int64_t>(id) * 3 + ident[i]);
141 return id;
142}
143
144
145#pragma pack(push, 1)
146/// A name (type, identifies, ...) in the TFile binary format
147struct RTFString {
148 char fLName{0};
149 char fData[255];
150 RTFString() = default;
151 RTFString(const std::string &str) {
152 R__ASSERT(str.length() < 256);
153 fLName = str.length();
154 memcpy(fData, str.data(), fLName);
155 }
156 char GetSize() const { return 1 + fLName; }
157};
158
159/// The timestamp format used in TFile; the default constructor initializes with the current time
160struct RTFDatetime {
161 RUInt32BE fDatetime;
162 RTFDatetime() {
163 auto now = std::chrono::system_clock::now();
164 auto tt = std::chrono::system_clock::to_time_t(now);
165 auto tm = *localtime(&tt);
166 fDatetime = (tm.tm_year + 1900 - 1995) << 26 | (tm.tm_mon + 1) << 22 | tm.tm_mday << 17 |
167 tm.tm_hour << 12 | tm.tm_min << 6 | tm.tm_sec;
168 }
169 explicit RTFDatetime(RUInt32BE val) : fDatetime(val) {}
170};
171
172/// The key part of a TFile record excluding the class, object, and title names
173struct RTFKey {
174 RInt32BE fNbytes{0};
175 RUInt16BE fVersion{4};
176 RUInt32BE fObjLen{0};
177 RTFDatetime fDatetime;
178 RUInt16BE fKeyLen{0};
179 RUInt16BE fCycle{1};
180 union {
181 struct {
182 RUInt32BE fSeekKey{0};
183 RUInt32BE fSeekPdir{0};
184 } fInfoShort;
185 struct {
186 RUInt64BE fSeekKey{0};
187 RUInt64BE fSeekPdir{0};
188 } fInfoLong;
189 };
190
191 std::uint32_t fKeyHeaderSize{18 + sizeof(fInfoShort)}; // not part of serialization
192
193 RTFKey() : fInfoShort() {}
194 RTFKey(std::uint64_t seekKey, std::uint64_t seekPdir,
195 const RTFString &clName, const RTFString &objName, const RTFString &titleName,
196 std::uint32_t szObjInMem, std::uint32_t szObjOnDisk = 0)
197 {
198 fObjLen = szObjInMem;
199 if ((seekKey > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) ||
200 (seekPdir > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())))
201 {
202 fKeyHeaderSize = 18 + sizeof(fInfoLong);
203 fKeyLen = fKeyHeaderSize + clName.GetSize() + objName.GetSize() + titleName.GetSize();
204 fInfoLong.fSeekKey = seekKey;
205 fInfoLong.fSeekPdir = seekPdir;
206 fVersion = fVersion + 1000;
207 } else {
208 fKeyHeaderSize = 18 + sizeof(fInfoShort);
209 fKeyLen = fKeyHeaderSize + clName.GetSize() + objName.GetSize() + titleName.GetSize();
210 fInfoShort.fSeekKey = seekKey;
211 fInfoShort.fSeekPdir = seekPdir;
212 }
213 fNbytes = fKeyLen + ((szObjOnDisk == 0) ? szObjInMem : szObjOnDisk);
214 }
215
216 std::uint32_t GetSize() const {
217 // Negative size indicates a gap in the file
218 if (fNbytes < 0)
219 return -fNbytes;
220 return fNbytes;
221 }
222
223 std::uint32_t GetHeaderSize() const {
224 if (fVersion >= 1000)
225 return 18 + sizeof(fInfoLong);
226 return 18 + sizeof(fInfoShort);
227 }
228
229 std::uint64_t GetSeekKey() const {
230 if (fVersion >= 1000)
231 return fInfoLong.fSeekKey;
232 return fInfoShort.fSeekKey;
233 }
234};
235
236/// The TFile global header
237struct RTFHeader {
238 char fMagic[4]{ 'r', 'o', 'o', 't' };
239 RUInt32BE fVersion{(ROOT_VERSION_CODE >> 16)*10000 +
240 ((ROOT_VERSION_CODE & 0xFF00) >> 8) * 100 +
241 (ROOT_VERSION_CODE & 0xFF)};
242 RUInt32BE fBEGIN{100};
243 union {
244 struct {
245 RUInt32BE fEND{0};
246 RUInt32BE fSeekFree{0};
247 RUInt32BE fNbytesFree{0};
248 RUInt32BE fNfree{1};
249 RUInt32BE fNbytesName{0};
250 unsigned char fUnits{4};
251 RUInt32BE fCompress{0};
252 RUInt32BE fSeekInfo{0};
253 RUInt32BE fNbytesInfo{0};
254 } fInfoShort;
255 struct {
256 RUInt64BE fEND{0};
257 RUInt64BE fSeekFree{0};
258 RUInt32BE fNbytesFree{0};
259 RUInt32BE fNfree{1};
260 RUInt32BE fNbytesName{0};
261 unsigned char fUnits{8};
262 RUInt32BE fCompress{0};
263 RUInt64BE fSeekInfo{0};
264 RUInt32BE fNbytesInfo{0};
265 } fInfoLong;
266 };
267
268 RTFHeader() : fInfoShort() {}
269 RTFHeader(int compression) : fInfoShort() {
270 fInfoShort.fCompress = compression;
271 }
272
273 void SetBigFile() {
274 if (fVersion >= 1000000)
275 return;
276
277 std::uint32_t end = fInfoShort.fEND;
278 std::uint32_t seekFree = fInfoShort.fSeekFree;
279 std::uint32_t nbytesFree = fInfoShort.fNbytesFree;
280 std::uint32_t nFree = fInfoShort.fNfree;
281 std::uint32_t nbytesName = fInfoShort.fNbytesName;
282 std::uint32_t compress = fInfoShort.fCompress;
283 std::uint32_t seekInfo = fInfoShort.fSeekInfo;
284 std::uint32_t nbytesInfo = fInfoShort.fNbytesInfo;
285 fInfoLong.fEND = end;
286 fInfoLong.fSeekFree = seekFree;
287 fInfoLong.fNbytesFree = nbytesFree;
288 fInfoLong.fNfree = nFree;
289 fInfoLong.fNbytesName = nbytesName;
290 fInfoLong.fUnits = 8;
291 fInfoLong.fCompress = compress;
292 fInfoLong.fSeekInfo = seekInfo;
293 fInfoLong.fNbytesInfo = nbytesInfo;
294 fVersion = fVersion + 1000000;
295 }
296
297 bool IsBigFile(std::uint64_t offset = 0) const {
298 return (fVersion >= 1000000) || (offset > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max()));
299 }
300
301 std::uint32_t GetSize() const {
302 std::uint32_t sizeHead = 4 + sizeof(fVersion) + sizeof(fBEGIN);
303 if (IsBigFile()) return sizeHead + sizeof(fInfoLong);
304 return sizeHead + sizeof(fInfoShort);
305 }
306
307 std::uint64_t GetEnd() const {
308 if (IsBigFile()) return fInfoLong.fEND;
309 return fInfoShort.fEND;
310 }
311
312 void SetEnd(std::uint64_t value) {
313 if (IsBigFile(value)) {
314 SetBigFile();
315 fInfoLong.fEND = value;
316 } else {
317 fInfoShort.fEND = value;
318 }
319 }
320
321 std::uint64_t GetSeekFree() const {
322 if (IsBigFile()) return fInfoLong.fSeekFree;
323 return fInfoShort.fSeekFree;
324 }
325
326 void SetSeekFree(std::uint64_t value) {
327 if (IsBigFile(value)) {
328 SetBigFile();
329 fInfoLong.fSeekFree = value;
330 } else {
331 fInfoShort.fSeekFree = value;
332 }
333 }
334
335 void SetNbytesFree(std::uint32_t value) {
336 if (IsBigFile()) {
337 fInfoLong.fNbytesFree = value;
338 } else {
339 fInfoShort.fNbytesFree = value;
340 }
341 }
342
343 void SetNbytesName(std::uint32_t value) {
344 if (IsBigFile()) {
345 fInfoLong.fNbytesName = value;
346 } else {
347 fInfoShort.fNbytesName = value;
348 }
349 }
350
351 std::uint64_t GetSeekInfo() const {
352 if (IsBigFile()) return fInfoLong.fSeekInfo;
353 return fInfoShort.fSeekInfo;
354 }
355
356 void SetSeekInfo(std::uint64_t value) {
357 if (IsBigFile(value)) {
358 SetBigFile();
359 fInfoLong.fSeekInfo = value;
360 } else {
361 fInfoShort.fSeekInfo = value;
362 }
363 }
364
365 void SetNbytesInfo(std::uint32_t value) {
366 if (IsBigFile()) {
367 fInfoLong.fNbytesInfo = value;
368 } else {
369 fInfoShort.fNbytesInfo = value;
370 }
371 }
372
373 void SetCompression(std::uint32_t value) {
374 if (IsBigFile()) {
375 fInfoLong.fCompress = value;
376 } else {
377 fInfoShort.fCompress = value;
378 }
379 }
380};
381
382
383/// A reference to an unused byte-range in a TFile
384struct RTFFreeEntry {
385 RUInt16BE fVersion{1};
386 union {
387 struct {
388 RUInt32BE fFirst{0};
389 RUInt32BE fLast{0};
390 } fInfoShort;
391 struct {
392 RUInt64BE fFirst{0};
393 RUInt64BE fLast{0};
394 } fInfoLong;
395 };
396
397 RTFFreeEntry() : fInfoShort() {}
398 void Set(std::uint64_t first, std::uint64_t last) {
399 if (last > static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) {
400 fVersion = fVersion + 1000;
401 fInfoLong.fFirst = first;
402 fInfoLong.fLast = last;
403 } else {
404 fInfoShort.fFirst = first;
405 fInfoShort.fLast = last;
406 }
407 }
408 std::uint32_t GetSize() { return (fVersion >= 1000) ? 18 : 10; }
409};
410
411/// Streamer info for TObject
412struct RTFObject {
413 RUInt16BE fVersion{1};
414 RUInt32BE fUniqueID{0}; // unused
415 RUInt32BE fBits;
416 explicit RTFObject(std::uint32_t bits) : fBits(bits) {}
417};
418
419/// Streamer info for data member RNTuple::fVersion
420struct RTFStreamerElementVersion {
421 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementVersion) - sizeof(RUInt32BE))};
422 RUInt16BE fVersion{4};
423
424 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 10)};
425 RUInt16BE fVersionNamed{1};
426 RTFObject fObjectNamed{0x02000000 | 0x01000000};
427 char fLName = 8;
428 char fName[8]{ 'f', 'V', 'e', 'r', 's', 'i', 'o', 'n' };
429 char fLTitle = 0;
430
431 RUInt32BE fType{13};
432 RUInt32BE fSize{4};
433 RUInt32BE fArrLength{0};
434 RUInt32BE fArrDim{0};
435 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
436 char fLTypeName = 12;
437 char fTypeName[12]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'i', 'n', 't' };
438};
439
440/// Streamer info for data member RNTuple::fSize
441struct RTFStreamerElementSize {
442 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementSize) - sizeof(RUInt32BE))};
443 RUInt16BE fVersion{4};
444
445 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 7)};
446 RUInt16BE fVersionNamed{1};
447 RTFObject fObjectNamed{0x02000000 | 0x01000000};
448 char fLName = 5;
449 char fName[5]{ 'f', 'S', 'i', 'z', 'e' };
450 char fLTitle = 0;
451
452 RUInt32BE fType{13};
453 RUInt32BE fSize{4};
454 RUInt32BE fArrLength{0};
455 RUInt32BE fArrDim{0};
456 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
457 char fLTypeName = 12;
458 char fTypeName[12]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'i', 'n', 't' };
459};
460
461/// Streamer info for data member RNTuple::fSeekHeader
462struct RTFStreamerElementSeekHeader {
463 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementSeekHeader) - sizeof(RUInt32BE))};
464 RUInt16BE fVersion{4};
465
466 RUInt32BE fByteCountNamed{0x40000000 |
467 (sizeof(RUInt16BE) + sizeof(RTFObject) + 13)};
468 RUInt16BE fVersionNamed{1};
469 RTFObject fObjectNamed{0x02000000 | 0x01000000};
470 char fLName = 11;
471 char fName[11]{ 'f', 'S', 'e', 'e', 'k', 'H', 'e', 'a', 'd', 'e', 'r' };
472 char fLTitle = 0;
473
474 RUInt32BE fType{14};
475 RUInt32BE fSize{8};
476 RUInt32BE fArrLength{0};
477 RUInt32BE fArrDim{0};
478 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
479 char fLTypeName = 13;
480 char fTypeName[13]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g' };
481};
482
483/// Streamer info for data member RNTuple::fNbytesHeader
484struct RTFStreamerElementNBytesHeader {
485 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementNBytesHeader) - sizeof(RUInt32BE))};
486 RUInt16BE fVersion{4};
487
488 RUInt32BE fByteCountNamed{0x40000000 |
489 (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
490 RUInt16BE fVersionNamed{1};
491 RTFObject fObjectNamed{0x02000000 | 0x01000000};
492 char fLName = 13;
493 char fName[13]{ 'f', 'N', 'B', 'y', 't', 'e', 's', 'H', 'e', 'a', 'd', 'e', 'r' };
494 char fLTitle = 0;
495
496 RUInt32BE fType{13};
497 RUInt32BE fSize{4};
498 RUInt32BE fArrLength{0};
499 RUInt32BE fArrDim{0};
500 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
501 char fLTypeName = 12;
502 char fTypeName[12]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'i', 'n', 't' };
503};
504
505/// Streamer info for data member RNTuple::fLenHeader
506struct RTFStreamerElementLenHeader {
507 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementLenHeader) - sizeof(RUInt32BE))};
508 RUInt16BE fVersion{4};
509
510 RUInt32BE fByteCountNamed{0x40000000 |
511 (sizeof(RUInt16BE) + sizeof(RTFObject) + 12)};
512 RUInt16BE fVersionNamed{1};
513 RTFObject fObjectNamed{0x02000000 | 0x01000000};
514 char fLName = 10;
515 char fName[10]{ 'f', 'L', 'e', 'n', 'H', 'e', 'a', 'd', 'e', 'r' };
516 char fLTitle = 0;
517
518 RUInt32BE fType{13};
519 RUInt32BE fSize{4};
520 RUInt32BE fArrLength{0};
521 RUInt32BE fArrDim{0};
522 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
523 char fLTypeName = 12;
524 char fTypeName[12]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'i', 'n', 't' };
525};
526
527/// Streamer info for data member RNTuple::fSeekFooter
528struct RTFStreamerElementSeekFooter {
529 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementSeekFooter) - sizeof(RUInt32BE))};
530 RUInt16BE fVersion{4};
531
532 RUInt32BE fByteCountNamed{0x40000000 |
533 (sizeof(RUInt16BE) + sizeof(RTFObject) + 13)};
534 RUInt16BE fVersionNamed{1};
535 RTFObject fObjectNamed{0x02000000 | 0x01000000};
536 char fLName = 11;
537 char fName[11]{ 'f', 'S', 'e', 'e', 'k', 'F', 'o', 'o', 't', 'e', 'r' };
538 char fLTitle = 0;
539
540 RUInt32BE fType{14};
541 RUInt32BE fSize{8};
542 RUInt32BE fArrLength{0};
543 RUInt32BE fArrDim{0};
544 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
545 char fLTypeName = 13;
546 char fTypeName[13]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g' };
547};
548
549/// Streamer info for data member RNTuple::fNbytesFooter
550struct RTFStreamerElementNBytesFooter {
551 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementNBytesFooter) - sizeof(RUInt32BE))};
552 RUInt16BE fVersion{4};
553
554 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 15)};
555 RUInt16BE fVersionNamed{1};
556 RTFObject fObjectNamed{0x02000000 | 0x01000000};
557 char fLName = 13;
558 char fName[13]{ 'f', 'N', 'B', 'y', 't', 'e', 's', 'F', 'o', 'o', 't', 'e', 'r' };
559 char fLTitle = 0;
560
561 RUInt32BE fType{13};
562 RUInt32BE fSize{4};
563 RUInt32BE fArrLength{0};
564 RUInt32BE fArrDim{0};
565 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
566 char fLTypeName = 12;
567 char fTypeName[12]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'i', 'n', 't' };
568};
569
570/// Streamer info for data member RNTuple::fLenFooter
571struct RTFStreamerElementLenFooter {
572 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementLenFooter) - sizeof(RUInt32BE))};
573 RUInt16BE fVersion{4};
574
575 RUInt32BE fByteCountNamed{0x40000000 | (sizeof(RUInt16BE) + sizeof(RTFObject) + 12)};
576 RUInt16BE fVersionNamed{1};
577 RTFObject fObjectNamed{0x02000000 | 0x01000000};
578 char fLName = 10;
579 char fName[10]{ 'f', 'L', 'e', 'n', 'F', 'o', 'o', 't', 'e', 'r' };
580 char fLTitle = 0;
581
582 RUInt32BE fType{13};
583 RUInt32BE fSize{4};
584 RUInt32BE fArrLength{0};
585 RUInt32BE fArrDim{0};
586 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
587 char fLTypeName = 12;
588 char fTypeName[12]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'i', 'n', 't' };
589};
590
591/// Streamer info for data member RNTuple::fReserved
592struct RTFStreamerElementReserved {
593 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerElementReserved) - sizeof(RUInt32BE))};
594 RUInt16BE fVersion{4};
595
596 RUInt32BE fByteCountNamed{0x40000000 |
597 (sizeof(RUInt16BE) + sizeof(RTFObject) + 11)};
598 RUInt16BE fVersionNamed{1};
599 RTFObject fObjectNamed{0x02000000 | 0x01000000};
600 char fLName = 9;
601 char fName[9]{ 'f', 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd' };
602 char fLTitle = 0;
603
604 RUInt32BE fType{14};
605 RUInt32BE fSize{8};
606 RUInt32BE fArrLength{0};
607 RUInt32BE fArrDim{0};
608 char fMaxIndex[20]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
609 char fLTypeName = 13;
610 char fTypeName[13]{ 'u', 'n', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'l', 'o', 'n', 'g' };
611};
612
613/// Streamer info frame for data member RNTuple::fVersion
614struct RTFStreamerVersion {
615 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerVersion) - sizeof(RUInt32BE))};
616 RUInt32BE fNewClassTag{0xffffffff};
617 char fClassName[19]{'T', 'S', 't', 'r', 'e', 'a', 'm', 'e', 'r', 'B', 'a', 's', 'i', 'c', 'T', 'y', 'p', 'e', '\0'};
618 RUInt32BE fByteCountRemaining{0x40000000 |
619 (sizeof(RTFStreamerVersion) - 2 * sizeof(RUInt32BE) - 19 /* strlen(fClassName) + 1 */ - sizeof(RUInt32BE))};
620 RUInt16BE fVersion{2};
621 RTFStreamerElementVersion fStreamerElementVersion;
622};
623
624/// Streamer info frame for data member RNTuple::fSize
625struct RTFStreamerSize {
626 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerSize) - sizeof(RUInt32BE))};
627 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
628 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerSize) - 3 * sizeof(RUInt32BE))};
629 RUInt16BE fVersion{2};
630 RTFStreamerElementSize fStreamerElementSize;
631};
632
633/// Streamer info frame for data member RNTuple::fSeekHeader
634struct RTFStreamerSeekHeader {
635 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerSeekHeader) - sizeof(RUInt32BE))};
636 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
637 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerSeekHeader) - 3 * sizeof(RUInt32BE))};
638 RUInt16BE fVersion{2};
639 RTFStreamerElementSeekHeader fStreamerElementSeekHeader;
640};
641
642/// Streamer info frame for data member RNTuple::fNbytesHeader
643struct RTFStreamerNBytesHeader {
644 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerNBytesHeader) - sizeof(RUInt32BE))};
645 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
646 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerNBytesHeader) - 3 * sizeof(RUInt32BE))};
647 RUInt16BE fVersion{2};
648 RTFStreamerElementNBytesHeader fStreamerElementNBytesHeader;
649};
650
651/// Streamer info frame for data member RNTuple::fLenHeader
652struct RTFStreamerLenHeader {
653 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerLenHeader) - sizeof(RUInt32BE))};
654 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
655 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerLenHeader) - 3 * sizeof(RUInt32BE))};
656 RUInt16BE fVersion{2};
657 RTFStreamerElementLenHeader fStreamerElementLenHeader;
658};
659
660/// Streamer info frame for data member RNTuple::fSeekFooter
661struct RTFStreamerSeekFooter {
662 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerSeekFooter) - sizeof(RUInt32BE))};
663 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
664 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerSeekFooter) - 3 * sizeof(RUInt32BE))};
665 RUInt16BE fVersion{2};
666 RTFStreamerElementSeekFooter fStreamerElementSeekFooter;
667};
668
669/// Streamer info frame for data member RNTuple::fNBytesFooter
670struct RTFStreamerNBytesFooter {
671 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerNBytesFooter) - sizeof(RUInt32BE))};
672 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
673 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerNBytesFooter) - 3 * sizeof(RUInt32BE))};
674 RUInt16BE fVersion{2};
675 RTFStreamerElementNBytesFooter fStreamerElementNBytesFooter;
676};
677
678/// Streamer info frame for data member RNTuple::fLenFooter
679struct RTFStreamerLenFooter {
680 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerLenFooter) - sizeof(RUInt32BE))};
681 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
682 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerLenFooter) - 3 * sizeof(RUInt32BE))};
683 RUInt16BE fVersion{2};
684 RTFStreamerElementLenFooter fStreamerElementLenFooter;
685};
686
687/// Streamer info frame for data member RNTuple::fReserved
688struct RTFStreamerReserved {
689 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerReserved) - sizeof(RUInt32BE))};
690 RUInt32BE fClassTag{0x80000000}; // Fix-up after construction, or'd with 0x80000000
691 RUInt32BE fByteCountRemaining{0x40000000 | (sizeof(RTFStreamerReserved) - 3 * sizeof(RUInt32BE))};
692 RUInt16BE fVersion{2};
693 RTFStreamerElementReserved fStreamerElementReserved;
694};
695
696/// Streamer info for class RNTuple
697struct RTFStreamerInfoObject {
698 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerInfoObject) - sizeof(fByteCount))};
699 RUInt32BE fNewClassTag{0xffffffff};
700 char fClassName[14]{ 'T', 'S', 't', 'r', 'e', 'a', 'm', 'e', 'r', 'I', 'n', 'f', 'o', '\0' };
701 RUInt32BE fByteCountRemaining{0x40000000 |
702 (sizeof(RTFStreamerInfoObject) - 2 * sizeof(RUInt32BE) - 14 - sizeof(RUInt32BE))};
703 RUInt16BE fVersion{9};
704
705 RUInt32BE fByteCountNamed{0x40000000 |
706 (sizeof(RUInt16BE) + sizeof(RTFObject) + 29 /* strlen("ROOT::Experimental::RNTuple") + 2 */)};
707 RUInt16BE fVersionNamed{1};
708 RTFObject fObjectNamed{0x02000000 | 0x01000000 | 0x00010000};
709 char fLName = 27;
710 char fName[27]{ 'R', 'O', 'O', 'T', ':', ':',
711 'E', 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l', ':', ':',
712 'R', 'N', 'T', 'u', 'p', 'l', 'e'};
713 char fLTitle = 0;
714
715 RInt32BE fChecksum{ChecksumRNTupleClass()};
716 RUInt32BE fVersionRNTuple{1};
717
718 RUInt32BE fByteCountObjArr{0x40000000 |
719 (sizeof(RUInt32BE) + 10 /* strlen(TObjArray) + 1 */ + sizeof(RUInt32BE) +
720 sizeof(RUInt16BE) + sizeof(RTFObject) + 1 + 2*sizeof(RUInt32BE) +
721 sizeof(fStreamers))};
722 RUInt32BE fNewClassTagObjArray{0xffffffff};
723 char fClassNameObjArray[10]{'T', 'O', 'b', 'j', 'A', 'r', 'r', 'a', 'y', '\0'};
724 RUInt32BE fByteCountObjArrRemaining{0x40000000 |
725 (sizeof(RUInt16BE) + sizeof(RTFObject) + 1 + 2*sizeof(RUInt32BE) +
726 sizeof(fStreamers))};
727 RUInt16BE fVersionObjArr{3};
728 RTFObject fObjectObjArr{0x02000000};
729 char fNameObjArr{0};
730
731 RUInt32BE fNObjects{9};
732 RUInt32BE fLowerBound{0};
733
734 struct {
735 RTFStreamerVersion fStreamerVersion;
736 RTFStreamerSize fStreamerSize;
737 RTFStreamerSeekHeader fStreamerSeekHeader;
738 RTFStreamerNBytesHeader fStreamerNBytesHeader;
739 RTFStreamerLenHeader fStreamerLenHeader;
740 RTFStreamerSeekFooter fStreamerSeekFooter;
741 RTFStreamerNBytesFooter fStreamerNBytesFooter;
742 RTFStreamerLenFooter fStreamerLenFooter;
743 RTFStreamerReserved fStreamerReserved;
744 } fStreamers;
745};
746
747/// The list of streamer info objects, for a new ntuple contains only the RNTuple class
748struct RTFStreamerInfoList {
749 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFStreamerInfoList) - sizeof(fByteCount))};
750 RUInt16BE fVersion{5};
751 RTFObject fObject{0x02000000};
752 char fName{0};
753 RUInt32BE fNObjects{1};
754 RTFStreamerInfoObject fStreamerInfo;
755 char fEnd{0};
756
757 std::uint32_t GetSize() const { return sizeof(RTFStreamerInfoList); }
758};
759
760/// The header of the directory key index
761struct RTFKeyList {
762 RUInt32BE fNKeys;
763 std::uint32_t GetSize() const { return sizeof(RTFKeyList); }
764 explicit RTFKeyList(std::uint32_t nKeys) : fNKeys(nKeys) {}
765};
766
767/// A streamed TFile object
768struct RTFFile {
769 char fModified{0};
770 char fWritable{1};
771 RTFDatetime fDateC;
772 RTFDatetime fDateM;
773 RUInt32BE fNBytesKeys{0};
774 RUInt32BE fNBytesName{0};
775 // The version of the key has to tell whether offsets are 32bit or 64bit long
776 union {
777 struct {
778 RUInt32BE fSeekDir{100};
779 RUInt32BE fSeekParent{0};
780 RUInt32BE fSeekKeys{0};
781 } fInfoShort;
782 struct {
783 RUInt64BE fSeekDir{100};
784 RUInt64BE fSeekParent{0};
785 RUInt64BE fSeekKeys{0};
786 } fInfoLong;
787 };
788
789 RTFFile() : fInfoShort() {}
790
791 std::uint32_t GetSize(std::uint32_t versionKey = 0) const {
792 if (versionKey >= 1000)
793 return 18 + sizeof(fInfoLong);
794 return 18 + sizeof(fInfoShort);
795 }
796
797 std::uint64_t GetSeekKeys(std::uint32_t versionKey = 0) const {
798 if (versionKey >= 1000)
799 return fInfoLong.fSeekKeys;
800 return fInfoShort.fSeekKeys;
801 }
802};
803
804/// A streamed RNTuple class
805struct RTFNTuple {
806 RUInt32BE fByteCount{0x40000000 | (sizeof(RTFNTuple) - sizeof(fByteCount))};
807 RUInt16BE fVersionClass{0};
808 RInt32BE fChecksum{ChecksumRNTupleClass()};
809 RUInt32BE fVersionInternal{0};
810 RUInt32BE fSize{sizeof(ROOT::Experimental::RNTuple)};
811 RUInt64BE fSeekHeader{0};
812 RUInt32BE fNBytesHeader{0};
813 RUInt32BE fLenHeader{0};
814 RUInt64BE fSeekFooter{0};
815 RUInt32BE fNBytesFooter{0};
816 RUInt32BE fLenFooter{0};
817 RUInt64BE fReserved{0};
818
819 RTFNTuple() = default;
820 explicit RTFNTuple(const ROOT::Experimental::RNTuple &inMemoryNTuple) {
821 fVersionInternal = inMemoryNTuple.fVersion;
822 fSize = inMemoryNTuple.fSize;
823 fSeekHeader = inMemoryNTuple.fSeekHeader;
824 fNBytesHeader = inMemoryNTuple.fNBytesHeader;
825 fLenHeader = inMemoryNTuple.fLenHeader;
826 fSeekFooter = inMemoryNTuple.fSeekFooter;
827 fNBytesFooter = inMemoryNTuple.fNBytesFooter;
828 fLenFooter = inMemoryNTuple.fLenFooter;
829 fReserved = inMemoryNTuple.fReserved;
830 }
831 std::uint32_t GetSize() const { return sizeof(RTFNTuple); }
832 ROOT::Experimental::RNTuple ToRNTuple() const {
834 ntuple.fVersion = fVersionInternal;
835 ntuple.fSize = fSize;
836 ntuple.fSeekHeader = fSeekHeader;
837 ntuple.fNBytesHeader = fNBytesHeader;
838 ntuple.fLenHeader = fLenHeader;
839 ntuple.fSeekFooter = fSeekFooter;
840 ntuple.fNBytesFooter = fNBytesFooter;
841 ntuple.fLenFooter = fLenFooter;
842 ntuple.fReserved = fReserved;
843 return ntuple;
844 }
845};
846
847/// The bare file global header
848struct RBareFileHeader {
849 char fMagic[7]{ 'r', 'n', 't', 'u', 'p', 'l', 'e' };
850 RUInt32BE fRootVersion{(ROOT_VERSION_CODE >> 16) * 10000 +
851 ((ROOT_VERSION_CODE & 0xFF00) >> 8) * 100 +
852 (ROOT_VERSION_CODE & 0xFF)};
853 RUInt32BE fFormatVersion{1};
854 RUInt32BE fCompress{0};
855 RTFNTuple fNTuple;
856 // followed by the ntuple name
857};
858#pragma pack(pop)
859
860/// The artifical class name shown for opaque RNTuple keys (see TBasket)
861static constexpr char const *kBlobClassName = "RBlob";
862/// The class name of the RNTuple anchor
863static constexpr char const *kNTupleClassName = "ROOT::Experimental::RNTuple";
864
865/// The RKeyBlob writes an invsisble key into a TFile. That is, a key that is not indexed in the list of keys,
866/// like a TBasket.
867class RKeyBlob : public TKey {
868public:
869 explicit RKeyBlob(TFile *file) : TKey(file) {
870 fClassName = kBlobClassName;
871 fKeylen += strlen(kBlobClassName);
872 }
873
874 /// Register a new key for a data record of size nbytes
875 void Reserve(size_t nbytes, std::uint64_t *seekKey)
876 {
877 Create(nbytes);
878 *seekKey = fSeekKey;
879 }
880};
881
882} // anonymous namespace
883
884
885namespace ROOT {
886namespace Experimental {
887namespace Internal {
888/// If a TFile container is written by a C stream (simple file), on dataset commit, the file header needs to be updated
889/// and the RNTuple object needs to be written at the offset that was reserved on file creation
890struct RTFileControlBlock {
891 RTFHeader fHeader;
892 std::uint32_t fSeekNTuple{0};
893};
894} // namespace ROOT
895} // namespace Experimental
896} // namespace Internal
897
898
900 : fRawFile(rawFile)
901{
902}
903
905{
906 char ident[4];
907 ReadBuffer(ident, 4, 0);
908 if (std::string(ident, 4) == "root")
909 return GetNTupleProper(ntupleName);
910 fIsBare = true;
911 return GetNTupleBare(ntupleName);
912}
913
914
916{
917 RTFHeader fileHeader;
918 ReadBuffer(&fileHeader, sizeof(fileHeader), 0);
919
920 RTFKey key;
921 RTFString name;
922 ReadBuffer(&key, sizeof(key), fileHeader.fBEGIN);
923 auto offset = fileHeader.fBEGIN + key.fKeyLen;
924 ReadBuffer(&name, 1, offset);
925 offset += name.GetSize();
926 ReadBuffer(&name, 1, offset);
927 offset += name.GetSize();
928 RTFFile file;
929 ReadBuffer(&file, sizeof(file), offset);
930
931 RUInt32BE nKeys;
932 offset = file.GetSeekKeys(key.fVersion);
933 ReadBuffer(&key, sizeof(key), offset);
934 offset += key.fKeyLen;
935 ReadBuffer(&nKeys, sizeof(nKeys), offset);
936 offset += sizeof(nKeys);
937 bool found = false;
938 for (unsigned int i = 0; i < nKeys; ++i) {
939 ReadBuffer(&key, sizeof(key), offset);
940 auto offsetNextKey = offset + key.fKeyLen;
941
942 offset += key.GetHeaderSize();
943 ReadBuffer(&name, 1, offset);
944 offset += name.GetSize();
945 ReadBuffer(&name, 1, offset);
946 ReadBuffer(&name, name.GetSize(), offset);
947 if (std::string_view(name.fData, name.fLName) == ntupleName) {
948 found = true;
949 break;
950 }
951 offset = offsetNextKey;
952 }
953 R__ASSERT(found);
954
955 ReadBuffer(&key, sizeof(key), key.GetSeekKey());
956 offset = key.GetSeekKey() + key.fKeyLen;
957 RTFNTuple ntuple;
958 ReadBuffer(&ntuple, sizeof(ntuple), offset);
959 return ntuple.ToRNTuple();
960}
961
963{
964 RBareFileHeader fileHeader;
965 ReadBuffer(&fileHeader, sizeof(fileHeader), 0);
966 RTFString name;
967 auto offset = sizeof(fileHeader);
968 ReadBuffer(&name, 1, offset);
969 ReadBuffer(&name, name.GetSize(), offset);
970 R__ASSERT(std::string_view(name.fData, name.fLName) == ntupleName);
971 offset += name.GetSize();
972
973 RTFNTuple ntuple;
974 ReadBuffer(&ntuple, sizeof(ntuple), offset);
975 return ntuple.ToRNTuple();
976}
977
978
979void ROOT::Experimental::Internal::RMiniFileReader::ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset)
980{
981 auto nread = fRawFile->ReadAt(buffer, nbytes, offset);
982 R__ASSERT(nread == nbytes);
983}
984
985
986////////////////////////////////////////////////////////////////////////////////
987
988
990{
991 if (fFile)
992 fclose(fFile);
993}
994
995
997 const void *buffer, size_t nbytes, std::int64_t offset)
998{
999 R__ASSERT(fFile);
1000 size_t retval;
1001 if ((offset >= 0) && (static_cast<std::uint64_t>(offset) != fFilePos)) {
1002 retval = fseek(fFile, offset, SEEK_SET);
1003 R__ASSERT(retval == 0);
1004 fFilePos = offset;
1005 }
1006 retval = fwrite(buffer, 1, nbytes, fFile);
1007 R__ASSERT(retval == nbytes);
1008 fFilePos += nbytes;
1009}
1010
1011
1013 const void *buffer, std::size_t nbytes, std::size_t len, std::int64_t offset,
1014 std::uint64_t directoryOffset,
1015 const std::string &className,
1016 const std::string &objectName,
1017 const std::string &title)
1018{
1019 if (offset < 0)
1020 offset = fFilePos;
1021 RTFString strClass{className};
1022 RTFString strObject{objectName};
1023 RTFString strTitle{title};
1024
1025 RTFKey key(offset, directoryOffset, strClass, strObject, strTitle, len, nbytes);
1026 Write(&key, key.fKeyHeaderSize, offset);
1027 Write(&strClass, strClass.GetSize());
1028 Write(&strObject, strObject.GetSize());
1029 Write(&strTitle, strTitle.GetSize());
1030 auto offsetData = fFilePos;
1031 if (buffer)
1032 Write(buffer, nbytes);
1033
1034 return offsetData;
1035}
1036
1037
1038////////////////////////////////////////////////////////////////////////////////
1039
1040
1042 const void *buffer, size_t nbytes, std::int64_t offset)
1043{
1044 R__ASSERT(fFile);
1045 fFile->Seek(offset);
1046 bool rv = fFile->WriteBuffer((char *)(buffer), nbytes);
1047 R__ASSERT(!rv);
1048}
1049
1050
1052 const void *buffer, size_t nbytes, size_t len)
1053{
1054 std::uint64_t offsetKey;
1055 RKeyBlob keyBlob(fFile);
1056 keyBlob.Reserve(nbytes, &offsetKey);
1057
1058 auto offset = offsetKey;
1059 RTFString strClass{kBlobClassName};
1060 RTFString strObject;
1061 RTFString strTitle;
1062 RTFKey keyHeader(offset, offset, strClass, strObject, strTitle, len, nbytes);
1063
1064 Write(&keyHeader, keyHeader.fKeyHeaderSize, offset);
1065 offset += keyHeader.fKeyHeaderSize;
1066 Write(&strClass, strClass.GetSize(), offset);
1067 offset += strClass.GetSize();
1068 Write(&strObject, strObject.GetSize(), offset);
1069 offset += strObject.GetSize();
1070 Write(&strTitle, strTitle.GetSize(), offset);
1071 offset += strTitle.GetSize();
1072 auto offsetData = offset;
1073 Write(buffer, nbytes, offset);
1074
1075 return offsetData;
1076}
1077
1078
1079////////////////////////////////////////////////////////////////////////////////
1080
1081
1083 : fNTupleName(name)
1084{
1085 fFileSimple.fControlBlock = std::make_unique<ROOT::Experimental::Internal::RTFileControlBlock>();
1086}
1087
1088
1090{
1091}
1092
1093
1095 std::string_view ntupleName, std::string_view path, int defaultCompression, ENTupleContainerFormat containerFormat)
1096{
1097 std::string fileName(path);
1098 size_t idxDirSep = fileName.find_last_of("\\/");
1099 if (idxDirSep != std::string::npos) {
1100 fileName.erase(0, idxDirSep + 1);
1101 }
1102 FILE *fileStream = fopen(std::string(path.data(), path.size()).c_str(), "wb");
1103 R__ASSERT(fileStream);
1104
1105 auto writer = new RNTupleFileWriter(ntupleName);
1106 writer->fFileSimple.fFile = fileStream;
1107 writer->fFileName = fileName;
1108
1109 switch (containerFormat) {
1111 writer->WriteTFileSkeleton(defaultCompression);
1112 break;
1114 writer->fIsBare = true;
1115 writer->WriteBareFileSkeleton(defaultCompression);
1116 break;
1117 default:
1118 R__ASSERT(false && "Internal error: unhandled container format");
1119 }
1120
1121 return writer;
1122}
1123
1124
1126 std::string_view ntupleName, std::string_view path, std::unique_ptr<TFile> &file)
1127{
1128 file = std::unique_ptr<TFile>(TFile::Open(std::string(path.data(), path.size()).c_str(), "RECREATE"));
1129 R__ASSERT(file && !file->IsZombie());
1130
1131 auto writer = new RNTupleFileWriter(ntupleName);
1132 writer->fFileProper.fFile = file.get();
1133 return writer;
1134}
1135
1136
1138 std::string_view ntupleName, TFile &file)
1139{
1140 auto writer = new RNTupleFileWriter(ntupleName);
1141 writer->fFileProper.fFile = &file;
1142 return writer;
1143}
1144
1145
1147{
1148 if (fFileProper) {
1149 // Easy case, the ROOT file header and the RNTuple streaming is taken care of by TFile
1150 fFileProper.fFile->WriteObject(&fNTupleAnchor, fNTupleName.c_str());
1151 fFileProper.fFile->Write();
1152 return;
1153 }
1154
1155 // Writing by C file stream: prepare the container format header and stream the RNTuple anchor object
1156 R__ASSERT(fFileSimple);
1157 RTFNTuple ntupleOnDisk(fNTupleAnchor);
1158
1159 if (fIsBare) {
1160 fFileSimple.Write(&ntupleOnDisk, ntupleOnDisk.GetSize(), fFileSimple.fControlBlock->fSeekNTuple);
1161 fflush(fFileSimple.fFile);
1162 return;
1163 }
1164
1165 fFileSimple.fControlBlock->fHeader.SetSeekFree(fFileSimple.fFilePos);
1166 RTFString strEmpty;
1167 RTFFreeEntry freeEntry;
1168 RTFKey keyFreeList(fFileSimple.fControlBlock->fHeader.GetSeekFree(), 100,
1169 strEmpty, strEmpty, strEmpty, freeEntry.GetSize());
1170 std::uint64_t firstFree = fFileSimple.fControlBlock->fHeader.GetSeekFree() + keyFreeList.GetSize();
1171 freeEntry.Set(firstFree, std::max(2000000000ULL, ((firstFree / 1000000000ULL) + 1) * 1000000000ULL));
1172 fFileSimple.WriteKey(
1173 &freeEntry, freeEntry.GetSize(), freeEntry.GetSize(), fFileSimple.fControlBlock->fHeader.GetSeekFree(),
1174 100, "", "", "");
1175 fFileSimple.fControlBlock->fHeader.SetNbytesFree(fFileSimple.fFilePos -
1176 fFileSimple.fControlBlock->fHeader.GetSeekFree());
1177 fFileSimple.fControlBlock->fHeader.SetEnd(fFileSimple.fFilePos);
1178
1179 auto szNTuple = ntupleOnDisk.GetSize();
1180 fFileSimple.WriteKey(&ntupleOnDisk, szNTuple, szNTuple, fFileSimple.fControlBlock->fSeekNTuple, 100,
1181 kNTupleClassName, fNTupleName);
1182
1183 fFileSimple.Write(&fFileSimple.fControlBlock->fHeader, fFileSimple.fControlBlock->fHeader.GetSize(), 0);
1184 fflush(fFileSimple.fFile);
1185}
1186
1187
1188std::uint64_t ROOT::Experimental::Internal::RNTupleFileWriter::WriteBlob(const void *data, size_t nbytes, size_t len)
1189{
1190 std::uint64_t offset;
1191 if (fFileSimple) {
1192 if (fIsBare) {
1193 offset = fFileSimple.fFilePos;
1194 fFileSimple.Write(data, nbytes);
1195 } else {
1196 offset = fFileSimple.WriteKey(data, nbytes, len, -1, 100, kBlobClassName);
1197 }
1198 } else {
1199 offset = fFileProper.WriteKey(data, nbytes, len);
1200 }
1201 return offset;
1202}
1203
1204
1206 const void *data, size_t nbytes, size_t lenHeader)
1207{
1208 auto offset = WriteBlob(data, nbytes, lenHeader);
1209 fNTupleAnchor.fLenHeader = lenHeader;
1210 fNTupleAnchor.fNBytesHeader = nbytes;
1211 fNTupleAnchor.fSeekHeader = offset;
1212 return offset;
1213}
1214
1215
1217 const void *data, size_t nbytes, size_t lenFooter)
1218{
1219 auto offset = WriteBlob(data, nbytes, lenFooter);
1220 fNTupleAnchor.fLenFooter = lenFooter;
1221 fNTupleAnchor.fNBytesFooter = nbytes;
1222 fNTupleAnchor.fSeekFooter = offset;
1223 return offset;
1224}
1225
1226
1228{
1229 RBareFileHeader bareHeader;
1230 bareHeader.fCompress = defaultCompression;
1231 fFileSimple.Write(&bareHeader, sizeof(bareHeader), 0);
1232 RTFString ntupleName{fNTupleName};
1233 fFileSimple.Write(&ntupleName, ntupleName.GetSize());
1234
1235 // Write zero-initialized ntuple to reserve the space; will be overwritten on commit
1236 RTFNTuple ntupleOnDisk;
1237 fFileSimple.fControlBlock->fSeekNTuple = fFileSimple.fFilePos;
1238 fFileSimple.Write(&ntupleOnDisk, ntupleOnDisk.GetSize());
1239}
1240
1241
1243{
1244 RTFString strTFile{"TFile"};
1245 RTFString strFileName{fFileName};
1246 RTFString strTList{"TList"};
1247 RTFString strStreamerInfo{"StreamerInfo"};
1248 RTFString strStreamerTitle{"Doubly linked list"};
1249 RTFString strRNTupleClass{"ROOT::Experimental::RNTuple"};
1250 RTFString strRNTupleName{fNTupleName};
1251 RTFString strEmpty;
1252
1253 fFileSimple.fControlBlock->fHeader = RTFHeader(defaultCompression);
1254
1255 // First record of the file: the TFile object at offset 100
1256 RTFFile fileRoot;
1257 RTFKey keyRoot(100, 0, strTFile, strFileName, strEmpty,
1258 fileRoot.GetSize() + strFileName.GetSize() + strEmpty.GetSize());
1259 std::uint32_t nbytesName = keyRoot.fKeyLen + strFileName.GetSize() + 1;
1260 fileRoot.fNBytesName = nbytesName;
1261 fFileSimple.fControlBlock->fHeader.SetNbytesName(nbytesName);
1262
1263 // Second record: the compressed StreamerInfo with the description of the RNTuple class.
1264 // This record usually comes at the end, but in this context we create a file with a single RNTuple only,
1265 // so we know beforehand all the types.
1266 fFileSimple.fControlBlock->fHeader.SetSeekInfo(100 + keyRoot.GetSize());
1267 RTFKey keyStreamerInfo(
1268 fFileSimple.fControlBlock->fHeader.GetSeekInfo(), 100, strTList, strStreamerInfo, strStreamerTitle, 0);
1269 RTFStreamerInfoList streamerInfo;
1270 auto classTagOffset = keyStreamerInfo.fKeyLen +
1271 offsetof(struct RTFStreamerInfoList, fStreamerInfo) +
1272 offsetof(struct RTFStreamerInfoObject, fStreamers) +
1273 offsetof(struct RTFStreamerVersion, fNewClassTag) + 2;
1274 streamerInfo.fStreamerInfo.fStreamers.fStreamerSize.fClassTag = 0x80000000 | classTagOffset;
1275 streamerInfo.fStreamerInfo.fStreamers.fStreamerSeekHeader.fClassTag = 0x80000000 | classTagOffset;
1276 streamerInfo.fStreamerInfo.fStreamers.fStreamerNBytesHeader.fClassTag = 0x80000000 | classTagOffset;
1277 streamerInfo.fStreamerInfo.fStreamers.fStreamerLenHeader.fClassTag = 0x80000000 | classTagOffset;
1278 streamerInfo.fStreamerInfo.fStreamers.fStreamerSeekFooter.fClassTag = 0x80000000 | classTagOffset;
1279 streamerInfo.fStreamerInfo.fStreamers.fStreamerNBytesFooter.fClassTag = 0x80000000 | classTagOffset;
1280 streamerInfo.fStreamerInfo.fStreamers.fStreamerLenFooter.fClassTag = 0x80000000 | classTagOffset;
1281 streamerInfo.fStreamerInfo.fStreamers.fStreamerReserved.fClassTag = 0x80000000 | classTagOffset;
1282 Detail::RNTupleCompressor compressor;
1283 auto szStreamerInfo = compressor(&streamerInfo, streamerInfo.GetSize(), 1);
1284 fFileSimple.WriteKey(compressor.GetZipBuffer(), szStreamerInfo, streamerInfo.GetSize(),
1285 fFileSimple.fControlBlock->fHeader.GetSeekInfo(), 100,
1286 "TList", "StreamerInfo", "Doubly linked list");
1287 fFileSimple.fControlBlock->fHeader.SetNbytesInfo(
1288 fFileSimple.fFilePos - fFileSimple.fControlBlock->fHeader.GetSeekInfo());
1289
1290 // Reserve the space for the RNTuple record, which will be written on commit
1291 RTFNTuple ntupleOnDisk;
1292 fFileSimple.fControlBlock->fSeekNTuple = fFileSimple.fFilePos;
1293 RTFKey keyRNTuple(fFileSimple.fControlBlock->fSeekNTuple, 100, strRNTupleClass, strRNTupleName, strEmpty,
1294 ntupleOnDisk.GetSize());
1295 fFileSimple.WriteKey(&ntupleOnDisk, ntupleOnDisk.GetSize(), ntupleOnDisk.GetSize(),
1296 fFileSimple.fControlBlock->fSeekNTuple, 100, "ROOT::Experimental::RNTUple", fNTupleName, "");
1297
1298 // The key index of the root TFile object, containing for the time being only the RNTuple key
1299 fileRoot.fInfoShort.fSeekKeys = fFileSimple.fFilePos;
1300 RTFKeyList keyList{1};
1301 RTFKey keyKeyList(fileRoot.GetSeekKeys(), 100, strEmpty, strEmpty, strEmpty, keyList.GetSize() + keyRNTuple.fKeyLen);
1302 fFileSimple.Write(&keyKeyList, keyKeyList.fKeyHeaderSize, fileRoot.GetSeekKeys());
1303 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1304 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1305 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1306 fFileSimple.Write(&keyList, keyList.GetSize());
1307 fFileSimple.Write(&keyRNTuple, keyRNTuple.fKeyHeaderSize);
1308 fFileSimple.Write(&strRNTupleClass, strRNTupleClass.GetSize());
1309 fFileSimple.Write(&strRNTupleName, strRNTupleName.GetSize());
1310 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1311 fileRoot.fNBytesKeys = fFileSimple.fFilePos - fileRoot.GetSeekKeys();
1312
1313 auto tail = fFileSimple.fFilePos;
1314 fFileSimple.Write(&keyRoot, keyRoot.fKeyHeaderSize, 100);
1315 fFileSimple.Write(&strTFile, strTFile.GetSize());
1316 fFileSimple.Write(&strFileName, strFileName.GetSize());
1317 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1318 fFileSimple.Write(&strFileName, strFileName.GetSize());
1319 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1320 fFileSimple.Write(&fileRoot, fileRoot.GetSize());
1321 fFileSimple.fFilePos = tail;
1322 auto retval = fseek(fFileSimple.fFile, tail, SEEK_SET);
1323 R__ASSERT(retval == 0);
1324 fFileSimple.fFilePos = tail;
1325}
size_t fSize
#define ROOT_VERSION_CODE
Definition: RVersion.h:21
#define R__ASSERT(e)
Definition: TError.h:96
XFontStruct * id
Definition: TGX11.cxx:108
char name[80]
Definition: TGX11.cxx:109
Binding & operator=(OUT(*fun)(void))
virtual void ReadBuffer(char *&buffer)
T1 fFirst
Definition: X11Events.mm:86
Helper class to compress data blocks in the ROOT compression frame format.
Definition: RNTupleZip.hxx:40
RNTuple GetNTupleProper(std::string_view ntupleName)
Used when the file turns out to be a TFile container.
Definition: RMiniFile.cxx:915
RNTuple GetNTuple(std::string_view ntupleName)
Extracts header and footer location for the RNTuple identified by ntupleName.
Definition: RMiniFile.cxx:904
RNTuple GetNTupleBare(std::string_view ntupleName)
Used when the file container turns out to be a bare file.
Definition: RMiniFile.cxx:962
void ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset)
Reads a given byte range from the file into the provided memory buffer.
Definition: RMiniFile.cxx:979
Write RNTuple data blocks in a TFile or a bare file container.
Definition: RMiniFile.hxx:135
std::uint64_t WriteBlob(const void *data, size_t nbytes, size_t len)
Writes a new record as an RBlob key into the file.
Definition: RMiniFile.cxx:1188
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...
Definition: RMiniFile.cxx:1216
void Commit()
Writes the RNTuple key to the file so that the header and footer keys can be found.
Definition: RMiniFile.cxx:1146
RFileSimple fFileSimple
For simple use cases, survives without libRIO dependency.
Definition: RMiniFile.hxx:177
static RNTupleFileWriter * Append(std::string_view ntupleName, TFile &file)
Add a new RNTuple identified by ntupleName to the existing TFile.
Definition: RMiniFile.cxx:1137
static RNTupleFileWriter * Recreate(std::string_view ntupleName, std::string_view path, int defaultCompression, ENTupleContainerFormat containerFormat)
Create or truncate the local file given by path with the new empty RNTuple identified by ntupleName.
Definition: RMiniFile.cxx:1094
void WriteTFileSkeleton(int defaultCompression)
For a TFile container written by a C file stream, write the records that constitute an empty file.
Definition: RMiniFile.cxx:1242
void WriteBareFileSkeleton(int defaultCompression)
For a bare file, which is necessarily written by a C file stream, write file header.
Definition: RMiniFile.cxx:1227
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...
Definition: RMiniFile.cxx:1205
The RRawFile provides read-only access to local and remote files.
Definition: RRawFile.hxx:40
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:53
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:3942
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:28
virtual void Create(Int_t nbytes, TFile *f=0)
Create a TKey object of specified size.
Definition: TKey.cxx:459
Long64_t fSeekKey
Location of object on file.
Definition: TKey.h:45
struct void * fTypeName
Definition: cppyy.h:9
#define Swap(a, b)
Definition: geom.c:201
Double_t x[n]
Definition: legend1.C:17
basic_string_view< char > string_view
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
Definition: file.py:1
Definition: first.py:1
Definition: writer.py:1
void Write(const void *buffer, size_t nbytes, std::int64_t offset)
Low-level writing using a TFile.
Definition: RMiniFile.cxx:1041
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...
Definition: RMiniFile.cxx:1051
std::unique_ptr< ROOT::Experimental::Internal::RTFileControlBlock > fControlBlock
Keeps track of TFile control structures, which need to be updated on committing the data set.
Definition: RMiniFile.hxx:152
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.
Definition: RMiniFile.cxx:996
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 ...
Definition: RMiniFile.cxx:1012
Entry point for an RNTuple in a ROOT file.
Definition: RMiniFile.hxx:52
std::uint64_t fSeekFooter
The file offset of the footer excluding the TKey part.
Definition: RMiniFile.hxx:64
std::uint32_t fLenHeader
The size of the uncompressed ntuple header.
Definition: RMiniFile.hxx:62
std::uint64_t fReserved
Currently unused, reserved for later use.
Definition: RMiniFile.hxx:70
std::uint32_t fVersion
Allows for evolving the struct in future versions.
Definition: RMiniFile.hxx:54
std::uint32_t fNBytesHeader
The size of the compressed ntuple header.
Definition: RMiniFile.hxx:60
std::uint32_t fSize
Allows for skipping the struct.
Definition: RMiniFile.hxx:56
std::uint32_t fNBytesFooter
The size of the compressed ntuple footer.
Definition: RMiniFile.hxx:66
std::uint32_t fLenFooter
The size of the uncompressed ntuple footer.
Definition: RMiniFile.hxx:68
std::uint64_t fSeekHeader
The file offset of the header excluding the TKey part.
Definition: RMiniFile.hxx:58
auto * tt
Definition: textangle.C:16