Skip to content

Commit 4954ae0

Browse files
committed
[ntuple] Introduce RImplSimple::RSharedData
1 parent 083c3bb commit 4954ae0

2 files changed

Lines changed: 77 additions & 59 deletions

File tree

tree/ntuple/inc/ROOT/RMiniFile.hxx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,25 @@ private:
163163
std::uint64_t fBlockOffset = 0;
164164
unsigned char *fBlock = nullptr;
165165

166-
/// For the simplest cases, a C file stream can be used for writing
167-
FILE *fFile = nullptr;
168166
/// Whether the C file stream has been opened with Direct I/O, introducing alignment requirements.
169167
bool fDirectIO = false;
170-
/// Keeps track of the seek offset
171-
std::uint64_t fFilePos = 0;
172-
/// Keeps track of the next key offset
173-
std::uint64_t fKeyOffset = 0;
168+
169+
struct RSharedData {
170+
/// For the simplest cases, a C file stream can be used for writing
171+
FILE *fFile = nullptr;
172+
/// Keeps track of the seek offset
173+
std::uint64_t fFilePos = 0;
174+
/// Keeps track of the next key offset
175+
std::uint64_t fKeyOffset = 0;
176+
177+
RSharedData(FILE *file) : fFile(file) {}
178+
~RSharedData()
179+
{
180+
if (fFile)
181+
fclose(fFile);
182+
}
183+
};
184+
std::shared_ptr<RSharedData> fShared = std::make_shared<RSharedData>(nullptr);
174185
/// Keeps track of TFile control structures, which need to be updated on committing the data set
175186
std::unique_ptr<ROOT::Internal::RTFileControlBlock> fControlBlock;
176187

@@ -195,7 +206,7 @@ private:
195206
/// it must be written *before* the returned offset. (Note that the array type is purely documentation, the
196207
/// argument is actually just a pointer.)
197208
std::uint64_t ReserveBlobKey(std::size_t nbytes, std::size_t len, unsigned char keyBuffer[kBlobKeyLen] = nullptr);
198-
operator bool() const { return fFile; }
209+
operator bool() const { return fShared->fFile; }
199210
};
200211

201212
template <typename T>

