Federico Mariani created CAMEL-24107:
----------------------------------------

             Summary: camel-xslt: stylesheet reload (contentCache=false / 
clearCachedStylesheet) is not thread-safe - stale pooled transformers keep 
serving the old stylesheet
                 Key: CAMEL-24107
                 URL: https://issues.apache.org/jira/browse/CAMEL-24107
             Project: Camel
          Issue Type: Bug
          Components: camel-xslt
    Affects Versions: 4.21.0
            Reporter: Federico Mariani
         Attachments: XsltReloadStalePooledTransformerTest.java

h3. Problem
With {{contentCache=false}}, {{XsltEndpoint.onExchange()}} calls 
{{loadResource()}} -> {{XsltBuilder.setTransformerSource()}} -> 
{{setTemplate()}} on *every exchange* with no synchronization. The same code 
path runs once after the managed {{clearCachedStylesheet}} JMX operation, which 
is advertised for production use. Several problems, in decreasing order of 
impact:

# *Stale pooled transformers survive the reload.* With {{transformerCacheSize > 
0}}, a {{Transformer}} polled from the pool before {{setTemplate()}} cleared it 
is re-offered to the pool in {{XsltBuilder.releaseTransformer()}} *after* the 
transform completes. Transformers compiled from the OLD stylesheet re-enter the 
pool and keep serving messages - the reload silently does not take effect for 
them.
# {{XsltBuilder.template}} is a plain non-volatile field written per message 
and read by every processing thread - no visibility guarantee.
# Concurrent {{factory.newTemplates()}} on the single shared 
{{TransformerFactory}} - JAXP does not guarantee {{TransformerFactory}} thread 
safety.
# {{cacheCleared}} is reset only after the load completes, so concurrent 
messages trigger redundant parallel reloads.

h3. Failure scenario
Any route using {{transformerCacheSize > 0}} together with 
{{contentCache=false}} (or an operator invoking {{clearCachedStylesheet}} while 
traffic is flowing): messages processed *after* the reload still produce output 
from the old stylesheet, indefinitely, as long as the stale transformer keeps 
cycling through the pool.

h3. Reproducer
Attached {{XsltReloadStalePooledTransformerTest.java}} - deterministic, no 
sleeps: message 1 blocks inside {{transformer.transform()}} while the 
stylesheet is reloaded (pool cleared), then completes and re-offers its 
old-stylesheet transformer; message 2 polls the pool and produces {{<one/>}} 
instead of {{<two/>}}.

h3. Fix direction
Guard reload with a lock (reload-once semantics), make {{template}} volatile, 
and invalidate pooled transformers generation-consistently with the template 
swap (e.g. tag transformers with the template generation and drop re-offered 
transformers from an older generation).
----
_This issue was researched and filed by Claude Code on behalf of [~fmariani] 
(GitHub: Croway), as part of a code review of camel-xslt and camel-xslt-saxon. 
The attached JUnit reproducer fails deterministically on current main 
(4.22.0-SNAPSHOT); place it in 
{{components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/}}._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to