Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions io/io/inc/TStreamerInfoActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ namespace TStreamerInfoActions {
void AddToOffset(Int_t delta);
void SetMissing();

/// Replace each action with `UseCacheVectorLoop` wrapping the original
/// action. Used by TBranchElement when a sub-branch must read its data
/// into the parent's on-file staging area (e.g. a split branch supplying
/// the source of a schema-evolution rule whose source is a nested
/// struct member).
void WrapAllActionsWithUseCacheVectorLoop(TVirtualStreamerInfo *info);

TActionSequence *CreateCopy();
static TActionSequence *CreateReadMemberWiseActions(TVirtualStreamerInfo *info, TVirtualCollectionProxy &proxy);
static TActionSequence *CreateReadMemberWiseActions(TVirtualStreamerInfo &info, std::unique_ptr<TLoopConfiguration> loopConfig);
Expand Down
15 changes: 15 additions & 0 deletions io/io/src/TStreamerInfoActions.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -5416,6 +5416,21 @@ void TStreamerInfoActions::TActionSequence::AddToOffset(Int_t delta)
}
}

void TStreamerInfoActions::TActionSequence::WrapAllActionsWithUseCacheVectorLoop(TVirtualStreamerInfo *info)
{
// Replace each action in the sequence with a UseCacheVectorLoop wrapping
// the original action. After this call, the actions iterate over the
// staging area pushed onto the buffer's data cache stack rather than the
// original (user) iteration range. The element offsets stored on the
// inner actions therefore must be relative to the staging element layout.

for (auto &configured : fActions) {
TConfiguredAction inner(configured);
configured.fLoopAction = UseCacheVectorLoop;
configured.fConfiguration = new TConfigurationUseCache(info, inner, /*repeat*/ kFALSE);
}
}

void TStreamerInfoActions::TActionSequence::SetMissing()
{
// Add the (potentially negative) delta to all the configuration's offset. This is used by
Expand Down
4 changes: 3 additions & 1 deletion tree/tree/inc/TBranchElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ class TBranchElement : public TBranch {
kOwnOnfileObj = BIT(19), ///< We are the owner of fOnfileObject.
kAddressSet = BIT(20), ///< The addressing set have been called for this branch
kMakeClass = BIT(21), ///< This branch has been switched to using the MakeClass Mode
kDecomposedObj = BIT(21) ///< More explicit alias for kMakeClass.
kDecomposedObj = BIT(21), ///< More explicit alias for kMakeClass.
kReadFromStagingArray = BIT(23) ///< This split sub-branch must read its data into the parent's on-file staging
///< area (e.g. for a schema-evolution rule with a nested split source).
};


Expand Down
43 changes: 43 additions & 0 deletions tree/tree/src/TBranchElement.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -3695,6 +3695,18 @@ void TBranchElement::InitializeOffsets()
dataName.Replace(dotpos,endpos-dotpos,subBranchElement->GetFullName());
}
TRealData* rd = pClass->GetRealData(dataName);
TRealData *stagingRd = nullptr;
if (!rd && fOnfileObject && fOnfileObject->fClass) {
// The data member does not exist in the user (target) class.
// If the parent owns an on-file staging area (e.g. for an I/O
// rule whose source is a struct member that has itself been
// split on disk), try the staging class. When found, the
// sub-branch will be redirected to read its bytes into the
// staging area rather than be skipped.
stagingRd = fOnfileObject->fClass->GetRealData(dataName);
if (stagingRd && stagingRd->TestBit(TRealData::kTransient))
stagingRd = nullptr;
}
if (rd && (!rd->TestBit(TRealData::kTransient) || alternateElement)) {
// -- Data member exists in the dictionary meta info, get the offset.
// If we are using an alternateElement, it is the target of a rule
Expand All @@ -3704,6 +3716,17 @@ void TBranchElement::InitializeOffsets()
// We are a rule with no specific target, it applies to the whole
// object, let's set the offset to zero
offset = 0;
} else if (stagingRd) {
// -- Staging redirect: read into the parent's on-file object.
offset = stagingRd->GetThisOffset();
subBranch->fOnfileObject = fOnfileObject;
subBranch->SetBit(kReadFromStagingArray);
// The sub-branch's read-action sequence may have been built
// earlier (before we had a chance to set the bit and the
// on-file object), so re-build it now to pick up the staging
// redirect. We defer this until after the per-sub-branch
// SetOffset call below to make sure the action offsets are
// computed against the staging element layout.
} else {
// -- No dictionary meta info for this data member, it must no
// longer exist
Expand Down Expand Up @@ -3767,6 +3790,13 @@ void TBranchElement::InitializeOffsets()
// 'localOffset', we need to remove it explicitly.
subBranch->SetOffset(offset - localOffset);
}
if (subBranch->TestBit(kReadFromStagingArray) && subBranch->fReadActionSequence) {
// The sub-branch's read action sequence may have been
// built before the staging-redirect bit was set above,
// so re-build it now to install the UseCacheVectorLoop
// wrappers (see TBranchElement::SetReadActionSequence).
subBranch->SetReadActionSequence();
}
}
} else {
// -- Set fBranchOffset for sub-branch.
Expand Down Expand Up @@ -5764,6 +5794,19 @@ void TBranchElement::SetReadActionSequence()
if (create) {
SetActionSequence(originalClass, localInfo, create, fReadActionSequence);
}

if (TestBit(kReadFromStagingArray) && fReadActionSequence && fOnfileObject) {
// The on-disk data for this split sub-branch needs to land in the
// parent's on-file staging area (e.g. it is the source of an I/O rule
// whose source member is a nested struct that has been split on disk).
// Replace each action with a UseCacheVectorLoop wrapping the original,
// so the action iterates over the staging area rather than the user
// collection. The element offsets configured on the inner actions are
// already expressed relative to the staging element layout.
TVirtualStreamerInfo *stagingInfo = fOnfileObject->fClass ? fOnfileObject->fClass->GetStreamerInfo() : nullptr;
if (stagingInfo)
fReadActionSequence->WrapAllActionsWithUseCacheVectorLoop(stagingInfo);
}
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading