Skip to content
This repository was archived by the owner on Oct 3, 2022. It is now read-only.
This repository was archived by the owner on Oct 3, 2022. It is now read-only.

Race Condition in JCacheManager between createCache() and getCache() #41

Description

@Yogu

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 if JCacheManager.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 sure allCaches does not include the cache
  • createCache adds the cache to the ehCache-backed cacheManager
  • Now, getCache(String, Class, Class) is called with the same argument.
  • getCache tries to find the same cache in allCaches but does it does not exist
  • getCache looks in the ehCache-backed cacheManager, and finds the cache as it's already added there
  • getCache creates a new JCache based on a JCacheConfiguration with the default configuration and puts it into allCaches
  • createCache creates a new JCache with the correct configuration and tries to add it with allCaches.putIfAbsent, but it already exists
  • createCache returns the misconfigured cache that is already present in allCaches, and does not call enableStatistics or enableManagement for it.

The same problem occurs when using the second overload, getCache(String):

  • createCache is called.
  • createCache makes sure allCaches does not include the cache
  • createCache adds the cache to the ehCache-backed cacheManager
  • getCache(String) is called with the same cache name as argument.
  • getCache looks in allCaches, but does not find the cache
  • getCache calls refreshAllCaches()
  • refreshAllCaches iterates over all caches in the ehCache-backed cacheManager, creates new JCache instances for them and puts them into allCaches
  • The problem is that new JCacheConfiguration() does not properly set the managementEnabled and statisticsEnabled attributes when a ehCache CacheConfiguration is provided as argument
  • createCache again uses the already existing, but misconfigured cache and returns that, enableStatistics and enableManagement are not called.

I see three possibilities to solve this problem:

  • Use synchronized on all the methods touching or reading allCaches. This may lead to performance loss, but is the simplest to implement
  • Use ReadWriteLock so that concurrent e.g. getCache or getCacheNames can be called concurrently.
  • Lock cache names right when they are created using a concurrent set, and do not synchronize ehcaches to allCaches for those in this set. However, I don't think this will work because getCache 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions