-
Notifications
You must be signed in to change notification settings - Fork 48
Race Condition in JCacheManager between createCache() and getCache() #41
Comments
Hey Jan, Now on the issue itself: There is indeed an issue there. There is even two afaict:
Now, solving these two can I think be a single changeset. I'd propose a fourth alternative: How about we change the If it succeeds, that thread is now responsible for installing the actual I think this minimizes the contention, while solving the race. How does that sound to you? |
Using Futures to reserve cache names before configuring them to prevent a different thread from creating it at the same time, possibly with broken configuration
Thanks for your reply. I did my best implementing the fix with Futures as you suggested. However, I'm not quite sure if it is completely correct, especially the error handling. Please have a look at #42. |
@Yogu Thanks a lot for the PR! I'll have a look... sadly probably not today anymore, but I'll put this on my todo list for tomorrow! |
@Yogu can you please sign a contributor agreement for acceptance of your fix? |
Sorry for the delay, I had to check some things first. I mailed the signed agreement to [email protected]. |
As far as I understand, jsr-107's
CacheManager
is supposed to be thread-safe, and it is only practical for it to be.There is a possibility for the cache configuration created by
JCacheManager.createCache()
to be configured incorrectly ifJCacheManager.getCache()
is called at the same time with the same cache name. In particular, there is a realistic chance that the statistics and management beans are not created.This works as follows:
createCache
is called.createCache
makes sureallCaches
does not include the cachecreateCache
adds the cache to the ehCache-backedcacheManager
getCache(String, Class, Class)
is called with the same argument.getCache
tries to find the same cache inallCaches
but does it does not existgetCache
looks in the ehCache-backedcacheManager
, and finds the cache as it's already added theregetCache
creates a newJCache
based on aJCacheConfiguration
with the default configuration and puts it intoallCaches
createCache
creates a newJCache
with the correct configuration and tries to add it withallCaches.putIfAbsent
, but it already existscreateCache
returns the misconfigured cache that is already present inallCaches
, and does not callenableStatistics
orenableManagement
for it.The same problem occurs when using the second overload,
getCache(String)
:createCache
is called.createCache
makes sureallCaches
does not include the cachecreateCache
adds the cache to the ehCache-backedcacheManager
getCache(String)
is called with the same cache name as argument.getCache
looks inallCaches
, but does not find the cachegetCache
callsrefreshAllCaches()
refreshAllCaches
iterates over all caches in the ehCache-backedcacheManager
, creates newJCache
instances for them and puts them intoallCaches
new JCacheConfiguration()
does not properly set themanagementEnabled
andstatisticsEnabled
attributes when a ehCacheCacheConfiguration
is provided as argumentcreateCache
again uses the already existing, but misconfigured cache and returns that,enableStatistics
andenableManagement
are not called.I see three possibilities to solve this problem:
synchronized
on all the methods touching or readingallCaches
. This may lead to performance loss, but is the simplest to implementReadWriteLock
so that concurrent e.g.getCache
orgetCacheNames
can be called concurrently.allCaches
for those in this set. However, I don't think this will work becausegetCache
is expected to wait for a cache being added to be completely configured befure returning it. That's only possible with locking.I will create a pull request to fix this when we have agreed on a solution.
The text was updated successfully, but these errors were encountered: