-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Add RFC101 text: Raster dataset read-only thread-safety #10676
Conversation
74d3915
to
f7a0fba
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I am just wondering whether this approach would play well with a "native" thread safe driver (assuming that in the future we will have one of them). Would it be possible for GDALCreateThreadSafeDataset to return the original poDS in that case without cloning?
.. code-block:: c | ||
|
||
bool GDALDatasetIsThreadSafe(GDALDatasetH hDS, int nScopeFlags, | ||
CSLConstList papszOptions); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the options are required here and not by the C++ version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The C++ version could easily be extended in a backwards compatible way by adding an optional parameter if we need it, but that would break the C API, and this provision to avoid having to do a GDALDatasetIsThreadSafeEx() in the future
source dataset can be re-opened by its name (GetDescription()), which is the | ||
case for datasets opened by GDALOpenEx(). A special implementation is also | ||
made for dataset instances of the MEM driver. But, there is currently no | ||
support for creating a thread-safe dataset wrapper on on-the-fly datasets |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please elaborate the difference between MEM and on-the-fly (or give a pointer to the docs)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added "(e.g GDALTranslate() or GDALWarp() with VRT as the output driver and with an empty filename, or custom GDALDataset implementation by external code)."
doc/source/development/rfc/rfc101_raster_dataset_threadsafety.rst
Outdated
Show resolved
Hide resolved
doc/source/development/rfc/rfc101_raster_dataset_threadsafety.rst
Outdated
Show resolved
Hide resolved
``std::unique_ptr<GDALRasterBand> GDALCreateThreadSafeRasterBand(GDALRasterBand* poBand, int nOpenFlags, bool bForce)`` | ||
function that would try to use GDALCreateThreadSafeDataset() internally if it | ||
manages to identify the dataset to which the band belongs to, and otherwise would | ||
fallback to protecting calls to the wrapped band with a mutex. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a good idea to me, provided that there are not any significant performance degradations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due to the mutex, there would definitely be serious performance degradation if most of the time is spent in reading th dataset. The only point would be ease of implementation for users that don't want to have to implement both a multi-thread efficient code path and a serialized code path. For some algorithms, input pixel acquisition might not be that consuming regarding other processing done, so that could still be worthwhile. This really depends on use cases.
For For |
changed in RFC text and candidate implementation |
…set *poDS, int nScopeFlags) to return a GDALDataset*
This looks pretty good! I don't really like the implicit opening on access of the inner datasets, but it does make the APl much easier to use compared to explicit opening. It might be worth adding a line or two with the rationale for this (unless I've missed it), for anyone reading this in the future. |
* Even updating a reduced number of drivers would be extremely difficult, in | ||
particular the GeoTIFF one, due to the underlying library not being reentrant, | ||
and deferred loading strategies and many state variables being modified even | ||
by read-only APIs. And this applies to most typical drivers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be feasible for Zarr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be feasible for Zarr?
There are quite a number of state variables. For example opening a group or array adds entries to maps. Even reading pixels in a array involves some caches. So, likely much less difficult than GeoTIFF, but still not a trivial effort (and really hard to convince oneself that mutexes have been taken in all places where they should be)
I believe the rationale is given in the "design discussion" section where the "natural" alternative of making the drivers themselves thread-safe is mentioned and considered unfeasible for pretty much all drivers. Hence, unless you would protect all calls to the "master" dataset with a mutex (which doesn't scale), there isn't much choice than re-opening them |
Sorry, I meant the alternate design where you know you have N threads and call a hypothetical Of course, that would make it much harder to use with automatic parallelization ( |
|
||
vs | ||
|
||
$ time multireadtest -thread_safe -t 4 -i 100 4096x4096.tif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why this is faster, since it's doing pretty much the same thing.
Perhaps it's the effect of removing the CPLSleep
call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it's the effect of removing the
CPLSleep
call?
The removal of the CPLSleep call applies to the "multireadtest -t 4" case too. But just retrying time measurement, I can see there's significant variation during runs, and sometimes classic is faster, sometimes pretty similar, so the above conclusion is not super relevant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to "But on a 4096x4096 raster with a number of iterations reduced to 100, the timings between the default and thread_safe modes are very similar."
isn't that what is mentioned in the motivation section: "Currently, given a GDALDataset instance is not thread-safe, this requires either to deal with I/O in a single thread, or through a mutex to protect against concurrent use, or one needs to open a separate GDALDataset for each worker thread." ? |
I'm wondering if GDALGetThreadSafeDataset wouldn't be a better name than GDALCreateThreadSafeDataset ? For 2 reasons:
|
I've opted for GDALGetThreadSafeDataset |
Rendered view at https://gdal--10676.org.readthedocs.build/en/10676/development/rfc/rfc101_raster_dataset_threadsafety.html