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

@Yogu

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.

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