|
30 | 30 | #include <RVersion.h> |
31 | 31 | #include <TDirectory.h> |
32 | 32 | #include <TError.h> |
| 33 | +#include <TVirtualStreamerInfo.h> |
33 | 34 |
|
34 | 35 | #include <algorithm> |
35 | 36 | #include <cstdio> |
@@ -85,6 +86,37 @@ void ROOT::Internal::RPageSinkFile::InitImpl(unsigned char *serializedHeader, st |
85 | 86 | fWriter->WriteNTupleHeader(zipBuffer.get(), szZipHeader, length); |
86 | 87 | } |
87 | 88 |
|
| 89 | +void ROOT::Internal::RPageSinkFile::UpdateSchema(const ROOT::Internal::RNTupleModelChangeset &changeset, |
| 90 | + ROOT::NTupleSize_t firstEntry) |
| 91 | +{ |
| 92 | + RPagePersistentSink::UpdateSchema(changeset, firstEntry); |
| 93 | + |
| 94 | + auto fnAddStreamerInfo = [this](const ROOT::RFieldBase *field) { |
| 95 | + const TClass *cl = nullptr; |
| 96 | + if (auto classField = dynamic_cast<const RClassField *>(field)) { |
| 97 | + cl = classField->GetClass(); |
| 98 | + } else if (auto streamerField = dynamic_cast<const RStreamerField *>(field)) { |
| 99 | + cl = streamerField->GetClass(); |
| 100 | + } |
| 101 | + if (!cl) |
| 102 | + return; |
| 103 | + |
| 104 | + auto streamerInfo = cl->GetStreamerInfo(field->GetTypeVersion()); |
| 105 | + if (!streamerInfo) { |
| 106 | + throw RException(R__FAIL(std::string("cannot get streamerInfo for ") + cl->GetName() + " [" + |
| 107 | + std::to_string(field->GetTypeVersion()) + "]")); |
| 108 | + } |
| 109 | + fInfosOfClassFields[streamerInfo->GetNumber()] = streamerInfo; |
| 110 | + }; |
| 111 | + |
| 112 | + for (const auto field : changeset.fAddedFields) { |
| 113 | + fnAddStreamerInfo(field); |
| 114 | + for (const auto &subField : *field) { |
| 115 | + fnAddStreamerInfo(&subField); |
| 116 | + } |
| 117 | + } |
| 118 | +} |
| 119 | + |
88 | 120 | inline ROOT::RNTupleLocator |
89 | 121 | ROOT::Internal::RPageSinkFile::WriteSealedPage(const RPageStorage::RSealedPage &sealedPage, std::size_t bytesPacked) |
90 | 122 | { |
@@ -244,7 +276,18 @@ ROOT::Internal::RPageSinkFile::CommitClusterGroupImpl(unsigned char *serializedP |
244 | 276 |
|
245 | 277 | void ROOT::Internal::RPageSinkFile::CommitDatasetImpl(unsigned char *serializedFooter, std::uint32_t length) |
246 | 278 | { |
247 | | - fWriter->UpdateStreamerInfos(fDescriptorBuilder.BuildStreamerInfos()); |
| 279 | + // Add the streamer info records from streamer fields: because of runtime polymorphism we may need to add additional |
| 280 | + // types not covered by the type names of the class fields |
| 281 | + for (const auto &extraTypeInfo : fDescriptorBuilder.GetDescriptor().GetExtraTypeInfoIterable()) { |
| 282 | + if (extraTypeInfo.GetContentId() != EExtraTypeInfoIds::kStreamerInfo) |
| 283 | + continue; |
| 284 | + // Ideally, we would avoid deserializing the streamer info records of the streamer fields that we just serialized. |
| 285 | + // However, this happens only once at the end of writing and only when streamer fields are used, so the |
| 286 | + // preference here is for code simplicity. |
| 287 | + fInfosOfClassFields.merge(RNTupleSerializer::DeserializeStreamerInfos(extraTypeInfo.GetContent()).Unwrap()); |
| 288 | + } |
| 289 | + fWriter->UpdateStreamerInfos(fInfosOfClassFields); |
| 290 | + |
248 | 291 | auto bufFooterZip = MakeUninitArray<unsigned char>(length); |
249 | 292 | auto szFooterZip = |
250 | 293 | RNTupleCompressor::Zip(serializedFooter, length, GetWriteOptions().GetCompression(), bufFooterZip.get()); |
|
0 commit comments