tree/ntuple/src/RMiniFile.cxx

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -997,9 +997,6 @@ void ROOT::Internal::RNTupleFileWriter::RImplSimple::AllocateBuffers(std::size_t
997997

998998
ROOT::Internal::RNTupleFileWriter::RImplSimple::~RImplSimple()
999999
{
1000-
if (fFile)
1001-
fclose(fFile);
1002-
10031000
std::align_val_t blockAlign{kBlockAlign};
10041001
if (fHeaderBlock)
10051002
::operator delete[](fHeaderBlock, blockAlign);
@@ -1020,77 +1017,81 @@ int FSeek64(FILE *stream, std::int64_t offset, int origin)
10201017

10211018
void ROOT::Internal::RNTupleFileWriter::RImplSimple::Flush()
10221019
{
1020+
auto &shared = *fShared;
1021+
10231022
// Write the last partially filled block, which may still need appropriate alignment for Direct I/O.
10241023
// If it is the first block, get the updated header block.
10251024
if (fBlockOffset == 0) {
10261025
std::size_t headerBlockSize = kHeaderBlockSize;
1027-
if (headerBlockSize > fFilePos) {
1028-
headerBlockSize = fFilePos;
1026+
if (headerBlockSize > shared.fFilePos) {
1027+
headerBlockSize = shared.fFilePos;
10291028
}
10301029
memcpy(fBlock, fHeaderBlock, headerBlockSize);
10311030
}
10321031

1033-
std::size_t retval = FSeek64(fFile, fBlockOffset, SEEK_SET);
1032+
std::size_t retval = FSeek64(shared.fFile, fBlockOffset, SEEK_SET);
10341033
if (retval)
10351034
throw RException(R__FAIL(std::string("Seek failed: ") + strerror(errno)));
10361035

1037-
std::size_t lastBlockSize = fFilePos - fBlockOffset;
1036+
std::size_t lastBlockSize = shared.fFilePos - fBlockOffset;
10381037
R__ASSERT(lastBlockSize <= fBlockSize);
10391038
if (fDirectIO) {
10401039
// Round up to a multiple of kBlockAlign.
10411040
lastBlockSize += kBlockAlign - 1;
10421041
lastBlockSize = (lastBlockSize / kBlockAlign) * kBlockAlign;
10431042
R__ASSERT(lastBlockSize <= fBlockSize);
10441043
}
1045-
retval = fwrite(fBlock, 1, lastBlockSize, fFile);
1044+
retval = fwrite(fBlock, 1, lastBlockSize, shared.fFile);
10461045
if (retval != lastBlockSize)
10471046
throw RException(R__FAIL(std::string("write failed: ") + strerror(errno)));
10481047

10491048
// Write the (updated) header block, unless it was part of the write above.
10501049
if (fBlockOffset > 0) {
1051-
retval = FSeek64(fFile, 0, SEEK_SET);
1050+
retval = FSeek64(shared.fFile, 0, SEEK_SET);
10521051
if (retval)
10531052
throw RException(R__FAIL(std::string("Seek failed: ") + strerror(errno)));
10541053

1055-
retval = fwrite(fHeaderBlock, 1, kHeaderBlockSize, fFile);
1054+
retval = fwrite(fHeaderBlock, 1, kHeaderBlockSize, shared.fFile);
10561055
if (retval != RImplSimple::kHeaderBlockSize)
10571056
throw RException(R__FAIL(std::string("write failed: ") + strerror(errno)));
10581057
}
10591058

1060-
retval = fflush(fFile);
1059+
retval = fflush(shared.fFile);
10611060
if (retval)
10621061
throw RException(R__FAIL(std::string("Flush failed: ") + strerror(errno)));
10631062
}
10641063

10651064
void ROOT::Internal::RNTupleFileWriter::RImplSimple::Write(const void *buffer, size_t nbytes, std::int64_t offset)
10661065
{
1067-
R__ASSERT(fFile);
1066+
auto &shared = *fShared;
1067+
1068+
R__ASSERT(shared.fFile);
10681069
size_t retval;
1069-
if ((offset >= 0) && (static_cast<std::uint64_t>(offset) != fFilePos)) {
1070-
fFilePos = offset;
1070+
if ((offset >= 0) && (static_cast<std::uint64_t>(offset) != shared.fFilePos)) {
1071+
shared.fFilePos = offset;
10711072
}
10721073

10731074
// Keep header block to overwrite on commit.
1074-
if (fFilePos < kHeaderBlockSize) {
1075+
if (shared.fFilePos < kHeaderBlockSize) {
10751076
std::size_t headerBytes = nbytes;
1076-
if (fFilePos + headerBytes > kHeaderBlockSize) {
1077-
headerBytes = kHeaderBlockSize - fFilePos;
1077+
if (shared.fFilePos + headerBytes > kHeaderBlockSize) {
1078+
headerBytes = kHeaderBlockSize - shared.fFilePos;
10781079
}
1079-
memcpy(fHeaderBlock + fFilePos, buffer, headerBytes);
1080+
memcpy(fHeaderBlock + shared.fFilePos, buffer, headerBytes);
10801081
}
10811082

1082-
R__ASSERT(fFilePos >= fBlockOffset);
1083+
R__ASSERT(shared.fFilePos >= fBlockOffset);
10831084

10841085
while (nbytes > 0) {
1085-
std::uint64_t posInBlock = fFilePos % fBlockSize;
1086-
std::uint64_t blockOffset = fFilePos - posInBlock;
1086+
std::uint64_t posInBlock = shared.fFilePos % fBlockSize;
1087+
std::uint64_t blockOffset = shared.fFilePos - posInBlock;
10871088
if (blockOffset != fBlockOffset) {
10881089
// Write the block.
1089-
retval = FSeek64(fFile, fBlockOffset, SEEK_SET);
1090+
retval = FSeek64(shared.fFile, fBlockOffset, SEEK_SET);
10901091
if (retval)
10911092
throw RException(R__FAIL(std::string("Seek failed: ") + strerror(errno)));
10921093

1093-
retval = fwrite(fBlock, 1, fBlockSize, fFile);
1094+
retval = fwrite(fBlock, 1, fBlockSize, shared.fFile);
10941095
if (retval != fBlockSize)
10951096
throw RException(R__FAIL(std::string("write failed: ") + strerror(errno)));
10961097

@@ -1106,7 +1107,7 @@ void ROOT::Internal::RNTupleFileWriter::RImplSimple::Write(const void *buffer, s
11061107
memcpy(fBlock + posInBlock, buffer, blockSize);
11071108
buffer = static_cast<const unsigned char *>(buffer) + blockSize;
11081109
nbytes -= blockSize;
1109-
fFilePos += blockSize;
1110+
shared.fFilePos += blockSize;
11101111
}
11111112
}
11121113

@@ -1116,20 +1117,22 @@ ROOT::Internal::RNTupleFileWriter::RImplSimple::WriteKey(const void *buffer, std
11161117
const std::string &className, const std::string &objectName,
11171118
const std::string &title)
11181119
{
1120+
auto &shared = *fShared;
1121+
11191122
if (offset > 0)
1120-
fKeyOffset = offset;
1123+
shared.fKeyOffset = offset;
11211124
RTFString strClass{className};
11221125
RTFString strObject{objectName};
11231126
RTFString strTitle{title};
11241127

1125-
RTFKey key(fKeyOffset, directoryOffset, strClass, strObject, strTitle, len, nbytes);
1126-
Write(&key, key.GetHeaderSize(), fKeyOffset);
1128+
RTFKey key(shared.fKeyOffset, directoryOffset, strClass, strObject, strTitle, len, nbytes);
1129+
Write(&key, key.GetHeaderSize(), shared.fKeyOffset);
11271130
Write(&strClass, strClass.GetSize());
11281131
Write(&strObject, strObject.GetSize());
11291132
Write(&strTitle, strTitle.GetSize());
1130-
auto offsetData = fFilePos;
1133+
auto offsetData = shared.fFilePos;
11311134
// The next key starts after the data.
1132-
fKeyOffset = offsetData + nbytes;
1135+
shared.fKeyOffset = offsetData + nbytes;
11331136
if (buffer)
11341137
Write(buffer, nbytes);
11351138

@@ -1139,17 +1142,19 @@ ROOT::Internal::RNTupleFileWriter::RImplSimple::WriteKey(const void *buffer, std
11391142
std::uint64_t ROOT::Internal::RNTupleFileWriter::RImplSimple::ReserveBlobKey(std::size_t nbytes, std::size_t len,
11401143
unsigned char keyBuffer[kBlobKeyLen])
11411144
{
1145+
auto &shared = *fShared;
1146+
11421147
if (keyBuffer) {
1143-
PrepareBlobKey(fKeyOffset, nbytes, len, keyBuffer);
1148+
PrepareBlobKey(shared.fKeyOffset, nbytes, len, keyBuffer);
11441149
} else {
11451150
unsigned char localKeyBuffer[kBlobKeyLen];
1146-
PrepareBlobKey(fKeyOffset, nbytes, len, localKeyBuffer);
1147-
Write(localKeyBuffer, kBlobKeyLen, fKeyOffset);
1151+
PrepareBlobKey(shared.fKeyOffset, nbytes, len, localKeyBuffer);
1152+
Write(localKeyBuffer, kBlobKeyLen, shared.fKeyOffset);
11481153
}
11491154

1150-
auto offsetData = fKeyOffset + kBlobKeyLen;
1155+
auto offsetData = shared.fKeyOffset + kBlobKeyLen;
11511156
// The next key starts after the data.
1152-
fKeyOffset = offsetData + nbytes;
1157+
shared.fKeyOffset = offsetData + nbytes;
11531158

11541159
return offsetData;
11551160
}
@@ -1272,7 +1277,7 @@ ROOT::Internal::RNTupleFileWriter::Recreate(std::string_view ntupleName, std::st
12721277

12731278
auto writer = std::unique_ptr<RNTupleFileWriter>(new RNTupleFileWriter(ntupleName, options.GetMaxKeySize()));
12741279
RImplSimple &fileSimple = std::get<RImplSimple>(writer->fFile);
1275-
fileSimple.fFile = fileStream;
1280+
fileSimple.fShared->fFile = fileStream;
12761281
fileSimple.fDirectIO = options.GetUseDirectIO();
12771282
fileSimple.AllocateBuffers(options.GetWriteBufferSize());
12781283
writer->fFileName = fileName;
@@ -1333,8 +1338,8 @@ void ROOT::Internal::RNTupleFileWriter::Seek(std::uint64_t offset)
13331338
if (!fileSimple)
13341339
throw RException(R__FAIL("invalid attempt to seek non-simple writer"));
13351340

1336-
fileSimple->fFilePos = offset;
1337-
fileSimple->fKeyOffset = offset;
1341+
fileSimple->fShared->fFilePos = offset;
1342+
fileSimple->fShared->fKeyOffset = offset;
13381343
// The next Write() will Flush() if necessary.
13391344
}
13401345

@@ -1470,8 +1475,8 @@ ROOT::Internal::RNTupleFileWriter::ReserveBlob(size_t nbytes, size_t len, unsign
14701475
std::uint64_t offset;
14711476
if (auto *fileSimple = std::get_if<RImplSimple>(&fFile)) {
14721477
if (fIsBare) {
1473-
offset = fileSimple->fKeyOffset;
1474-
fileSimple->fKeyOffset += nbytes;
1478+
offset = fileSimple->fShared->fKeyOffset;
1479+
fileSimple->fShared->fKeyOffset += nbytes;
14751480
} else {
14761481
offset = fileSimple->ReserveBlobKey(nbytes, len, keyBuffer);
14771482
}
@@ -1525,11 +1530,11 @@ void ROOT::Internal::RNTupleFileWriter::WriteBareFileSkeleton(int defaultCompres
15251530

15261531
// Write zero-initialized ntuple to reserve the space; will be overwritten on commit
15271532
RTFNTuple ntupleOnDisk;
1528-
fileSimple.fControlBlock->fSeekNTuple = fileSimple.fFilePos;
1533+
fileSimple.fControlBlock->fSeekNTuple = fileSimple.fShared->fFilePos;
15291534
fileSimple.Write(&ntupleOnDisk, ntupleOnDisk.GetSize());
15301535
std::uint64_t checksum = 0;
15311536
fileSimple.Write(&checksum, sizeof(checksum));
1532-
fileSimple.fKeyOffset = fileSimple.fFilePos;
1537+
fileSimple.fShared->fKeyOffset = fileSimple.fShared->fFilePos;
15331538
}
15341539

15351540
void ROOT::Internal::RNTupleFileWriter::WriteTFileStreamerInfo(int compression)
@@ -1554,7 +1559,7 @@ void ROOT::Internal::RNTupleFileWriter::WriteTFileStreamerInfo(int compression)
15541559
RTFString strStreamerInfo{"StreamerInfo"};
15551560
RTFString strStreamerTitle{"Doubly linked list"};
15561561
auto &fileSimple = std::get<RImplSimple>(fFile);
1557-
fileSimple.fControlBlock->fHeader.SetSeekInfo(fileSimple.fKeyOffset);
1562+
fileSimple.fControlBlock->fHeader.SetSeekInfo(fileSimple.fShared->fKeyOffset);
15581563
auto keyLen = RTFKey(fileSimple.fControlBlock->fHeader.GetSeekInfo(), RTFHeader::kBEGIN, strTList, strStreamerInfo,
15591564
strStreamerTitle, 0)
15601565
.fKeyLen;
@@ -1572,7 +1577,7 @@ void ROOT::Internal::RNTupleFileWriter::WriteTFileStreamerInfo(int compression)
15721577
fileSimple.WriteKey(zipStreamerInfos.get(), szZipStreamerInfos, lenPayload,
15731578
fileSimple.fControlBlock->fHeader.GetSeekInfo(), RTFHeader::kBEGIN, "TList", "StreamerInfo",
15741579
"Doubly linked list");
1575-
fileSimple.fControlBlock->fHeader.SetNbytesInfo(fileSimple.fFilePos -
1580+
fileSimple.fControlBlock->fHeader.SetNbytesInfo(fileSimple.fShared->fFilePos -
15761581
fileSimple.fControlBlock->fHeader.GetSeekInfo());
15771582
}
15781583

@@ -1587,7 +1592,8 @@ void ROOT::Internal::RNTupleFileWriter::WriteTFileKeysList(std::uint64_t anchorS
15871592
RTFKey keyRNTuple(fileSimple.fControlBlock->fSeekNTuple, RTFHeader::kBEGIN, strRNTupleClass, strRNTupleName,
15881593
strEmpty, RTFNTuple::GetSizePlusChecksum(), anchorSize);
15891594

1590-
fileSimple.fControlBlock->fFileRecord.SetSeekKeys(fileSimple.fKeyOffset);
1595+
auto &fileShared = *fileSimple.fShared;
1596+
fileSimple.fControlBlock->fFileRecord.SetSeekKeys(fileShared.fKeyOffset);
15911597
RTFKeyList keyList{1};
15921598
RTFKey keyKeyList(fileSimple.fControlBlock->fFileRecord.GetSeekKeys(), RTFHeader::kBEGIN, strEmpty, strFileName,
15931599
strEmpty, keyList.GetSize() + keyRNTuple.fKeyLen);
@@ -1602,14 +1608,15 @@ void ROOT::Internal::RNTupleFileWriter::WriteTFileKeysList(std::uint64_t anchorS
16021608
fileSimple.Write(&strRNTupleName, strRNTupleName.GetSize());
16031609
fileSimple.Write(&strEmpty, strEmpty.GetSize());
16041610
fileSimple.fControlBlock->fFileRecord.fNBytesKeys =
1605-
fileSimple.fFilePos - fileSimple.fControlBlock->fFileRecord.GetSeekKeys();
1606-
fileSimple.fKeyOffset = fileSimple.fFilePos;
1611+
fileShared.fFilePos - fileSimple.fControlBlock->fFileRecord.GetSeekKeys();
1612+
fileShared.fKeyOffset = fileShared.fFilePos;
16071613
}
16081614

16091615
void ROOT::Internal::RNTupleFileWriter::WriteTFileFreeList()
16101616
{
16111617
auto &fileSimple = std::get<RImplSimple>(fFile);
1612-
fileSimple.fControlBlock->fHeader.SetSeekFree(fileSimple.fKeyOffset);
1618+
auto &fileShared = *fileSimple.fShared;
1619+
fileSimple.fControlBlock->fHeader.SetSeekFree(fileShared.fKeyOffset);
16131620
RTFString strEmpty;
16141621
RTFString strFileName{fFileName};
16151622
RTFFreeEntry freeEntry;
@@ -1619,9 +1626,9 @@ void ROOT::Internal::RNTupleFileWriter::WriteTFileFreeList()
16191626
freeEntry.Set(firstFree, std::max(2000000000ULL, ((firstFree / 1000000000ULL) + 1) * 1000000000ULL));
16201627
fileSimple.WriteKey(&freeEntry, freeEntry.GetSize(), freeEntry.GetSize(),
16211628
fileSimple.fControlBlock->fHeader.GetSeekFree(), RTFHeader::kBEGIN, "", fFileName, "");
1622-
fileSimple.fControlBlock->fHeader.SetNbytesFree(fileSimple.fFilePos -
1629+
fileSimple.fControlBlock->fHeader.SetNbytesFree(fileShared.fFilePos -
16231630
fileSimple.fControlBlock->fHeader.GetSeekFree());
1624-
fileSimple.fControlBlock->fHeader.SetEnd(fileSimple.fFilePos);
1631+
fileSimple.fControlBlock->fHeader.SetEnd(fileShared.fFilePos);
16251632
}
16261633

16271634
std::uint64_t ROOT::Internal::RNTupleFileWriter::WriteTFileNTupleKey(int compression)
@@ -1633,7 +1640,7 @@ std::uint64_t ROOT::Internal::RNTupleFileWriter::WriteTFileNTupleKey(int compres
16331640
RTFNTuple ntupleOnDisk(fNTupleAnchor);
16341641
RUInt64BE checksum{XXH3_64bits(ntupleOnDisk.GetPtrCkData(), ntupleOnDisk.GetSizeCkData())};
16351642
auto &fileSimple = std::get<RImplSimple>(fFile);
1636-
fileSimple.fControlBlock->fSeekNTuple = fileSimple.fKeyOffset;
1643+
fileSimple.fControlBlock->fSeekNTuple = fileSimple.fShared->fKeyOffset;
16371644

16381645
char keyBuf[RTFNTuple::GetSizePlusChecksum()];
16391646

@@ -1677,13 +1684,13 @@ void ROOT::Internal::RNTupleFileWriter::WriteTFileSkeleton(int defaultCompressio
16771684
fileSimple.Write(&strFileName, strFileName.GetSize());
16781685
fileSimple.Write(&strEmpty, strEmpty.GetSize());
16791686
// Will be overwritten on commit
1680-
fileSimple.fControlBlock->fSeekFileRecord = fileSimple.fFilePos;
1687+
fileSimple.fControlBlock->fSeekFileRecord = fileSimple.fShared->fFilePos;
16811688
fileSimple.Write(&fileSimple.fControlBlock->fFileRecord, fileSimple.fControlBlock->fFileRecord.GetSize());
16821689
fileSimple.Write(&uuid, uuid.GetSize());
16831690

16841691
// Padding bytes to allow the TFile record to grow for a big file
16851692
RUInt32BE padding{0};
16861693
for (int i = 0; i < 3; ++i)
16871694
fileSimple.Write(&padding, sizeof(padding));
1688-
fileSimple.fKeyOffset = fileSimple.fFilePos;
1695+
fileSimple.fShared->fKeyOffset = fileSimple.fShared->fFilePos;
16891696
}

0 commit comments

Comments
 (0)