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