diff --git a/tree/ntuple/inc/ROOT/RMiniFile.hxx b/tree/ntuple/inc/ROOT/RMiniFile.hxx index f7614695b0067..8c1205416d09b 100644 --- a/tree/ntuple/inc/ROOT/RMiniFile.hxx +++ b/tree/ntuple/inc/ROOT/RMiniFile.hxx @@ -68,6 +68,10 @@ private: /// what happens in `RNTupleFileWriter::WriteBlob()`. std::uint64_t fMaxKeySize = 0; + /// Information about the streamer info record cache on file open from the TFile header. Used in LoadStreamerInfo. + std::uint64_t fSeekKeyInfo = 0; + std::uint64_t fNbytesKeyAndInfo = 0; + /// Used when the file container turns out to be a bare file RResult GetNTupleBare(std::string_view ntupleName); /// Used when the file turns out to be a TFile container. The ntuplePath variable is either the ntuple name @@ -96,7 +100,7 @@ public: void ReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset); /// Like ReadBuffer but returns a RResult instead of throwing. ROOT::RResult TryReadBuffer(void *buffer, size_t nbytes, std::uint64_t offset); - /// Attempts to load the streamer info from the file. + /// Load the streamer info from the file into the global list of streamer infos void LoadStreamerInfo(); std::uint64_t GetMaxKeySize() const { return fMaxKeySize; } diff --git a/tree/ntuple/inc/ROOT/RPageStorage.hxx b/tree/ntuple/inc/ROOT/RPageStorage.hxx index b670e5989a447..dfcf2d11d411c 100644 --- a/tree/ntuple/inc/ROOT/RPageStorage.hxx +++ b/tree/ntuple/inc/ROOT/RPageStorage.hxx @@ -906,10 +906,6 @@ public: /// connecting streamer fields so that emulated classes can be read. void RegisterStreamerInfos(); - /// Forces the loading of ROOT StreamerInfo from the underlying file. This currently only has an effect for - /// TFile-backed sources. - virtual void LoadStreamerInfo() = 0; - /// Creates a new PageSource using the same underlying file as this but referring to a different RNTuple, /// described by `anchorLink`. virtual std::unique_ptr OpenWithDifferentAnchor(const ROOT::Internal::RNTupleLink &anchorLink, diff --git a/tree/ntuple/inc/ROOT/RPageStorageDaos.hxx b/tree/ntuple/inc/ROOT/RPageStorageDaos.hxx index d2b017516d2ab..b5ff59bddd0e6 100644 --- a/tree/ntuple/inc/ROOT/RPageStorageDaos.hxx +++ b/tree/ntuple/inc/ROOT/RPageStorageDaos.hxx @@ -176,8 +176,6 @@ public: /// Return the object class used for user data OIDs in this ntuple. std::string GetObjectClass() const; - void LoadStreamerInfo() final; - std::unique_ptr OpenWithDifferentAnchor(const ROOT::Internal::RNTupleLink &anchorLink, const ROOT::RNTupleReadOptions &options = {}) final; }; // class RPageSourceDaos diff --git a/tree/ntuple/inc/ROOT/RPageStorageFile.hxx b/tree/ntuple/inc/ROOT/RPageStorageFile.hxx index c1881042c4ee3..d94feff68f1e7 100644 --- a/tree/ntuple/inc/ROOT/RPageStorageFile.hxx +++ b/tree/ntuple/inc/ROOT/RPageStorageFile.hxx @@ -189,8 +189,6 @@ public: std::vector> LoadClusters(std::span clusterKeys) final; - - void LoadStreamerInfo() final; }; // class RPageSourceFile } // namespace Internal diff --git a/tree/ntuple/src/RMiniFile.cxx b/tree/ntuple/src/RMiniFile.cxx index 79048d0a9f016..bd4e95fd7bfd2 100644 --- a/tree/ntuple/src/RMiniFile.cxx +++ b/tree/ntuple/src/RMiniFile.cxx @@ -723,16 +723,15 @@ std::uint64_t ROOT::Internal::RMiniFileReader::SearchInDirectory(std::uint64_t & void ROOT::Internal::RMiniFileReader::LoadStreamerInfo() { - RTFHeader fileHeader; - ReadBuffer(&fileHeader, sizeof(fileHeader), 0); - - const std::uint64_t seekKeyInfo = fileHeader.GetSeekInfo(); + if (fIsBare == 0) + return; RTFKey key; - ReadBuffer(&key, sizeof(key), seekKeyInfo); + ReadBuffer(&key, sizeof(key), fSeekKeyInfo); - const std::uint64_t nbytesInfo = fileHeader.GetNbytesInfo() - key.fKeyLen; - const std::uint64_t seekInfo = seekKeyInfo + key.fKeyLen; + R__ASSERT(fNbytesKeyAndInfo >= key.fKeyLen); + const std::uint64_t nbytesInfo = fNbytesKeyAndInfo - key.fKeyLen; + const std::uint64_t seekInfo = fSeekKeyInfo + key.fKeyLen; const std::uint32_t uncompLenInfo = key.fObjLen; auto streamerInfo = MakeUninitArray(uncompLenInfo); if (nbytesInfo == uncompLenInfo) { @@ -770,6 +769,9 @@ ROOT::RResult ROOT::Internal::RMiniFileReader::GetNTupleProper(st RTFHeader fileHeader; ReadBuffer(&fileHeader, sizeof(fileHeader), 0); + fSeekKeyInfo = fileHeader.GetSeekInfo(); + fNbytesKeyAndInfo = fileHeader.GetNbytesInfo(); + RTFKey key; RTFString name; ReadBuffer(&key, sizeof(key), fileHeader.fBEGIN); @@ -817,6 +819,7 @@ ROOT::RResult ROOT::Internal::RMiniFileReader::GetNTupleProper(st const auto objNbytes = key.GetSize() - key.fKeyLen; auto res = GetNTupleProperAtOffset(offset, objNbytes, key.fObjLen); + return res; } diff --git a/tree/ntuple/src/RNTupleMerger.cxx b/tree/ntuple/src/RNTupleMerger.cxx index 3b54445c39287..7d88c4070fc3c 100644 --- a/tree/ntuple/src/RNTupleMerger.cxx +++ b/tree/ntuple/src/RNTupleMerger.cxx @@ -1393,10 +1393,6 @@ ROOT::RResult RNTupleMerger::Merge(std::span sources, const // Merge main loop for (RPageSource *source : sources) { - // We need to make sure the streamer info from the source files is loaded otherwise we may not be able - // to build the streamer info of user-defined types unless we have their dictionaries available. - source->LoadStreamerInfo(); - source->Attach(RNTupleSerializer::EDescriptorDeserializeMode::kForWriting); auto srcDescriptor = source->GetSharedDescriptorGuard(); mergeData.fSrcDescriptor = &srcDescriptor.GetRef(); diff --git a/tree/ntuple/src/RPageStorageDaos.cxx b/tree/ntuple/src/RPageStorageDaos.cxx index 7e5651f8d6761..0e3bffc8d0c6c 100644 --- a/tree/ntuple/src/RPageStorageDaos.cxx +++ b/tree/ntuple/src/RPageStorageDaos.cxx @@ -596,11 +596,6 @@ ROOT::Experimental::Internal::RPageSourceDaos::LoadClusters(std::span ROOT::Experimental::Internal::RPageSourceDaos::OpenWithDifferentAnchor(const ROOT::Internal::RNTupleLink &, const ROOT::RNTupleReadOptions &) diff --git a/tree/ntuple/src/RPageStorageFile.cxx b/tree/ntuple/src/RPageStorageFile.cxx index 3e7ffd15eba40..effcdd4bd9a06 100644 --- a/tree/ntuple/src/RPageStorageFile.cxx +++ b/tree/ntuple/src/RPageStorageFile.cxx @@ -425,6 +425,10 @@ void ROOT::Internal::RPageSourceFile::LoadStructureImpl() // Otherwise, the page source was created by OpenFromAnchor() if (!fAnchor) { fAnchor = fReader.GetNTuple(fNTupleName).Unwrap(); + // We couple finding the RNTuple anchor to loading the streamer infos. + // If we already have the anchor, we must have opened the file before (either through TFile or by the source of + // OpenWithDifferentAnchor(), in which case we already loaded the streamer info) . + fReader.LoadStreamerInfo(); } fReader.SetMaxKeySize(fAnchor->GetMaxKeySize()); @@ -711,8 +715,3 @@ ROOT::Internal::RPageSourceFile::LoadClusters(std::span clusterK return clusters; } - -void ROOT::Internal::RPageSourceFile::LoadStreamerInfo() -{ - fReader.LoadStreamerInfo(); -} diff --git a/tree/ntuple/test/ntuple_cluster.cxx b/tree/ntuple/test/ntuple_cluster.cxx index 32808d8a0830e..6121a09d61e1e 100644 --- a/tree/ntuple/test/ntuple_cluster.cxx +++ b/tree/ntuple/test/ntuple_cluster.cxx @@ -43,7 +43,6 @@ class RPageSourceMock : public RPageSource { std::unique_ptr CloneImpl() const final { return nullptr; } void LoadPageListImpl(const ROOT::RNTupleLocator &, unsigned char *) final {} void LoadSealedPageImpl(const ROOT::RNTupleLocator &, RSealedPage &) final {} - void LoadStreamerInfo() final {} std::unique_ptr OpenWithDifferentAnchor(const ROOT::Internal::RNTupleLink &, const ROOT::RNTupleReadOptions &) final { diff --git a/tree/ntuple/test/ntuple_emulated.cxx b/tree/ntuple/test/ntuple_emulated.cxx index 013a8f1fd30bf..d61f7a5d6c84f 100644 --- a/tree/ntuple/test/ntuple_emulated.cxx +++ b/tree/ntuple/test/ntuple_emulated.cxx @@ -9,6 +9,8 @@ TEST(RNTupleEmulated, EmulatedFields_Simple) FileRaii fileGuard("test_ntuple_emulated_fields.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -32,12 +34,6 @@ TEST(RNTupleEmulated, EmulatedFields_Simple) auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "Outer_Simple").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); @@ -93,9 +89,6 @@ TEST(RNTupleEmulated, EmulatedFields_Simple) RNTupleDescriptor::RCreateModelOptions cmOpts; cmOpts.SetEmulateUnknownTypes(true); - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TClass::Init", "no dictionary for class", - /*matchFullMessage=*/false); std::unique_ptr file(TFile::Open(fileGuard.GetPath().c_str())); std::unique_ptr ntpl(file->Get("ntpl")); reader = RNTupleReader::Open(cmOpts, *ntpl); @@ -121,6 +114,8 @@ TEST(RNTupleEmulated, EmulatedFields_Vecs) FileRaii fileGuard("test_ntuple_emulated_fields_vecs.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -144,12 +139,6 @@ TEST(RNTupleEmulated, EmulatedFields_Vecs) auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("outers", "std::vector").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); @@ -222,6 +211,8 @@ TEST(RNTupleEmulated, EmulatedFields_VecsTemplatedWrapper) { FileRaii fileGuard("test_ntuple_emulated_fields_vecs_templated_wrapper.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -298,6 +289,8 @@ TEST(RNTupleEmulated, EmulatedFields_EmptyStruct) FileRaii fileGuard("test_ntuple_emulated_emptystruct.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -316,12 +309,6 @@ TEST(RNTupleEmulated, EmulatedFields_EmptyStruct) auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "Outer_EmptyStruct").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); @@ -373,6 +360,8 @@ TEST(RNTupleEmulated, EmulatedFields_EmptyVec) FileRaii fileGuard("test_ntuple_emulated_emptyvec.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -396,11 +385,6 @@ TEST(RNTupleEmulated, EmulatedFields_EmptyVec) ProcessLine("ptrInners->push_back(Inner_EmptyVec{});"); ProcessLine("ptrInners->push_back(Inner_EmptyVec{});"); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); writer.reset(); }); @@ -453,6 +437,8 @@ TEST(RNTupleEmulated, EmulatedFields_Write) FileRaii fileGuard("test_ntuple_emulated_write.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { fileGuard.PreserveFile(); @@ -476,11 +462,6 @@ TEST(RNTupleEmulated, EmulatedFields_Write) auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); writer.reset(); }); @@ -504,6 +485,8 @@ TEST(RNTupleEmulated, CollectionProxy) { FileRaii fileGuard("test_ntuple_emulated_collproxy.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + // Declare a custom type in a separate process, then write it through a custom collection proxy. // In the main process we load the generated RNTuple without having its dictionary available and we verify // we can read it (only) via field emulation (as an untyped VectorField). @@ -648,11 +631,6 @@ TEST(RNTupleEmulated, CollectionProxy) ProcessLine("pProxyC->v.clear();"); writer->Fill(); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); writer.reset(); }); @@ -692,6 +670,8 @@ TEST(RNTupleEmulated, MergeEmulated) FileRaii fileGuard2("test_ntuple_merge_emulated2.root"); FileRaii fileGuardOut("test_ntuple_merge_emulated_out.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { fileGuard1.PreserveFile(); fileGuard2.PreserveFile(); @@ -726,11 +706,6 @@ TEST(RNTupleEmulated, MergeEmulated) ProcessLine("ptr2->fInt2 = 66;"); writer2->Fill(); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); writer.reset(); writer2.reset(); }); @@ -745,9 +720,6 @@ TEST(RNTupleEmulated, MergeEmulated) } { - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.requiredDiag(kWarning, "TClass::Init", "no dictionary", /*matchFullMessage=*/false); - auto destination = std::make_unique("ntuple", fileGuardOut.GetPath(), RNTupleWriteOptions()); RNTupleMerger merger{std::move(destination)}; auto res = merger.Merge(sourcePtrs); diff --git a/tree/ntuple/test/ntuple_endian.cxx b/tree/ntuple/test/ntuple_endian.cxx index a1b22baf4adfe..9255a5d5c46ff 100644 --- a/tree/ntuple/test/ntuple_endian.cxx +++ b/tree/ntuple/test/ntuple_endian.cxx @@ -93,7 +93,6 @@ class RPageSourceMock : public RPageSource { std::unique_ptr CloneImpl() const final { return nullptr; } void LoadPageListImpl(const ROOT::RNTupleLocator &, unsigned char *) final {} void LoadSealedPageImpl(const ROOT::RNTupleLocator &, RSealedPage &) final {} - void LoadStreamerInfo() final {} std::unique_ptr OpenWithDifferentAnchor(const ROOT::Internal::RNTupleLink &, const ROOT::RNTupleReadOptions &) final diff --git a/tree/ntuple/test/ntuple_evolution_shape.cxx b/tree/ntuple/test/ntuple_evolution_shape.cxx index e06a6c46acc42..e0befde54ec88 100644 --- a/tree/ntuple/test/ntuple_evolution_shape.cxx +++ b/tree/ntuple/test/ntuple_evolution_shape.cxx @@ -114,6 +114,8 @@ TEST(RNTupleEvolution, AddedMemberObject) { FileRaii fileGuard("test_ntuple_evolution_added_member_object.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -131,12 +133,6 @@ struct AddedMemberObject { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "AddedMemberObject").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); @@ -357,6 +353,8 @@ TEST(RNTupleEvolution, RenamedMemberClass) // RNTuple currently does not support automatic schema evolution when a class is renamed. FileRaii fileGuard("test_ntuple_evolution_renamed_member_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -373,12 +371,6 @@ struct RenamedMemberClass { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "RenamedMemberClass").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for members). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); @@ -448,6 +440,8 @@ TEST(RNTupleEvolution, AddedBaseClass) { FileRaii fileGuard("test_ntuple_evolution_added_base_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -464,12 +458,6 @@ struct AddedBaseDerived : public AddedBaseIntermediate { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "AddedBaseDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); @@ -513,6 +501,8 @@ TEST(RNTupleEvolution, AddedSecondBaseClass) { FileRaii fileGuard("test_ntuple_evolution_added_second_base_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -529,12 +519,6 @@ struct AddedSecondBaseDerived : public AddedSecondBaseFirst { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "AddedSecondBaseDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); @@ -572,6 +556,8 @@ TEST(RNTupleEvolution, PrependSecondBaseClass) // automatically evolve this case, even if the member fields and on-disk columns are compatible. FileRaii fileGuard("test_ntuple_evolution_prepend_second_base_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -588,12 +574,6 @@ struct PrependSecondBaseDerived : public PrependSecondBaseFirst { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "PrependSecondBaseDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); @@ -623,6 +603,8 @@ TEST(RNTupleEvolution, AddedIntermediateClass) { FileRaii fileGuard("test_ntuple_evolution_added_intermediate_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -639,12 +621,6 @@ struct AddedIntermediateDerived : public AddedIntermediateBase { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "AddedIntermediateDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); @@ -674,6 +650,8 @@ TEST(RNTupleEvolution, RemovedBaseClass) { FileRaii fileGuard("test_ntuple_evolution_removed_base_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -693,12 +671,6 @@ struct RemovedBaseDerived : public RemovedBaseIntermediate { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "RemovedBaseDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); @@ -738,6 +710,8 @@ TEST(RNTupleEvolution, RemovedIntermediateClass) { FileRaii fileGuard("test_ntuple_evolution_removed_intermediate_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -757,12 +731,6 @@ struct RemovedIntermediateDerived : public RemovedIntermediate { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "RemovedIntermediateDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); @@ -789,6 +757,8 @@ TEST(RNTupleEvolution, RemovedSecondBaseClass) { FileRaii fileGuard("test_ntuple_evolution_removed_second_base_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -808,12 +778,6 @@ struct RemovedSecondBaseDerived : public RemovedSecondBaseFirst, public RemovedS auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "RemovedSecondBaseDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); @@ -841,6 +805,8 @@ TEST(RNTupleEvolution, RenamedBaseClass) // RNTuple currently does not support automatic schema evolution when a class is renamed. FileRaii fileGuard("test_ntuple_evolution_renamed_base_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -857,12 +823,6 @@ struct RenamedBaseDerived : public RenamedBase1 { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "RenamedBaseDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); @@ -890,6 +850,8 @@ TEST(RNTupleEvolution, RenamedIntermediateClass) // RNTuple currently does not support automatic schema evolution when a class is renamed. FileRaii fileGuard("test_ntuple_evolution_renamed_intermediate_class.root"); + EXPECT_NO_STREAMER_OR_DICTIONARY(); + ExecInFork([&] { // The child process writes the file and exits, but the file must be preserved to be read by the parent. fileGuard.PreserveFile(); @@ -909,12 +871,6 @@ struct RenamedIntermediateDerived : public RenamedIntermediate1 { auto model = RNTupleModel::Create(); model->AddField(RFieldBase::Create("f", "RenamedIntermediateDerived").Unwrap()); - // TStreamerInfo::Build will report a warning for interpreted classes (but only for base classes). - // See also https://github.com/root-project/root/issues/9371 - ROOT::TestSupport::CheckDiagsRAII diagRAII; - diagRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", - /*matchFullMessage=*/false); - auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); writer->Fill(); }); diff --git a/tree/ntuple/test/ntuple_pages.cxx b/tree/ntuple/test/ntuple_pages.cxx index 2cfea078846b7..909f091072887 100644 --- a/tree/ntuple/test/ntuple_pages.cxx +++ b/tree/ntuple/test/ntuple_pages.cxx @@ -13,7 +13,6 @@ class RPageSourceMock : public RPageSource { std::unique_ptr CloneImpl() const final { return nullptr; } void LoadPageListImpl(const ROOT::RNTupleLocator &, unsigned char *) final {} void LoadSealedPageImpl(const ROOT::RNTupleLocator &, RSealedPage &) final {} - void LoadStreamerInfo() final {} std::unique_ptr OpenWithDifferentAnchor(const ROOT::Internal::RNTupleLink &, const ROOT::RNTupleReadOptions &) final { diff --git a/tree/ntuple/test/ntuple_test.hxx b/tree/ntuple/test/ntuple_test.hxx index 32ea44985503e..1a12aa84bdd0a 100644 --- a/tree/ntuple/test/ntuple_test.hxx +++ b/tree/ntuple/test/ntuple_test.hxx @@ -150,4 +150,11 @@ void PatchRNTupleSection(std::string_view filePath, std::uint64_t sectionSeek, s std::uint64_t patchedOffsetIntoSection, const std::byte *bytesToWrite, std::size_t bytesToWriteLen, EEndianness sectionEndianness); +// TStreamerInfo::Build will report a warning for interpreted classes (but only for members). +// See also https://github.com/root-project/root/issues/9371 +#define EXPECT_NO_STREAMER_OR_DICTIONARY() \ + ROOT::TestSupport::CheckDiagsRAII diagNoStreamerOrDictRAII; \ + diagNoStreamerOrDictRAII.optionalDiag(kWarning, "TStreamerInfo::Build", "has no streamer or dictionary", false); \ + diagNoStreamerOrDictRAII.optionalDiag(kWarning, "TClass::Init", "no dictionary for class", false) + #endif