47#ifndef R__LITTLE_ENDIAN
50#define R__LITTLE_ENDIAN 1
52#define R__LITTLE_ENDIAN 0
63 std::uint16_t fValBE = 0;
64 static std::uint16_t
Swap(std::uint16_t val)
66#if R__LITTLE_ENDIAN == 1
67 return RByteSwap<
sizeof(val)>::bswap(val);
74 RUInt16BE() =
default;
75 explicit RUInt16BE(
const std::uint16_t val) : fValBE(
Swap(val)) {}
76 operator std::uint16_t()
const {
return Swap(fValBE); }
77 RUInt16BE &
operator=(
const std::uint16_t val)
87 std::uint32_t fValBE = 0;
88 static std::uint32_t
Swap(std::uint32_t val)
90#if R__LITTLE_ENDIAN == 1
91 return RByteSwap<
sizeof(val)>::bswap(val);
98 RUInt32BE() =
default;
99 explicit RUInt32BE(
const std::uint32_t val) : fValBE(
Swap(val)) {}
100 operator std::uint32_t()
const {
return Swap(fValBE); }
101 RUInt32BE &
operator=(
const std::uint32_t val)
111 std::int32_t fValBE = 0;
112 static std::int32_t
Swap(std::int32_t val)
114#if R__LITTLE_ENDIAN == 1
115 return RByteSwap<
sizeof(val)>::bswap(val);
122 RInt32BE() =
default;
123 explicit RInt32BE(
const std::int32_t val) : fValBE(
Swap(val)) {}
124 operator std::int32_t()
const {
return Swap(fValBE); }
125 RInt32BE &
operator=(
const std::int32_t val)
135 std::uint64_t fValBE = 0;
136 static std::uint64_t
Swap(std::uint64_t val)
138#if R__LITTLE_ENDIAN == 1
139 return RByteSwap<
sizeof(val)>::bswap(val);
146 RUInt64BE() =
default;
147 explicit RUInt64BE(
const std::uint64_t val) : fValBE(
Swap(val)) {}
148 operator std::uint64_t()
const {
return Swap(fValBE); }
149 RUInt64BE &
operator=(
const std::uint64_t val)
159 unsigned char fLName{0};
161 RTFString() =
default;
162 RTFString(
const std::string &str)
167 fLName = str.length();
168 memcpy(fData, str.data(), fLName);
170 std::size_t GetSize()
const
184 auto now = std::chrono::system_clock::now();
185 auto tt = std::chrono::system_clock::to_time_t(now);
186 auto tm = *localtime(&
tt);
187 fDatetime = (tm.tm_year + 1900 - 1995) << 26 | (tm.tm_mon + 1) << 22 | tm.tm_mday << 17 | tm.tm_hour << 12 |
188 tm.tm_min << 6 | tm.tm_sec;
190 explicit RTFDatetime(RUInt32BE val) : fDatetime(val) {}
196 RUInt16BE fVersion{4};
197 RUInt32BE fObjLen{0};
198 RTFDatetime fDatetime;
199 RUInt16BE fKeyLen{0};
203 RUInt32BE fSeekKey{0};
204 RUInt32BE fSeekPdir{0};
207 RUInt64BE fSeekKey{0};
208 RUInt64BE fSeekPdir{0};
212 std::uint32_t fKeyHeaderSize{18 +
sizeof(fInfoShort)};
214 RTFKey() : fInfoShort() {}
215 RTFKey(std::uint64_t seekKey, std::uint64_t seekPdir,
const RTFString &clName,
const RTFString &objName,
216 const RTFString &titleName, std::size_t szObjInMem, std::size_t szObjOnDisk = 0)
218 R__ASSERT(szObjInMem < std::numeric_limits<std::int32_t>::max());
219 R__ASSERT(szObjOnDisk < std::numeric_limits<std::int32_t>::max());
220 fObjLen = szObjInMem;
221 if ((seekKey >
static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) ||
222 (seekPdir >
static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max()))) {
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;
229 fKeyHeaderSize = 18 +
sizeof(fInfoShort);
230 fKeyLen = fKeyHeaderSize + clName.GetSize() + objName.GetSize() + titleName.GetSize();
231 fInfoShort.fSeekKey = seekKey;
232 fInfoShort.fSeekPdir = seekPdir;
234 fNbytes = fKeyLen + ((szObjOnDisk == 0) ? szObjInMem : szObjOnDisk);
239 if (fVersion >= 1000)
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;
251 std::uint32_t GetSize()
const
259 std::uint32_t GetHeaderSize()
const
261 if (fVersion >= 1000)
262 return 18 +
sizeof(fInfoLong);
263 return 18 +
sizeof(fInfoShort);
266 std::uint64_t GetSeekKey()
const
268 if (fVersion >= 1000)
269 return fInfoLong.fSeekKey;
270 return fInfoShort.fSeekKey;
276 char fMagic[4]{
'r',
'o',
'o',
't'};
279 RUInt32BE fBEGIN{100};
283 RUInt32BE fSeekFree{0};
284 RUInt32BE fNbytesFree{0};
286 RUInt32BE fNbytesName{0};
287 unsigned char fUnits{4};
288 RUInt32BE fCompress{0};
289 RUInt32BE fSeekInfo{0};
290 RUInt32BE fNbytesInfo{0};
294 RUInt64BE fSeekFree{0};
295 RUInt32BE fNbytesFree{0};
297 RUInt32BE fNbytesName{0};
298 unsigned char fUnits{8};
299 RUInt32BE fCompress{0};
300 RUInt64BE fSeekInfo{0};
301 RUInt32BE fNbytesInfo{0};
305 RTFHeader() : fInfoShort() {}
306 RTFHeader(
int compression) : fInfoShort() { fInfoShort.fCompress = compression; }
310 if (fVersion >= 1000000)
314 std::uint32_t end = fInfoShort.fEND;
315 std::uint32_t seekFree = fInfoShort.fSeekFree;
316 std::uint32_t nbytesFree = fInfoShort.fNbytesFree;
317 std::uint32_t nFree = fInfoShort.fNfree;
318 std::uint32_t nbytesName = fInfoShort.fNbytesName;
319 std::uint32_t compress = fInfoShort.fCompress;
320 std::uint32_t seekInfo = fInfoShort.fSeekInfo;
321 std::uint32_t nbytesInfo = fInfoShort.fNbytesInfo;
322 fInfoLong.fEND = end;
323 fInfoLong.fSeekFree = seekFree;
324 fInfoLong.fNbytesFree = nbytesFree;
325 fInfoLong.fNfree = nFree;
326 fInfoLong.fNbytesName = nbytesName;
327 fInfoLong.fUnits = 8;
328 fInfoLong.fCompress = compress;
329 fInfoLong.fSeekInfo = seekInfo;
330 fInfoLong.fNbytesInfo = nbytesInfo;
331 fVersion = fVersion + 1000000;
335 bool IsBigFile(std::uint64_t
offset = 0)
const
337 return (fVersion >= 1000000) || (
offset >
static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max()));
340 std::uint32_t GetSize()
const
342 std::uint32_t sizeHead = 4 +
sizeof(fVersion) +
sizeof(fBEGIN);
344 return sizeHead +
sizeof(fInfoLong);
345 return sizeHead +
sizeof(fInfoShort);
348 std::uint64_t GetEnd()
const
351 return fInfoLong.fEND;
352 return fInfoShort.fEND;
355 void SetEnd(std::uint64_t
value)
357 if (IsBigFile(
value)) {
359 fInfoLong.fEND =
value;
361 fInfoShort.fEND =
value;
365 std::uint64_t GetSeekFree()
const
368 return fInfoLong.fSeekFree;
369 return fInfoShort.fSeekFree;
372 void SetSeekFree(std::uint64_t
value)
374 if (IsBigFile(
value)) {
376 fInfoLong.fSeekFree =
value;
378 fInfoShort.fSeekFree =
value;
382 void SetNbytesFree(std::uint32_t
value)
385 fInfoLong.fNbytesFree =
value;
387 fInfoShort.fNbytesFree =
value;
391 void SetNbytesName(std::uint32_t
value)
394 fInfoLong.fNbytesName =
value;
396 fInfoShort.fNbytesName =
value;
400 std::uint64_t GetSeekInfo()
const
403 return fInfoLong.fSeekInfo;
404 return fInfoShort.fSeekInfo;
407 void SetSeekInfo(std::uint64_t
value)
409 if (IsBigFile(
value)) {
411 fInfoLong.fSeekInfo =
value;
413 fInfoShort.fSeekInfo =
value;
417 void SetNbytesInfo(std::uint32_t
value)
420 fInfoLong.fNbytesInfo =
value;
422 fInfoShort.fNbytesInfo =
value;
426 void SetCompression(std::uint32_t
value)
429 fInfoLong.fCompress =
value;
431 fInfoShort.fCompress =
value;
438 RUInt16BE fVersion{1};
450 RTFFreeEntry() : fInfoShort() {}
451 void Set(std::uint64_t first, std::uint64_t last)
453 if (last >
static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) {
454 fVersion = fVersion + 1000;
455 fInfoLong.fFirst = first;
456 fInfoLong.fLast = last;
458 fInfoShort.fFirst = first;
459 fInfoShort.fLast = last;
462 std::uint32_t GetSize() {
return (fVersion >= 1000) ? 18 : 10; }
468 std::uint32_t GetSize()
const {
return sizeof(RTFKeyList); }
469 explicit RTFKeyList(std::uint32_t nKeys) : fNKeys(nKeys) {}
474 RUInt16BE fClassVersion{5};
477 RUInt32BE fNBytesKeys{0};
478 RUInt32BE fNBytesName{0};
482 RUInt32BE fSeekDir{100};
483 RUInt32BE fSeekParent{0};
484 RUInt32BE fSeekKeys{0};
487 RUInt64BE fSeekDir{100};
488 RUInt64BE fSeekParent{0};
489 RUInt64BE fSeekKeys{0};
493 RTFFile() : fInfoShort() {}
496 std::uint32_t GetSize()
const
498 if (fClassVersion >= 1000)
499 return sizeof(RTFFile);
500 return 18 +
sizeof(fInfoShort);
503 std::uint64_t GetSeekKeys()
const
505 if (fClassVersion >= 1000)
506 return fInfoLong.fSeekKeys;
507 return fInfoShort.fSeekKeys;
510 void SetSeekKeys(std::uint64_t seekKeys)
512 if (seekKeys >
static_cast<unsigned int>(std::numeric_limits<std::int32_t>::max())) {
513 std::uint32_t seekDir = fInfoShort.fSeekDir;
514 std::uint32_t seekParent = fInfoShort.fSeekParent;
515 fInfoLong.fSeekDir = seekDir;
516 fInfoLong.fSeekParent = seekParent;
517 fInfoLong.fSeekKeys = seekKeys;
518 fClassVersion = fClassVersion + 1000;
520 fInfoShort.fSeekKeys = seekKeys;
527 RUInt16BE fVersionClass{1};
528 unsigned char fUUID[16] = {0};
531 std::uint32_t GetSize()
const {
return sizeof(RTFUUID); }
540 RUInt32BE fByteCount{0x40000000 | (
sizeof(RTFNTuple) -
sizeof(fByteCount))};
541 RUInt16BE fVersionClass{6};
542 RUInt16BE fVersionEpoch{0};
543 RUInt16BE fVersionMajor{0};
544 RUInt16BE fVersionMinor{0};
545 RUInt16BE fVersionPatch{0};
546 RUInt64BE fSeekHeader{0};
547 RUInt64BE fNBytesHeader{0};
548 RUInt64BE fLenHeader{0};
549 RUInt64BE fSeekFooter{0};
550 RUInt64BE fNBytesFooter{0};
551 RUInt64BE fLenFooter{0};
552 RUInt64BE fMaxKeySize{0};
554 static constexpr std::uint32_t GetSizePlusChecksum() {
return sizeof(RTFNTuple) +
sizeof(std::uint64_t); }
556 RTFNTuple() =
default;
571 std::uint32_t GetSize()
const {
return sizeof(RTFNTuple); }
573 std::uint32_t GetOffsetCkData() {
return sizeof(fByteCount) +
sizeof(fVersionClass); }
574 std::uint32_t GetSizeCkData() {
return GetSize() - GetOffsetCkData(); }
575 unsigned char *GetPtrCkData() {
return reinterpret_cast<unsigned char *
>(
this) + GetOffsetCkData(); }
579struct RBareFileHeader {
580 char fMagic[7]{
'r',
'n',
't',
'u',
'p',
'l',
'e'};
583 RUInt32BE fFormatVersion{1};
584 RUInt32BE fCompress{0};
591constexpr char const *kBlobClassName =
"RBlob";
593constexpr char const *kNTupleClassName =
"ROOT::Experimental::RNTuple";
598namespace Experimental {
625 void Reserve(
size_t nbytes, std::uint64_t *seekKey)
643 constexpr size_t kChunkOffsetSize =
sizeof(std::uint64_t);
645 assert(nbytes > maxChunkSize);
646 size_t nChunks = (nbytes + maxChunkSize - 1) / maxChunkSize;
648 size_t nbytesTail = nbytes % maxChunkSize;
649 size_t nbytesExtra = (nbytesTail > 0) * (maxChunkSize - nbytesTail);
650 size_t nbytesChunkOffsets = (nChunks - 1) * kChunkOffsetSize;
651 if (nbytesChunkOffsets > nbytesExtra) {
653 nbytesChunkOffsets += kChunkOffsetSize;
660 R__ASSERT(nbytesChunkOffsets <= maxChunkSize);
668 std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch,
669 std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter,
670 std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize)
692 if (std::string(ident, 4) ==
"root")
693 return GetNTupleProper(ntupleName);
695 return GetNTupleBare(ntupleName);
701 RTFHeader fileHeader;
702 ReadBuffer(&fileHeader,
sizeof(fileHeader), 0);
706 ReadBuffer(&key,
sizeof(key), fileHeader.fBEGIN);
708 std::uint64_t
offset = fileHeader.fBEGIN + key.fKeyLen;
718 offset = file.GetSeekKeys();
724 for (
unsigned int i = 0; i < nKeys; ++i) {
726 auto offsetNextKey =
offset + key.fKeyLen;
728 offset += key.GetHeaderSize();
731 if (std::string_view(
name.fData,
name.fLName) != kNTupleClassName) {
738 if (std::string_view(
name.fData,
name.fLName) == ntupleName) {
745 return R__FAIL(
"no RNTuple named '" + std::string(ntupleName) +
"' in file '" + fRawFile->GetUrl() +
"'");
748 offset = key.GetSeekKey() + key.fKeyLen;
750 constexpr size_t kMinNTupleSize = 70;
751 if (key.fObjLen < kMinNTupleSize) {
752 return R__FAIL(
"invalid anchor size: " + std::to_string(key.fObjLen) +
" < " + std::to_string(
sizeof(RTFNTuple)));
756 auto bufAnchor = std::make_unique<unsigned char[]>(std::max<size_t>(key.fObjLen,
sizeof(RTFNTuple)));
757 RTFNTuple *ntuple =
new (bufAnchor.get()) RTFNTuple;
759 auto objNbytes = key.GetSize() - key.fKeyLen;
761 if (objNbytes != key.fObjLen) {
763 decompressor.
Unzip(bufAnchor.get(), objNbytes, key.fObjLen);
766 if (ntuple->fVersionClass < 4) {
767 return R__FAIL(
"invalid anchor, unsupported pre-release of RNTuple");
772 auto lenCkData = key.fObjLen - ntuple->GetOffsetCkData() -
sizeof(uint64_t);
773 auto ckCalc = XXH3_64bits(ntuple->GetPtrCkData(), lenCkData);
777 if (ntuple->fVersionClass == 4) {
778 ckOnDisk = ntuple->fMaxKeySize;
779 ntuple->fMaxKeySize = 0;
781 RUInt64BE *ckOnDiskPtr =
reinterpret_cast<RUInt64BE *
>(bufAnchor.get() + key.fObjLen -
sizeof(uint64_t));
782 ckOnDisk =
static_cast<uint64_t
>(*ckOnDiskPtr);
784 if (ckCalc != ckOnDisk) {
785 return R__FAIL(
"RNTuple anchor checksum mismatch");
788 fMaxKeySize = ntuple->fMaxKeySize;
790 return CreateAnchor(ntuple->fVersionEpoch, ntuple->fVersionMajor, ntuple->fVersionMinor, ntuple->fVersionPatch,
791 ntuple->fSeekHeader, ntuple->fNBytesHeader, ntuple->fLenHeader, ntuple->fSeekFooter,
792 ntuple->fNBytesFooter, ntuple->fLenFooter, ntuple->fMaxKeySize);
798 RBareFileHeader fileHeader;
799 ReadBuffer(&fileHeader,
sizeof(fileHeader), 0);
801 auto offset =
sizeof(fileHeader);
804 std::string_view foundName(
name.fData,
name.fLName);
805 if (foundName != ntupleName) {
806 return R__FAIL(
"expected RNTuple named '" + std::string(ntupleName) +
"' but instead found '" +
807 std::string(foundName) +
"' in file '" + fRawFile->GetUrl() +
"'");
813 std::uint64_t onDiskChecksum;
814 ReadBuffer(&onDiskChecksum,
sizeof(onDiskChecksum),
offset +
sizeof(ntuple));
815 auto checksum = XXH3_64bits(ntuple.GetPtrCkData(), ntuple.GetSizeCkData());
816 if (checksum !=
static_cast<uint64_t
>(onDiskChecksum))
817 return R__FAIL(
"RNTuple bare file: anchor checksum mismatch");
819 fMaxKeySize = ntuple.fMaxKeySize;
821 return CreateAnchor(ntuple.fVersionEpoch, ntuple.fVersionMajor, ntuple.fVersionMinor, ntuple.fVersionPatch,
822 ntuple.fSeekHeader, ntuple.fNBytesHeader, ntuple.fLenHeader, ntuple.fSeekFooter,
823 ntuple.fNBytesFooter, ntuple.fLenFooter, ntuple.fMaxKeySize);
829 if (fMaxKeySize == 0 || nbytes <= fMaxKeySize) {
831 nread = fRawFile->ReadAt(buffer, nbytes,
offset);
835 const size_t nbytesChunkOffsets = (nChunks - 1) *
sizeof(std::uint64_t);
836 const size_t nbytesFirstChunk = fMaxKeySize - nbytesChunkOffsets;
837 uint8_t *bufCur =
reinterpret_cast<uint8_t *
>(buffer);
840 nread = fRawFile->ReadAt(bufCur, fMaxKeySize,
offset);
845 bufCur += nbytesFirstChunk;
846 nread -= nbytesChunkOffsets;
848 const auto chunkOffsets = std::make_unique<std::uint64_t[]>(nChunks - 1);
849 memcpy(chunkOffsets.get(), bufCur, nbytesChunkOffsets);
851 size_t remainingBytes = nbytes - nbytesFirstChunk;
852 std::uint64_t *curChunkOffset = &chunkOffsets[0];
855 std::uint64_t chunkOffset;
859 const size_t bytesToRead = std::min<size_t>(fMaxKeySize, remainingBytes);
861 R__ASSERT(
static_cast<size_t>(bufCur -
reinterpret_cast<uint8_t *
>(buffer)) <= nbytes - bytesToRead);
863 auto nbytesRead = fRawFile->ReadAt(bufCur, bytesToRead, chunkOffset);
866 nread += bytesToRead;
867 bufCur += bytesToRead;
868 remainingBytes -= bytesToRead;
869 }
while (remainingBytes > 0);
878 static_assert(kHeaderBlockSize % kBlockAlign == 0,
"invalid header block size");
879 static_assert(kBlockSize % kBlockAlign == 0,
"invalid block size");
880 std::align_val_t blockAlign{kBlockAlign};
881 fHeaderBlock =
static_cast<unsigned char *
>(::operator
new[](kHeaderBlockSize, blockAlign));
882 memset(fHeaderBlock, 0, kHeaderBlockSize);
883 fBlock =
static_cast<unsigned char *
>(::operator
new[](kBlockSize, blockAlign));
884 memset(fBlock, 0, kBlockSize);
892 std::align_val_t blockAlign{kBlockAlign};
893 ::operator
delete[](fHeaderBlock, blockAlign);
894 ::operator
delete[](fBlock, blockAlign);
898int FSeek64(FILE *stream, std::int64_t
offset,
int origin)
901 return fseeko64(stream,
offset, origin);
903 return fseek(stream,
offset, origin);
912 if (fBlockOffset == 0) {
913 std::size_t headerBlockSize = kHeaderBlockSize;
914 if (headerBlockSize > fFilePos) {
915 headerBlockSize = fFilePos;
917 memcpy(fBlock, fHeaderBlock, headerBlockSize);
920 std::size_t retval = FSeek64(fFile, fBlockOffset, SEEK_SET);
924 std::size_t lastBlockSize = fFilePos - fBlockOffset;
928 lastBlockSize += kBlockAlign - 1;
929 lastBlockSize = (lastBlockSize / kBlockAlign) * kBlockAlign;
932 retval = fwrite(fBlock, 1, lastBlockSize, fFile);
933 if (retval != lastBlockSize)
937 if (fBlockOffset > 0) {
938 retval = FSeek64(fFile, 0, SEEK_SET);
942 retval = fwrite(fHeaderBlock, 1, kHeaderBlockSize, fFile);
943 if (retval != RFileSimple::kHeaderBlockSize)
947 retval = fflush(fFile);
957 if ((
offset >= 0) && (
static_cast<std::uint64_t
>(
offset) != fFilePos)) {
962 if (fFilePos < kHeaderBlockSize) {
963 std::size_t headerBytes = nbytes;
964 if (fFilePos + headerBytes > kHeaderBlockSize) {
965 headerBytes = kHeaderBlockSize - fFilePos;
967 memcpy(fHeaderBlock + fFilePos, buffer, headerBytes);
973 std::uint64_t posInBlock = fFilePos % kBlockSize;
974 std::uint64_t blockOffset = fFilePos - posInBlock;
975 if (blockOffset != fBlockOffset) {
977 retval = FSeek64(fFile, fBlockOffset, SEEK_SET);
981 retval = fwrite(fBlock, 1, kBlockSize, fFile);
982 if (retval != kBlockSize)
986 memset(fBlock, 0, kBlockSize);
989 fBlockOffset = blockOffset;
990 std::size_t blockSize = nbytes;
991 if (blockSize > kBlockSize - posInBlock) {
992 blockSize = kBlockSize - posInBlock;
994 memcpy(fBlock + posInBlock, buffer, blockSize);
995 buffer =
static_cast<const unsigned char *
>(buffer) + blockSize;
997 fFilePos += blockSize;
1002 const void *buffer, std::size_t nbytes, std::size_t
len, std::int64_t
offset, std::uint64_t directoryOffset,
1003 const std::string &className,
const std::string &objectName,
const std::string &title)
1007 RTFString strClass{className};
1008 RTFString strObject{objectName};
1009 RTFString strTitle{title};
1011 RTFKey key(fKeyOffset, directoryOffset, strClass, strObject, strTitle,
len, nbytes);
1012 Write(&key, key.fKeyHeaderSize, fKeyOffset);
1013 Write(&strClass, strClass.GetSize());
1014 Write(&strObject, strObject.GetSize());
1015 Write(&strTitle, strTitle.GetSize());
1016 auto offsetData = fFilePos;
1018 fKeyOffset = offsetData + nbytes;
1020 Write(buffer, nbytes);
1032 bool rv = fFile->WriteBuffer((
char *)(buffer), nbytes);
1040 std::uint64_t offsetKey;
1044 keyBlob.
Reserve(nbytes, &offsetKey);
1047 RTFString strClass{kBlobClassName};
1048 RTFString strObject;
1050 RTFKey keyHeader(
offset,
offset, strClass, strObject, strTitle,
len, nbytes);
1052 keyHeader.MakeBigKey();
1054 Write(&keyHeader, keyHeader.fKeyHeaderSize,
offset);
1055 offset += keyHeader.fKeyHeaderSize;
1056 Write(&strClass, strClass.GetSize(),
offset);
1057 offset += strClass.GetSize();
1058 Write(&strObject, strObject.GetSize(),
offset);
1059 offset += strObject.GetSize();
1060 Write(&strTitle, strTitle.GetSize(),
offset);
1061 offset += strTitle.GetSize();
1062 auto offsetData =
offset;
1064 Write(buffer, nbytes,
offset);
1082std::unique_ptr<ROOT::Experimental::Internal::RNTupleFileWriter>
1087 std::string fileName(path);
1088 size_t idxDirSep = fileName.find_last_of(
"\\/");
1089 if (idxDirSep != std::string::npos) {
1090 fileName.erase(0, idxDirSep + 1);
1093 int flags = O_WRONLY | O_CREAT | O_TRUNC;
1096 flags |= O_LARGEFILE;
1101 int fd = open(std::string(path).c_str(), flags, 0666);
1102 FILE *fileStream = fdopen(fd,
"wb");
1105 FILE *fileStream = fopen64(std::string(path.data(), path.size()).c_str(),
"wb");
1107 FILE *fileStream = fopen(std::string(path.data(), path.size()).c_str(),
"wb");
1112 std::setvbuf(fileStream,
nullptr, _IONBF, 0);
1115 writer->fFileSimple.fFile = fileStream;
1117 writer->fFileName = fileName;
1120 switch (containerFormat) {
1121 case EContainerFormat::kTFile:
writer->WriteTFileSkeleton(defaultCompression);
break;
1122 case EContainerFormat::kBare:
1124 writer->WriteBareFileSkeleton(defaultCompression);
1126 default:
R__ASSERT(
false &&
"Internal error: unhandled container format");
1132std::unique_ptr<ROOT::Experimental::Internal::RNTupleFileWriter>
1134 std::uint64_t maxKeySize)
1137 writer->fFileProper.fFile = &file;
1144 fStreamerInfoMap.insert(streamerInfos.cbegin(), streamerInfos.cend());
1151 fFileProper.fFile->WriteObject(&fNTupleAnchor, fNTupleName.c_str());
1156 for (
auto [
_, info] : fStreamerInfoMap)
1159 fFileProper.fFile->Write();
1167 RTFNTuple ntupleOnDisk(fNTupleAnchor);
1169 std::uint64_t checksum = XXH3_64bits(ntupleOnDisk.GetPtrCkData(), ntupleOnDisk.GetSizeCkData());
1170 memcpy(fFileSimple.fHeaderBlock + fFileSimple.fControlBlock->fSeekNTuple, &ntupleOnDisk, ntupleOnDisk.GetSize());
1171 memcpy(fFileSimple.fHeaderBlock + fFileSimple.fControlBlock->fSeekNTuple + ntupleOnDisk.GetSize(), &checksum,
1173 fFileSimple.Flush();
1177 WriteTFileNTupleKey();
1178 WriteTFileKeysList();
1179 WriteTFileStreamerInfo();
1180 WriteTFileFreeList();
1183 memcpy(fFileSimple.fHeaderBlock, &fFileSimple.fControlBlock->fHeader, fFileSimple.fControlBlock->fHeader.GetSize());
1184 R__ASSERT(fFileSimple.fControlBlock->fSeekFileRecord + fFileSimple.fControlBlock->fFileRecord.GetSize() <
1185 RFileSimple::kHeaderBlockSize);
1186 memcpy(fFileSimple.fHeaderBlock + fFileSimple.fControlBlock->fSeekFileRecord,
1187 &fFileSimple.fControlBlock->fFileRecord, fFileSimple.fControlBlock->fFileRecord.GetSize());
1189 fFileSimple.Flush();
1194 auto writeKey = [
this](
const void *payload,
size_t nBytes,
size_t length) {
1198 offset = fFileSimple.fKeyOffset;
1199 fFileSimple.Write(payload, nBytes);
1200 fFileSimple.fKeyOffset += nBytes;
1202 offset = fFileSimple.WriteKey(payload, nBytes,
length, -1, 100, kBlobClassName);
1205 offset = fFileProper.WriteKey(payload, nBytes,
length);
1210 const std::uint64_t maxKeySize = fNTupleAnchor.fMaxKeySize;
1213 if (nbytes <= maxKeySize) {
1215 return writeKey(
data, nbytes,
len);
1232 const size_t nbytesChunkOffsets = (nChunks - 1) *
sizeof(std::uint64_t);
1233 const size_t nbytesFirstChunk = maxKeySize - nbytesChunkOffsets;
1236 const uint8_t *chunkData =
reinterpret_cast<const uint8_t *
>(
data) + nbytesFirstChunk;
1237 size_t remainingBytes = nbytes - nbytesFirstChunk;
1239 const auto chunkOffsetsToWrite = std::make_unique<std::uint64_t[]>(nChunks - 1);
1240 std::uint64_t chunkOffsetIdx = 0;
1243 const size_t bytesNextChunk = std::min<size_t>(remainingBytes, maxKeySize);
1244 const std::uint64_t
offset = writeKey(chunkData, bytesNextChunk, bytesNextChunk);
1249 remainingBytes -= bytesNextChunk;
1250 chunkData += bytesNextChunk;
1252 }
while (remainingBytes > 0);
1255 const std::uint64_t firstOffset = ReserveBlob(maxKeySize, maxKeySize);
1256 WriteIntoReservedBlob(
data, nbytesFirstChunk, firstOffset);
1257 const std::uint64_t chunkOffsetsOffset = firstOffset + nbytesFirstChunk;
1258 WriteIntoReservedBlob(chunkOffsetsToWrite.get(), nbytesChunkOffsets, chunkOffsetsOffset);
1266 R__ASSERT(nbytes <= fNTupleAnchor.GetMaxKeySize());
1271 offset = fFileSimple.fKeyOffset;
1272 fFileSimple.fKeyOffset += nbytes;
1274 offset = fFileSimple.WriteKey(
nullptr, nbytes,
len, -1, 100, kBlobClassName);
1277 offset = fFileProper.WriteKey(
nullptr, nbytes,
len);
1286 fFileSimple.Write(buffer, nbytes,
offset);
1288 fFileProper.Write(buffer, nbytes,
offset);
1295 auto offset = WriteBlob(
data, nbytes, lenHeader);
1296 fNTupleAnchor.fLenHeader = lenHeader;
1297 fNTupleAnchor.fNBytesHeader = nbytes;
1298 fNTupleAnchor.fSeekHeader =
offset;
1305 auto offset = WriteBlob(
data, nbytes, lenFooter);
1306 fNTupleAnchor.fLenFooter = lenFooter;
1307 fNTupleAnchor.fNBytesFooter = nbytes;
1308 fNTupleAnchor.fSeekFooter =
offset;
1314 RBareFileHeader bareHeader;
1315 bareHeader.fCompress = defaultCompression;
1316 fFileSimple.Write(&bareHeader,
sizeof(bareHeader), 0);
1317 RTFString ntupleName{fNTupleName};
1318 fFileSimple.Write(&ntupleName, ntupleName.GetSize());
1321 RTFNTuple ntupleOnDisk;
1322 fFileSimple.fControlBlock->fSeekNTuple = fFileSimple.fFilePos;
1323 fFileSimple.Write(&ntupleOnDisk, ntupleOnDisk.GetSize());
1324 std::uint64_t checksum = 0;
1325 fFileSimple.Write(&checksum,
sizeof(checksum));
1326 fFileSimple.fKeyOffset = fFileSimple.fFilePos;
1336 TList streamerInfoList;
1337 for (
auto [
_, info] : fStreamerInfoMap) {
1338 streamerInfoList.
Add(info);
1347 RTFString strTList{
"TList"};
1348 RTFString strStreamerInfo{
"StreamerInfo"};
1349 RTFString strStreamerTitle{
"Doubly linked list"};
1350 fFileSimple.fControlBlock->fHeader.SetSeekInfo(fFileSimple.fKeyOffset);
1352 RTFKey(fFileSimple.fControlBlock->fHeader.GetSeekInfo(), 100, strTList, strStreamerInfo, strStreamerTitle, 0)
1358 assert(buffer.
Length() > keyLen);
1359 const auto bufPayload = buffer.
Buffer() + keyLen;
1360 const auto lenPayload = buffer.
Length() - keyLen;
1363 auto zipStreamerInfos = std::make_unique<unsigned char[]>(lenPayload);
1364 auto szZipStreamerInfos = compressor.
Zip(bufPayload, lenPayload, 1, zipStreamerInfos.get());
1366 fFileSimple.WriteKey(zipStreamerInfos.get(), szZipStreamerInfos, lenPayload,
1367 fFileSimple.fControlBlock->fHeader.GetSeekInfo(), 100,
"TList",
"StreamerInfo",
1368 "Doubly linked list");
1369 fFileSimple.fControlBlock->fHeader.SetNbytesInfo(fFileSimple.fFilePos -
1370 fFileSimple.fControlBlock->fHeader.GetSeekInfo());
1376 RTFString strRNTupleClass{
"ROOT::Experimental::RNTuple"};
1377 RTFString strRNTupleName{fNTupleName};
1378 RTFString strFileName{fFileName};
1380 RTFKey keyRNTuple(fFileSimple.fControlBlock->fSeekNTuple, 100, strRNTupleClass, strRNTupleName, strEmpty,
1381 RTFNTuple::GetSizePlusChecksum());
1383 fFileSimple.fControlBlock->fFileRecord.SetSeekKeys(fFileSimple.fKeyOffset);
1384 RTFKeyList keyList{1};
1385 RTFKey keyKeyList(fFileSimple.fControlBlock->fFileRecord.GetSeekKeys(), 100, strEmpty, strFileName, strEmpty,
1386 keyList.GetSize() + keyRNTuple.fKeyLen);
1387 fFileSimple.Write(&keyKeyList, keyKeyList.fKeyHeaderSize, fFileSimple.fControlBlock->fFileRecord.GetSeekKeys());
1388 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1389 fFileSimple.Write(&strFileName, strFileName.GetSize());
1390 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1391 fFileSimple.Write(&keyList, keyList.GetSize());
1392 fFileSimple.Write(&keyRNTuple, keyRNTuple.fKeyHeaderSize);
1394 fFileSimple.Write(&strRNTupleClass, strRNTupleClass.GetSize());
1395 fFileSimple.Write(&strRNTupleName, strRNTupleName.GetSize());
1396 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1397 fFileSimple.fControlBlock->fFileRecord.fNBytesKeys =
1398 fFileSimple.fFilePos - fFileSimple.fControlBlock->fFileRecord.GetSeekKeys();
1399 fFileSimple.fKeyOffset = fFileSimple.fFilePos;
1404 fFileSimple.fControlBlock->fHeader.SetSeekFree(fFileSimple.fKeyOffset);
1406 RTFString strFileName{fFileName};
1407 RTFFreeEntry freeEntry;
1408 RTFKey keyFreeList(fFileSimple.fControlBlock->fHeader.GetSeekFree(), 100, strEmpty, strFileName, strEmpty,
1409 freeEntry.GetSize());
1410 std::uint64_t firstFree = fFileSimple.fControlBlock->fHeader.GetSeekFree() + keyFreeList.GetSize();
1411 freeEntry.Set(firstFree, std::max(2000000000ULL, ((firstFree / 1000000000ULL) + 1) * 1000000000ULL));
1412 fFileSimple.WriteKey(&freeEntry, freeEntry.GetSize(), freeEntry.GetSize(),
1413 fFileSimple.fControlBlock->fHeader.GetSeekFree(), 100,
"", fFileName,
"");
1414 fFileSimple.fControlBlock->fHeader.SetNbytesFree(fFileSimple.fFilePos -
1415 fFileSimple.fControlBlock->fHeader.GetSeekFree());
1416 fFileSimple.fControlBlock->fHeader.SetEnd(fFileSimple.fFilePos);
1421 RTFString strRNTupleClass{
"ROOT::Experimental::RNTuple"};
1422 RTFString strRNTupleName{fNTupleName};
1425 RTFNTuple ntupleOnDisk(fNTupleAnchor);
1426 RUInt64BE checksum{XXH3_64bits(ntupleOnDisk.GetPtrCkData(), ntupleOnDisk.GetSizeCkData())};
1427 fFileSimple.fControlBlock->fSeekNTuple = fFileSimple.fKeyOffset;
1429 char keyBuf[RTFNTuple::GetSizePlusChecksum()];
1432 memcpy(keyBuf, &ntupleOnDisk,
sizeof(RTFNTuple));
1433 memcpy(keyBuf +
sizeof(RTFNTuple), &checksum,
sizeof(checksum));
1435 fFileSimple.WriteKey(keyBuf,
sizeof(keyBuf),
sizeof(keyBuf), fFileSimple.fControlBlock->fSeekNTuple, 100,
1436 "ROOT::Experimental::RNTuple", fNTupleName,
"");
1441 RTFString strTFile{
"TFile"};
1442 RTFString strFileName{fFileName};
1445 fFileSimple.fControlBlock->fHeader = RTFHeader(defaultCompression);
1450 RTFKey keyRoot(100, 0, strTFile, strFileName, strEmpty,
1451 sizeof(RTFFile) + strFileName.GetSize() + strEmpty.GetSize() + uuid.GetSize());
1452 std::uint32_t nbytesName = keyRoot.fKeyLen + strFileName.GetSize() + 1;
1453 fFileSimple.fControlBlock->fFileRecord.fNBytesName = nbytesName;
1454 fFileSimple.fControlBlock->fHeader.SetNbytesName(nbytesName);
1456 fFileSimple.Write(&keyRoot, keyRoot.fKeyHeaderSize, 100);
1458 fFileSimple.Write(&strTFile, strTFile.GetSize());
1459 fFileSimple.Write(&strFileName, strFileName.GetSize());
1460 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1462 fFileSimple.Write(&strFileName, strFileName.GetSize());
1463 fFileSimple.Write(&strEmpty, strEmpty.GetSize());
1465 fFileSimple.fControlBlock->fSeekFileRecord = fFileSimple.fFilePos;
1466 fFileSimple.Write(&fFileSimple.fControlBlock->fFileRecord, fFileSimple.fControlBlock->fFileRecord.GetSize());
1467 fFileSimple.Write(&uuid, uuid.GetSize());
1470 RUInt32BE padding{0};
1471 for (
int i = 0; i < 3; ++i)
1472 fFileSimple.Write(&padding,
sizeof(padding));
1473 fFileSimple.fKeyOffset = fFileSimple.fFilePos;
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
static size_t ComputeNumChunks(size_t nbytes, size_t maxChunkSize)
#define ROOT_VERSION_CODE
#define ClassDefInlineOverride(name, id)
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
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 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 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 length
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
Binding & operator=(OUT(*fun)(void))
void ReadBuffer(char *&buffer) override
The RKeyBlob writes an invisible key into a TFile.
void Reserve(size_t nbytes, std::uint64_t *seekKey)
Register a new key for a data record of size nbytes.
RResult< RNTuple > GetNTuple(std::string_view ntupleName)
Extracts header and footer location for the RNTuple identified by ntupleName.
RMiniFileReader()=default
RResult< RNTuple > GetNTupleProper(std::string_view ntupleName)
Used when the file turns out to be a TFile container.
RNTuple CreateAnchor(std::uint16_t versionEpoch, std::uint16_t versionMajor, std::uint16_t versionMinor, std::uint16_t versionPatch, std::uint64_t seekHeader, std::uint64_t nbytesHeader, std::uint64_t lenHeader, std::uint64_t seekFooter, std::uint64_t nbytesFooter, std::uint64_t lenFooter, std::uint64_t maxKeySize)
RResult< RNTuple > GetNTupleBare(std::string_view ntupleName)
Used when the file container turns out to be a bare file.
void ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset)
Reads a given byte range from the file into the provided memory buffer.
Helper class to compress data blocks in the ROOT compression frame format.
size_t Zip(const void *from, size_t nbytes, int compression, Writer_t fnWriter)
Returns the size of the compressed data.
Helper class to uncompress data blocks in the ROOT compression frame format.
static 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.
RNTupleFileWriter(std::string_view name, std::uint64_t maxKeySize)
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...
static std::unique_ptr< RNTupleFileWriter > Append(std::string_view ntupleName, TFile &file, std::uint64_t maxKeySize)
Add a new RNTuple identified by ntupleName to the existing TFile.
void WriteTFileKeysList()
Write the TList with the RNTuple key.
void UpdateStreamerInfos(const RNTupleSerializer::StreamerInfoMap_t &streamerInfos)
Ensures that the pass streamer info is written to the file.
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.
void WriteTFileNTupleKey()
The only key that will be visible in file->ls()
void WriteTFileFreeList()
Last record in the file.
EContainerFormat
For testing purposes, RNTuple data can be written into a bare file container instead of a ROOT file.
static std::unique_ptr< RNTupleFileWriter > Recreate(std::string_view ntupleName, std::string_view path, EContainerFormat containerFormat, const RNTupleWriteOptions &options)
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...
RNTuple fNTupleAnchor
Header and footer location of the ntuple, written on Commit()
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...
RNTupleSerializer::StreamerInfoMap_t fStreamerInfoMap
Set of streamer info records that should be written to the file.
static std::uint32_t SerializeUInt64(std::uint64_t val, void *buffer)
std::map< Int_t, TVirtualStreamerInfo * > StreamerInfoMap_t
static std::uint32_t DeserializeUInt64(const void *buffer, std::uint64_t &val)
Base class for all ROOT issued exceptions.
Common user-tunable settings for storing ntuples.
int GetCompression() const
bool GetUseDirectIO() const
std::uint64_t GetMaxKeySize() const
Representation of an RNTuple data set in a ROOT file.
std::uint16_t fVersionMajor
Changing the major version indicates forward incompatible changes; such changes should correspond to ...
std::uint64_t fSeekFooter
The file offset of the footer excluding the TKey part.
std::uint64_t GetLenFooter() const
std::uint64_t fMaxKeySize
The maximum size for a TKey payload. Payloads bigger than this size will be written as multiple blobs...
std::uint64_t GetNBytesHeader() const
std::uint64_t GetLenHeader() const
std::uint16_t fVersionMinor
Changing the minor version indicates new optional fields added to the RNTuple meta-data.
std::uint16_t fVersionEpoch
Version of the RNTuple binary format that the writer supports (see specification).
std::uint16_t GetVersionEpoch() const
std::uint64_t fNBytesFooter
The size of the compressed ntuple footer.
std::uint64_t fLenFooter
The size of the uncompressed ntuple footer.
std::uint64_t GetNBytesFooter() const
std::uint64_t GetMaxKeySize() const
std::uint64_t GetSeekHeader() const
std::uint64_t fLenHeader
The size of the uncompressed ntuple header.
std::uint64_t fNBytesHeader
The size of the compressed ntuple header.
std::uint16_t GetVersionMinor() const
std::uint16_t fVersionPatch
Changing the patch version indicates new backported features from newer binary format versions.
std::uint16_t GetVersionMajor() const
std::uint16_t GetVersionPatch() const
std::uint64_t GetSeekFooter() const
std::uint64_t fSeekHeader
The file offset of the header excluding the TKey part.
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
The RRawFile provides read-only access to local and remote files.
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
void TagStreamerInfo(TVirtualStreamerInfo *info) override
Mark the classindex of the current file as using this TStreamerInfo.
void SetParent(TObject *parent)
Set parent owning this buffer.
void SetBufferOffset(Int_t offset=0)
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Int_t Sizeof() const override
Return the size in bytes of the key header structure.
Int_t fVersion
Key version identifier.
Short_t fKeylen
Number of bytes for the key itself.
Long64_t fSeekKey
Location of object on file.
virtual void Create(Int_t nbytes, TFile *f=nullptr)
Create a TKey object of specified size.
TString fClassName
Object Class name.
void Streamer(TBuffer &) override
Stream all objects in the collection to or from the I/O buffer.
void Add(TObject *obj) override
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Helper templated class for swapping bytes; specializations for N={2,4,8} are provided below.
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...
std::uint64_t fSeekNTuple
std::uint64_t fSeekFileRecord