shashank created CAMEL-26287:
--------------------------------
Summary: camel-jcache - stopping a jcache endpoint closes the
caching provider, so removing one route breaks the caches of every other jcache
endpoint
Key: CAMEL-26287
URL: https://issues.apache.org/jira/browse/CAMEL-26287
Project: Camel
Issue Type: Bug
Components: camel-jcache
Reporter: shashank
Assignee: shashank
{{JCacheEndpoint.doStop}} calls {{JCacheManager.close()}}, which closes the
cache, the cache manager and the caching provider of the endpoint (main
36bebb520a63, {{JCacheManager}} lines 88-106). The provider comes from
{{Caching.getCachingProvider()}}, a JVM singleton, and the JCache API gives the
same cache manager for the same uri and the same cache for the same name: all
jcache endpoints of the JVM (and the jcache idempotent, aggregation and
key-value repositories, which use {{JCacheManager}} too) share them. Closing
the provider closes all its cache managers and caches.
An endpoint is stopped when the only route that uses it is removed (a reload, a
route template removed, JMX/controlbus), and when its CamelContext stops.
Afterwards every operation of every other jcache endpoint fails with
{{IllegalStateException: Cache operations can not be performed. The cache
closed}} (Hazelcast provider), for good: {{JCacheManager}} keeps the closed
cache. Examples:
* two routes {{to("jcache://orders")}} and {{to("jcache://sessions")}}; the
second route is removed: the first fails;
* a consumer route {{from("jcache://orders?filteredEvents=...")}} and a
producer route {{to("jcache://orders")}} (two endpoints, one cache); the
consumer route is removed: the producer fails;
* two CamelContexts in one JVM: stopping one breaks the jcache endpoints of the
other (read, not run); the same for a stopped jcache repository.
*Fix*: {{JCacheManager}} counts (JVM-wide) the managers that use each provider,
cache manager and cache it got in {{getCache()}}; {{close()}} closes each of
them only when it is the last manager that uses it, and forgets them, so a
closed manager no longer hands out a closed cache. Each manager releases only
what it counted: one whose {{getCache()}} failed (a missing cache with
{{createCacheIfNotExists=false}}) does not close the provider and cache manager
while others use them. A single endpoint still closes all three when it stops,
as before. A cache given to the {{JCacheManager(Cache)}} constructor is still
not closed. Users of the provider outside Camel's {{JCacheManager}}
(application code, {{JCachePolicy}}) are not counted, so they still see it
closed when the last jcache endpoint or repository stops.
*Tests*: new {{JCacheRemoveRouteTest}} (Hazelcast JCache provider, as the
module tests), 3 tests, all fail on main (3 runs):
{{removingARouteKeepsTheCachesOfTheOtherRoutes}} and
{{removingTheConsumerRouteOfACacheKeepsItsProducer}} with the exception above,
{{theLastManagerOfACacheClosesIt}} ({{expected: <false> but was: <true>}}: the
first of two managers closed the shared cache); and
{{JCacheManagerTest.aManagerThatCouldNotGetItsCacheDoesNotCloseTheCacheManagerOfTheOthers}},
which fails on main the same way. With the fix camel-jcache has 95 tests, 0
failures.
*How it was found*: a code sweep for endpoints whose {{doStop}} releases
something other endpoints still use, after a random lifecycle-sequence harness
found the same kind of defect in camel-disruptor.
*Affected*: main, camel-4.22.x, camel-4.18.x and camel-4.14.x (same
{{JCacheManager.close()}}; read, not run).
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)