Skip to content
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

Parallelize snap caching #31374

Merged
merged 17 commits into from
Sep 6, 2019
Merged

Conversation

troopa81
Copy link
Contributor

Description

This PR is the main (and last) PR of the proposed GRANT Snap Cache Improvements

For the record the 2 other PRs : #30947 and #31143. Second one is a prerequisite for this PR so it could work without seg fault and dead locks.

The idea of this PR is to parallelize for each layer the snap cache computing (sequential at the moment) using QtConcurrent API and to make it non blocking. As a consequence it is still possible to use QGIS even if snap cache is currently building. User can for instance start to edit node while the snap cache build is in progress.

Snaping information appears for each layer as soon as they're ready, we don't wait all layers to be ready anymore.

As a consequence, there si no progress bar anymore. Indeed, the total number of snap cache to build can vary as we move the cursor in the map.

Here is 2 videos, showing the difference between actual behavior and this PR (on a worst use case).

Actual (17 seconds to build)

snap_wo_thread

This PR (around 7 seconds to build in total)

snap_w_thread

Implementation details

Snaping informations are retrieved from QgsSnappingUtils (snapToMap) or directly from QgsPointLocator (in QgsVertexTool for instance), so I choose to parallelize in QgsPointLocator::init method.

If the QgsPointLocator needs to be updated (because the user move the cursor outside the index area of interest for instance) but is already being built, the modifications are discarded. The modifications will be taken into account next time (when cursor will move again) once the built is finished. A running QgsPointLocator cannot be modified (to avoid shared memory to be modified from different thread).

TODO

Once we agree on the general behavior, I will write some unit tests and correct existing ones.

Checklist

  • Commit messages are descriptive and explain the rationale for changes
  • Commits which fix bugs include Fixes #11111 at the bottom of the commit message
  • I have read the QGIS Coding Standards and this PR complies with them
  • New unit tests have been added for core changes
  • I have run the scripts/prepare-commit.sh script before each commit
  • I have evaluated whether it is appropriate for this PR to be backported, backport requests are left as label or comment

Copy link
Member

@wonder-sk wonder-sk left a comment

Choose a reason for hiding this comment

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

Nice to see the initial work towards better snapping cache land!

From a brief look at the code:

  • one can't simply run rebuildIndex() in a worker thread - this is dangerous and may cause crashes. One should not do anything with map layer objects in worker threads (for example, while building snap index, the map layer could get removed in the GUI and the object destroyed). For map rendering in worker threads, this is solved by doing two steps: 1. copying anything needed from layers in main thread, 2. doing the actual work in the worker thread - with safe access to everything. This is also the reason why you were getting crashes with postgres connections - the mutex lockers should not be needed if the rebuildIndex() is adjusted to be safe to be run in worker thread.
  • I think these changes break the API. Currently I can create a custom QgsPointLocator/QgsSnappingUtils in my python code and use it for spatial queries. With this PR such code would fail because the implementation would be giving me invalid results while the index is being built. I think this needs to be addressed by a new flag in QgsPointLocator/QgsSnappingUtils which would indicate whether the client code does not mind to temporarily get no results while the async index building is in progress
  • it would be good to still have the indication that snapping index is being built - maybe using a temporary message bar entry which would get hidden as soon as the indexing is done?

@m-kuhn
Copy link
Member

m-kuhn commented Aug 25, 2019

it would be good to still have the indication that snapping index is being built - maybe using a temporary message bar entry which would get hidden as soon as the indexing is done?

... or by using the task manager for this?

@wonder-sk
Copy link
Member

... or by using the task manager for this?

That would be an option as well, but how would it work if user has some other tasks running in the background - couldn't this in theory block snap index creation for extended amount of time?

@m-kuhn
Copy link
Member

m-kuhn commented Aug 25, 2019

I guess we'll need some sort of scheduler / priority handling if this is an issue.

@nyalldawson
Copy link
Collaborator

Well, that'll be an issue regardless of whether task manager is used or not. If all threads are busy, e.g. doing background tasks, then the concurrent snapping job will be delayed anyway...

@troopa81
Copy link
Contributor Author

troopa81 commented Sep 3, 2019

@wonder-sk I made the modifications so the worker thread won't access any unsafe data
344570f and add a asynchronous boolean in the API 323351e.

I also refactor the code so it use the task manager.

snap_task_manager

@troopa81 troopa81 changed the title [WIP] Parallelize snap caching Parallelize snap caching Sep 4, 2019
Copy link
Member

@wonder-sk wonder-sk left a comment

Choose a reason for hiding this comment

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

Thanks for the updates - they are looking good.

I am still a bit worried about the possible side effects of these changes. There may be existing code calling e.g. iface.mapCanvas().snappingUtils().locatorForLayer(vl).nearestVertex(...) for some operation, which would be now getting invalid matches (at least for a short amount of time), but I am unable to judge how serious this may be. So I guess let's get this merged, and in case of new issues we would add a new parameter to nearestVertex() and similar methods that would indicate whether the client code tolerates invalid matches in case the locator is having its index built.

src/core/qgspointlocator.cpp Show resolved Hide resolved
src/core/qgspointlocator.h Outdated Show resolved Hide resolved
src/core/qgspointlocator.h Outdated Show resolved Hide resolved
src/core/qgspointlocator.h Outdated Show resolved Hide resolved
src/gui/qgsmapcanvassnappingutils.cpp Outdated Show resolved Hide resolved
@troopa81
Copy link
Contributor Author

troopa81 commented Sep 6, 2019

Thanks @wonder-sk, I made the modifications

@mhugo
Copy link

mhugo commented Sep 6, 2019

We are waiting for Travis to turn green and I will merge if no objection ...

@m-kuhn
Copy link
Member

m-kuhn commented Sep 6, 2019

Can we have the final ok by @wonder-sk ? He has done an excellent job reviewing this PR, so I'd be happy to have his final ok (hopefully soon) rather than merge-for-the-sake-of-freeze.

@wonder-sk
Copy link
Member

+1 to merge when travis is green...

@troopa81
Copy link
Contributor Author

troopa81 commented Sep 6, 2019

@m-kuhn @wonder-sk hugo wan't sure to get back soon enough to merge before feature freeze. Could you merge now this PR is green?

@m-kuhn m-kuhn merged commit 87b1aa9 into qgis:master Sep 6, 2019
@m-kuhn
Copy link
Member

m-kuhn commented Sep 6, 2019

Thanks !

@nyalldawson
Copy link
Collaborator

@troopa81 This has broken some map tools, like the offset tool, which rely on snapping. Can you please investigate?

@nyalldawson
Copy link
Collaborator

Also seems to be causing crashes on exit

@troopa81
Copy link
Contributor Author

troopa81 commented Sep 9, 2019

@nyalldawson Indeed, sorry about that. I'll try to propose a quick fix

troopa81 added a commit to troopa81/QGIS that referenced this pull request Oct 17, 2019
nyalldawson pushed a commit that referenced this pull request Oct 18, 2019
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.

None yet

5 participants