Additional fixes for std::pair's StreamerInfo handling#10230
Additional fixes for std::pair's StreamerInfo handling#10230pcanal merged 19 commits intoroot-project:masterfrom
Conversation
|
Starting build on |
|
For the record the following issue is still left: |
|
Build failed on ROOT-debian10-i386/cxx14. Failing tests:
|
|
Build failed on ROOT-ubuntu16/nortcxxmod. Failing tests:
|
|
Build failed on windows10/cxx14. Failing tests:
|
|
Starting build on |
|
Build failed on ROOT-performance-centos8-multicore/default. Failing tests:
And 7 more |
|
Build failed on ROOT-ubuntu16/nortcxxmod. Failing tests:
And 10 more |
|
Build failed on mac11/cxx17. Failing tests:
And 7 more |
bfc3736 to
8c249ba
Compare
|
Starting build on |
|
Build failed on ROOT-debian10-i386/cxx14. Failing tests: |
|
Build failed on ROOT-performance-centos8-multicore/default. Failing tests: |
|
Build failed on ROOT-ubuntu2004/soversion. Failing tests: |
|
Build failed on ROOT-ubuntu16/nortcxxmod. Failing tests: |
This is done also for multimap.
When encountering a data member of a class that is a enum or if it is use in a map or multimap, record the enum in the rootpcm.
This was a fatal typo in 9678405 pair: properly update StreamerInfo.
We already had TListOfEnumsWithLock but TListOfEnums::FindObject is used by rootcling
In the 'root_serialization' use case, we ended in TBufferFile::WriteClassBuffer with no StreamerInfo created yet for the TClass for `std::vector<float>` and thus go into the branch that creates the StreamerInfo ... However, at least in that case, the call to `BuildRealData` induced the creation of the StreamerInfo but the code in `TBufferFile::WriteClassBuffer` did not notice and thus create a second one and tried to register it in the same slot. (The actual negative side effect was only an error message and a memory leak).
This happened in a user case where the container (map) for a pair of an enum, which had not dictionary and something else that did have a dictionary.
This was happening when, inadvertently, StreamerInfo were created multiple times and then immeditately deleted (for map<enumtype_without_dict, somethinelse>)
a16f3c8 to
6189bb9
Compare
|
Starting build on |
| virtual ~TVirtualCollectionProxy() {}; | ||
|
|
||
| // Reset the info gathered from StreamerInfos and value's TClass. | ||
| virtual Bool_t Reset() { return kTRUE; }; |
There was a problem hiding this comment.
| virtual Bool_t Reset() { return kTRUE; }; | |
| virtual Bool_t Reset() { return kTRUE; } |
What does the return value indicate?
There was a problem hiding this comment.
That the reset failing somehow ... I guess this could/should be replaced by throwing an exception but this code is not using them anywhere else ....
|
|
||
| fCollectionProxy->Reset(); | ||
| TIter nextClass(gROOT->GetListOfClasses()); | ||
| while (auto acl = (TClass*)nextClass()) { |
There was a problem hiding this comment.
Really?! This can iterate through a million classes with the experiments...
There was a problem hiding this comment.
Well, only, 10s of thousands but yep ... However the case should be rare-ish this days. It requires: "load file, read data and/or manipulate the TClass and then load the library" (Note that we have a similar loop in TClass::ReplaceWith that so far as not been 'noticed').
| TIter nextClass(gROOT->GetListOfClasses()); | ||
| while (auto acl = (TClass*)nextClass()) { | ||
| if (acl == this) continue; | ||
| if (acl->fCollectionProxy && acl->fCollectionProxy->GetValueClass() == pcl) { |
There was a problem hiding this comment.
Alternatively you could flag the state of the collection proxy as "before we have authoritative info", and then reset and update in GetValueClass() when pcl's state doesn't correspond to that flag?
There was a problem hiding this comment.
I don't think it would change much. It is already functionally the case (the GetValueClass() == pcl). For fully initialized proxy this is "just" a function call and an atomic pointer load (the alternative would only, possibly, save the function call by inlining).
| } | ||
| } | ||
|
|
||
| TIter next(pcl->GetStreamerInfos()); |
There was a problem hiding this comment.
Would it not make sense to update this before telling all collection proxies to update their value class, just in case in the future we get a dependency of the proxies on the value steamer info?
There was a problem hiding this comment.
Possibly, this is a 'high' risk change (potential order of deletions and/or state change issues, etc.). So I will try it in a different PR (and there is a potential optimization with the same type of risk 5 lines above that I'll try too)
There was a problem hiding this comment.
Actually it is confirmed. The objects (ActionSequence) deleted in the CollectionProxy's Reset are pointing/using the information from the StreamerInfo (that is deleted/destroyed by the StreamerInfo's Clear).
| /// Specialize FindObject to do search for the | ||
| /// a enum just by name or create it if its not already in the list | ||
|
|
||
| TObject *TListOfEnums::FindObject(const char *name) const |
There was a problem hiding this comment.
Do other overloads of FindObject also add? I don't remember that... Maybe consider renaming to FindOrAdd()?
There was a problem hiding this comment.
They should :) ... at least for this (type) of container. Semantically 'nothing' is added, it is just delayed loading. This is a trade-off between pre-loading all enums (and actively harvesting them at each transaction) and this type of gymnastics. (i.e. the cost of avoiding this const_cast is added unused memory alllocation/retention and added (unused) run-time cost)
| TInterpreter::DeclId_t decl; | ||
| if (GetClass()) decl = gInterpreter->GetEnum(GetClass(), name); | ||
| else decl = gInterpreter->GetEnum(nullptr, name); | ||
| if (decl) result = const_cast<TListOfEnums *>(this)->Get(decl, name); |
There was a problem hiding this comment.
Eew. Can we make this function non-const?
There was a problem hiding this comment.
Not without being backward incompatible (We would probably need to expose this type rather than its base). Note: this is existing code that is just moved around.
| { | ||
| auto temp = new TListOfEnums(); | ||
| auto temp = cl->fEnums.load() ? cl->fEnums.load() : | ||
| IsFromRootCling() ? new TListOfEnums() : new TListOfEnumsWithLock(); |
There was a problem hiding this comment.
Is the lock so expensive to warrant the extra code complexity?
There was a problem hiding this comment.
Probably not, especially since the mutex are probably not even on in the IsFromRootCling. This one liners is the easiest fix and so we should remove this complexity in a different PR. See #10339 for tracking.
|
Starting build on |
This repairs crash seem in testProxiesAndCategories on the v6.24 branches and a few additional issues seen during testing.