[tree] fix I/O rule for vector<T> with nested split source#22375
[tree] fix I/O rule for vector<T> with nested split source#22375bendavid wants to merge 2 commits into
Conversation
When reading a split TTree branch holding vector<T>, where T has a schema- evolution rule whose source member is itself nested inside a struct, the rule fired but the new top-level member stayed at its default value because the on-file staging area was never populated. The leaf sub-branch for the nested source (e.g. ve99.fDeep.fDeepMember) could not resolve its path in the user (target) class layout, so it was marked missing and skipped at read time, leaving the staging area used by the rule uninitialized. Detect this case in TBranchElement::InitializeOffsets by also looking up the data member in the parent's on-file staging class. When found, propagate fOnfileObject to the sub-branch, flag it with the new kReadFromStagingArray bit, and re-build its read action sequence. The sequence is then wrapped with UseCacheVectorLoop so the inner action iterates over the staging area with the staging element stride and writes at the offset within the staging element, leaving the rule with a properly filled staging area to read from. Fixes root-project#19773. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
CI note: the debian13 /
I've pushed a clang-format fixup for the lint job; that workflow run (and the others on the new SHA) is currently in |
Test Results 22 files 22 suites 3d 11h 44m 1s ⏱️ For more details on these failures, see this check. Results for commit bf98b74. |
|
CI on the new SHA (bf98b74) is now green except for one unrelated test:
This |
Summary
TTreebranch holdingvector<T>whose schema-evolution rule sources a member nested inside a struct (e.g.source = "Deep fDeep"), the rule fired but the new top-level target stayed at its default because the on-file staging area was never populated.TBranchElement::InitializeOffsetsby also looking up the data member in the parent's on-file staging class. When found, propagatefOnfileObjectto the sub-branch, flag it with a newkReadFromStagingArraybit, and re-build its read action sequence.UseCacheVectorLoop(new helperTActionSequence::WrapAllActionsWithUseCacheVectorLoop) so the inner action iterates the staging area with the staging element stride and writes at the offset within the staging element — leaving the rule with a properly filled staging area to read from.Background
This is the spin-off failure noted in #19773: the fix from #19688 / 121dc61 handles a split sub-object with a rule on the value type when the rule's source is a flat member (e.g.
fOldMember → fNewMember). When the rule's source is itself a struct member that has been further split on disk (ve99.fDeep.fDeepMember), the existing logic marked the leaf sub-branch missing (becausefDeepno longer exists in the user class) and the stagingfDeepwas never filled before the rule ran.Test plan
Verified locally with the reproducer from the issue (
mini.tar.gz):vector<T>Also verified manually:
fA/fB/fCof mixed types, three rule targets) — all values populated.RenameSplitCollectionregression case (EvolutionStruct_V2::fOldMember → EvolutionStruct_V3::fNewMemberovervector<T>with split level 99) still passes.A gtest mirroring the issue reproducer should be added under
tree/tree/test/(alongsideevolution.cxxfrom #19688) — happy to add it in this PR if reviewers prefer.Some additional context: This affects reading CMS ALCARECO files produced with older (Run 2) CMSSW releases in newer Run 3-era releases which is relevant for some analysis workflows.
🤖 Generated with Claude Code