Refactor backend library loading and rename Arrow suffix to PodioArrow - #999
Refactor backend library loading and rename Arrow suffix to PodioArrow#999arnavdham wants to merge 8 commits into
Conversation
| * Registration is expected to happen during shared library loading/startup, | ||
| * before worker threads query the registry. After registration the registry is |
There was a problem hiding this comment.
A bit misleading, the loading happens lazily on getConverter/getReader calls, so users must not use those in multi-threaded context.
There was a problem hiding this comment.
But this initialization is thread safe. Once lazy loading is complete MT is completely fine.
There was a problem hiding this comment.
Right, so it does matter when lazy loading happens. Races can occur if several threads start up and simultaneously try to initialize reader.
There was a problem hiding this comment.
We can discuss this in our meet but I think the arrowConverterLibraryLoader will only be initialsed once and as it is a local static variable it is thread safe. https://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11
There was a problem hiding this comment.
This makes sense now. We agreed, the text can be improved to specify which library this sentence is talking about (libpodioArrow or libedm4hepArrow etc)
There was a problem hiding this comment.
Better comment added.
There was a problem hiding this comment.
I think this one is not correct, libpodioArrow.so is not a data model, so registry does not get updated when that one is loaded (it may contain the main symbol for the registry).
There was a problem hiding this comment.
So I just remove libpodioArrow.so as example?
There was a problem hiding this comment.
This looks good, thank you.
|
|
||
| for (auto& lib : fs::directory_iterator(dir)) { | ||
| const auto filename = lib.path().filename().string(); | ||
| if (filename.find("Arrow") != std::string::npos && filename.find("libarrow") == std::string::npos) { |
There was a problem hiding this comment.
Why can it be either one? libarrow must come from arrow-cpp, which libpodioArrow is meant to link against, so it gets loaded as a dependency.
There was a problem hiding this comment.
I believe, we agreed not to name the library Mapper, but simply Arrow.
There was a problem hiding this comment.
Only checking for Arrow now.
|
|
||
| for (auto& lib : fs::directory_iterator(dir)) { | ||
| const auto filename = lib.path().filename().string(); | ||
| if (filename.find("Arrow") != std::string::npos) { |
There was a problem hiding this comment.
I think this is ok because of the capital A; in a view the directories in LD_LIBRARY_PATH may contain lots of libraries, and in particular libarrow.so, which doesn't match. But if there were multiple podio datamodels that means all the arrow libraries are opened. This is just a comment, since I had to think about this case and check which names are used in LCG stacks (there doesn't seem to be anything else with Arrow in their name in the top level folders).
There was a problem hiding this comment.
You could also give this a slightly less generic suffix that is less likely to clash. That might require to change parts of the code gen in some cmake macro I would assume (without having checked).
There was a problem hiding this comment.
For this to work, I think we will have to make changes downstream(edm4hep) as well so I would suggest keeping it as Arrow for simplicity.
There was a problem hiding this comment.
A more impactful improvement would be to load only a relevant library for the model(s) used in a file, which would likely also resolve this.
There was a problem hiding this comment.
I don't think getting the library would be easy. Also we don't have files right now as everything is in memory
There was a problem hiding this comment.
For this to work, I think we will have to make changes downstream(edm4hep) as well so I would suggest keeping it as Arrow for simplicity.
I don't think there has been a podio release yet with the functionality, so the most we would break at this point is some nightly builds for which we don't make too many guarantees. So if we want to make this change, now is essentially the time.
A more impactful improvement would be to load only a relevant library for the model(s) used in a file, which would likely also resolve this.
There is generally room for improvement here, see also: #403 I don't think we need to worry too much about performance here in general. There have been some interesting interactions with cvmfs and root dictionary loading, but realistically people will have only a (very) small number of datamodels to consider and even the fallback of going through LD_LIBRARY_PATH will only do a scan for matching libraries once.
There was a problem hiding this comment.
I don't think there has been a podio release yet with the functionality, so the most we would break at this point is some nightly builds for which we don't make too many guarantees. So if we want to make this change, now is essentially the time.
Would you like to suggest a name? We had ArrowMapper which I did not like at the time.
There is generally room for improvement here, see also: #403 I don't think we need to worry too much about performance here in general.
Right, my point was that loading an irrelevant Arrow library is on the same scale of a problem.
I don't think getting the library would be easy. Also we don't have files right now as everything is in memory
A library name can go to Table metadata.
There was a problem hiding this comment.
Would you like to suggest a name? We had
ArrowMapperwhich I did not like at the time.
I don't have a strong opinion on this one. One could even do PodioArrow (or any variation of that) to be very specific. Given that all the builds and environment building are pretty well automated, I don't think too many people will look at the generated library names in any case.
|
Any more comments @veprbl? Looks good to me as it is |
tmadlener
left a comment
There was a problem hiding this comment.
At least the library loading part looks like an almost copy of what we do for SIO (i.e. SIOBlockLibraryLoader is essentially ArrowConverterLibraryLoader with some string replacements). Can those two be generalized into one configurable library loader that works for both? Configuration would probably take the env variable name, a library pattern and probably some designator for the log messages.
|
|
||
| for (auto& lib : fs::directory_iterator(dir)) { | ||
| const auto filename = lib.path().filename().string(); | ||
| if (filename.find("Arrow") != std::string::npos) { |
There was a problem hiding this comment.
You could also give this a slightly less generic suffix that is less likely to clash. That might require to change parts of the code gen in some cmake macro I would assume (without having checked).
I could do this. |
tmadlener
left a comment
There was a problem hiding this comment.
Thanks for pulling out the generic bits, looks good to me.
I am wondering whether we want the fallback to LD_LIBRARY_PATH for Arrow as well. For SIO it's essentially mainly there because we need it for some backwards compatibility, which is not really a concern yet for Arrow.
So no scanning if podio_arrow_path is not set? Maybe bool allowFallbackToLDLibraryPath can be added to the constructor of BackendLibraryLoader set to true for SIO and false for arrow? @veprbl @tmadlener |
Yes, exactly. I have no strong opinion here.
If we decide to not have the fallback for arrow that would be the technical way of doing it probably. |
|
I'm not in favor of removing LD_LIBRARY_PATH. If anything, non-standard PODIO_ARROW_PATH should be retired. |
So I keep the current implementation and just change |
Let's do that, please. |
I don't think any changes in edm4hep would be necessary? Shouldn't a corresponding change in the |
https://github.com/key4hep/EDM4hep/pull/502/changes the changes made here would have to be renamed from edm4hepArrow to edm4hepPodioArrow |
|
Have renamed to PodioArrow |
|
Ah yes, missed the fact that we use the target names directly there. In that case this would need a change in EDM4hep as well. |
|
key4hep/EDM4hep#509 Change in edm4hep |
| @@ -28,11 +30,16 @@ void ArrowConverterRegistry::registerReader(const std::string& typeName, BufferR | |||
| } | |||
|
|
|||
| ArrowConverterRegistry::BufferReaderFunc ArrowConverterRegistry::getReader(const std::string& typeName) const { | |||
| loadArrowLibraries(); | |||
| auto it = m_readerRegistry.find(typeName); | |||
| if (it != m_readerRegistry.end()) { | |||
| return it->second; | |||
| } | |||
| return nullptr; | |||
| } | |||
There was a problem hiding this comment.
Sorry for being rather slow here, but IIUC, this might happen on multiple threads concurrently here. The getReader (potentially also the getConverter, but there I haven't fully understood the logic yet, I think) is called in a section which podio assumes is safe to be called from multiple threads. In SIO we load the libraries during the construction of the reader. This can't be placed into the ArrowConverterRegistry constructor because we will actually try to call into that from the loaded libraries, I think. But maybe there is some place where we have slightly less potential problems with trying to load from multiple threads.
There was a problem hiding this comment.
That was the question we had too. In the end, it seems like Arnav's implementation relies on a guarantee that static local variable initialization is thread safe in C++.
There was a problem hiding this comment.
Ah yes, good point. I missed the static assignment in the loadXYZLibraries. In that case I think threading should pose no issues and, I think this also gives us a guarantee of happening exactly once.
There was a problem hiding this comment.
So ig this can be merged now if there are no more comments?
Make Arrow mapper registration follow the same runtime-loading model as SIO, while refactoring the underlying library loading logic for both backends into a generalized, thread-safe loader.
podio::utilities::BackendLibraryLoaderused by both SIO and Arrow.ArrowtoPodioArrow(e.g.libedm4hepPodioArrow.so) to avoid potential clashes withlibarrow.soduring dynamicLD_LIBRARY_PATHscanning.BEGINRELEASENOTES
BackendLibraryLoader.PODIO_ADD_ARROWfromArrowtoPodioArrowto prevent dynamic loading collisions. Downstream projects will need to update their CMake aliases accordingly.ENDRELEASENOTES