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 a recursive update with a ConcurrentHashMap in `RefreshingAddre… #3530

Merged
merged 1 commit into from
May 12, 2021

Conversation

ikhoon
Copy link
Contributor

@ikhoon ikhoon commented May 6, 2021

…ssResolver`

Motivation:

I saw an infinite test that never terminates on our CI build with Java 8
That is caused by a recursive update which invalidates a cache when failed to query DNS recodes.
See #3528 for details

Modifications:

  • Invalidate a cache asynchronously to avoid recursive updates

Result:

…ssResolver`

Motivation:

I saw an inifite test that never terminates on our CI build with Java 8
That is caused by a recursive update when invalidating a cache on a failed DNS query.
See line#3528 for details

Modifications:

- Invalidate a cache asynchronously to avoid recursive updates

Result:

- You no longer see an infinity loop or an `IllegalStateException: Recurse update`
  when invalidating a DNS cache.
- Fixes line#3528
@ikhoon ikhoon added the defect label May 6, 2021
@ikhoon ikhoon added this to the 1.8.0 milestone May 6, 2021
@ikhoon ikhoon requested review from minwoox and trustin as code owners May 6, 2021 10:09
@codecov
Copy link

codecov bot commented May 6, 2021

Codecov Report

Merging #3530 (2206733) into master (031bc8e) will decrease coverage by 0.01%.
The diff coverage is 100.00%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #3530      +/-   ##
============================================
- Coverage     73.93%   73.91%   -0.02%     
+ Complexity    14206    14203       -3     
============================================
  Files          1245     1245              
  Lines         54187    54187              
  Branches       6929     6929              
============================================
- Hits          40061    40051      -10     
- Misses        10586    10596      +10     
  Partials       3540     3540              
Impacted Files Coverage Δ Complexity Δ
...corp/armeria/client/RefreshingAddressResolver.java 76.42% <100.00%> (+1.42%) 20.00 <1.00> (+1.00)
...om/linecorp/armeria/client/HttpSessionHandler.java 73.14% <0.00%> (-8.58%) 49.00% <0.00%> (-4.00%)
...ria/common/stream/PublisherBasedStreamMessage.java 81.87% <0.00%> (-1.88%) 20.00% <0.00%> (-1.00%)
...p/armeria/internal/common/eureka/InstanceInfo.java 51.75% <0.00%> (-0.88%) 23.00% <0.00%> (-1.00%)
.../linecorp/armeria/client/Http1ResponseDecoder.java 66.66% <0.00%> (-0.61%) 44.00% <0.00%> (-1.00%)
...a/com/linecorp/armeria/client/HttpChannelPool.java 78.41% <0.00%> (-0.28%) 67.00% <0.00%> (ø%)
...corp/armeria/common/logging/DefaultRequestLog.java 76.63% <0.00%> (+0.25%) 222.00% <0.00%> (+1.00%)
...armeria/internal/common/CancellationScheduler.java 78.09% <0.00%> (+0.41%) 86.00% <0.00%> (+1.00%)
...rmeria/common/stream/ConcatArrayStreamMessage.java 80.21% <0.00%> (+2.19%) 10.00% <0.00%> (ø%)
... and 2 more

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 031bc8e...2206733. Read the comment docs.

@ben-manes
Copy link

Alternatively, you might be able to return null from the loader to not cache the entry? My naive reading of the code leads me to believe that would have a similar effect, as the future's value is resolved to null instead.

Caffeine also offers an AsyncCache and custom expiration. I'd have hoped that some of this code could be simpler by using that, e.g. by not scheduling the invalidation yourself. In that instance the entry could be resolved as expired immediately to cause it to be evicted.

@ikhoon
Copy link
Contributor Author

ikhoon commented May 7, 2021

Alternatively, you might be able to return null from the loader to not cache the entry? My naive reading of the code leads me to believe that would have a similar effect, as the future's value is resolved to null instead.

The returned CompletableFuture is usually resolved lazily except for some error cases. In that case, it should be difficult to run null.

Caffeine also offers an AsyncCache and custom expiration. I'd have hoped that some of this code could be simpler by using that, e.g. by not scheduling the invalidation yourself. In that instance the entry could be resolved as expired immediately to cause it to be evicted.

Nice suggestion. AsyncCache and custom expiration look promising. Let us take a look how it works and is applicable.

Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

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

Thanks, @ikhoon!

@trustin
Copy link
Member

trustin commented May 10, 2021

Nice suggestion. AsyncCache and custom expiration look promising. Let us take a look how it works and is applicable.

This sounds better to me.

Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

Thanks, @ikhoon!
AsyncCache also sounds good.

@ikhoon
Copy link
Contributor Author

ikhoon commented May 11, 2021

AsyncCache also sounds good.

Filed an issue for this. #3547

@trustin
Copy link
Member

trustin commented May 12, 2021

Thanks, @ikhoon. Let's merge this first and then migrate to AsyncCache. Special thanks to @ben-manes for chiming in. 🙇

@trustin trustin merged commit 9ca805f into line:master May 12, 2021
@ikhoon ikhoon deleted the refreshing-resolver-deadlock branch May 12, 2021 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Infinity loop on cache miss in RefreshingAddressResolver
4 participants