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

fix: algorithm concurrency #761

Merged
merged 4 commits into from
Jul 7, 2020

Conversation

jeffdgr8
Copy link
Contributor

@jeffdgr8 jeffdgr8 commented Jul 2, 2020

Lock and unlock a local algorithm reference. Ensure methods operate on the same algorithm reference during lock, operation, and unlock. Ensure algorithm reference is not replaced while in use.

This crash is caused by calling ClusterManager.setAlgorithm() immediately after ClusterManager.cluster() such that the mAlgorithm reference is changed in the middle of the background cluster task. So mAlgorithm.lock() and mAlgorithm.unlock() are actually referencing first the old and then the new algorithm. The thread that called setAlgorithm() is the one that locks the algorithm and the AsyncTask background thread is the one that attempts to unlock it, resulting in the crash.

This bug was introduced in #506 when the algorithm lock was moved from the ClusterManager to the Algorithm, which allows the algorithm to be accessed by a ViewModel, outside the ClusterManager, which can be recreated as part of the view layer.

Also restores #601 to use thread pools, since this wasn't the cause for this bug.

Fixes #660 🦕

jeffdgr8 added 2 commits July 2, 2020 02:30
Ensure methods operate on the same algorithm reference during lock, operation, and unlock. Ensure algorithm reference is not replaced while in use.
@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Jul 2, 2020
@codecov
Copy link

codecov bot commented Jul 2, 2020

Codecov Report

Merging #761 into master will decrease coverage by 0.11%.
The diff coverage is 0.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #761      +/-   ##
==========================================
- Coverage   39.20%   39.09%   -0.12%     
==========================================
  Files          71       71              
  Lines        4076     4088      +12     
  Branches      609      609              
==========================================
  Hits         1598     1598              
- Misses       2375     2387      +12     
  Partials      103      103              
Impacted Files Coverage Δ
...google/maps/android/clustering/ClusterManager.java 0.00% <0.00%> (ø)
.../clustering/algo/PreCachingAlgorithmDecorator.java 0.00% <0.00%> (ø)
...ndroid/clustering/view/DefaultClusterRenderer.java 0.00% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dab0ae0...ee6d12d. Read the comment docs.

Copy link
Contributor

@arriolac arriolac 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 fixing, @jeffdgr8! I just have one question related to the chosen Executor.

@@ -79,6 +81,7 @@
private final ClusterManager<T> mClusterManager;
private final float mDensity;
private boolean mAnimate;
private final Executor mExecutor = Executors.newSingleThreadExecutor();
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason this should be single threaded vs. a larger thread pool? Making this single threaded changes the current behavior/performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, as noted by @barbeau #601 (comment) when reviewing the original PR, the implementation is effectively single threaded already, which is why I chose to use a single thread executor. There's only ever one render task in flight and potentially one queued up to run next.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it! That wasn't immediately obvious to me so this is definitely a nice improvement 👍

@@ -156,11 +162,12 @@ public void setAnimation(boolean animate) {
* {@link #cluster()} for the map to be cleared.
*/
public void clearItems() {
mAlgorithm.lock();
Algorithm<T> algorithm = getAlgorithm();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should these local declarations of Algorithm be declared final, to be safe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, good call. That makes it more explicit they should remain constant through the entire method execution.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done ee6d12d

Copy link
Contributor

@arriolac arriolac left a comment

Choose a reason for hiding this comment

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

:shipit:

@arriolac arriolac merged commit bad7771 into googlemaps:master Jul 7, 2020
googlemaps-bot pushed a commit that referenced this pull request Jul 7, 2020
## [2.0.2](v2.0.1...v2.0.2) (2020-07-07)

### Bug Fixes

* algorithm concurrency ([#761](#761)) ([bad7771](bad7771))
@jeffdgr8 jeffdgr8 deleted the fix-algorithm-concurrency branch July 8, 2020 00:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

android-map-utils: Crash in ClusterTask
4 participants