Skip to content

[tree] Fix interaction between GetEntries and GetListOfFriends #17822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

vepadulano
Copy link
Member

@vepadulano vepadulano commented Feb 25, 2025

Fixes #17820

Full analysis of the issue follows:

  1. TChain::GetEntries calls TChain::LoadTree(TTree::kMaxEntries - 1)

  2. Internally, this will set fReadEntry == -2, due to how LoadTree works and the fact it's trying to read beyond the last entry in the chain

  3. This has an effect here

    root/tree/tree/src/TChain.cxx

    Lines 1675 to 1679 in f33985d

    if (treeReadEntry == -2) {
    // an entry after the end of the chain was requested (it usually happens when GetEntries is called)
    t->LoadTree(entry);
    } else {
    t->LoadTreeFriend(entry, this);
    where t is the current friend being traversed in the list of friends of the chain. We call t->LoadTree(TTree::kMaxEntries - 1).

  4. Inside the call to LoadTree on the friend, we reach this line

    InvalidateCurrentTree();
    where the fTree data member of the friend is invalidated.

  5. Back to the LoadTree of the main chain, these lines

    root/tree/tree/src/TChain.cxx

    Lines 1681 to 1684 in f33985d

    TTree* friend_t = t->GetTree();
    if (friend_t) {
    auto localfe = fTree->AddFriend(t, fe->GetName());
    localfe->SetBit(TFriendElement::kFromChain);
    would normally connect the fTree data member of the main chain to the current friend, so the list of friends is properly populated. But due to 4., friend->GetTree() will return nullptr so the connection won't happen.

@vepadulano vepadulano self-assigned this Feb 25, 2025
@vepadulano
Copy link
Member Author

Note that the current change apparently fixed the attached reproducer on my local machine, but evidently something is still missing. Suggestions on how to proceed are welcome!

Copy link

github-actions bot commented Feb 25, 2025

Test Results

    18 files      18 suites   4d 3h 32m 23s ⏱️
 2 723 tests  2 723 ✅ 0 💤 0 ❌
47 277 runs  47 277 ✅ 0 💤 0 ❌

Results for commit 7af23c6.

♻️ This comment has been updated with latest results.

@vepadulano vepadulano force-pushed the tchain-index-getlistoffriends branch from 57f1841 to 6c75a77 Compare February 26, 2025 23:14
@vepadulano vepadulano force-pushed the tchain-index-getlistoffriends branch 3 times, most recently from 4095d0c to 5fbb4b1 Compare February 27, 2025 17:52
@pcanal
Copy link
Member

pcanal commented Feb 27, 2025

This should also fix #17843

Fixes root-project#17820

Full analysis of the issue follows:

1. TChain::GetEntries calls TChain::LoadTree(TTree::kMaxEntries - 1)

2. Internally, this will set fReadEntry == -2, due to how LoadTree works and the
   fact it's trying to read beyond the last entry in the chain

3. This has an effect here https://github.com/root-project/root/blob/f33985dca2d6bc505e83498f7b4561ddd969be17/tree/tree/src/TChain.cxx#L1675-L1679
   where `t` is the current friend being traversed in the list of friends of the *chain*.
   We call `t->LoadTree(TTree::kMaxEntries - 1)`.

4. Inside the call to LoadTree on the friend, we reach this line
   https://github.com/root-project/root/blob/f33985dca2d6bc505e83498f7b4561ddd969be17/tree/tree/src/TChain.cxx#L1484
   where the fTree data member of the friend is invalidated.

5. Back to the LoadTree of the main chain, these lines
   https://github.com/root-project/root/blob/f33985dca2d6bc505e83498f7b4561ddd969be17/tree/tree/src/TChain.cxx#L1681-L1684
   would normally connect the fTree data member of the main chain to the current friend, so the list of friends
   is properly populated. But due to 4., `friend->GetTree()` will return nullptr so the connection won't happen.

This commit changes the implementation of TChain::GetEntries, so that
after computing the total number of entries the chain is brought back
to an invalid but recoverable state, and if the previous read entry was
at least zero, the cursor is moved to it.

Co-authored-by: Philippe Canal <[email protected]>
@vepadulano vepadulano force-pushed the tchain-index-getlistoffriends branch from 5fbb4b1 to dd06918 Compare March 3, 2025 12:25
pcanal added 2 commits March 3, 2025 14:45
Avoid calling LoadTree when it will be a no-op and especially don't undo work we wont be able to
redo
Calling GetEntriesFast is enough to know if you reach past the end (if we are in the last
file then it will return the precise number or something too large if we are far).
Calling GetEntries can move the cursor of the chain and thus change the state of the parent.
@ferdymercury
Copy link
Collaborator

ferdymercury commented Mar 4, 2025

This should also fix #17843

Thanks. I rebuilt locally ROOT in Debug mode using master + this patch but I still see the same crash.

Copy link
Member

@pcanal pcanal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@vepadulano vepadulano merged commit 1a2736d into root-project:master Mar 4, 2025
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wrong interaction between indexed TTree friend, GetEntries, GetListOfFriends
3 participants