-
Notifications
You must be signed in to change notification settings - Fork 1.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
asyncLoad
occasionally called with Object
due to race between refreshAfterWrite
and expireAfterAccess
#715
Comments
Thanks! If you can put a unit test together that would be really great. It hasn't been reported before, but your description makes sense. |
The logic to trigger the refresh reads the key but doesn't check afterwards that caffeine/caffeine/src/main/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java Lines 1265 to 1268 in fa552a5
|
Yep that is exactly what I was thinking. And also agree testing is tricky. Need to get the node to be evicted while the read is happening. Could possibly hook into the |
Actually, this theory can't be 100% correct because the value is set to |
Ah - but it could be |
right. Since those are two different fields so one could be set before the other is and cause it to pass the visibility check. Those nulls are mostly for weak/soft reference collection and not liveliness. |
When a read triggers a refresh, it captures the key and value into local variables and performs validation checks. This should have included verifying that the entry is still alive (vs retired, dead). Otherwise, the key may be an internal sentinel and the refresh will fail. This has no harmful effects due to being logged and swallowed.
I was able to write a unit test using your idea of stats as a hook. I also made the sentinel keys proper classes so that it will be easier to debug in the future. Would you be able to canary 3.1.1-SNAPSHOT? If not, I can release and we can verify as a follow-up. Thankfully this should be a benign bug since the |
When a read triggers a refresh, it captures the key and value into local variables and performs validation checks. This should have included verifying that the entry is still alive (vs retired, dead). Otherwise, the key may be an internal sentinel and the refresh will fail. This has no harmful effects due to being logged and swallowed.
Interesting. In our case the error is not being fully swallowed by caffeine because we are coalescing the refreshes and normal loads. So once an invalid key is requested to be refreshed, it is added to a batch, then every other key that is requested with it also fails because of the class cast exception because the batch is polluted. So in our case it is more than noise, although it's probably not having much of a customer impact since it is fairly infrequent. I will see if we can canary this. If not, I will definitely follow up if it still happens after we upgrade. |
Any updates? I'm all set on my side
|
I wasn't able to get to this today and will be on leave for a week, so feel free to cut the release and I will followup when I get a chance. |
thanks, will do! |
Released 3.1.1 |
@ben-manes Hey sorry for the delayed follow up on this. We finally got this out into production and it's fixed the issue. Thanks for the quick resolution! |
awesome 🥳 |
We're seeing some
ClassCastExceptions
(in our code) after our cache loaderasyncLoad
seems to be invoked with anObject
instead of the expected key typeK
. We are using the cache configured withrefreshAfterWrite
andexpireAfterAccess
and I suspect this may be happening because theexpireAfterAccess
will cause the cacheNode
to eventually be evicted and then die, which will set the Nodekey
toDEAD_STRONG_KEY
(new Object()
). At the same time, the node is being refreshed, and so theasyncLoad
method is called with the dead key.I'll take a look if I can reproduce in a unit test, but wanted to open this issue to see if you had seen this before or if we are using it wrong.
Our cache is roughly configured like this
The text was updated successfully, but these errors were encountered: